Index: uspace/app/bdsh/cmds/modules/bdd/bdd.c
===================================================================
--- uspace/app/bdsh/cmds/modules/bdd/bdd.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/bdsh/cmds/modules/bdd/bdd.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -102,5 +102,5 @@
 	}
 
-	rc = block_init(handle, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, handle, 2048);
 	if (rc != EOK)  {
 		printf("%s: Error initializing libblock.\n", cmdname);
Index: uspace/app/bdsh/cmds/modules/cat/cat.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -64,4 +64,6 @@
 static sysarg_t console_rows = 0;
 static bool should_quit = false;
+
+static console_ctrl_t *console = NULL;
 
 static struct option const long_options[] = {
@@ -102,18 +104,20 @@
 static void waitprompt()
 {
-	console_set_pos(fphone(stdout), 0, console_rows-1);
-	console_set_color(fphone(stdout), COLOR_BLUE, COLOR_WHITE, 0);
+	console_set_pos(console, 0, console_rows-1);
+	console_set_color(console, COLOR_BLUE, COLOR_WHITE, 0);
+	
 	printf("ENTER/SPACE/PAGE DOWN - next page, "
 	       "ESC/Q - quit, C - continue unpaged");
 	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_NORMAL);
+	
+	console_set_style(console, STYLE_NORMAL);
 }
 
 static void waitkey()
 {
-	console_event_t ev;
+	kbd_event_t ev;
 	
 	while (true) {
-		if (!console_get_event(fphone(stdin), &ev)) {
+		if (!console_get_kbd_event(console, &ev)) {
 			return;
 		}
@@ -138,7 +142,7 @@
 static void newpage()
 {
-	console_clear(fphone(stdout));
+	console_clear(console);
 	chars_remaining = console_cols;
-	lines_remaining = console_rows-1;
+	lines_remaining = console_rows - 1;
 }
 
@@ -238,4 +242,5 @@
 	console_rows = 0;
 	should_quit = false;
+	console = console_init(stdin, stdout);
 
 	argc = cli_count_args(argv);
@@ -280,5 +285,5 @@
 	
 	if (more) {
-		rc = console_get_size(fphone(stdout), &cols, &rows);
+		rc = console_get_size(console, &cols, &rows);
 		if (rc != EOK) {
 			printf("%s - cannot get console size\n", cmdname);
Index: uspace/app/bdsh/cmds/modules/kcon/kcon.c
===================================================================
--- uspace/app/bdsh/cmds/modules/kcon/kcon.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/bdsh/cmds/modules/kcon/kcon.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -32,5 +32,4 @@
 #include <stdlib.h>
 #include <io/console.h>
-#include <vfs/vfs.h>
 #include "config.h"
 #include "util.h"
@@ -42,13 +41,12 @@
 static const char *cmdname = "kcon";
 
-/* Dispays help for kcon in various levels */
+/* Display help for kcon in various levels */
 void help_cmd_kcon(unsigned int level)
 {
 	printf("`kcon' switches to the kernel debug console.\n");
-
-	if (level != HELP_SHORT) {
-		printf("Usage:  %s\n", cmdname);
-	}
-
+	
+	if (level != HELP_SHORT)
+		printf("Usage: %s\n", cmdname);
+	
 	return;
 }
@@ -57,17 +55,15 @@
 int cmd_kcon(char **argv)
 {
-	unsigned int argc;
-
-	argc = cli_count_args(argv);
-
+	unsigned int argc = cli_count_args(argv);
+	
 	if (argc != 1) {
 		printf("%s - incorrect number of arguments. Try `%s --help'\n",
-			cmdname, cmdname);
+		    cmdname, cmdname);
 		return CMD_FAILURE;
 	}
-
-	console_kcon_enable(fphone(stdout));
-
-	return CMD_SUCCESS;
+	
+	if (console_kcon())
+		return CMD_SUCCESS;
+	else
+		return CMD_FAILURE;
 }
-
Index: uspace/app/bdsh/cmds/modules/mount/mount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -51,5 +51,5 @@
 {
 	static char helpfmt[] =
-	    "Usage:  %s <fstype> <mp> <dev> [<moptions>]\n";
+	    "Usage:  %s <fstype> <mp> [dev] [<moptions>]\n";
 	if (level == HELP_SHORT) {
 		printf("'%s' mounts a file system.\n", cmdname);
@@ -66,4 +66,5 @@
 	unsigned int argc;
 	const char *mopts = "";
+	const char *dev = "";
 	int rc, c, opt_ind;
 
@@ -79,13 +80,15 @@
 	}
 
-	if ((argc < 4) || (argc > 5)) {
+	if ((argc < 3) || (argc > 5)) {
 		printf("%s: invalid number of arguments. Try `mount --help'\n",
 		    cmdname);
 		return CMD_FAILURE;
 	}
+	if (argc > 3)
+		dev = argv[3];
 	if (argc == 5)
 		mopts = argv[4];
 
-	rc = mount(argv[1], argv[2], argv[3], mopts, 0);
+	rc = mount(argv[1], argv[2], dev, mopts, 0);
 	if (rc != EOK) {
 		printf("Unable to mount %s filesystem to %s on %s (rc=%d)\n",
Index: uspace/app/bdsh/input.c
===================================================================
--- uspace/app/bdsh/input.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/bdsh/input.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -110,10 +110,10 @@
 	char *str;
 	int rc;
-
-	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_EMPHASIS);
+	
+	console_flush(tinput->console);
+	console_set_style(tinput->console, STYLE_EMPHASIS);
 	printf("%s", usr->prompt);
-	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_NORMAL);
+	console_flush(tinput->console);
+	console_set_style(tinput->console, STYLE_NORMAL);
 
 	rc = tinput_read(tinput, &str);
Index: uspace/app/blkdump/Makefile
===================================================================
--- uspace/app/blkdump/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/blkdump/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX)
+BINARY = blkdump
+
+SOURCES = \
+	blkdump.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/blkdump/blkdump.c
===================================================================
--- uspace/app/blkdump/blkdump.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/blkdump/blkdump.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+/**
+ * @file	blockdump.c
+ * @brief	Tool for dumping content of block devices
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libblock.h>
+#include <mem.h>
+#include <devmap.h>
+#include <byteorder.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#define NAME	"blkdump"
+
+static void syntax_print(void);
+static void print_hex_row(uint8_t *data, size_t length, size_t bytes_per_row);
+
+int main(int argc, char **argv)
+{
+
+	int rc;
+	char *dev_path;
+	devmap_handle_t handle;
+	size_t block_size;
+	char *endptr;
+	aoff64_t block_offset = 0;
+	aoff64_t block_count = 1;
+	aoff64_t dev_nblocks;
+	uint8_t *data;
+	size_t data_offset;
+	aoff64_t current;
+	aoff64_t limit;
+	bool relative = false;
+	
+	if (argc < 2) {
+		printf(NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+
+	--argc; ++argv;
+
+	if (str_cmp(*argv, "--relative") == 0) {
+		--argc; ++argv;
+		relative = true;
+	}
+	
+	if (str_cmp(*argv, "--offset") == 0) {
+		--argc; ++argv;
+		if (*argv == NULL) {
+			printf(NAME ": Error, argument missing (offset).\n");
+			syntax_print();
+			return 1;
+		}
+
+		block_offset = strtol(*argv, &endptr, 10);
+		if (*endptr != '\0') {
+			printf(NAME ": Error, invalid argument (offset).\n");
+			syntax_print();
+			return 1;
+		}
+
+		--argc; ++argv;
+	}
+	
+	if (str_cmp(*argv, "--count") == 0) {
+		--argc; ++argv;
+		if (*argv == NULL) {
+			printf(NAME ": Error, argument missing (count).\n");
+			syntax_print();
+			return 1;
+		}
+
+		block_count = strtol(*argv, &endptr, 10);
+		if (*endptr != '\0') {
+			printf(NAME ": Error, invalid argument (count).\n");
+			syntax_print();
+			return 1;
+		}
+
+		--argc; ++argv;
+	}
+
+	if (argc != 1) {
+		printf(NAME ": Error, unexpected argument.\n");
+		syntax_print();
+		return 1;
+	}
+
+	dev_path = *argv;
+
+	rc = devmap_device_get_handle(dev_path, &handle, 0);
+	if (rc != EOK) {
+		printf(NAME ": Error resolving device `%s'.\n", dev_path);
+		return 2;
+	}
+
+	rc = block_init(EXCHANGE_SERIALIZE, handle, 2048);
+	if (rc != EOK)  {
+		printf(NAME ": Error initializing libblock.\n");
+		return 2;
+	}
+
+	rc = block_get_bsize(handle, &block_size);
+	if (rc != EOK) {
+		printf(NAME ": Error determining device block size.\n");
+		return 2;
+	}
+
+	rc = block_get_nblocks(handle, &dev_nblocks);
+	if (rc != EOK) {
+		printf(NAME ": Warning, failed to obtain block device size.\n");
+	}
+
+	printf("Device %s has %" PRIuOFF64 " blocks, %" PRIuOFF64 " bytes each\n", dev_path, dev_nblocks, (aoff64_t) block_size);
+
+	data = malloc(block_size);
+	if (data == NULL) {
+		printf(NAME ": Error allocating data buffer of %" PRIuOFF64 " bytes", (aoff64_t) block_size);
+		block_fini(handle);
+		return 3;
+	}
+	
+	limit = block_offset + block_count;
+	for (current = block_offset; current < limit; current++) {
+		rc = block_read_direct(handle, current, 1, data);
+		if (rc != EOK) {
+			printf(NAME ": Error reading block at %" PRIuOFF64 " \n", current);
+			free(data);
+			return 3;
+		}
+		
+		printf("---- Block %" PRIuOFF64 " (at %" PRIuOFF64 ") ----\n", current, current*block_size);
+		
+		for (data_offset = 0; data_offset < block_size; data_offset += 16) {
+			if (relative) {
+				printf("%8" PRIxOFF64 ": ", (aoff64_t) data_offset);
+			}
+			else {
+				printf("%8" PRIxOFF64 ": ", current*block_size + data_offset);
+			}
+			print_hex_row(data+data_offset, block_size-data_offset, 16);
+			printf("\n");
+		}
+		printf("\n");
+	}
+	
+	free(data);
+
+	block_fini(handle);
+
+	return 0;
+}
+
+/**
+ * Print a row of 16 bytes as commonly seen in hexadecimal dumps
+ */
+static void print_hex_row(uint8_t *data, size_t length, size_t bytes_per_row) {
+	size_t pos;
+	uint8_t b;
+	
+	if (length > bytes_per_row) {
+		length = bytes_per_row;
+	}
+	
+	/* Print hexadecimal values */
+	for (pos = 0; pos < length; pos++) {
+		if (pos == length/2) {
+			printf(" ");
+		}
+		printf("%02hhX ", data[pos]);
+	}
+	
+	/* Pad with spaces if we have less than 16 bytes */
+	for (pos = length; pos < bytes_per_row; pos++) {
+		if (pos == length/2) {
+			printf(" ");
+		}
+		printf("   ");
+	}
+	
+	/* Print printable characters */
+	for (pos = 0; pos < length; pos++) {
+		if (pos == length/2) {
+			printf(" ");
+		}
+		b = data[pos];
+		if (b >= 32 && b < 128) {
+			putchar(b);
+		}
+		else {
+			putchar('.');
+		}
+	}
+}
+
+static void syntax_print(void)
+{
+	printf("syntax: blkdump [--relative] [--offset <num_blocks>] [--count <num_blocks>] <device_name>\n");
+}
+
+/**
+ * @}
+ */
Index: uspace/app/bnchmark/Makefile
===================================================================
--- uspace/app/bnchmark/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/bnchmark/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2011 Martin Sucha
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+BINARY = bnchmark
+
+SOURCES = \
+	bnchmark.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/bnchmark/bnchmark.c
===================================================================
--- uspace/app/bnchmark/bnchmark.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/bnchmark/bnchmark.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup test
+ * @{
+ */
+
+/**
+ * @file	bnchmark.c
+ * This program measures time for various actions and writes the results
+ * to a file.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <mem.h>
+#include <devmap.h>
+#include <byteorder.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <time.h>
+#include <dirent.h>
+
+#define NAME	"bnchmark"
+#define BUFSIZE 8096
+#define MBYTE (1024*1024)
+
+typedef int(*measure_func_t)(void *);
+typedef unsigned long umseconds_t; /* milliseconds */
+
+static void syntax_print(void);
+
+static int measure(measure_func_t fn, void* data, umseconds_t *result)
+{
+	struct timeval start_time;
+	int rc;
+	rc = gettimeofday(&start_time, NULL);
+	if (rc != EOK) {
+		fprintf(stderr, "gettimeofday failed\n");
+		return rc;
+	}
+	
+	rc = fn(data);
+	if (rc != EOK) {
+		fprintf(stderr, "measured function failed\n");
+		return rc;
+	}
+
+	struct timeval final_time;
+	rc = gettimeofday(&final_time, NULL);
+	if (rc != EOK) {
+		fprintf(stderr, "gettimeofday failed\n");
+		return rc;
+	}
+	
+	/* Calculate time difference in milliseconds */
+	*result = ((final_time.tv_usec - start_time.tv_usec) / 1000) +
+	    ((final_time.tv_sec - start_time.tv_sec) * 1000);
+	return EOK;
+}
+
+static int sequential_read_file(void *data)
+{
+	char *path = (char *) data;
+	char *buf = malloc(BUFSIZE);
+
+	if (buf == NULL) {
+		return ENOMEM;
+	}
+	
+	FILE *file = fopen(path, "r");
+	if (file == NULL) {
+		fprintf(stderr, "Failed opening file: %s\n", path);
+		free(buf);
+		return EIO;
+	}
+	
+	while (!feof(file)) {
+		fread(buf, 1, BUFSIZE, file);
+		if (ferror(file)) {
+			fprintf(stderr, "Failed reading file\n");
+			fclose(file);
+			free(buf);
+			return EIO;
+		}
+	}
+	
+	fclose(file);
+	free(buf);
+	return EOK;
+}
+
+static int sequential_read_dir(void *data)
+{
+	char *path = (char *) data;
+	
+	DIR *dir = opendir(path);
+	if (dir == NULL) {
+		fprintf(stderr, "Failed opening directory: %s\n", path);
+		return EIO;
+	}
+
+	struct dirent *dp;
+	
+	while ((dp = readdir(dir))) {
+		/* Do nothing */
+	}
+	
+	closedir(dir);
+	return EOK;
+}
+
+int main(int argc, char **argv)
+{
+	int rc;
+	umseconds_t milliseconds_taken;
+	char *path = NULL;
+	measure_func_t fn = NULL;
+	int iteration;
+	int iterations;
+	char *log_str = NULL;
+	char *test_type = NULL;
+	char *endptr;
+	
+	if (argc < 5) {
+		fprintf(stderr, NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	if (argc > 5) {
+		fprintf(stderr, NAME ": Error, too many arguments.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	// Skip program name
+	--argc; ++argv;
+
+	iterations = strtol(*argv, &endptr, 10);
+	if (*endptr != '\0') {
+		printf(NAME ": Error, invalid argument (iterations).\n");
+		syntax_print();
+		return 1;
+	}
+	
+	--argc; ++argv;
+	test_type = *argv;
+
+	--argc; ++argv;
+	log_str = *argv;
+
+	--argc; ++argv;
+	path = *argv;
+	
+	if (str_cmp(test_type, "sequential-file-read") == 0) {
+		fn = sequential_read_file;
+	}
+	else if (str_cmp(test_type, "sequential-dir-read") == 0) {
+		fn = sequential_read_dir;
+	}
+	else {
+		fprintf(stderr, "Error, unknown test type\n");
+		syntax_print();
+		return 1;
+	}
+
+	for (iteration = 0; iteration < iterations; iteration++) {
+		rc = measure(fn, path, &milliseconds_taken);
+		if (rc != EOK) {
+			fprintf(stderr, "Error %d\n", rc);
+			return 1;
+		}
+	
+		printf("%s;%s;%s;%lu;ms\n", test_type, path, log_str, milliseconds_taken);
+	}
+
+	return 0;
+}
+
+
+static void syntax_print(void)
+{
+	fprintf(stderr, "syntax: " NAME " <iterations> <test type> <log-str> <path>\n");
+	fprintf(stderr, "  <iterations>    number of times to run a given test\n");
+	fprintf(stderr, "  <test-type>     one of:\n");
+	fprintf(stderr, "                    sequential-file-read\n");
+	fprintf(stderr, "                    sequential-dir-read\n");
+	fprintf(stderr, "  <log-str>       a string to attach to results\n");
+	fprintf(stderr, "  <path>          file/directory to use for testing\n");
+}
+
+/**
+ * @}
+ */
Index: uspace/app/edit/edit.c
===================================================================
--- uspace/app/edit/edit.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/edit/edit.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -94,5 +94,5 @@
 } doc_t;
 
-static int con;
+static console_ctrl_t *con;
 static doc_t doc;
 static bool done;
@@ -115,7 +115,7 @@
 static void cursor_setvis(bool visible);
 
-static void key_handle_unmod(console_event_t const *ev);
-static void key_handle_ctrl(console_event_t const *ev);
-static void key_handle_shift(console_event_t const *ev);
+static void key_handle_unmod(kbd_event_t const *ev);
+static void key_handle_ctrl(kbd_event_t const *ev);
+static void key_handle_shift(kbd_event_t const *ev);
 static void key_handle_movement(unsigned int key, bool shift);
 
@@ -158,5 +158,5 @@
 int main(int argc, char *argv[])
 {
-	console_event_t ev;
+	kbd_event_t ev;
 	coord_t coord;
 	bool new_file;
@@ -164,5 +164,5 @@
 	spt_t pt;
 
-	con = fphone(stdout);
+	con = console_init(stdin, stdout);
 	console_clear(con);
 
@@ -219,5 +219,5 @@
 
 	while (!done) {
-		console_get_event(con, &ev);
+		console_get_kbd_event(con, &ev);
 		pane.rflags = 0;
 
@@ -277,5 +277,5 @@
 
 /** Handle key without modifier. */
-static void key_handle_unmod(console_event_t const *ev)
+static void key_handle_unmod(kbd_event_t const *ev)
 {
 	switch (ev->key) {
@@ -320,5 +320,5 @@
 
 /** Handle Shift-key combination. */
-static void key_handle_shift(console_event_t const *ev)
+static void key_handle_shift(kbd_event_t const *ev)
 {
 	switch (ev->key) {
@@ -344,5 +344,5 @@
 
 /** Handle Ctrl-key combination. */
-static void key_handle_ctrl(console_event_t const *ev)
+static void key_handle_ctrl(kbd_event_t const *ev)
 {
 	switch (ev->key) {
@@ -497,5 +497,5 @@
 static char *filename_prompt(char const *prompt, char const *init_value)
 {
-	console_event_t ev;
+	kbd_event_t ev;
 	char *str;
 	wchar_t buffer[INFNAME_MAX_LEN + 1];
@@ -517,5 +517,5 @@
 
 	while (!done) {
-		console_get_event(con, &ev);
+		console_get_kbd_event(con, &ev);
 
 		if (ev.type == KEY_PRESS) {
@@ -531,5 +531,5 @@
 					if (nc > 0) {
 						putchar('\b');
-						fflush(stdout);
+						console_flush(con);
 						--nc;
 					}
@@ -541,5 +541,5 @@
 					if (ev.c >= 32 && nc < max_len) {
 						putchar(ev.c);
-						fflush(stdout);
+						console_flush(con);
 						buffer[nc++] = ev.c;
 					}
@@ -689,5 +689,5 @@
 		for (j = 0; j < scr_columns; ++j)
 			putchar(' ');
-		fflush(stdout);
+		console_flush(con);
 	}
 
@@ -757,7 +757,7 @@
 		if (coord_cmp(&csel_start, &rbc) <= 0 &&
 		    coord_cmp(&rbc, &csel_end) < 0) {
-			fflush(stdout);
+			console_flush(con);
 			console_set_style(con, STYLE_SELECTED);
-			fflush(stdout);
+			console_flush(con);
 		}
 
@@ -768,13 +768,13 @@
 		while (pos < size) {
 			if ((csel_start.row == rbc.row) && (csel_start.column == s_column)) {
-				fflush(stdout);
+				console_flush(con);
 				console_set_style(con, STYLE_SELECTED);
-				fflush(stdout);
+				console_flush(con);
 			}
 	
 			if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
-				fflush(stdout);
+				console_flush(con);
 				console_set_style(con, STYLE_NORMAL);
-				fflush(stdout);
+				console_flush(con);
 			}
 	
@@ -794,7 +794,7 @@
 
 		if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
-			fflush(stdout);
+			console_flush(con);
 			console_set_style(con, STYLE_NORMAL);
-			fflush(stdout);
+			console_flush(con);
 		}
 
@@ -808,5 +808,5 @@
 		for (j = 0; j < fill; ++j)
 			putchar(' ');
-		fflush(stdout);
+		console_flush(con);
 		console_set_style(con, STYLE_NORMAL);
 	}
@@ -833,5 +833,5 @@
 	int pos = scr_columns - 1 - n;
 	printf("%*s", pos, "");
-	fflush(stdout);
+	console_flush(con);
 	console_set_style(con, STYLE_NORMAL);
 
@@ -1158,5 +1158,5 @@
 	int pos = -(scr_columns - 3);
 	printf(" %*s ", pos, str);
-	fflush(stdout);
+	console_flush(con);
 	console_set_style(con, STYLE_NORMAL);
 
Index: uspace/app/ext2info/Makefile
===================================================================
--- uspace/app/ext2info/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/ext2info/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBEXT2_PREFIX)/libext2.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBEXT2_PREFIX)
+BINARY = ext2info
+
+SOURCES = \
+	ext2info.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/ext2info/ext2info.c
===================================================================
--- uspace/app/ext2info/ext2info.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/ext2info/ext2info.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,624 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+/**
+ * @file	ext2info.c
+ * @brief	Tool for displaying information about ext2 filesystem
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libblock.h>
+#include <mem.h>
+#include <devmap.h>
+#include <byteorder.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <libext2.h>
+#include <assert.h>
+
+#define NAME	"ext2info"
+
+static void syntax_print(void);
+static void print_superblock(ext2_superblock_t *);
+static void print_block_groups(ext2_filesystem_t *);
+static void print_block_group(ext2_block_group_t *);
+static void print_inode_by_number(ext2_filesystem_t *, uint32_t, bool, uint32_t,
+    bool, bool);
+static void print_data(unsigned char *, size_t);
+static void print_inode(ext2_filesystem_t *, ext2_inode_t *, bool);
+static void print_inode_data(ext2_filesystem_t *, ext2_inode_t *, uint32_t);
+static void print_directory_contents(ext2_filesystem_t *, ext2_inode_ref_t *);
+
+#define ARG_SUPERBLOCK 1
+#define ARG_BLOCK_GROUPS 2
+#define ARG_INODE 4
+#define ARG_NO_CHECK 8
+#define ARG_INODE_DATA 16
+#define ARG_INODE_LIST 32
+#define ARG_INODE_BLOCKS 64
+#define ARG_COMMON (ARG_SUPERBLOCK)
+#define ARG_ALL 127
+
+
+int main(int argc, char **argv)
+{
+
+	int rc;
+	char *endptr;
+	char *dev_path;
+	devmap_handle_t handle;
+	ext2_filesystem_t filesystem;
+	int arg_flags;
+	uint32_t inode = 0;
+	uint32_t inode_data = 0;
+	
+	arg_flags = 0;
+	
+	if (argc < 2) {
+		printf(NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	/* Skip program name */
+	--argc; ++argv;
+	
+	if (argc > 0 && str_cmp(*argv, "--no-check") == 0) {
+		--argc; ++argv;
+		arg_flags |= ARG_NO_CHECK;
+	}
+	
+	if (argc > 0 && str_cmp(*argv, "--superblock") == 0) {
+		--argc; ++argv;
+		arg_flags |= ARG_SUPERBLOCK;
+	}
+	
+	if (argc > 0 && str_cmp(*argv, "--block-groups") == 0) {
+		--argc; ++argv;
+		arg_flags |= ARG_BLOCK_GROUPS;
+	}
+	
+	if (argc > 0 && str_cmp(*argv, "--inode") == 0) {
+		--argc; ++argv;
+		if (argc == 0) {
+			printf(NAME ": Argument expected for --inode\n");
+			return 2;
+		}
+		
+		inode = strtol(*argv, &endptr, 10);
+		if (*endptr != '\0') {
+			printf(NAME ": Error, invalid argument for --inode.\n");
+			syntax_print();
+			return 1;
+		}
+		
+		arg_flags |= ARG_INODE;
+		--argc; ++argv;
+		
+		if (argc > 0 && str_cmp(*argv, "--blocks") == 0) {
+			--argc; ++argv;
+			arg_flags |= ARG_INODE_BLOCKS;
+		}
+		
+		if (argc > 0 && str_cmp(*argv, "--data") == 0) {
+			--argc; ++argv;
+			if (argc == 0) {
+				printf(NAME ": Argument expected for --data\n");
+				return 2;
+			}
+			
+			inode_data = strtol(*argv, &endptr, 10);
+			if (*endptr != '\0') {
+				printf(NAME ": Error, invalid argument for --data.\n");
+				syntax_print();
+				return 1;
+			}
+			
+			arg_flags |= ARG_INODE_DATA;
+			--argc; ++argv;
+		}
+		
+		if (argc > 0 && str_cmp(*argv, "--list") == 0) {
+			--argc; ++argv;
+			arg_flags |= ARG_INODE_LIST;
+		}
+	}
+
+	if (argc < 1) {
+		printf(NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+	else if (argc > 1) {
+		printf(NAME ": Error, unexpected argument.\n");
+		syntax_print();
+		return 1;
+	}
+	assert(argc == 1);
+	
+	/* Display common things by default */
+	if ((arg_flags & ARG_ALL) == 0) {
+		arg_flags = ARG_COMMON;
+	}
+
+	dev_path = *argv;
+
+	rc = devmap_device_get_handle(dev_path, &handle, 0);
+	if (rc != EOK) {
+		printf(NAME ": Error resolving device `%s'.\n", dev_path);
+		return 2;
+	}
+
+	rc = ext2_filesystem_init(&filesystem, handle);
+	if (rc != EOK)  {
+		printf(NAME ": Error initializing libext2.\n");
+		return 3;
+	}
+	
+	rc = ext2_filesystem_check_sanity(&filesystem);
+	if (rc != EOK) {
+		printf(NAME ": Filesystem did not pass sanity check.\n");
+		if (!(arg_flags & ARG_NO_CHECK)) {
+			return 3;
+		}
+	}
+	
+	if (arg_flags & ARG_SUPERBLOCK) {
+		print_superblock(filesystem.superblock);
+	}
+	
+	if (arg_flags & ARG_BLOCK_GROUPS) {
+		print_block_groups(&filesystem);
+	}
+	
+	if (arg_flags & ARG_INODE) {
+		print_inode_by_number(&filesystem, inode, arg_flags & ARG_INODE_DATA,
+		    inode_data, arg_flags & ARG_INODE_LIST,
+		    arg_flags & ARG_INODE_BLOCKS);
+	}
+
+	ext2_filesystem_fini(&filesystem);
+
+	return 0;
+}
+
+
+static void syntax_print(void)
+{
+	printf("syntax: ext2info [--no-check] [--superblock] [--block-groups] "
+	    "[--inode <i-number> [--blocks] [--data <block-number>] [--list]] "
+	    "<device_name>\n");
+}
+
+static void print_superblock(ext2_superblock_t *superblock)
+{
+	uint16_t magic;
+	uint32_t first_block;
+	uint32_t block_size;
+	uint32_t fragment_size;
+	uint32_t blocks_per_group;
+	uint32_t fragments_per_group;
+	uint32_t rev_major;
+	uint16_t rev_minor;
+	uint16_t state;
+	uint32_t first_inode;
+	uint16_t inode_size;
+	uint32_t total_blocks;
+	uint32_t reserved_blocks;
+	uint32_t free_blocks;
+	uint32_t total_inodes;
+	uint32_t free_inodes;	
+	uint32_t os;
+	
+	int pos;
+	unsigned char c;
+	
+	magic = ext2_superblock_get_magic(superblock);
+	first_block = ext2_superblock_get_first_block(superblock);
+	block_size = ext2_superblock_get_block_size(superblock);
+	fragment_size = ext2_superblock_get_fragment_size(superblock);
+	blocks_per_group = ext2_superblock_get_blocks_per_group(superblock);
+	fragments_per_group = ext2_superblock_get_fragments_per_group(superblock);
+	rev_major = ext2_superblock_get_rev_major(superblock);
+	rev_minor = ext2_superblock_get_rev_minor(superblock);
+	state = ext2_superblock_get_state(superblock);
+	first_inode = ext2_superblock_get_first_inode(superblock);
+	inode_size = ext2_superblock_get_inode_size(superblock);
+	total_blocks = ext2_superblock_get_total_block_count(superblock);
+	reserved_blocks = ext2_superblock_get_reserved_block_count(superblock);
+	free_blocks = ext2_superblock_get_free_block_count(superblock);
+	total_inodes = ext2_superblock_get_total_inode_count(superblock);
+	free_inodes = ext2_superblock_get_free_inode_count(superblock);
+	os = ext2_superblock_get_os(superblock);
+	
+	printf("Superblock:\n");
+	
+	if (magic == EXT2_SUPERBLOCK_MAGIC) {
+		printf("  Magic value: %X (correct)\n", magic);
+	}
+	else {
+		printf("  Magic value: %X (incorrect)\n", magic);
+	}
+	
+	printf("  Revision: %u.%hu\n", rev_major, rev_minor);
+	printf("  State: %hu\n", state);
+	printf("  Creator OS: %u\n", os);
+	printf("  First block: %u\n", first_block);
+	printf("  Block size: %u bytes (%u KiB)\n", block_size, block_size/1024);
+	printf("  Blocks per group: %u\n", blocks_per_group);
+	printf("  Total blocks: %u\n", total_blocks);
+	printf("  Reserved blocks: %u\n", reserved_blocks);
+	printf("  Free blocks: %u\n", free_blocks);
+	printf("  Fragment size: %u bytes (%u KiB)\n", fragment_size,
+	    fragment_size/1024);
+	printf("  Fragments per group: %u\n", fragments_per_group);
+	printf("  First inode: %u\n", first_inode);
+	printf("  Inode size: %hu bytes\n", inode_size);
+	printf("  Total inodes: %u\n", total_inodes);
+	printf("  Free inodes: %u\n", free_inodes);
+	
+	
+	if (rev_major == 1) {
+		printf("  UUID: ");
+		for (pos = 0; pos < 16; pos++) {
+			printf("%02x", superblock->uuid[pos]);
+		}
+		printf("\n");
+		
+		printf("  Volume label: ");
+		for (pos = 0; pos < 16; pos++) {
+			c = superblock->volume_name[pos];
+			if (c >= 32 && c < 128) {
+				putchar(c);
+			}
+			else {
+				putchar(' ');
+			}
+		}
+		printf("\n");
+	}
+	
+}
+
+void print_block_groups(ext2_filesystem_t *filesystem)
+{
+	uint32_t block_group_count;
+	uint32_t i;
+	ext2_block_group_ref_t *block_group_ref;
+	int rc;
+	
+	printf("Block groups:\n");
+	
+	block_group_count = ext2_superblock_get_block_group_count(
+	    filesystem->superblock);
+	
+	for (i = 0; i < block_group_count; i++) {
+		printf("  Block group %u\n", i);
+		rc = ext2_filesystem_get_block_group_ref(filesystem, i, &block_group_ref);
+		if (rc != EOK) {
+			printf("    Failed reading block group\n");
+			continue;
+		}
+		
+		print_block_group(block_group_ref->block_group);
+		
+		rc = ext2_filesystem_put_block_group_ref(block_group_ref);
+		if (rc != EOK) {
+			printf("    Failed freeing block group\n");
+		}
+	}
+	
+}
+
+void print_block_group(ext2_block_group_t *bg)
+{
+	uint32_t block_bitmap_block;
+	uint32_t inode_bitmap_block;
+	uint32_t inode_table_first_block;
+	uint16_t free_block_count;
+	uint16_t free_inode_count;
+	uint16_t directory_inode_count;
+	
+	block_bitmap_block = ext2_block_group_get_block_bitmap_block(bg);
+	inode_bitmap_block = ext2_block_group_get_inode_bitmap_block(bg);
+	inode_table_first_block = ext2_block_group_get_inode_table_first_block(bg);
+	free_block_count = ext2_block_group_get_free_block_count(bg);
+	free_inode_count = ext2_block_group_get_free_inode_count(bg);
+	directory_inode_count = ext2_block_group_get_directory_inode_count(bg);
+	
+	printf("    Block bitmap block: %u\n", block_bitmap_block);
+	printf("    Inode bitmap block: %u\n", inode_bitmap_block);
+	printf("    Inode table's first block: %u\n", inode_table_first_block);
+	printf("    Free blocks: %u\n", free_block_count);
+	printf("    Free inodes: %u\n", free_inode_count);
+	printf("    Directory inodes: %u\n", directory_inode_count);
+}
+
+void print_inode_by_number(ext2_filesystem_t *fs, uint32_t inode, 
+    bool print_data, uint32_t data, bool list, bool blocks)
+{
+	int rc;
+	ext2_inode_ref_t *inode_ref;
+	
+	printf("Inode %u\n", inode);
+	
+	rc = ext2_filesystem_get_inode_ref(fs, inode, &inode_ref);
+	if (rc != EOK) {
+		printf("  Failed getting inode ref\n");
+		return;
+	}
+	
+	print_inode(fs, inode_ref->inode, blocks);
+	if (print_data) {
+		print_inode_data(fs, inode_ref->inode, data);
+	}
+	
+	if (list && ext2_inode_is_type(fs->superblock, inode_ref->inode,
+	    EXT2_INODE_MODE_DIRECTORY)) {
+		print_directory_contents(fs, inode_ref);
+	}
+	
+	rc = ext2_filesystem_put_inode_ref(inode_ref);
+	if (rc != EOK) {
+		printf("  Failed putting inode ref\n");
+	}
+}
+
+void print_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, bool blocks)
+{
+	uint32_t mode;
+	uint32_t mode_type;
+	uint32_t user_id;
+	uint32_t group_id;
+	uint64_t size;
+	uint16_t usage_count;
+	uint32_t flags;
+	uint16_t access;
+	const char *type;
+	uint32_t total_blocks;
+	uint32_t i;
+	uint32_t range_start;
+	uint32_t range_last;
+	uint32_t range_start_file;
+	uint32_t range_last_file;
+	uint32_t range_current;
+	uint32_t range_expected;
+	uint32_t block_size;
+	uint64_t file_blocks;
+	bool printed_range;
+	int rc;
+	
+	block_size = ext2_superblock_get_block_size(fs->superblock);
+	mode = ext2_inode_get_mode(fs->superblock, inode);
+	mode_type = mode & EXT2_INODE_MODE_TYPE_MASK;
+	user_id = ext2_inode_get_user_id(fs->superblock, inode);
+	group_id = ext2_inode_get_group_id(fs->superblock, inode);
+	size = ext2_inode_get_size(fs->superblock, inode);
+	usage_count = ext2_inode_get_usage_count(inode);
+	flags = ext2_inode_get_flags(inode);
+	total_blocks = ext2_inode_get_reserved_blocks(fs->superblock, inode);
+	file_blocks = 0;
+	if (size > 0) {
+		file_blocks = ((size-1)/block_size)+1;
+	}
+	
+	type = "Unknown";
+	if (mode_type == EXT2_INODE_MODE_BLOCKDEV) {
+		type = "Block device";
+	}
+	else if (mode_type == EXT2_INODE_MODE_FIFO) {
+		type = "Fifo (pipe)";
+	}
+	else if (mode_type == EXT2_INODE_MODE_CHARDEV) {
+		type = "Character device";
+	}
+	else if (mode_type == EXT2_INODE_MODE_DIRECTORY) {
+		type = "Directory";
+	}
+	else if (mode_type == EXT2_INODE_MODE_FILE) {
+		type = "File";
+	}
+	else if (mode_type == EXT2_INODE_MODE_SOFTLINK) {
+		type = "Soft link";
+	}
+	else if (mode_type == EXT2_INODE_MODE_SOCKET) {
+		type = "Socket";
+	}
+	
+	access = mode & EXT2_INODE_MODE_ACCESS_MASK;
+	
+	
+	printf("  Mode: %08x (Type: %s, Access bits: %04ho)\n", mode, type, access);
+	printf("  User ID: %u\n", user_id);
+	printf("  Group ID: %u\n", group_id);
+	printf("  Size: %" PRIu64 "\n", size);
+	printf("  Usage (link) count: %u\n", usage_count);
+	printf("  Flags: %u\n", flags);
+	printf("  Total allocated blocks: %u\n", total_blocks);
+	
+	if (blocks) {
+		printf("  Block list: ");
+		
+		range_start = 0;
+		range_current = 0;
+		range_last = 0;
+		
+		printed_range = false;
+		
+		for (i = 0; i <= file_blocks; i++) {
+			if (i < file_blocks) {
+				rc = ext2_filesystem_get_inode_data_block_index(fs, inode, i, &range_current);
+				if (rc != EOK) {
+					printf("Error reading data block indexes\n");
+					return;
+				}
+			}
+			if (range_last == 0) {
+				range_expected = 0;
+			}
+			else {
+				range_expected = range_last + 1;
+			}
+			if (range_current != range_expected) {
+				if (i > 0) {
+					if (printed_range) {
+						printf(", ");
+					}
+					if (range_start == 0 && range_last == 0) {
+						if (range_start_file == range_last_file) {
+							printf("%u N/A", range_start_file);
+						}
+						else {
+							printf("[%u, %u] N/A", range_start_file,
+								range_last_file);
+						}
+					}
+					else {
+						if (range_start_file == range_last_file) {
+							printf("%u -> %u", range_start_file, range_start);
+						}
+						else {
+							printf("[%u, %u] -> [%u, %u]", range_start_file,
+								range_last_file, range_start, range_last);
+						}
+					}
+					printed_range = true;
+				}
+				range_start = range_current;
+				range_start_file = i;
+			}
+			range_last = range_current;
+			range_last_file = i;
+		}
+		printf("\n");
+	}
+}
+
+void print_data(unsigned char *data, size_t size)
+{
+	unsigned char c;
+	size_t i;
+	
+	for (i = 0; i < size; i++) {
+		c = data[i];
+		if (c >= 32 && c < 127) {
+			putchar(c);
+		}
+		else {
+			putchar('.');
+		}
+	}
+}
+
+void print_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t data)
+{
+	int rc;
+	uint32_t data_block_index;
+	block_t *block;
+	
+	rc = ext2_filesystem_get_inode_data_block_index(fs, inode, data,
+	    &data_block_index);
+	
+	if (rc != EOK) {
+		printf("Failed getting data block #%u\n", data);
+		return;
+	}
+	
+	printf("Data for inode contents block #%u is located in filesystem "
+	    "block %u\n", data, data_block_index);
+	
+	printf("Data preview (only printable characters):\n");
+	
+	rc = block_get(&block, fs->device, data_block_index, 0);
+	if (rc != EOK) {
+		printf("Failed reading filesystem block %u\n", data_block_index);
+		return;
+	}
+	
+	print_data(block->data, block->size);
+	printf("\n");	
+	
+	rc = block_put(block);
+	if (rc != EOK) {
+		printf("Failed putting filesystem block\n");
+	}
+	
+}
+
+void print_directory_contents(ext2_filesystem_t *fs,
+    ext2_inode_ref_t *inode_ref)
+{
+	int rc;
+	ext2_directory_iterator_t it;
+	size_t name_size;
+	uint32_t inode;
+	
+	printf("  Directory contents:\n");
+	
+	rc = ext2_directory_iterator_init(&it, fs, inode_ref);
+	if (rc != EOK) {
+		printf("Failed initializing directory iterator\n");
+		return;
+	}
+	
+	while (it.current != NULL) {
+		name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
+		    it.current);
+		printf("    ");
+		print_data(&it.current->name, name_size);
+		
+		inode = ext2_directory_entry_ll_get_inode(it.current);
+		printf(" --> %u\n", inode);
+		
+		rc = ext2_directory_iterator_next(&it);
+		if (rc != EOK) {
+			printf("Failed reading directory contents\n");
+			goto cleanup;
+		}
+	}
+
+cleanup:
+	rc = ext2_directory_iterator_fini(&it);
+	if (rc != EOK) {
+		printf("Failed cleaning-up directory iterator\n");
+	}
+	
+}
+
+/**
+ * @}
+ */
Index: uspace/app/init/Makefile
===================================================================
--- uspace/app/init/Makefile	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/init/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -30,4 +30,5 @@
 USPACE_PREFIX = ../..
 BINARY = init
+STATIC_NEEDED = y
 
 SOURCES = \
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/init/init.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -176,24 +176,19 @@
 static void console(const char *dev)
 {
-	char hid_in[DEVMAP_NAME_MAXLEN];
-	int rc;
-	
-	snprintf(hid_in, DEVMAP_NAME_MAXLEN, "%s/%s", DEVFS_MOUNT_POINT, dev);
-	
-	printf("%s: Spawning %s %s\n", NAME, SRV_CONSOLE, hid_in);
+	printf("%s: Spawning %s %s\n", NAME, SRV_CONSOLE, dev);
 	
 	/* Wait for the input device to be ready */
 	devmap_handle_t handle;
-	rc = devmap_device_get_handle(dev, &handle, IPC_FLAG_BLOCKING);
-	if (rc != EOK) {
-		printf("%s: Error waiting on %s (%s)\n", NAME, hid_in,
-		    str_error(rc));
-		return;
-	}
-	
-	rc = task_spawnl(NULL, SRV_CONSOLE, SRV_CONSOLE, hid_in, NULL);
+	int rc = devmap_device_get_handle(dev, &handle, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		printf("%s: Error waiting on %s (%s)\n", NAME, dev,
+		    str_error(rc));
+		return;
+	}
+	
+	rc = task_spawnl(NULL, SRV_CONSOLE, SRV_CONSOLE, dev, NULL);
 	if (rc != EOK) {
 		printf("%s: Error spawning %s %s (%s)\n", NAME, SRV_CONSOLE,
-		    hid_in, str_error(rc));
+		    dev, str_error(rc));
 	}
 }
@@ -272,7 +267,5 @@
 	mount_tmpfs();
 	
-#ifdef CONFIG_START_DEVMAN
 	spawn("/srv/devman");
-#endif
 	spawn("/srv/apic");
 	spawn("/srv/i8259");
Index: uspace/app/klog/klog.c
===================================================================
--- uspace/app/klog/klog.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/klog/klog.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -44,7 +44,20 @@
 #include <io/klog.h>
 #include <sysinfo.h>
+#include <malloc.h>
+#include <fibril_synch.h>
+#include <adt/list.h>
+#include <adt/prodcons.h>
 
 #define NAME       "klog"
 #define LOG_FNAME  "/log/klog"
+
+/* Producer/consumer buffers */
+typedef struct {
+	link_t link;
+	size_t length;
+	wchar_t *data;
+} item_t;
+
+static prodcons_t pc;
 
 /* Pointer to klog area */
@@ -52,26 +65,120 @@
 static size_t klog_length;
 
-static FILE *log;
-
-static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
-{
+/* Notification mutex */
+static FIBRIL_MUTEX_INITIALIZE(mtx);
+
+/** Klog producer
+ *
+ * Copies the contents of a character buffer to local
+ * producer/consumer queue.
+ *
+ * @param length Number of characters to copy.
+ * @param data   Pointer to the kernel klog buffer.
+ *
+ */
+static void producer(size_t length, wchar_t *data)
+{
+	item_t *item = (item_t *) malloc(sizeof(item_t));
+	if (item == NULL)
+		return;
+	
+	size_t sz = sizeof(wchar_t) * length;
+	wchar_t *buf = (wchar_t *) malloc(sz);
+	if (data == NULL) {
+		free(item);
+		return;
+	}
+	
+	memcpy(buf, data, sz);
+	
+	link_initialize(&item->link);
+	item->length = length;
+	item->data = buf;
+	prodcons_produce(&pc, &item->link);
+}
+
+/** Klog consumer
+ *
+ * Waits in an infinite loop for the character data created by
+ * the producer and outputs them to stdout and optionally into
+ * a file.
+ *
+ * @param data Unused.
+ *
+ * @return Always EOK (unreachable).
+ *
+ */
+static int consumer(void *data)
+{
+	FILE *log = fopen(LOG_FNAME, "a");
+	if (log == NULL)
+		printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME,
+		    str_error(errno));
+	
+	while (true) {
+		link_t *link = prodcons_consume(&pc);
+		item_t *item = list_get_instance(link, item_t, link);
+		
+		for (size_t i = 0; i < item->length; i++)
+			putchar(item->data[i]);
+		
+		if (log != NULL) {
+			for (size_t i = 0; i < item->length; i++)
+				fputc(item->data[i], log);
+			
+			fflush(log);
+			fsync(fileno(log));
+		}
+		
+		free(item->data);
+		free(item);
+	}
+	
+	fclose(log);
+	return EOK;
+}
+
+/** Kernel notification handler
+ *
+ * Receives kernel klog notifications.
+ *
+ * @param callid IPC call ID.
+ * @param call   IPC call structure.
+ *
+ */
+static void notification_received(ipc_callid_t callid, ipc_call_t *call)
+{
+	/*
+	 * Make sure we process only a single notification
+	 * at any time to limit the chance of the consumer
+	 * starving.
+	 *
+	 * Note: Usually the automatic masking of the klog
+	 * notifications on the kernel side does the trick
+	 * of limiting the chance of accidentally copying
+	 * the same data multiple times. However, due to
+	 * the non-blocking architecture of klog notifications,
+	 * this possibility cannot be generally avoided.
+	 */
+	
+	fibril_mutex_lock(&mtx);
+	
 	size_t klog_start = (size_t) IPC_GET_ARG1(*call);
 	size_t klog_len = (size_t) IPC_GET_ARG2(*call);
 	size_t klog_stored = (size_t) IPC_GET_ARG3(*call);
-	size_t i;
-	
-	for (i = klog_len - klog_stored; i < klog_len; i++) {
-		wchar_t ch = klog[(klog_start + i) % klog_length];
-		
-		putchar(ch);
-		
-		if (log != NULL)
-			fputc(ch, log);
-	}
-	
-	if (log != NULL) {
-		fflush(log);
-		fsync(fileno(log));
-	}
+	
+	size_t offset = (klog_start + klog_len - klog_stored) % klog_length;
+	
+	/* Copy data from the ring buffer */
+	if (offset + klog_stored >= klog_length) {
+		size_t split = klog_length - offset;
+		
+		producer(split, klog + offset);
+		producer(klog_stored - split, klog);
+	} else
+		producer(klog_stored, klog + offset);
+	
+	event_unmask(EVENT_KLOG);
+	fibril_mutex_unlock(&mtx);
 }
 
@@ -111,4 +218,6 @@
 	}
 	
+	prodcons_initialize(&pc);
+	async_set_interrupt_received(notification_received);
 	rc = event_subscribe(EVENT_KLOG, 0);
 	if (rc != EOK) {
@@ -118,15 +227,16 @@
 	}
 	
-	/*
-	 * Mode "a" would be definitively much better here, but it is
-	 * not well supported by the FAT driver.
-	 */
-	log = fopen(LOG_FNAME, "w");
-	if (log == NULL)
-		printf("%s: Unable to create log file %s (%s)\n", NAME, LOG_FNAME,
-		    str_error(errno));
-	
-	async_set_interrupt_received(interrupt_received);
+	fid_t fid = fibril_create(consumer, NULL);
+	if (!fid) {
+		fprintf(stderr, "%s: Unable to create consumer fibril\n",
+		    NAME);
+		return ENOMEM;
+	}
+	
+	fibril_add_ready(fid);
+	event_unmask(EVENT_KLOG);
 	klog_update();
+	
+	task_retval(0);
 	async_manager();
 	
Index: uspace/app/lsusb/Makefile
===================================================================
--- uspace/app/lsusb/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/lsusb/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2011 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+BINARY = lsusb
+
+LIBS = \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS = \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+SOURCES = \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/lsusb/main.c
===================================================================
--- uspace/app/lsusb/main.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/lsusb/main.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010-2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lsusb
+ * @{
+ */
+/**
+ * @file
+ * Listing of USB host controllers.
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+#include <getopt.h>
+#include <devman.h>
+#include <devmap.h>
+#include <usb/dev/hub.h>
+#include <usb/hc.h>
+
+#define NAME "lsusb"
+
+#define MAX_USB_ADDRESS USB11_ADDRESS_MAX
+#define MAX_FAILED_ATTEMPTS 10
+#define MAX_PATH_LENGTH 1024
+
+static void print_found_hc(size_t class_index, const char *path)
+{
+	// printf(NAME ": host controller %zu is `%s'.\n", class_index, path);
+	printf("Bus %02zu: %s\n", class_index, path);
+}
+static void print_found_dev(usb_address_t addr, const char *path)
+{
+	// printf(NAME ":     device with address %d is `%s'.\n", addr, path);
+	printf("  Device %02d: %s\n", addr, path);
+}
+
+static void print_hc_devices(devman_handle_t hc_handle)
+{
+	int rc;
+	usb_hc_connection_t conn;
+
+	usb_hc_connection_initialize(&conn, hc_handle);
+	rc = usb_hc_connection_open(&conn);
+	if (rc != EOK) {
+		printf(NAME ": failed to connect to HC: %s.\n",
+		    str_error(rc));
+		return;
+	}
+	usb_address_t addr;
+	for (addr = 1; addr < MAX_USB_ADDRESS; addr++) {
+		devman_handle_t dev_handle;
+		rc = usb_hc_get_handle_by_address(&conn, addr, &dev_handle);
+		if (rc != EOK) {
+			continue;
+		}
+		char path[MAX_PATH_LENGTH];
+		rc = devman_get_device_path(dev_handle, path, MAX_PATH_LENGTH);
+		if (rc != EOK) {
+			continue;
+		}
+		print_found_dev(addr, path);
+	}
+	usb_hc_connection_close(&conn);
+}
+
+int main(int argc, char *argv[])
+{
+	size_t class_index = 0;
+	size_t failed_attempts = 0;
+
+	while (failed_attempts < MAX_FAILED_ATTEMPTS) {
+		class_index++;
+		devman_handle_t hc_handle = 0;
+		int rc = usb_ddf_get_hc_handle_by_class(class_index, &hc_handle);
+		if (rc != EOK) {
+			failed_attempts++;
+			continue;
+		}
+		char path[MAX_PATH_LENGTH];
+		rc = devman_get_device_path(hc_handle, path, MAX_PATH_LENGTH);
+		if (rc != EOK) {
+			continue;
+		}
+		print_found_hc(class_index, path);
+		print_hc_devices(hc_handle);
+	}
+
+	return 0;
+}
+
+
+/** @}
+ */
Index: uspace/app/mkbd/Makefile
===================================================================
--- uspace/app/mkbd/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/mkbd/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2011 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+BINARY = mkbd
+
+LIBS = \
+	$(LIBUSBHID_PREFIX)/libusbhid.a \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a 
+EXTRA_CFLAGS = \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include \
+	-I$(LIBUSBHID_PREFIX)/include 
+
+SOURCES = \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/mkbd/main.c
===================================================================
--- uspace/app/mkbd/main.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/mkbd/main.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup mkbd
+ * @{
+ */
+/**
+ * @file
+ * Sample application using the data from multimedia keys on keyboard
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+#include <getopt.h>
+#include <devman.h>
+#include <devmap.h>
+#include <usb/dev/hub.h>
+#include <usb/hid/iface.h>
+#include <usb/dev/pipes.h>
+#include <async.h>
+#include <usb/hid/usages/core.h>
+#include <usb/hid/hidparser.h>
+#include <usb/hid/hiddescriptor.h>
+#include <usb/hid/usages/consumer.h>
+#include <assert.h>
+
+#define NAME "mkbd"
+
+static async_sess_t *dev_sess = NULL;
+
+static int initialize_report_parser(async_sess_t *dev_sess,
+    usb_hid_report_t **report)
+{
+	*report = (usb_hid_report_t *) malloc(sizeof(usb_hid_report_t));
+	if (*report == NULL)
+		return ENOMEM;
+	
+	int rc = usb_hid_report_init(*report);
+	if (rc != EOK) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		return rc;
+	}
+	
+	/* Get the report descriptor length from the device */
+	size_t report_desc_size;
+	rc = usbhid_dev_get_report_descriptor_length(dev_sess,
+	    &report_desc_size);
+	if (rc != EOK) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		return rc;
+	}
+	
+	if (report_desc_size == 0) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		// TODO: other error code?
+		return EINVAL;
+	}
+	
+	uint8_t *desc = (uint8_t *) malloc(report_desc_size);
+	if (desc == NULL) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		return ENOMEM;
+	}
+	
+	/* Get the report descriptor from the device */
+	size_t actual_size;
+	rc = usbhid_dev_get_report_descriptor(dev_sess, desc, report_desc_size,
+	    &actual_size);
+	if (rc != EOK) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		free(desc);
+		return rc;
+	}
+	
+	if (actual_size != report_desc_size) {
+		usb_hid_free_report(*report);
+		*report = NULL;
+		free(desc);
+		// TODO: other error code?
+		return EINVAL;
+	}
+	
+	/* Initialize the report parser */
+	
+	rc = usb_hid_parse_report_descriptor(*report, desc, report_desc_size);
+	free(desc);
+	
+	if (rc != EOK) {
+		free(desc);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+static void print_key(uint8_t *buffer, size_t size, usb_hid_report_t *report)
+{
+	assert(buffer != NULL);
+	assert(report != NULL);
+	
+	uint8_t report_id;
+	int rc = usb_hid_parse_report(report, buffer, size, &report_id);
+	if (rc != EOK)
+		return;
+	
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	if (path == NULL) {
+		return;
+	}
+	
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
+	
+	usb_hid_report_path_set_report_id(path, report_id);
+
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+	    report, NULL, path, USB_HID_PATH_COMPARE_END
+	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+	    USB_HID_REPORT_TYPE_INPUT);
+	
+	while (field != NULL) {
+		if (field->value != 0) {
+			const char *key_str = 
+			    usbhid_multimedia_usage_to_str(field->usage);
+			printf("Pressed key: %s\n", key_str);
+		}
+		
+		field = usb_hid_report_get_sibling(
+		    report, field, path, USB_HID_PATH_COMPARE_END
+		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+		    USB_HID_REPORT_TYPE_INPUT);
+	}
+	
+	usb_hid_report_path_free(path);
+}
+
+#define MAX_PATH_LENGTH 1024
+
+static void print_usage(char *app_name)
+{
+#define _INDENT "      "
+	printf(NAME ": Print out what multimedia keys were pressed.\n\n");
+	printf("Usage: %s device\n", app_name);
+	printf(_INDENT "The device is a devman path to the device.\n");
+#undef _OPTION
+#undef _INDENT
+}
+
+int main(int argc, char *argv[])
+{
+	int act_event = -1;
+	
+	if (argc <= 1) {
+		print_usage(argv[0]);
+		return -1;
+	}
+	
+	char *devpath = argv[1];
+	
+	devman_handle_t dev_handle = 0;
+	
+	int rc = usb_resolve_device_handle(devpath, NULL, NULL, &dev_handle);
+	if (rc != EOK) {
+		printf("Device not found or not of USB kind: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	async_sess_t *sess = devman_device_connect(EXCHANGE_SERIALIZE,
+	    dev_handle, 0);
+	if (!sess) {
+		printf(NAME ": failed to connect to the device (handle %"
+		       PRIun "): %s.\n", dev_handle, str_error(errno));
+		return errno;
+	}
+	
+	dev_sess = sess;
+	
+	char path[MAX_PATH_LENGTH];
+	rc = devman_get_device_path(dev_handle, path, MAX_PATH_LENGTH);
+	if (rc != EOK) {
+		return ENOMEM;
+	}
+	
+	printf("Device path: %s\n", path);
+	
+	
+	usb_hid_report_t *report = NULL;
+	rc = initialize_report_parser(dev_sess, &report);
+	if (rc != EOK) {
+		printf("Failed to initialize report parser: %s\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	assert(report != NULL);
+	
+	size_t size;
+	rc = usbhid_dev_get_event_length(dev_sess, &size);
+	if (rc != EOK) {
+		printf("Failed to get event length: %s.\n", str_error(rc));
+		return rc;
+	}
+	
+	uint8_t *event = (uint8_t *)malloc(size);
+	if (event == NULL) {
+		// TODO: hangup phone?
+		return ENOMEM;
+	}
+	
+	size_t actual_size;
+	int event_nr;
+	
+	while (true) {
+		/** @todo Try blocking call. */
+		rc = usbhid_dev_get_event(dev_sess, event, size, &actual_size, 
+		    &event_nr, 0);
+		if (rc != EOK) {
+			// TODO: hangup phone?
+			printf("Error in getting event from the HID driver:"
+			    "%s.\n", str_error(rc));
+			break;
+		}
+		
+		if (event_nr > act_event) {
+			print_key(event, size, report);
+			act_event = event_nr;
+		}
+		
+		async_usleep(10000);
+	}
+	
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/mkfat/mkfat.c
===================================================================
--- uspace/app/mkfat/mkfat.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/mkfat/mkfat.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -144,5 +144,5 @@
 	}
 
-	rc = block_init(handle, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, handle, 2048);
 	if (rc != EOK)  {
 		printf(NAME ": Error initializing libblock.\n");
Index: uspace/app/ping/ping.c
===================================================================
--- uspace/app/ping/ping.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/ping/ping.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -36,4 +36,5 @@
 
 #include <async.h>
+#include <async_obsolete.h>
 #include <stdio.h>
 #include <str.h>
@@ -355,5 +356,5 @@
 			    str_error(ret));
 			
-			async_hangup(icmp_phone);
+			async_obsolete_hangup(icmp_phone);
 			return ret;
 		}
@@ -370,5 +371,5 @@
 			    str_error(ret));
 			
-			async_hangup(icmp_phone);
+			async_obsolete_hangup(icmp_phone);
 			return ret;
 		}
@@ -390,5 +391,5 @@
 	}
 	
-	async_hangup(icmp_phone);
+	async_obsolete_hangup(icmp_phone);
 	
 	return 0;
Index: uspace/app/redir/redir.c
===================================================================
--- uspace/app/redir/redir.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/redir/redir.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -49,5 +49,5 @@
 static void usage(void)
 {
-	printf("Usage: %s [-i <stdin>] [-o <stdout>] [-e <stderr>] -- <cmd> [args ...]\n",
+	fprintf(stderr, "Usage: %s [-i <stdin>] [-o <stdout>] [-e <stderr>] -- <cmd> [args ...]\n",
 	    NAME);
 }
@@ -83,5 +83,5 @@
 	args = (const char **) calloc(argc + 1, sizeof(char *));
 	if (!args) {
-		printf("No memory available\n");
+		fprintf(stderr, "No memory available\n");
 		return 0;
 	}
@@ -98,6 +98,7 @@
 	
 	if (rc != EOK) {
-		printf("%s: Error spawning %s (%s)\n", NAME, argv[0],
+		fprintf(stderr, "%s: Error spawning %s (%s)\n", NAME, argv[0],
 		    str_error(rc));
+		return 0;
 	}
 	
Index: uspace/app/stats/stats.c
===================================================================
--- uspace/app/stats/stats.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/stats/stats.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -69,13 +69,19 @@
 	size_t i;
 	for (i = 0; i < count; i++) {
-		uint64_t resmem, virtmem, ucycles, kcycles;
-		char resmem_suffix, virtmem_suffix, usuffix, ksuffix;
-		
-		order_suffix(stats_tasks[i].resmem, &resmem, &resmem_suffix);
-		order_suffix(stats_tasks[i].virtmem, &virtmem, &virtmem_suffix);
+		uint64_t resmem;
+		uint64_t virtmem;
+		uint64_t ucycles;
+		uint64_t kcycles;
+		const char *resmem_suffix;
+		const char *virtmem_suffix;
+		char usuffix;
+		char ksuffix;
+		
+		bin_order_suffix(stats_tasks[i].resmem, &resmem, &resmem_suffix, true);
+		bin_order_suffix(stats_tasks[i].virtmem, &virtmem, &virtmem_suffix, true);
 		order_suffix(stats_tasks[i].ucycles, &ucycles, &usuffix);
 		order_suffix(stats_tasks[i].kcycles, &kcycles, &ksuffix);
 		
-		printf("%-8" PRIu64 " %7zu %9" PRIu64 "%c %8" PRIu64 "%c"
+		printf("%-8" PRIu64 " %7zu %7" PRIu64 "%s %6" PRIu64 "%s"
 		    " %8" PRIu64 "%c %8" PRIu64 "%c %s\n",
 		    stats_tasks[i].task_id, stats_tasks[i].threads,
Index: uspace/app/taskdump/elf_core.c
===================================================================
--- uspace/app/taskdump/elf_core.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/taskdump/elf_core.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -62,7 +62,7 @@
 #include "include/elf_core.h"
 
-static off64_t align_foff_up(off64_t foff, uintptr_t vaddr, size_t page_size);
-static int write_all(int fd, void *data, size_t len);
-static int write_mem_area(int fd, as_area_info_t *area, int phoneid);
+static off64_t align_foff_up(off64_t, uintptr_t, size_t);
+static int write_all(int, void *, size_t);
+static int write_mem_area(int, as_area_info_t *, async_sess_t *);
 
 #define BUFFER_SIZE 0x1000
@@ -71,13 +71,17 @@
 /** Save ELF core file.
  *
- * @param file_name	Name of file to save to.
- * @param ainfo		Array of @a n memory area info structures.
- * @param n		Number of memory areas.
- * @param phoneid	Debugging phone.
- *
- * @return		EOK on sucess, ENOENT if file cannot be created,
- *			ENOMEM on out of memory, EIO on write error.
- */
-int elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n, int phoneid)
+ * @param file_name Name of file to save to.
+ * @param ainfo     Array of @a n memory area info structures.
+ * @param n         Number of memory areas.
+ * @param sess      Debugging session.
+ *
+ * @return EOK on sucess.
+ * @return ENOENT if file cannot be created.
+ * @return ENOMEM on out of memory.
+ * @return EIO on write error.
+ *
+ */
+int elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n,
+    async_sess_t *sess)
 {
 	elf_header_t elf_hdr;
@@ -189,5 +193,5 @@
 			return EIO;
 		}
-		if (write_mem_area(fd, &ainfo[i], phoneid) != EOK) {
+		if (write_mem_area(fd, &ainfo[i], sess) != EOK) {
 			printf("Failed writing memory data.\n");
 			free(p_hdr);
@@ -215,11 +219,12 @@
 /** Write memory area from application to core file.
  *
- * @param fd		File to write to.
- * @param area		Memory area info structure.
- * @param phoneid	Debugging phone.
- *
- * @return		EOK on success, EIO on failure.
- */
-static int write_mem_area(int fd, as_area_info_t *area, int phoneid)
+ * @param fd   File to write to.
+ * @param area Memory area info structure.
+ * @param sess Debugging session.
+ *
+ * @return EOK on success, EIO on failure.
+ *
+ */
+static int write_mem_area(int fd, as_area_info_t *area, async_sess_t *sess)
 {
 	size_t to_copy;
@@ -233,5 +238,5 @@
 	while (total < area->size) {
 		to_copy = min(area->size - total, BUFFER_SIZE);
-		rc = udebug_mem_read(phoneid, buffer, addr, to_copy);
+		rc = udebug_mem_read(sess, buffer, addr, to_copy);
 		if (rc < 0) {
 			printf("Failed reading task memory.\n");
Index: uspace/app/taskdump/include/elf_core.h
===================================================================
--- uspace/app/taskdump/include/elf_core.h	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/taskdump/include/elf_core.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -36,5 +36,8 @@
 #define ELF_CORE_H_
 
-int elf_core_save(const char *file_name, as_area_info_t *ainfo, unsigned int n, int phoneid);
+#include <async.h>
+
+extern int elf_core_save(const char *, as_area_info_t *, unsigned int,
+    async_sess_t *);
 
 #endif
Index: uspace/app/taskdump/taskdump.c
===================================================================
--- uspace/app/taskdump/taskdump.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/taskdump/taskdump.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -54,5 +54,5 @@
 #define LINE_BYTES 16
 
-static int phoneid;
+static async_sess_t *sess;
 static task_id_t task_id;
 static bool write_core_file;
@@ -104,6 +104,6 @@
 		printf("Failed dumping address space areas.\n");
 
-	udebug_end(phoneid);
-	async_hangup(phoneid);
+	udebug_end(sess);
+	async_hangup(sess);
 
 	return 0;
@@ -112,30 +112,27 @@
 static int connect_task(task_id_t task_id)
 {
-	int rc;
-
-	rc = async_connect_kbox(task_id);
-
-	if (rc == ENOTSUP) {
-		printf("You do not have userspace debugging support "
-		    "compiled in the kernel.\n");
-		printf("Compile kernel with 'Support for userspace debuggers' "
-		    "(CONFIG_UDEBUG) enabled.\n");
-		return rc;
-	}
-
-	if (rc < 0) {
+	async_sess_t *ksess = async_connect_kbox(task_id);
+	
+	if (!ksess) {
+		if (errno == ENOTSUP) {
+			printf("You do not have userspace debugging support "
+			    "compiled in the kernel.\n");
+			printf("Compile kernel with 'Support for userspace debuggers' "
+			    "(CONFIG_UDEBUG) enabled.\n");
+			return errno;
+		}
+		
 		printf("Error connecting\n");
-		printf("async_connect_kbox(%" PRIu64 ") -> %d ", task_id, rc);
-		return rc;
-	}
-
-	phoneid = rc;
-
-	rc = udebug_begin(phoneid);
+		printf("async_connect_kbox(%" PRIu64 ") -> %d ", task_id, errno);
+		return errno;
+	}
+	
+	int rc = udebug_begin(ksess);
 	if (rc < 0) {
 		printf("udebug_begin() -> %d\n", rc);
 		return rc;
 	}
-
+	
+	sess = ksess;
 	return 0;
 }
@@ -213,5 +210,5 @@
 
 	/* TODO: See why NULL does not work. */
-	rc = udebug_thread_read(phoneid, &dummy_buf, 0, &copied, &needed);
+	rc = udebug_thread_read(sess, &dummy_buf, 0, &copied, &needed);
 	if (rc < 0) {
 		printf("udebug_thread_read() -> %d\n", rc);
@@ -227,5 +224,5 @@
 	thash_buf = malloc(buf_size);
 
-	rc = udebug_thread_read(phoneid, thash_buf, buf_size, &copied, &needed);
+	rc = udebug_thread_read(sess, thash_buf, buf_size, &copied, &needed);
 	if (rc < 0) {
 		printf("udebug_thread_read() -> %d\n", rc);
@@ -262,5 +259,5 @@
 	int rc;
 
-	rc = udebug_areas_read(phoneid, &dummy_buf, 0, &copied, &needed);
+	rc = udebug_areas_read(sess, &dummy_buf, 0, &copied, &needed);
 	if (rc < 0) {
 		printf("udebug_areas_read() -> %d\n", rc);
@@ -271,5 +268,5 @@
 	ainfo_buf = malloc(buf_size);
 
-	rc = udebug_areas_read(phoneid, ainfo_buf, buf_size, &copied, &needed);
+	rc = udebug_areas_read(sess, ainfo_buf, buf_size, &copied, &needed);
 	if (rc < 0) {
 		printf("udebug_areas_read() -> %d\n", rc);
@@ -296,5 +293,5 @@
 	if (write_core_file) {
 		printf("Writing core file '%s'\n", core_file_name);
-		rc = elf_core_save(core_file_name, ainfo_buf, n_areas, phoneid);
+		rc = elf_core_save(core_file_name, ainfo_buf, n_areas, sess);
 		if (rc != EOK) {
 			printf("Failed writing core file.\n");
@@ -316,5 +313,5 @@
 	int rc;
 
-	rc = udebug_regs_read(phoneid, thash, &istate);
+	rc = udebug_regs_read(sess, thash, &istate);
 	if (rc < 0) {
 		printf("Failed reading registers (%d).\n", rc);
@@ -359,5 +356,5 @@
 	(void) arg;
 
-	rc = udebug_mem_read(phoneid, &data, addr, sizeof(data));
+	rc = udebug_mem_read(sess, &data, addr, sizeof(data));
 	if (rc < 0) {
 		printf("Warning: udebug_mem_read() failed.\n");
@@ -430,5 +427,5 @@
 	int rc;
 
-	rc = udebug_name_read(phoneid, &dummy_buf, 0, &copied, &needed);
+	rc = udebug_name_read(sess, &dummy_buf, 0, &copied, &needed);
 	if (rc < 0)
 		return NULL;
@@ -436,5 +433,5 @@
 	name_size = needed;
 	name = malloc(name_size + 1);
-	rc = udebug_name_read(phoneid, name, name_size, &copied, &needed);
+	rc = udebug_name_read(sess, name, name_size, &copied, &needed);
 	if (rc < 0) {
 		free(name);
Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tester/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -29,8 +29,11 @@
 
 USPACE_PREFIX = ../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBEXT2_PREFIX)/libext2.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBEXT2_PREFIX)
 BINARY = tester
 
 SOURCES = \
 	tester.c \
+	util.c \
 	thread/thread1.c \
 	print/print1.c \
@@ -48,8 +51,14 @@
 	ipc/ping_pong.c \
 	loop/loop1.c \
+	mm/common.c \
 	mm/malloc1.c \
+	mm/malloc2.c \
+	mm/malloc3.c \
+	mm/mapping1.c \
 	devs/devman1.c \
+	devs/devman2.c \
 	hw/misc/virtchar1.c \
-	hw/serial/serial1.c
+	hw/serial/serial1.c \
+	libext2/libext2_1.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/tester/console/console1.c
===================================================================
--- uspace/app/tester/console/console1.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tester/console/console1.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -50,19 +50,21 @@
 {
 	if (!test_quiet) {
+		console_ctrl_t *console = console_init(stdin, stdout);
+		
 		printf("Style test: ");
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_NORMAL);
+		console_flush(console);
+		console_set_style(console, STYLE_NORMAL);
 		printf(" normal ");
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_EMPHASIS);
+		console_flush(console);
+		console_set_style(console, STYLE_EMPHASIS);
 		printf(" emphasized ");
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_INVERTED);
+		console_flush(console);
+		console_set_style(console, STYLE_INVERTED);
 		printf(" inverted ");
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_SELECTED);
+		console_flush(console);
+		console_set_style(console, STYLE_SELECTED);
 		printf(" selected ");
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_NORMAL);
+		console_flush(console);
+		console_set_style(console, STYLE_NORMAL);
 		printf("\n");
 		
@@ -73,11 +75,11 @@
 		for (j = 0; j < 2; j++) {
 			for (i = COLOR_BLACK; i <= COLOR_WHITE; i++) {
-				fflush(stdout);
-				console_set_color(fphone(stdout), i, COLOR_WHITE,
+				console_flush(console);
+				console_set_color(console, i, COLOR_WHITE,
 				    j ? CATTR_BRIGHT : 0);
 				printf(" %s ", color_name[i]);
 			}
-			fflush(stdout);
-			console_set_style(fphone(stdout), STYLE_NORMAL);
+			console_flush(console);
+			console_set_style(console, STYLE_NORMAL);
 			putchar('\n');
 		}
@@ -86,11 +88,11 @@
 		for (j = 0; j < 2; j++) {
 			for (i = COLOR_BLACK; i <= COLOR_WHITE; i++) {
-				fflush(stdout);
-				console_set_color(fphone(stdout), COLOR_WHITE, i,
+				console_flush(console);
+				console_set_color(console, COLOR_WHITE, i,
 				    j ? CATTR_BRIGHT : 0);
 				printf(" %s ", color_name[i]);
 			}
-			fflush(stdout);
-			console_set_style(fphone(stdout), STYLE_NORMAL);
+			console_flush(console);
+			console_set_style(console, STYLE_NORMAL);
 			putchar('\n');
 		}
@@ -99,28 +101,28 @@
 		
 		for (i = 0; i < 255; i += 16) {
-			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), (255 - i) << 16, i << 16);
+			console_flush(console);
+			console_set_rgb_color(console, (255 - i) << 16, i << 16);
 			putchar('X');
 		}
-		fflush(stdout);
-		console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+		console_flush(console);
+		console_set_color(console, COLOR_BLACK, COLOR_WHITE, 0);
 		putchar('\n');
 		
 		for (i = 0; i < 255; i += 16) {
-			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), (255 - i) << 8, i << 8);
+			console_flush(console);
+			console_set_rgb_color(console, (255 - i) << 8, i << 8);
 			putchar('X');
 		}
-		fflush(stdout);
-		console_set_color(fphone(stdout), COLOR_BLACK, COLOR_WHITE, 0);
+		console_flush(console);
+		console_set_color(console, COLOR_BLACK, COLOR_WHITE, 0);
 		putchar('\n');
 		
 		for (i = 0; i < 255; i += 16) {
-			fflush(stdout);
-			console_set_rgb_color(fphone(stdout), 255 - i, i);
+			console_flush(console);
+			console_set_rgb_color(console, 255 - i, i);
 			putchar('X');
 		}
-		fflush(stdout);
-		console_set_style(fphone(stdout), STYLE_NORMAL);
+		console_flush(console);
+		console_set_style(console, STYLE_NORMAL);
 		putchar('\n');
 	}
Index: uspace/app/tester/devs/devman2.c
===================================================================
--- uspace/app/tester/devs/devman2.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/devs/devman2.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup tester
+ * @brief Test devman service.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <inttypes.h>
+#include <errno.h>
+#include <str_error.h>
+#include <sys/types.h>
+#include <async.h>
+#include <devman.h>
+#include <str.h>
+#include <async.h>
+#include <vfs/vfs.h>
+#include <vfs/vfs_sess.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "../tester.h"
+
+#define DEVICE_CLASS "test3"
+
+const char *test_devman2(void)
+{
+	size_t idx = 1;
+	int rc = EOK;
+	const char *err_msg = NULL;
+	char *path = NULL;
+	while (rc == EOK) {
+		rc = asprintf(&path, "/dev/class/%s\\%zu", DEVICE_CLASS, idx);
+		if (rc < 0) {
+			continue;
+		}
+		int fd = open(path, O_RDONLY);
+		if (fd < 0) {
+			TPRINTF("Failed opening `%s': %s.\n",
+			    path, str_error(fd));
+			rc = fd;
+			err_msg = "Failed opening file";
+			continue;
+		}
+		async_sess_t *sess = fd_session(EXCHANGE_SERIALIZE, fd);
+		close(fd);
+		if (sess == NULL) {
+			TPRINTF("Failed opening phone: %s.\n", str_error(errno));
+			rc = errno;
+			err_msg = "Failed opening file descriptor phone";
+			continue;
+		}
+		async_hangup(sess);
+		TPRINTF("Path `%s' okay.\n", path);
+		free(path);
+		idx++;
+		rc = EOK;
+	}
+	
+	if (path != NULL)
+		free(path);
+	
+	return err_msg;
+}
+
+/** @}
+ */
Index: uspace/app/tester/devs/devman2.def
===================================================================
--- uspace/app/tester/devs/devman2.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/devs/devman2.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,6 @@
+{
+	"devman2",
+	"devman test",
+	&test_devman2,
+	false
+},
Index: uspace/app/tester/hw/misc/virtchar1.c
===================================================================
--- uspace/app/tester/hw/misc/virtchar1.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tester/hw/misc/virtchar1.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -43,4 +43,5 @@
 #include <str.h>
 #include <vfs/vfs.h>
+#include <vfs/vfs_sess.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -66,17 +67,17 @@
 	TPRINTF("   ...file handle %d\n", fd);
 
-	TPRINTF(" Asking for phone...\n");
-	int phone = fd_phone(fd);
-	if (phone < 0) {
+	TPRINTF(" Asking for session...\n");
+	async_sess_t *sess = fd_session(EXCHANGE_SERIALIZE, fd);
+	if (!sess) {
 		close(fd);
-		TPRINTF("   ...error: %s\n", str_error(phone));
-		return "Failed to get phone to device";
+		TPRINTF("   ...error: %s\n", str_error(errno));
+		return "Failed to get session to device";
 	}
-	TPRINTF("   ...phone is %d\n", phone);
+	TPRINTF("   ...session is %p\n", sess);
 	
 	TPRINTF(" Will try to read...\n");
 	size_t i;
 	char buffer[BUFFER_SIZE];
-	char_dev_read(phone, buffer, BUFFER_SIZE);
+	char_dev_read(sess, buffer, BUFFER_SIZE);
 	TPRINTF(" ...verifying that we read zeroes only...\n");
 	for (i = 0; i < BUFFER_SIZE; i++) {
@@ -88,6 +89,6 @@
 	
 	/* Clean-up. */
-	TPRINTF(" Closing phones and file descriptors\n");
-	async_hangup(phone);
+	TPRINTF(" Closing session and file descriptor\n");
+	async_hangup(sess);
 	close(fd);
 	
Index: uspace/app/tester/hw/serial/serial1.c
===================================================================
--- uspace/app/tester/hw/serial/serial1.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tester/hw/serial/serial1.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -71,22 +71,18 @@
 		}
 	
-	int res = devman_get_phone(DEVMAN_CLIENT, IPC_FLAG_BLOCKING);
-	
 	devman_handle_t handle;
-	res = devman_device_get_handle("/hw/pci0/00:01.0/com1/a", &handle,
+	int res = devman_device_get_handle("/hw/pci0/00:01.0/com1/a", &handle,
 	    IPC_FLAG_BLOCKING);
 	if (res != EOK)
 		return "Could not get serial device handle";
 	
-	int phone = devman_device_connect(handle, IPC_FLAG_BLOCKING);
-	if (phone < 0) {
-		devman_hangup_phone(DEVMAN_CLIENT);
+	async_sess_t *sess = devman_device_connect(EXCHANGE_SERIALIZE, handle,
+	    IPC_FLAG_BLOCKING);
+	if (!sess)
 		return "Unable to connect to serial device";
-	}
 	
 	char *buf = (char *) malloc(cnt + 1);
 	if (buf == NULL) {
-		async_hangup(phone);
-		devman_hangup_phone(DEVMAN_CLIENT);
+		async_hangup(sess);
 		return "Failed to allocate input buffer";
 	}
@@ -97,19 +93,23 @@
 	sysarg_t old_word_size;
 	
-	res = async_req_0_4(phone, SERIAL_GET_COM_PROPS, &old_baud,
+	async_exch_t *exch = async_exchange_begin(sess);
+	res = async_req_0_4(exch, SERIAL_GET_COM_PROPS, &old_baud,
 	    &old_par, &old_word_size, &old_stop);
+	async_exchange_end(exch);
+	
 	if (res != EOK) {
 		free(buf);
-		async_hangup(phone);
-		devman_hangup_phone(DEVMAN_CLIENT);
+		async_hangup(sess);
 		return "Failed to get old serial communication parameters";
 	}
 	
-	res = async_req_4_0(phone, SERIAL_SET_COM_PROPS, 1200,
+	exch = async_exchange_begin(sess);
+	res = async_req_4_0(exch, SERIAL_SET_COM_PROPS, 1200,
 	    SERIAL_NO_PARITY, 8, 1);
+	async_exchange_end(exch);
+	
 	if (EOK != res) {
 		free(buf);
-		async_hangup(phone);
-		devman_hangup_phone(DEVMAN_CLIENT);
+		async_hangup(sess);
 		return "Failed to set serial communication parameters";
 	}
@@ -120,21 +120,25 @@
 	size_t total = 0;
 	while (total < cnt) {
-		ssize_t read = char_dev_read(phone, buf, cnt - total);
+		ssize_t read = char_dev_read(sess, buf, cnt - total);
 		
 		if (read < 0) {
-			async_req_4_0(phone, SERIAL_SET_COM_PROPS, old_baud,
+			exch = async_exchange_begin(sess);
+			async_req_4_0(exch, SERIAL_SET_COM_PROPS, old_baud,
 			    old_par, old_word_size, old_stop);
+			async_exchange_end(exch);
+			
 			free(buf);
-			async_hangup(phone);
-			devman_hangup_phone(DEVMAN_CLIENT);
+			async_hangup(sess);
 			return "Failed read from serial device";
 		}
 		
 		if ((size_t) read > cnt - total) {
-			async_req_4_0(phone, SERIAL_SET_COM_PROPS, old_baud,
+			exch = async_exchange_begin(sess);
+			async_req_4_0(exch, SERIAL_SET_COM_PROPS, old_baud,
 			    old_par, old_word_size, old_stop);
+			async_exchange_end(exch);
+			
 			free(buf);
-			async_hangup(phone);
-			devman_hangup_phone(DEVMAN_CLIENT);
+			async_hangup(sess);
 			return "Read more data than expected";
 		}
@@ -151,21 +155,25 @@
 			 * direction of data transfer.
 			 */
-			ssize_t written = char_dev_write(phone, buf, read);
+			ssize_t written = char_dev_write(sess, buf, read);
 			
 			if (written < 0) {
-				async_req_4_0(phone, SERIAL_SET_COM_PROPS, old_baud,
+				exch = async_exchange_begin(sess);
+				async_req_4_0(exch, SERIAL_SET_COM_PROPS, old_baud,
 				    old_par, old_word_size, old_stop);
+				async_exchange_end(exch);
+				
 				free(buf);
-				async_hangup(phone);
-				devman_hangup_phone(DEVMAN_CLIENT);
+				async_hangup(sess);
 				return "Failed write to serial device";
 			}
 			
 			if (written != read) {
-				async_req_4_0(phone, SERIAL_SET_COM_PROPS, old_baud,
+				exch = async_exchange_begin(sess);
+				async_req_4_0(exch, SERIAL_SET_COM_PROPS, old_baud,
 				    old_par, old_word_size, old_stop);
+				async_exchange_end(exch);
+				
 				free(buf);
-				async_hangup(phone);
-				devman_hangup_phone(DEVMAN_CLIENT);
+				async_hangup(sess);
 				return "Written less data than read from serial device";
 			}
@@ -180,11 +188,13 @@
 	
 	size_t eot_size = str_size(EOT);
-	ssize_t written = char_dev_write(phone, (void *) EOT, eot_size);
-	
-	async_req_4_0(phone, SERIAL_SET_COM_PROPS, old_baud,
+	ssize_t written = char_dev_write(sess, (void *) EOT, eot_size);
+	
+	exch = async_exchange_begin(sess);
+	async_req_4_0(exch, SERIAL_SET_COM_PROPS, old_baud,
 	    old_par, old_word_size, old_stop);
+	async_exchange_end(exch);
+	
 	free(buf);
-	async_hangup(phone);
-	devman_hangup_phone(DEVMAN_CLIENT);
+	async_hangup(sess);
 	
 	if (written < 0)
Index: uspace/app/tester/ipc/ping_pong.c
===================================================================
--- uspace/app/tester/ipc/ping_pong.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tester/ipc/ping_pong.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -30,5 +30,5 @@
 #include <stdlib.h>
 #include <sys/time.h>
-#include <ipc/ns.h>
+#include <ns.h>
 #include <async.h>
 #include <errno.h>
@@ -61,5 +61,5 @@
 		size_t i;
 		for (i = 0; i < COUNT_GRANULARITY; i++) {
-			int retval = async_req_0_0(PHONE_NS, NS_PING);
+			int retval = ns_ping();
 			
 			if (retval != EOK) {
Index: uspace/app/tester/libext2/libext2_1.c
===================================================================
--- uspace/app/tester/libext2/libext2_1.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/libext2/libext2_1.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "../tester.h"
+#include "../util.h"
+#include <libext2.h>
+#include <malloc.h>
+
+static ext2_superblock_t *fake_superblock1()
+{
+	uint8_t *buf;
+	int i;
+	
+	buf = malloc(EXT2_SUPERBLOCK_SIZE);
+	if (buf == NULL) {
+		return NULL;
+	}
+	
+	for (i = 0; i < EXT2_SUPERBLOCK_SIZE; i++) {
+		buf[i] = i % 256;
+	}
+	
+	return (ext2_superblock_t *) buf;
+}
+
+const char *test_libext2_1(void)
+{
+	ext2_superblock_t *fake1;
+	
+	TPRINTF("Testing libext2 superblock getters...\n");
+	TPRINTF("Simple test for correct position and byte order\n");
+	
+	fake1 = fake_superblock1();
+	if (fake1 == NULL) {
+		return "Failed allocating memory for test superblock 1";
+	}
+	
+	ASSERT_EQ_32(0x03020100, ext2_superblock_get_total_inode_count(fake1),
+	    "Failed getting total inode count");
+	ASSERT_EQ_32(0x07060504, ext2_superblock_get_total_block_count(fake1),
+	    "Failed getting total block count");
+	ASSERT_EQ_32(0x0B0A0908, ext2_superblock_get_reserved_block_count(fake1),
+	    "Failed getting reserved block count");
+	ASSERT_EQ_32(0x0F0E0D0C, ext2_superblock_get_free_block_count(fake1),
+	    "Failed getting free block count");
+	ASSERT_EQ_32(0x13121110, ext2_superblock_get_free_inode_count(fake1),
+	    "Failed getting free inode count");
+	ASSERT_EQ_32(0x17161514, ext2_superblock_get_first_block(fake1),
+	    "Failed getting first block number");
+	ASSERT_EQ_32(0x1B1A1918, ext2_superblock_get_block_size_log2(fake1),
+	    "Failed getting log block size");
+	ASSERT_EQ_32(0x1F1E1D1C, ext2_superblock_get_fragment_size_log2(fake1),
+	    "Failed getting log fragment size");
+	ASSERT_EQ_32(0x23222120, ext2_superblock_get_blocks_per_group(fake1),
+	    "Failed getting blocks per group");
+	ASSERT_EQ_32(0x27262524, ext2_superblock_get_fragments_per_group(fake1),
+	    "Failed getting fragments per group");
+	ASSERT_EQ_32(0x2B2A2928, ext2_superblock_get_inodes_per_group(fake1),
+	    "Failed getting inodes per group");
+	ASSERT_EQ_16(0x3938, ext2_superblock_get_magic(fake1),
+	    "Failed getting magic number");
+	ASSERT_EQ_16(0x3B3A, ext2_superblock_get_state(fake1),
+	    "Failed getting state");
+	ASSERT_EQ_16(0x3F3E, ext2_superblock_get_rev_minor(fake1),
+	    "Failed getting minor revision number");
+	ASSERT_EQ_32(0x4B4A4948, ext2_superblock_get_os(fake1),
+	    "Failed getting OS");
+	ASSERT_EQ_32(0x4F4E4D4C, ext2_superblock_get_rev_major(fake1),
+	    "Failed getting major revision number");
+	ASSERT_EQ_32(0x57565554, ext2_superblock_get_first_inode(fake1),
+	    "Failed getting first inode number");
+	ASSERT_EQ_16(0x5958, ext2_superblock_get_inode_size(fake1),
+	    "Failed getting size");
+	ASSERT_EQ_8(0x68, fake1->uuid[0], "UUID position is incorrect");
+	ASSERT_EQ_8(0x78, fake1->volume_name[0],
+	    "Volume name position is incorrect");
+	
+	return NULL;
+}
Index: uspace/app/tester/libext2/libext2_1.def
===================================================================
--- uspace/app/tester/libext2/libext2_1.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/libext2/libext2_1.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,6 @@
+{
+	"libext2_1",
+	"Superblock getters test",
+	&test_libext2_1,
+	true
+},
Index: uspace/app/tester/mm/common.c
===================================================================
--- uspace/app/tester/mm/common.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/mm/common.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2009 Martin Decky
+ * Copyright (c) 2009 Tomas Bures
+ * Copyright (c) 2009 Lubomir Bulej
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <malloc.h>
+#include <as.h>
+#include <adt/list.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "../tester.h"
+#include "common.h"
+
+/*
+ * Global error flag. The flag is set if an error
+ * is encountered (overlapping blocks, inconsistent
+ * block data, etc.)
+ */
+bool error_flag = false;
+
+/*
+ * Memory accounting: the amount of allocated memory and the
+ * number and list of allocated blocks.
+ */
+size_t mem_allocated;
+size_t mem_blocks_count;
+
+static LIST_INITIALIZE(mem_blocks);
+static LIST_INITIALIZE(mem_areas);
+
+/** Initializes the memory accounting structures.
+ *
+ */
+void init_mem(void)
+{
+	mem_allocated = 0;
+	mem_blocks_count = 0;
+}
+
+/** Cleanup all allocated memory blocks and mapped areas.
+ *
+ * Set the global error_flag if an error occurs.
+ *
+ */
+void done_mem(void)
+{
+	link_t *link;
+	
+	while ((link = list_head(&mem_blocks)) != NULL) {
+		mem_block_t *block = list_get_instance(link, mem_block_t, link);
+		free_block(block);
+	}
+	
+	while ((link = list_head(&mem_areas)) != NULL) {
+		mem_area_t *area = list_get_instance(link, mem_area_t, link);
+		unmap_area(area);
+	}
+}
+
+static bool overlap_match(link_t *link, void *addr, size_t size)
+{
+	mem_block_t *block = list_get_instance(link, mem_block_t, link);
+	
+	/* Entry block control structure <mbeg, mend) */
+	uint8_t *mbeg = (uint8_t *) block;
+	uint8_t *mend = (uint8_t *) block + sizeof(mem_block_t);
+	
+	/* Entry block memory <bbeg, bend) */
+	uint8_t *bbeg = (uint8_t *) block->addr;
+	uint8_t *bend = (uint8_t *) block->addr + block->size;
+	
+	/* Data block <dbeg, dend) */
+	uint8_t *dbeg = (uint8_t *) addr;
+	uint8_t *dend = (uint8_t *) addr + size;
+	
+	/* Check for overlaps */
+	if (((mbeg >= dbeg) && (mbeg < dend)) ||
+	    ((mend > dbeg) && (mend <= dend)) ||
+	    ((bbeg >= dbeg) && (bbeg < dend)) ||
+	    ((bend > dbeg) && (bend <= dend)))
+		return true;
+	
+	return false;
+}
+
+/** Test overlap
+ *
+ * Test whether a block starting at @addr overlaps with another,
+ * previously allocated memory block or its control structure.
+ *
+ * @param addr Initial address of the block
+ * @param size Size of the block
+ *
+ * @return False if the block does not overlap.
+ *
+ */
+static int test_overlap(void *addr, size_t size)
+{
+	bool fnd = false;
+	
+	list_foreach(mem_blocks, link) {
+		if (overlap_match(link, addr, size)) {
+			fnd = true;
+			break;
+		}
+	}
+	
+	return fnd;
+}
+
+static void check_consistency(const char *loc)
+{
+	/* Check heap consistency */
+	void *prob = heap_check();
+	if (prob != NULL) {
+		TPRINTF("\nError: Heap inconsistency at %p in %s.\n",
+		    prob, loc);
+		TSTACKTRACE();
+		error_flag = true;
+	}
+}
+
+/** Checked malloc
+ *
+ * Allocate @size bytes of memory and check whether the chunk comes
+ * from the non-mapped memory region and whether the chunk overlaps
+ * with other, previously allocated, chunks.
+ *
+ * @param size Amount of memory to allocate
+ *
+ * @return NULL if the allocation failed. Sets the global error_flag to
+ *         true if the allocation succeeded but is illegal.
+ *
+ */
+static void *checked_malloc(size_t size)
+{
+	void *data;
+	
+	/* Allocate the chunk of memory */
+	data = malloc(size);
+	check_consistency("checked_malloc");
+	if (data == NULL)
+		return NULL;
+	
+	/* Check for overlaps with other chunks */
+	if (test_overlap(data, size)) {
+		TPRINTF("\nError: Allocated block overlaps with another "
+		    "previously allocated block.\n");
+		TSTACKTRACE();
+		error_flag = true;
+	}
+	
+	return data;
+}
+
+
+/* Allocate block
+ *
+ * Allocate a block of memory of @size bytes and add record about it into
+ * the mem_blocks list. Return a pointer to the block holder structure or
+ * NULL if the allocation failed.
+ *
+ * If the allocation is illegal (e.g. the memory does not come from the
+ * right region or some of the allocated blocks overlap with others),
+ * set the global error_flag.
+ *
+ * @param size Size of the memory block
+ *
+ */
+mem_block_t *alloc_block(size_t size)
+{
+	/* Check for allocation limit */
+	if (mem_allocated >= MAX_ALLOC)
+		return NULL;
+	
+	/* Allocate the block holder */
+	mem_block_t *block =
+	    (mem_block_t *) checked_malloc(sizeof(mem_block_t));
+	if (block == NULL)
+		return NULL;
+	
+	link_initialize(&block->link);
+	
+	/* Allocate the block memory */
+	block->addr = checked_malloc(size);
+	if (block->addr == NULL) {
+		free(block);
+		check_consistency("alloc_block");
+		return NULL;
+	}
+	
+	block->size = size;
+	
+	/* Register the allocated block */
+	list_append(&block->link, &mem_blocks);
+	mem_allocated += size + sizeof(mem_block_t);
+	mem_blocks_count++;
+	
+	return block;
+}
+
+/** Free block
+ *
+ * Free the block of memory and the block control structure allocated by
+ * alloc_block. Set the global error_flag if an error occurs.
+ *
+ * @param block Block control structure
+ *
+ */
+void free_block(mem_block_t *block)
+{
+	/* Unregister the block */
+	list_remove(&block->link);
+	mem_allocated -= block->size + sizeof(mem_block_t);
+	mem_blocks_count--;
+	
+	/* Free the memory */
+	free(block->addr);
+	check_consistency("free_block (a)");
+	free(block);
+	check_consistency("free_block (b)");
+}
+
+/** Calculate expected value
+ *
+ * Compute the expected value of a byte located at @pos in memory
+ * block described by @block.
+ *
+ * @param block Memory block control structure
+ * @param pos   Position in the memory block data area
+ *
+ */
+static inline uint8_t block_expected_value(mem_block_t *block, uint8_t *pos)
+{
+	return ((uintptr_t) block ^ (uintptr_t) pos) & 0xff;
+}
+
+/** Fill block
+ *
+ * Fill the memory block controlled by @block with data.
+ *
+ * @param block Memory block control structure
+ *
+ */
+void fill_block(mem_block_t *block)
+{
+	for (uint8_t *pos = block->addr, *end = pos + block->size;
+	    pos < end; pos++)
+		*pos = block_expected_value(block, pos);
+	
+	check_consistency("fill_block");
+}
+
+/** Check block
+ *
+ * Check whether the block @block contains the data it was filled with.
+ * Set global error_flag if an error occurs.
+ *
+ * @param block Memory block control structure
+ *
+ */
+void check_block(mem_block_t *block)
+{
+	for (uint8_t *pos = block->addr, *end = pos + block->size;
+	    pos < end; pos++) {
+		if (*pos != block_expected_value(block, pos)) {
+			TPRINTF("\nError: Corrupted content of a data block.\n");
+			TSTACKTRACE();
+			error_flag = true;
+			return;
+		}
+	}
+}
+
+/** Get random block
+ *
+ * Select a random memory block from the list of allocated blocks.
+ *
+ * @return Block control structure or NULL if the list is empty.
+ *
+ */
+mem_block_t *get_random_block(void)
+{
+	if (mem_blocks_count == 0)
+		return NULL;
+	
+	unsigned int idx = rand() % mem_blocks_count;
+	link_t *entry = list_nth(&mem_blocks, idx);
+	
+	if (entry == NULL) {
+		TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
+		TSTACKTRACE();
+		error_flag = true;
+	}
+	
+	return list_get_instance(entry, mem_block_t, link);
+}
+
+/* Map memory area
+ *
+ * Map a memory area of @size bytes and add record about it into
+ * the mem_areas list. Return a pointer to the area holder structure or
+ * NULL if the mapping failed.
+ *
+ * @param size Size of the memory area
+ *
+ */
+mem_area_t *map_area(size_t size)
+{
+	/* Allocate the area holder */
+	mem_area_t *area =
+	    (mem_area_t *) checked_malloc(sizeof(mem_area_t));
+	if (area == NULL)
+		return NULL;
+	
+	link_initialize(&area->link);
+	
+	/* Map the memory area */
+	void *addr = as_get_mappable_page(size);
+	if (addr == NULL) {
+		free(area);
+		check_consistency("map_area (a)");
+		return NULL;
+	}
+	
+	area->addr = as_area_create(addr, size, AS_AREA_WRITE | AS_AREA_READ);
+	if (area->addr == (void *) -1) {
+		free(area);
+		check_consistency("map_area (b)");
+		return NULL;
+	}
+	
+	area->size = size;
+	
+	/* Register the allocated area */
+	list_append(&area->link, &mem_areas);
+	
+	return area;
+}
+
+/** Unmap area
+ *
+ * Unmap the memory area and free the block control structure.
+ * Set the global error_flag if an error occurs.
+ *
+ * @param area Memory area control structure
+ *
+ */
+void unmap_area(mem_area_t *area)
+{
+	/* Unregister the area */
+	list_remove(&area->link);
+	
+	/* Free the memory */
+	int ret = as_area_destroy(area->addr);
+	if (ret != EOK)
+		error_flag = true;
+	
+	free(area);
+	check_consistency("unmap_area");
+}
+
+/** Calculate expected value
+ *
+ * Compute the expected value of a byte located at @pos in memory
+ * area described by @area.
+ *
+ * @param area Memory area control structure
+ * @param pos  Position in the memory area data area
+ *
+ */
+static inline uint8_t area_expected_value(mem_area_t *area, uint8_t *pos)
+{
+	return ((uintptr_t) area ^ (uintptr_t) pos) & 0xaa;
+}
+
+/** Fill area
+ *
+ * Fill the memory area controlled by @area with data.
+ *
+ * @param area Memory area control structure
+ *
+ */
+void fill_area(mem_area_t *area)
+{
+	for (uint8_t *pos = area->addr, *end = pos + area->size;
+	    pos < end; pos++)
+		*pos = area_expected_value(area, pos);
+	
+	check_consistency("fill_area");
+}
Index: uspace/app/tester/mm/common.h
===================================================================
--- uspace/app/tester/mm/common.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/mm/common.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup tester
+ * @{
+ */
+/** @file
+ */
+
+#ifndef MM_COMMON_H_
+#define MM_COMMON_H_
+
+#include <sys/types.h>
+#include <bool.h>
+#include <adt/list.h>
+
+#define MAX_ALLOC  (16 * 1024 * 1024)
+
+#define AREA_GRANULARITY  16
+#define AREA_SIZE         (4 * PAGE_SIZE)
+
+typedef struct {
+	/* Address of the start of the block */
+	void *addr;
+	
+	/* Size of the memory block */
+	size_t size;
+	
+	/* Link to other blocks */
+	link_t link;
+} mem_block_t;
+
+typedef struct {
+	/* Address of the start of the area */
+	void *addr;
+	
+	/* Size of the memory area */
+	size_t size;
+	/* Link to other areas */
+	link_t link;
+} mem_area_t;
+
+/*
+ * Subphase control structures: subphase termination conditions,
+ * probabilities of individual actions, subphase control structure.
+ */
+
+typedef struct {
+	unsigned int max_cycles;
+	unsigned int no_memory;
+	unsigned int no_allocated;
+} sp_term_cond_t;
+
+typedef struct {
+	unsigned int alloc;
+	unsigned int free;
+} sp_action_prob_t;
+
+typedef struct {
+	const char *name;
+	sp_term_cond_t cond;
+	sp_action_prob_t prob;
+} subphase_t;
+
+/*
+ * Phase control structures: The minimum and maximum block size that
+ * can be allocated during the phase execution, phase control structure.
+ */
+
+typedef struct {
+	size_t min_block_size;
+	size_t max_block_size;
+} ph_alloc_size_t;
+
+typedef struct {
+	const char *name;
+	ph_alloc_size_t alloc;
+	subphase_t *subphases;
+} phase_t;
+
+extern bool error_flag;
+extern size_t mem_allocated;
+extern size_t mem_blocks_count;
+
+#define RETURN_IF_ERROR \
+	do { \
+		if (error_flag) \
+			return; \
+	} while (0)
+
+extern void init_mem(void);
+extern void done_mem(void);
+
+extern mem_block_t *alloc_block(size_t);
+extern void free_block(mem_block_t *);
+extern void fill_block(mem_block_t *);
+extern void check_block(mem_block_t *);
+extern mem_block_t *get_random_block(void);
+
+extern mem_area_t *map_area(size_t);
+extern void fill_area(mem_area_t *);
+extern void unmap_area(mem_area_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/tester/mm/malloc1.c
===================================================================
--- uspace/app/tester/mm/malloc1.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tester/mm/malloc1.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -30,7 +30,6 @@
 
 #include <stdio.h>
-#include <unistd.h>
 #include <stdlib.h>
-#include <malloc.h>
+#include "common.h"
 #include "../tester.h"
 
@@ -45,55 +44,4 @@
  */
 
-/**
- * sizeof_array
- * @array array to determine the size of
- *
- * Returns the size of @array in array elements.
- */
-#define sizeof_array(array) \
-	(sizeof(array) / sizeof((array)[0]))
-
-#define MAX_ALLOC (16 * 1024 * 1024)
-
-/*
- * Subphase control structures: subphase termination conditions,
- * probabilities of individual actions, subphase control structure.
- */
-
-typedef struct {
-	unsigned int max_cycles;
-	unsigned int no_memory;
-	unsigned int no_allocated;
-} sp_term_cond_s;
-
-typedef struct {
-	unsigned int alloc;
-	unsigned int free;
-} sp_action_prob_s;
-
-typedef struct {
-	const char *name;
-	sp_term_cond_s cond;
-	sp_action_prob_s prob;
-} subphase_s;
-
-
-/*
- * Phase control structures: The minimum and maximum block size that
- * can be allocated during the phase execution, phase control structure.
- */
-
-typedef struct {
-	size_t min_block_size;
-	size_t max_block_size;
-} ph_alloc_size_s;
-
-typedef struct {
-	const char *name;
-	ph_alloc_size_s alloc;
-	subphase_s *subphases;
-} phase_s;
-
-
 /*
  * Subphases are defined separately here. This is for two reasons:
@@ -101,5 +49,5 @@
  * how many subphases a phase contains.
  */
-static subphase_s subphases_32B[] = {
+static subphase_t subphases_32B[] = {
 	{
 		.name = "Allocation",
@@ -140,5 +88,5 @@
 };
 
-static subphase_s subphases_128K[] = {
+static subphase_t subphases_128K[] = {
 	{
 		.name = "Allocation",
@@ -179,5 +127,5 @@
 };
 
-static subphase_s subphases_default[] = {
+static subphase_t subphases_default[] = {
 	{
 		.name = "Allocation",
@@ -217,10 +165,9 @@
 	}
 };
-
 
 /*
  * Phase definitions.
  */
-static phase_s phases[] = {
+static phase_t phases[] = {
 	{
 		.name = "32 B memory blocks",
@@ -257,307 +204,10 @@
 };
 
-
-/*
- * Global error flag. The flag is set if an error
- * is encountered (overlapping blocks, inconsistent
- * block data, etc.)
- */
-static bool error_flag = false;
-
-/*
- * Memory accounting: the amount of allocated memory and the
- * number and list of allocated blocks.
- */
-static size_t mem_allocated;
-static size_t mem_blocks_count;
-
-static LIST_INITIALIZE(mem_blocks);
-
-typedef struct {
-	/* Address of the start of the block */
-	void *addr;
-	
-	/* Size of the memory block */
-	size_t size;
-	
-	/* link to other blocks */
-	link_t link;
-} mem_block_s;
-
-typedef mem_block_s *mem_block_t;
-
-
-/** init_mem
- *
- * Initializes the memory accounting structures.
- *
- */
-static void init_mem(void)
+static void do_subphase(phase_t *phase, subphase_t *subphase)
 {
-	mem_allocated = 0;
-	mem_blocks_count = 0;
-}
-
-
-static bool overlap_match(link_t *entry, void *addr, size_t size)
-{
-	mem_block_t mblk = list_get_instance(entry, mem_block_s, link);
-	
-	/* Entry block control structure <mbeg, mend) */
-	uint8_t *mbeg = (uint8_t *) mblk;
-	uint8_t *mend = (uint8_t *) mblk + sizeof(mem_block_s);
-	
-	/* Entry block memory <bbeg, bend) */
-	uint8_t *bbeg = (uint8_t *) mblk->addr;
-	uint8_t *bend = (uint8_t *) mblk->addr + mblk->size;
-	
-	/* Data block <dbeg, dend) */
-	uint8_t *dbeg = (uint8_t *) addr;
-	uint8_t *dend = (uint8_t *) addr + size;
-	
-	/* Check for overlaps */
-	if (((mbeg >= dbeg) && (mbeg < dend)) ||
-		((mend > dbeg) && (mend <= dend)) ||
-		((bbeg >= dbeg) && (bbeg < dend)) ||
-		((bend > dbeg) && (bend <= dend)))
-		return true;
-	
-	return false;
-}
-
-
-/** test_overlap
- *
- * Test whether a block starting at @addr overlaps with another, previously
- * allocated memory block or its control structure.
- *
- * @param addr Initial address of the block
- * @param size Size of the block
- *
- * @return false if the block does not overlap.
- *
- */
-static int test_overlap(void *addr, size_t size)
-{
-	link_t *entry;
-	bool fnd = false;
-	
-	for (entry = mem_blocks.next; entry != &mem_blocks; entry = entry->next) {
-		if (overlap_match(entry, addr, size)) {
-			fnd = true;
-			break;
-		}
-	}
-	
-	return fnd;
-}
-
-
-/** checked_malloc
- *
- * Allocate @size bytes of memory and check whether the chunk comes
- * from the non-mapped memory region and whether the chunk overlaps
- * with other, previously allocated, chunks.
- *
- * @param size Amount of memory to allocate
- *
- * @return NULL if the allocation failed. Sets the global error_flag to
- *         true if the allocation succeeded but is illegal.
- *
- */
-static void *checked_malloc(size_t size)
-{
-	void *data;
-	
-	/* Allocate the chunk of memory */
-	data = malloc(size);
-	if (data == NULL)
-		return NULL;
-	
-	/* Check for overlaps with other chunks */
-	if (test_overlap(data, size)) {
-		TPRINTF("\nError: Allocated block overlaps with another "
-			"previously allocated block.\n");
-		error_flag = true;
-	}
-	
-	return data;
-}
-
-
-/** alloc_block
- *
- * Allocate a block of memory of @size bytes and add record about it into
- * the mem_blocks list. Return a pointer to the block holder structure or
- * NULL if the allocation failed.
- *
- * If the allocation is illegal (e.g. the memory does not come from the
- * right region or some of the allocated blocks overlap with others),
- * set the global error_flag.
- *
- * @param size Size of the memory block
- *
- */
-static mem_block_t alloc_block(size_t size)
-{
-	/* Check for allocation limit */
-	if (mem_allocated >= MAX_ALLOC)
-		return NULL;
-	
-	/* Allocate the block holder */
-	mem_block_t block = (mem_block_t) checked_malloc(sizeof(mem_block_s));
-	if (block == NULL)
-		return NULL;
-	
-	link_initialize(&block->link);
-	
-	/* Allocate the block memory */
-	block->addr = checked_malloc(size);
-	if (block->addr == NULL) {
-		free(block);
-		return NULL;
-	}
-	
-	block->size = size;
-	
-	/* Register the allocated block */
-	list_append(&block->link, &mem_blocks);
-	mem_allocated += size + sizeof(mem_block_s);
-	mem_blocks_count++;
-	
-	return block;
-}
-
-
-/** free_block
- *
- * Free the block of memory and the block control structure allocated by
- * alloc_block. Set the global error_flag if an error occurs.
- *
- * @param block Block control structure
- *
- */
-static void free_block(mem_block_t block)
-{
-	/* Unregister the block */
-	list_remove(&block->link);
-	mem_allocated -= block->size + sizeof(mem_block_s);
-	mem_blocks_count--;
-	
-	/* Free the memory */
-	free(block->addr);
-	free(block);
-}
-
-
-/** expected_value
- *
- * Compute the expected value of a byte located at @pos in memory
- * block described by @blk.
- *
- * @param blk Memory block control structure
- * @param pos Position in the memory block data area
- *
- */
-static inline uint8_t expected_value(mem_block_t blk, uint8_t *pos)
-{
-	return ((unsigned long) blk ^ (unsigned long) pos) & 0xff;
-}
-
-
-/** fill_block
- *
- * Fill the memory block controlled by @blk with data.
- *
- * @param blk Memory block control structure
- *
- */
-static void fill_block(mem_block_t blk)
-{
-	uint8_t *pos;
-	uint8_t *end;
-	
-	for (pos = blk->addr, end = pos + blk->size; pos < end; pos++)
-		*pos = expected_value(blk, pos);
-}
-
-
-/** check_block
- *
- * Check whether the block @blk contains the data it was filled with.
- * Set global error_flag if an error occurs.
- *
- * @param blk Memory block control structure
- *
- */
-static void check_block(mem_block_t blk)
-{
-	uint8_t *pos;
-	uint8_t *end;
-	
-	for (pos = blk->addr, end = pos + blk->size; pos < end; pos++) {
-		if (*pos != expected_value (blk, pos)) {
-			TPRINTF("\nError: Corrupted content of a data block.\n");
-			error_flag = true;
-			return;
-		}
-	}
-}
-
-
-static link_t *list_get_nth(link_t *list, unsigned int i)
-{
-	unsigned int cnt = 0;
-	link_t *entry;
-	
-	for (entry = list->next; entry != list; entry = entry->next) {
-		if (cnt == i)
-			return entry;
-		
-		cnt++;
-	}
-	
-	return NULL;
-}
-
-
-/** get_random_block
- *
- * Select a random memory block from the list of allocated blocks.
- *
- * @return Block control structure or NULL if the list is empty.
- *
- */
-static mem_block_t get_random_block(void)
-{
-	if (mem_blocks_count == 0)
-		return NULL;
-	
-	unsigned int blkidx = rand() % mem_blocks_count;
-	link_t *entry = list_get_nth(&mem_blocks, blkidx);
-	
-	if (entry == NULL) {
-		TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
-		error_flag = true;
-	}
-	
-	return list_get_instance(entry, mem_block_s, link);
-}
-
-
-#define RETURN_IF_ERROR \
-{ \
-	if (error_flag) \
-		return; \
-}
-
-
-static void do_subphase(phase_s *phase, subphase_s *subphase)
-{
-	unsigned int cycles;
-	for (cycles = 0; /* always */; cycles++) {
-		
-		if (subphase->cond.max_cycles &&
-			cycles >= subphase->cond.max_cycles) {
+	for (unsigned int cycles = 0; /* always */; cycles++) {
+		
+		if ((subphase->cond.max_cycles) &&
+		    (cycles >= subphase->cond.max_cycles)) {
 			/*
 			 * We have performed the required number of
@@ -572,9 +222,12 @@
 		unsigned int rnd = rand() % 100;
 		if (rnd < subphase->prob.alloc) {
-			/* Compute a random number lying in interval <min_block_size, max_block_size> */
+			/*
+			 * Compute a random number lying in interval
+			 * <min_block_size, max_block_size>
+			 */
 			int alloc = phase->alloc.min_block_size +
 			    (rand() % (phase->alloc.max_block_size - phase->alloc.min_block_size + 1));
 			
-			mem_block_t blk = alloc_block(alloc);
+			mem_block_t *blk = alloc_block(alloc);
 			RETURN_IF_ERROR;
 			
@@ -585,12 +238,12 @@
 					break;
 				}
-				
 			} else {
 				TPRINTF("A");
 				fill_block(blk);
+				RETURN_IF_ERROR;
 			}
 			
 		} else if (rnd < subphase->prob.free) {
-			mem_block_t blk = get_random_block();
+			mem_block_t *blk = get_random_block();
 			if (blk == NULL) {
 				TPRINTF("F(R)");
@@ -599,5 +252,4 @@
 					break;
 				}
-				
 			} else {
 				TPRINTF("R");
@@ -614,11 +266,8 @@
 }
 
-
-static void do_phase(phase_s *phase)
+static void do_phase(phase_t *phase)
 {
-	unsigned int subno;
-	
-	for (subno = 0; subno < 3; subno++) {
-		subphase_s *subphase = & phase->subphases [subno];
+	for (unsigned int subno = 0; subno < 3; subno++) {
+		subphase_t *subphase = &phase->subphases[subno];
 		
 		TPRINTF(".. Sub-phase %u (%s)\n", subno + 1, subphase->name);
@@ -632,7 +281,7 @@
 	init_mem();
 	
-	unsigned int phaseno;
-	for (phaseno = 0; phaseno < sizeof_array(phases); phaseno++) {
-		phase_s *phase = &phases[phaseno];
+	for (unsigned int phaseno = 0; phaseno < sizeof_array(phases);
+	    phaseno++) {
+		phase_t *phase = &phases[phaseno];
 		
 		TPRINTF("Entering phase %u (%s)\n", phaseno + 1, phase->name);
@@ -645,4 +294,6 @@
 	}
 	
+	TPRINTF("Cleaning up.\n");
+	done_mem();
 	if (error_flag)
 		return "Test failed";
Index: uspace/app/tester/mm/malloc2.c
===================================================================
--- uspace/app/tester/mm/malloc2.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/mm/malloc2.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 Jakub Jermar 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include "../tester.h"
+
+const char *test_malloc2(void)
+{
+	int cnt = 0;
+	char *p;
+
+	TPRINTF("Provoking the kernel into overcommitting memory to us...\n");
+	while ((p = malloc(1024 * 1024))) {
+		TPRINTF("%dM ", ++cnt);
+		*p = 'A';
+	}
+	TPRINTF("\nWas refused more memory as expected.\n");
+
+	return NULL;
+}
Index: uspace/app/tester/mm/malloc2.def
===================================================================
--- uspace/app/tester/mm/malloc2.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/mm/malloc2.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,6 @@
+{
+	"malloc2",
+	"Memory reservation feature test",
+	&test_malloc2,
+	false	
+},
Index: uspace/app/tester/mm/malloc3.c
===================================================================
--- uspace/app/tester/mm/malloc3.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/mm/malloc3.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2009 Martin Decky
+ * Copyright (c) 2009 Tomas Bures
+ * Copyright (c) 2009 Lubomir Bulej
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "common.h"
+#include "../tester.h"
+
+/*
+ * The test is a slight adaptation of malloc1 test. The major difference
+ * is that the test forces the heap allocator to create multiple
+ * heap areas by creating disturbing address space areas.
+ */
+
+static subphase_t subphases_32B[] = {
+	{
+		.name = "Allocation",
+		.cond = {
+			.max_cycles = 200,
+			.no_memory = 1,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 90,
+			.free = 100
+		}
+	},
+	{
+		.name = "Alloc/Dealloc",
+		.cond = {
+			.max_cycles = 200,
+			.no_memory = 0,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 50,
+			.free = 100
+		}
+	},
+	{
+		.name = "Deallocation",
+		.cond = {
+			.max_cycles = 0,
+			.no_memory = 0,
+			.no_allocated = 1,
+		},
+		.prob = {
+			.alloc = 10,
+			.free = 100
+		}
+	}
+};
+
+static subphase_t subphases_128K[] = {
+	{
+		.name = "Allocation",
+		.cond = {
+			.max_cycles = 0,
+			.no_memory = 1,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 70,
+			.free = 100
+		}
+	},
+	{
+		.name = "Alloc/Dealloc",
+		.cond = {
+			.max_cycles = 30,
+			.no_memory = 0,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 50,
+			.free = 100
+		}
+	},
+	{
+		.name = "Deallocation",
+		.cond = {
+			.max_cycles = 0,
+			.no_memory = 0,
+			.no_allocated = 1,
+		},
+		.prob = {
+			.alloc = 30,
+			.free = 100
+		}
+	}
+};
+
+static subphase_t subphases_default[] = {
+	{
+		.name = "Allocation",
+		.cond = {
+			.max_cycles = 0,
+			.no_memory = 1,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 90,
+			.free = 100
+		}
+	},
+	{
+		.name = "Alloc/Dealloc",
+		.cond = {
+			.max_cycles = 200,
+			.no_memory = 0,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 50,
+			.free = 100
+		}
+	},
+	{
+		.name = "Deallocation",
+		.cond = {
+			.max_cycles = 0,
+			.no_memory = 0,
+			.no_allocated = 1,
+		},
+		.prob = {
+			.alloc = 10,
+			.free = 100
+		}
+	}
+};
+
+/*
+ * Phase definitions.
+ */
+static phase_t phases[] = {
+	{
+		.name = "32 B memory blocks",
+		.alloc = {
+			.min_block_size = 32,
+			.max_block_size = 32
+		},
+		.subphases = subphases_32B
+	},
+	{
+		.name = "128 KB memory blocks",
+		.alloc = {
+			.min_block_size = 128 * 1024,
+			.max_block_size = 128 * 1024
+		},
+		.subphases = subphases_128K
+	},
+	{
+		.name = "2500 B memory blocks",
+		.alloc = {
+			.min_block_size = 2500,
+			.max_block_size = 2500
+		},
+		.subphases = subphases_default
+	},
+	{
+		.name = "1 B .. 250000 B memory blocks",
+		.alloc = {
+			.min_block_size = 1,
+			.max_block_size = 250000
+		},
+		.subphases = subphases_default
+	}
+};
+
+static void do_subphase(phase_t *phase, subphase_t *subphase)
+{
+	for (unsigned int cycles = 0; /* always */; cycles++) {
+		
+		if ((subphase->cond.max_cycles) &&
+		    (cycles >= subphase->cond.max_cycles)) {
+			/*
+			 * We have performed the required number of
+			 * cycles. End the current subphase.
+			 */
+			break;
+		}
+		
+		/*
+		 * Decide whether we alloc or free memory in this step.
+		 */
+		unsigned int rnd = rand() % 100;
+		if (rnd < subphase->prob.alloc) {
+			/*
+			 * Compute a random number lying in interval
+			 * <min_block_size, max_block_size>
+			 */
+			int alloc = phase->alloc.min_block_size +
+			    (rand() % (phase->alloc.max_block_size - phase->alloc.min_block_size + 1));
+			
+			mem_block_t *blk = alloc_block(alloc);
+			RETURN_IF_ERROR;
+			
+			if (blk == NULL) {
+				TPRINTF("F(A)");
+				if (subphase->cond.no_memory) {
+					/* We filled the memory. Proceed to next subphase */
+					break;
+				}
+			} else {
+				TPRINTF("A");
+				fill_block(blk);
+				RETURN_IF_ERROR;
+				
+				if ((mem_blocks_count % AREA_GRANULARITY) == 0) {
+					mem_area_t *area = map_area(AREA_SIZE);
+					RETURN_IF_ERROR;
+					
+					if (area != NULL) {
+						TPRINTF("*");
+						fill_area(area);
+						RETURN_IF_ERROR;
+					} else
+						TPRINTF("F(*)");
+				}
+			}
+			
+		} else if (rnd < subphase->prob.free) {
+			mem_block_t *blk = get_random_block();
+			if (blk == NULL) {
+				TPRINTF("F(R)");
+				if (subphase->cond.no_allocated) {
+					/* We free all the memory. Proceed to next subphase. */
+					break;
+				}
+			} else {
+				TPRINTF("R");
+				check_block(blk);
+				RETURN_IF_ERROR;
+				
+				free_block(blk);
+				RETURN_IF_ERROR;
+			}
+		}
+	}
+	
+	TPRINTF("\n..  finished.\n");
+}
+
+static void do_phase(phase_t *phase)
+{
+	for (unsigned int subno = 0; subno < 3; subno++) {
+		subphase_t *subphase = &phase->subphases[subno];
+		
+		TPRINTF(".. Sub-phase %u (%s)\n", subno + 1, subphase->name);
+		do_subphase(phase, subphase);
+		RETURN_IF_ERROR;
+	}
+}
+
+const char *test_malloc3(void)
+{
+	init_mem();
+	
+	for (unsigned int phaseno = 0; phaseno < sizeof_array(phases);
+	    phaseno++) {
+		phase_t *phase = &phases[phaseno];
+		
+		TPRINTF("Entering phase %u (%s)\n", phaseno + 1, phase->name);
+		
+		do_phase(phase);
+		if (error_flag)
+			break;
+		
+		TPRINTF("Phase finished.\n");
+	}
+	
+	TPRINTF("Cleaning up.\n");
+	done_mem();
+	if (error_flag)
+		return "Test failed";
+	
+	return NULL;
+}
Index: uspace/app/tester/mm/malloc3.def
===================================================================
--- uspace/app/tester/mm/malloc3.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/mm/malloc3.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,6 @@
+{
+	"malloc3",
+	"Multi-heap memory allocator test",
+	&test_malloc3,
+	true
+},
Index: uspace/app/tester/mm/mapping1.c
===================================================================
--- uspace/app/tester/mm/mapping1.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/mm/mapping1.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <as.h>
+#include <errno.h>
+#include "../tester.h"
+
+#define BUFFER1_PAGES 4
+#define BUFFER2_PAGES 2
+
+static void *create_as_area(size_t size)
+{
+	void *result = as_get_mappable_page(size);
+	TPRINTF("Creating AS area...\n");
+	if (as_area_create(result, size,
+	    AS_AREA_READ | AS_AREA_WRITE) != result) {
+		return NULL;
+	}
+	return result;
+}
+
+static void touch_area(void *area, size_t size)
+{
+	TPRINTF("Touching (faulting-in) AS area...\n");
+	
+	char *ptr = (char *)area;
+	
+	while (size > 0) {
+		*ptr = 0;
+		size--;
+		ptr++;
+	}
+}
+
+#define VERIFY_MAPPING(area, page_count, expected_rc) \
+    verify_mapping((area), (page_count), (expected_rc), #expected_rc)
+
+static bool verify_mapping(void *area, int page_count, int expected_rc,
+    const char *expected_rc_str)
+{
+	TPRINTF("Verifying mapping (expected: %s).\n", expected_rc_str);
+	int i;
+	for (i = 0; i < page_count; i++) {
+		void *page_start = ((char *)area) + PAGE_SIZE * i;
+		int rc = as_get_physical_mapping(page_start, NULL);
+		if (rc != expected_rc) {
+			TPRINTF("as_get_physical_mapping() = %d != %d\n",
+			    rc, expected_rc);
+			return false;
+		}
+	}
+	return true;
+}
+
+const char *test_mapping1(void)
+{
+	int rc;
+	
+	size_t buffer1_len = BUFFER1_PAGES * PAGE_SIZE;
+	size_t buffer2_len = BUFFER2_PAGES * PAGE_SIZE;
+	void *buffer1 = create_as_area(buffer1_len);
+	void *buffer2 = create_as_area(buffer2_len);
+	if (!buffer1 || !buffer2) {
+		return "Cannot allocate memory";
+	}
+	
+	touch_area(buffer1, buffer1_len);
+	touch_area(buffer2, buffer2_len);
+	
+	/* Now verify that mapping to physical frames exist. */
+	if (!VERIFY_MAPPING(buffer1, BUFFER1_PAGES, EOK)) {
+		return "Failed to find mapping (buffer1)";
+	}
+	if (!VERIFY_MAPPING(buffer2, BUFFER2_PAGES, EOK)) {
+		return "Failed to find mapping (buffer2)";
+	}
+	
+	/* Let's destroy the buffer1 area and access it again. */
+	rc = as_area_destroy(buffer1);
+	if (rc != EOK) {
+		return "Failed to destroy AS area";
+	}
+	if (!VERIFY_MAPPING(buffer1, BUFFER1_PAGES, ENOENT)) {
+		return "Mapping of destroyed area still exists";
+	}
+	
+	/* clean-up */
+	rc = as_area_destroy(buffer2);
+	if (rc != EOK) {
+		return "Failed to destroy AS area";
+	}
+	
+	return NULL;
+}
Index: uspace/app/tester/mm/mapping1.def
===================================================================
--- uspace/app/tester/mm/mapping1.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/mm/mapping1.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,6 @@
+{
+	"mapping1",
+	"Page mapping test",
+	&test_mapping1,
+	true
+},
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tester/tester.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -62,7 +62,12 @@
 #include "loop/loop1.def"
 #include "mm/malloc1.def"
+#include "mm/malloc2.def"
+#include "mm/malloc3.def"
+#include "mm/mapping1.def"
 #include "hw/serial/serial1.def"
 #include "hw/misc/virtchar1.def"
+#include "libext2/libext2_1.def"
 #include "devs/devman1.def"
+#include "devs/devman2.def"
 	{NULL, NULL, NULL, false}
 };
Index: uspace/app/tester/tester.h
===================================================================
--- uspace/app/tester/tester.h	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tester/tester.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -38,4 +38,5 @@
 #include <sys/types.h>
 #include <bool.h>
+#include <stacktrace.h>
 
 #define IPC_TEST_SERVICE  10240
@@ -46,10 +47,26 @@
 extern char **test_argv;
 
+/**
+ * sizeof_array
+ * @array array to determine the size of
+ *
+ * Returns the size of @array in array elements.
+ */
+#define sizeof_array(array) \
+	(sizeof(array) / sizeof((array)[0]))
+
 #define TPRINTF(format, ...) \
-	{ \
+	do { \
 		if (!test_quiet) { \
-			fprintf(stderr, format, ##__VA_ARGS__); \
+			fprintf(stderr, (format), ##__VA_ARGS__); \
 		} \
-	}
+	} while (0)
+
+#define TSTACKTRACE() \
+	do { \
+		if (!test_quiet) { \
+			stacktrace_print(); \
+		} \
+	} while (0)
 
 typedef const char *(*test_entry_t)(void);
@@ -78,7 +95,12 @@
 extern const char *test_loop1(void);
 extern const char *test_malloc1(void);
+extern const char *test_malloc2(void);
+extern const char *test_malloc3(void);
+extern const char *test_mapping1(void);
 extern const char *test_serial1(void);
 extern const char *test_virtchar1(void);
+extern const char *test_libext2_1(void);
 extern const char *test_devman1(void);
+extern const char *test_devman2(void);
 
 extern test_t tests[];
Index: uspace/app/tester/util.c
===================================================================
--- uspace/app/tester/util.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/util.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup tester
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include "util.h"
+#undef ASSERT_EQ_FN_DEF
+#define ASSERT_EQ_FN_DEF(type, fmt, fmtx) \
+bool assert_eq_fn_##type(type exp, type act, const char *act_desc) \
+{ \
+	if (exp != act) { \
+		fprintf(stderr, "Expected %s to be %" fmt " (0x%" fmtx "),"\
+		    " but was %" fmt " (0x%" fmtx ") \n", \
+		    act_desc, exp, exp, act, act); \
+	} \
+	return exp != act; \
+}
+
+#include "util_functions.def"
+
+
+/** @}
+ */
Index: uspace/app/tester/util.h
===================================================================
--- uspace/app/tester/util.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/util.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup tester
+ * @{
+ */
+/** @file
+ */
+
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <stdio.h>
+#include "tester.h"
+
+#define ASSERT_EQ_FN_DEF(type, fmt, fmtx) \
+extern bool assert_eq_fn_##type(type, type, const char *);
+
+#include "util_functions.def"
+
+#define ASSERT_EQ_64(exp, act, msg) \
+{if (assert_eq_fn_uint64_t(exp, act, #act)) {return msg;}}
+
+#define ASSERT_EQ_32(exp, act, msg) \
+{if (assert_eq_fn_uint32_t(exp, act, #act)) {return msg;}}
+
+#define ASSERT_EQ_16(exp, act, msg) \
+{if (assert_eq_fn_uint16_t(exp, act, #act)) {return msg;}}
+
+#define ASSERT_EQ_8(exp, act, msg) \
+{if (assert_eq_fn_uint8_t(exp, act, #act)) {return msg;}}
+
+#endif
+
+/** @}
+ */
Index: uspace/app/tester/util_functions.def
===================================================================
--- uspace/app/tester/util_functions.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/tester/util_functions.def	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,4 @@
+ASSERT_EQ_FN_DEF(uint8_t, "hhu", "hhx")
+ASSERT_EQ_FN_DEF(uint16_t, "hu", "hx")
+ASSERT_EQ_FN_DEF(uint32_t, "u", "x")
+ASSERT_EQ_FN_DEF(uint64_t, PRIu64, PRIx64)
Index: uspace/app/testread/Makefile
===================================================================
--- uspace/app/testread/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/testread/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2011 Martin Sucha
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+BINARY = testread
+
+SOURCES = \
+	testread.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/testread/testread.c
===================================================================
--- uspace/app/testread/testread.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/testread/testread.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2011 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup test
+ * @{
+ */
+
+/**
+ * @file	testread.c
+ * This program checks if the file contains a pattern of increasing
+ * 64 bit unsigned integers (that may overflow at some point)
+ * stored in little endian byte order.
+ * This is to verify that the filesystem reads
+ * the files correctly.
+ * If the file does not contain specified pattern, it stops
+ * at the point where the file does not match and prints
+ * the byte offset at which the error occured.
+ * While checking the file, the program displays how many megabytes
+ * it has already read, how long it took to read the last megabyte
+ * and current and average read speed.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <mem.h>
+#include <devmap.h>
+#include <byteorder.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <time.h>
+
+#define NAME	"testread"
+#define BUFELEMS 1024
+#define MBYTE (1024*1024)
+
+static void syntax_print(void);
+
+int main(int argc, char **argv)
+{
+
+	FILE *file;
+	char *file_name;
+	uint64_t *buf;
+	uint64_t expected;
+	aoff64_t offset;
+	aoff64_t next_mark;
+	aoff64_t last_mark;
+	unsigned int i;
+	bool check_enabled = true;
+	bool progress = true;
+	
+	if (argc < 2) {
+		printf(NAME ": Error, argument missing.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	/* Skip program name */
+	--argc; ++argv;
+	
+	if (argc > 0 && str_cmp(*argv, "--no-check") == 0) {
+		check_enabled = false;
+		--argc; ++argv;
+	}
+	
+	if (argc > 0 && str_cmp(*argv, "--no-progress") == 0) {
+		progress = false;
+		--argc; ++argv;
+	}
+	
+	if (argc != 1) {
+		printf(NAME ": Error, unexpected argument.\n");
+		syntax_print();
+		return 1;
+	}
+	
+	file_name = *argv;
+	
+	buf = calloc(BUFELEMS, sizeof(uint64_t));
+	if (buf == NULL) {
+		printf("Failed allocating buffer\n");
+		return 1;
+	}
+	
+	file = fopen(file_name, "r");
+	if (file == NULL) {
+		printf("Failed opening file\n");
+		return 1;
+	}
+	
+	expected = 0;
+	offset = 0;
+	next_mark = 0;
+	last_mark = 0;
+	struct timeval prev_time;
+	struct timeval start_time;
+	int rc;
+	rc = gettimeofday(&start_time, NULL);
+	if (rc != EOK) {
+		printf("gettimeofday failed\n");
+		fclose(file);
+		free(buf);
+		return 1;
+	}
+	prev_time = start_time;
+	
+	while (!feof(file)) {
+		size_t elems = fread(buf, sizeof(uint64_t), BUFELEMS, file);
+		if (ferror(file)) {
+			printf("Failed reading file\n");
+			fclose(file);
+			free(buf);
+			return 1;
+		}
+		
+		for (i = 0; i < elems; i++) {
+			if (check_enabled && uint64_t_le2host(buf[i]) != expected) {
+				printf("Unexpected value at offset %" PRIuOFF64 "\n", offset);
+				fclose(file);
+				free(buf);
+				return 2;
+			}
+			expected++;
+			offset += sizeof(uint64_t);
+		}
+		
+		if (progress && offset >= next_mark) {
+			struct timeval cur_time;
+			rc = gettimeofday(&cur_time, NULL);
+			if (rc != EOK) {
+				printf("gettimeofday failed\n");
+				fclose(file);
+				free(buf);
+				return 1;
+			}
+			uint32_t last_run = cur_time.tv_sec - prev_time.tv_sec;
+			uint32_t total_time = cur_time.tv_sec - start_time.tv_sec;
+			if (last_run > 0 && total_time > 0) {
+				printf("%" PRIuOFF64 "M - time: %u s, "
+				    "cur: %"PRIuOFF64 " B/s, avg: %" PRIuOFF64 " B/s\n",
+				    offset / MBYTE, last_run,
+				    (offset-last_mark)/last_run,
+				    offset/total_time);
+				prev_time = cur_time;
+				last_mark = offset;
+			}
+			next_mark += MBYTE;
+		}
+	}
+	
+	struct timeval final_time;
+	rc = gettimeofday(&final_time, NULL);
+	if (rc != EOK) {
+		printf("gettimeofday failed\n");
+		fclose(file);
+		free(buf);
+		return 1;
+	}
+	
+	uint32_t total_run_time = final_time.tv_sec - start_time.tv_sec;
+	if (total_run_time > 0) {
+		printf("total bytes: %" PRIuOFF64 
+		    ", total time: %u s, avg speed: %" PRIuOFF64 " B/s\n",
+		    offset,
+		    total_run_time,
+		    offset/total_run_time);
+	}
+	
+	fclose(file);
+	free(buf);
+
+	return 0;
+}
+
+
+static void syntax_print(void)
+{
+	printf("syntax: testread <filename>\n");
+}
+
+/**
+ * @}
+ */
Index: uspace/app/tetris/Makefile
===================================================================
--- uspace/app/tetris/Makefile	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tetris/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -34,5 +34,4 @@
 	shapes.c \
 	scores.c \
-	input.c \
 	tetris.c \
 	screen.c
Index: uspace/app/tetris/input.c
===================================================================
--- uspace/app/tetris/input.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ 	(revision )
@@ -1,197 +1,0 @@
-/*	$OpenBSD: input.c,v 1.12 2005/04/13 02:33:08 deraadt Exp $	*/
-/*    $NetBSD: input.c,v 1.3 1996/02/06 22:47:33 jtc Exp $    */
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)input.c	8.1 (Berkeley) 5/31/93
- */
-
-/** @addtogroup tetris
- * @{
- */
-/** @file
- */
-
-/*
- * Tetris input.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <stdio.h>
-
-#include <errno.h>
-#include <unistd.h>
-#include <str.h>
-
-#include "input.h"
-#include "tetris.h"
-
-#include <async.h>
-#include <vfs/vfs.h>
-#include <io/console.h>
-#include <ipc/console.h>
-
-/* return true iff the given timeval is positive */
-#define	TV_POS(tv) \
-	((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0))
-
-/* subtract timeval `sub' from `res' */
-#define	TV_SUB(res, sub) \
-	(res)->tv_sec -= (sub)->tv_sec; \
-	(res)->tv_usec -= (sub)->tv_usec; \
-	if ((res)->tv_usec < 0) { \
-		(res)->tv_usec += 1000000; \
-		(res)->tv_sec--; \
-	}
-
-/* We will use a hack here - if lastchar is non-zero, it is
- * the last character read. We will somehow simulate the select
- * semantics.
- */
-static aid_t getchar_inprog = 0;
-static char lastchar = '\0';
-
-/*
- * Do a `read wait': select for reading from stdin, with timeout *tvp.
- * On return, modify *tvp to reflect the amount of time spent waiting.
- * It will be positive only if input appeared before the time ran out;
- * otherwise it will be zero or perhaps negative.
- *
- * If tvp is nil, wait forever, but return if select is interrupted.
- *
- * Return 0 => no input, 1 => can read() from stdin
- *
- */
-int rwait(struct timeval *tvp)
-{
-	struct timeval starttv, endtv, *s;
-	static ipc_call_t charcall;
-	sysarg_t rc;
-	
-	/*
-	 * Someday, select() will do this for us.
-	 * Just in case that day is now, and no one has
-	 * changed this, we use a temporary.
-	 */
-	if (tvp) {
-		(void) gettimeofday(&starttv, NULL);
-		endtv = *tvp;
-		s = &endtv;
-	} else
-		s = NULL;
-	
-	if (!lastchar) {
-again:
-		if (!getchar_inprog) {
-			getchar_inprog = async_send_0(fphone(stdin),
-			    CONSOLE_GET_EVENT, &charcall);
-		}
-		
-		if (!s)
-			async_wait_for(getchar_inprog, &rc);
-		else if (async_wait_timeout(getchar_inprog, &rc, s->tv_usec) == ETIMEOUT) {
-			tvp->tv_sec = 0;
-			tvp->tv_usec = 0;
-			return (0);
-		}
-		
-		getchar_inprog = 0;
-		if (rc)
-			stop("end of file, help");
-		
-		if (IPC_GET_ARG1(charcall) == KEY_RELEASE)
-			goto again;
-		
-		lastchar = IPC_GET_ARG4(charcall);
-	}
-	
-	if (tvp) {
-		/* since there is input, we may not have timed out */
-		(void) gettimeofday(&endtv, NULL);
-		TV_SUB(&endtv, &starttv);
-		TV_SUB(tvp, &endtv);  /* adjust *tvp by elapsed time */
-	}
-	
-	return 1;
-}
-
-/*
- * `sleep' for the current turn time (using select).
- * Eat any input that might be available.
- */
-void tsleep(void)
-{
-	struct timeval tv;
-	
-	tv.tv_sec = 0;
-	tv.tv_usec = fallrate;
-	while (TV_POS(&tv))
-		if (rwait(&tv)) {
-			lastchar = '\0';
-		} else
-			break;
-}
-
-/*
- * getchar with timeout.
- */
-int tgetchar(void)
-{
-	static struct timeval timeleft;
-	char c;
-	
-	/*
-	 * Reset timeleft to fallrate whenever it is not positive.
-	 * In any case, wait to see if there is any input.  If so,
-	 * take it, and update timeleft so that the next call to
-	 * tgetchar() will not wait as long.  If there is no input,
-	 * make timeleft zero or negative, and return -1.
-	 *
-	 * Most of the hard work is done by rwait().
-	 */
-	if (!TV_POS(&timeleft)) {
-		faster();  /* go faster */
-		timeleft.tv_sec = 0;
-		timeleft.tv_usec = fallrate;
-	}
-	
-	if (!rwait(&timeleft))
-		return -1;
-	
-	c = lastchar;
-	lastchar = '\0';
-	return ((int) (unsigned char) c);
-}
-
-/** @}
- */
Index: uspace/app/tetris/input.h
===================================================================
--- uspace/app/tetris/input.h	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ 	(revision )
@@ -1,49 +1,0 @@
-/*	$OpenBSD: input.h,v 1.5 2003/06/03 03:01:41 millert Exp $	*/
-/*	$NetBSD: input.h,v 1.2 1995/04/22 07:42:36 cgd Exp $	*/
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)input.h	8.1 (Berkeley) 5/31/93
- */
-
-/** @addtogroup tetris
- * @{
- */
-/** @file
- */
-
-extern int rwait(struct timeval *);
-extern int tgetchar(void);
-extern void tsleep(void);
-
-/** @}
- */
Index: uspace/app/tetris/scores.c
===================================================================
--- uspace/app/tetris/scores.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tetris/scores.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: scores.c,v 1.11 2006/04/20 03:25:36 ray Exp $	*/
-/*	$NetBSD: scores.c,v 1.2 1995/04/22 07:42:38 cgd Exp $	*/
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)scores.c	8.1 (Berkeley) 5/31/93
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** Attributations
+ *
+ * scores.c 8.1 (Berkeley) 5/31/93
+ * NetBSD: scores.c,v 1.2 1995/04/22 07:42:38 cgd
+ * OpenBSD: scores.c,v 1.11 2006/04/20 03:25:36 ray
+ *
+ * Based upon BSD Tetris
+ *
+ * Copyright (c) 1992, 1993
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
  */
 
@@ -60,5 +68,4 @@
 #include <err.h>
 #include <time.h>
-
 #include "screen.h"
 #include "tetris.h"
@@ -118,5 +125,5 @@
 	int j;
 	size_t off;
-	console_event_t ev;
+	kbd_event_t ev;
 	
 	clear_screen();
@@ -133,6 +140,6 @@
 	
 	while (1) {
-		fflush(stdout);
-		if (!console_get_event(fphone(stdin), &ev))
+		console_flush(console);
+		if (!console_get_kbd_event(console, &ev))
 			exit(1);
 		
Index: uspace/app/tetris/scores.h
===================================================================
--- uspace/app/tetris/scores.h	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tetris/scores.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: scores.h,v 1.5 2003/06/03 03:01:41 millert Exp $	*/
-/*	$NetBSD: scores.h,v 1.2 1995/04/22 07:42:40 cgd Exp $	*/
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 
-/*-
+/** Attributations
+ *
+ * scores.h 8.1 (Berkeley) 5/31/93
+ * NetBSD: scores.h,v 1.2 1995/04/22 07:42:40 cgd
+ * OpenBSD: scores.h,v 1.5 2003/06/03 03:01:41 millert
+ *
+ * Based upon BSD Tetris
+ *
  * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
  *
  * This code is derived from software contributed to Berkeley by
  * Chris Torek and Darren F. Provine.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)scores.h	8.1 (Berkeley) 5/31/93
  */
 
@@ -41,5 +49,4 @@
 /** @file
  */
-
 
 /*
Index: uspace/app/tetris/screen.c
===================================================================
--- uspace/app/tetris/screen.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tetris/screen.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: screen.c,v 1.13 2006/04/20 03:25:36 ray Exp $	*/
-/*	$NetBSD: screen.c,v 1.4 1995/04/29 01:11:36 mycroft Exp $	*/
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)screen.c	8.1 (Berkeley) 5/31/93
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** Attributations
+ *
+ * screen.c 8.1 (Berkeley) 5/31/93
+ * NetBSD: screen.c,v 1.4 1995/04/29 01:11:36 mycroft
+ * OpenBSD: screen.c,v 1.13 2006/04/20 03:25:36 ray
+ *
+ * Based upon BSD Tetris
+ *
+ * Copyright (c) 1992, 1993
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
  */
 
@@ -69,4 +77,8 @@
 static const struct shape *lastshape;
 
+static suseconds_t timeleft = 0;
+
+console_ctrl_t *console;
+
 
 /*
@@ -82,6 +94,6 @@
 static void start_standout(uint32_t color)
 {
-	fflush(stdout);
-	console_set_rgb_color(fphone(stdout), 0xffffff,
+	console_flush(console);
+	console_set_rgb_color(console, 0xffffff,
 	    use_color ? color : 0x000000);
 }
@@ -89,11 +101,11 @@
 static void resume_normal(void)
 {
-	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_NORMAL);
+	console_flush(console);
+	console_set_style(console, STYLE_NORMAL);
 }
 
 void clear_screen(void)
 {
-	console_clear(fphone(stdout));
+	console_clear(console);
 	moveto(0, 0);
 }
@@ -105,5 +117,5 @@
 {
 	resume_normal();
-	console_clear(fphone(stdout));
+	console_clear(console);
 	curscore = -1;
 	memset(curscreen, 0, sizeof(curscreen));
@@ -115,5 +127,5 @@
 void scr_init(void)
 {
-	console_cursor_visibility(fphone(stdout), 0);
+	console_cursor_visibility(console, 0);
 	resume_normal();
 	scr_clear();
@@ -122,6 +134,6 @@
 void moveto(sysarg_t r, sysarg_t c)
 {
-	fflush(stdout);
-	console_set_pos(fphone(stdout), c, r);
+	console_flush(console);
+	console_set_pos(console, c, r);
 }
 
@@ -130,5 +142,5 @@
 static int get_display_size(winsize_t *ws)
 {
-	return console_get_size(fphone(stdout), &ws->ws_col, &ws->ws_row);
+	return console_get_size(console, &ws->ws_col, &ws->ws_row);
 }
 
@@ -136,5 +148,5 @@
 {
 	sysarg_t ccap;
-	int rc = console_get_color_cap(fphone(stdout), &ccap);
+	int rc = console_get_color_cap(console, &ccap);
 	
 	if (rc != 0)
@@ -179,5 +191,5 @@
 void scr_end(void)
 {
-	console_cursor_visibility(fphone(stdout), 1);
+	console_cursor_visibility(console, 1);
 }
 
@@ -302,5 +314,5 @@
 		resume_normal();
 	
-	fflush(stdout);
+	console_flush(console);
 }
 
@@ -322,4 +334,80 @@
 }
 
+/** Sleep for the current turn time
+ *
+ * Eat any input that might be available.
+ *
+ */
+void tsleep(void)
+{
+	suseconds_t timeout = fallrate;
+	
+	while (timeout > 0) {
+		kbd_event_t event;
+		
+		if (!console_get_kbd_event_timeout(console, &event, &timeout))
+			break;
+	}
+}
+
+/** Get char with timeout
+ *
+ */
+int tgetchar(void)
+{
+	/*
+	 * Reset timeleft to fallrate whenever it is not positive
+	 * and increase speed.
+	 */
+	
+	if (timeleft <= 0) {
+		faster();
+		timeleft = fallrate;
+	}
+	
+	/*
+	 * Wait to see if there is any input. If so, take it and
+	 * update timeleft so that the next call to tgetchar()
+	 * will not wait as long. If there is no input,
+	 * make timeleft zero and return -1.
+	 */
+	
+	wchar_t c = 0;
+	
+	while (c == 0) {
+		kbd_event_t event;
+		
+		if (!console_get_kbd_event_timeout(console, &event, &timeleft)) {
+			timeleft = 0;
+			return -1;
+		}
+		
+		if (event.type == KEY_PRESS)
+			c = event.c;
+	}
+	
+	return (int) c;
+}
+
+/** Get char without timeout
+ *
+ */
+int twait(void)
+{
+	wchar_t c = 0;
+	
+	while (c == 0) {
+		kbd_event_t event;
+		
+		if (!console_get_kbd_event(console, &event))
+			return -1;
+		
+		if (event.type == KEY_PRESS)
+			c = event.c;
+	}
+	
+	return (int) c;
+}
+
 /** @}
  */
Index: uspace/app/tetris/screen.h
===================================================================
--- uspace/app/tetris/screen.h	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tetris/screen.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: screen.h,v 1.5 2003/06/03 03:01:41 millert Exp $	*/
-/*	$NetBSD: screen.h,v 1.2 1995/04/22 07:42:42 cgd Exp $	*/
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 
-/*-
+/** Attributations
+ *
+ * screen.h 8.1 (Berkeley) 5/31/93
+ * NetBSD: screen.h,v 1.2 1995/04/22 07:42:42 cgd
+ * OpenBSD: screen.h,v 1.5 2003/06/03 03:01:41 millert
+ *
+ * Based upon BSD Tetris
+ *
  * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
  *
  * This code is derived from software contributed to Berkeley by
  * Chris Torek and Darren F. Provine.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)screen.h	8.1 (Berkeley) 5/31/93
  */
 
@@ -48,4 +56,5 @@
 
 #include <sys/types.h>
+#include <io/console.h>
 #include <async.h>
 #include <bool.h>
@@ -56,4 +65,5 @@
 } winsize_t;
 
+extern console_ctrl_t *console;
 extern winsize_t winsize;
 
@@ -61,5 +71,4 @@
 extern void clear_screen(void);
 
-/* just calls putchar; for tputs */
 extern int put(int);
 extern void scr_clear(void);
@@ -70,4 +79,8 @@
 extern void scr_update(void);
 
+extern void tsleep(void);
+extern int tgetchar(void);
+extern int twait(void);
+
 /** @}
  */
Index: uspace/app/tetris/shapes.c
===================================================================
--- uspace/app/tetris/shapes.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tetris/shapes.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: shapes.c,v 1.8 2004/07/10 07:26:24 deraadt Exp $	*/
-/*	$NetBSD: shapes.c,v 1.2 1995/04/22 07:42:44 cgd Exp $	*/
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 
-/*-
+/** Attributations
+ *
+ * shapes.c 8.1 (Berkeley) 5/31/93
+ * NetBSD: shapes.c,v 1.2 1995/04/22 07:42:44 cgd
+ * OpenBSD: shapes.c,v 1.8 2004/07/10 07:26:24 deraadt
+ *
+ * Based upon BSD Tetris
+ *
  * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
  *
  * This code is derived from software contributed to Berkeley by
  * Chris Torek and Darren F. Provine.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)shapes.c	8.1 (Berkeley) 5/31/93
  */
 
Index: uspace/app/tetris/tetris.c
===================================================================
--- uspace/app/tetris/tetris.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tetris/tetris.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: tetris.c,v 1.21 2006/04/20 03:24:12 ray Exp $	*/
-/*	$NetBSD: tetris.c,v 1.2 1995/04/22 07:42:47 cgd Exp $	*/
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)tetris.c	8.1 (Berkeley) 5/31/93
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** Attributations
+ *
+ * tetris.c 8.1 (Berkeley) 5/31/93
+ * NetBSD: tetris.c,v 1.2 1995/04/22 07:42:47 cgd
+ * OpenBSD: tetris.c,v 1.21 2006/04/20 03:24:12 ray
+ *
+ * Based upon BSD Tetris
+ *
+ * Copyright (c) 1992, 1993
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek and Darren F. Provine.
+ *
  */
 
@@ -56,6 +64,4 @@
 #include <unistd.h>
 #include <getopt.h>
-
-#include "input.h"
 #include "scores.h"
 #include "screen.h"
@@ -245,8 +251,10 @@
 	int ch;
 	
+	console = console_init(stdin, stdout);
+	
 	keys = "jkl pq";
 	
 	classic = 0;
-	showpreview = 1; 
+	showpreview = 1;
 	
 	while ((ch = getopt(argc, argv, "ck:ps")) != -1)
@@ -371,6 +379,6 @@
 					scr_msg(key_msg, 0);
 					scr_msg(msg, 1);
-					(void) fflush(stdout);
-				} while (rwait((struct timeval *) NULL) == -1);
+					console_flush(console);
+				} while (!twait());
 				
 				scr_msg(msg, 0);
Index: uspace/app/tetris/tetris.h
===================================================================
--- uspace/app/tetris/tetris.h	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/tetris/tetris.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -1,37 +1,45 @@
-/*	$OpenBSD: tetris.h,v 1.9 2003/06/03 03:01:41 millert Exp $	*/
-/*	$NetBSD: tetris.h,v 1.2 1995/04/22 07:42:48 cgd Exp $	*/
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 
-/*-
+/** Attributations
+ *
+ * tetris.h 8.1 (Berkeley) 5/31/93
+ * NetBSD: tetris.h,v 1.2 1995/04/22 07:42:48 cgd
+ * OpenBSD: tetris.h,v 1.9 2003/06/03 03:01:41 millert
+ *
+ * Based upon BSD Tetris
+ *
  * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
+ *      The Regents of the University of California.
+ *      Distributed under BSD license.
  *
  * This code is derived from software contributed to Berkeley by
  * Chris Torek and Darren F. Provine.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)tetris.h	8.1 (Berkeley) 5/31/93
  */
 
Index: uspace/app/top/Makefile
===================================================================
--- uspace/app/top/Makefile	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/top/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -33,6 +33,5 @@
 SOURCES = \
 	top.c \
-	screen.c \
-	input.c
+	screen.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/top/input.c
===================================================================
--- uspace/app/top/input.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ 	(revision )
@@ -1,200 +1,0 @@
-/*	$OpenBSD: input.c,v 1.12 2005/04/13 02:33:08 deraadt Exp $	*/
-/*    $NetBSD: input.c,v 1.3 1996/02/06 22:47:33 jtc Exp $    */
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)input.c	8.1 (Berkeley) 5/31/93
- */
-
-/** @addtogroup top
- * @{
- */
-/** @file
- */
-
-/*
- * Top input.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <stdio.h>
-
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <str.h>
-
-#include "input.h"
-
-#include <async.h>
-#include <vfs/vfs.h>
-#include <io/console.h>
-#include <ipc/console.h>
-
-#define USEC_COUNT 1000000
-
-/* return true iff the given timeval is positive */
-#define	TV_POS(tv) \
-	((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0))
-
-/* subtract timeval `sub' from `res' */
-#define	TV_SUB(res, sub) \
-	(res)->tv_sec -= (sub)->tv_sec; \
-	(res)->tv_usec -= (sub)->tv_usec; \
-	if ((res)->tv_usec < 0) { \
-		(res)->tv_usec += 1000000; \
-		(res)->tv_sec--; \
-	}
-
-/* We will use a hack here - if lastchar is non-zero, it is
- * the last character read. We will somehow simulate the select
- * semantics.
- */
-static aid_t getchar_inprog = 0;
-static char lastchar = '\0';
-
-/*
- * Do a `read wait': select for reading from stdin, with timeout *tvp.
- * On return, modify *tvp to reflect the amount of time spent waiting.
- * It will be positive only if input appeared before the time ran out;
- * otherwise it will be zero or perhaps negative.
- *
- * If tvp is nil, wait forever, but return if select is interrupted.
- *
- * Return 0 => no input, 1 => can read() from stdin
- *
- */
-int rwait(struct timeval *tvp)
-{
-	struct timeval starttv, endtv, *s;
-	static ipc_call_t charcall;
-	sysarg_t rc;
-	
-	/*
-	 * Someday, select() will do this for us.
-	 * Just in case that day is now, and no one has
-	 * changed this, we use a temporary.
-	 */
-	if (tvp) {
-		(void) gettimeofday(&starttv, NULL);
-		endtv = *tvp;
-		s = &endtv;
-	} else
-		s = NULL;
-	
-	if (!lastchar) {
-again:
-		if (!getchar_inprog) {
-			getchar_inprog = async_send_0(fphone(stdin),
-			    CONSOLE_GET_EVENT, &charcall);
-		}
-		
-		if (!s)
-			async_wait_for(getchar_inprog, &rc);
-		else if (async_wait_timeout(getchar_inprog, &rc, s->tv_usec) == ETIMEOUT) {
-			tvp->tv_sec = 0;
-			tvp->tv_usec = 0;
-			return (0);
-		}
-		
-		getchar_inprog = 0;
-		if (rc) {
-			printf("End of file, bug?\n");
-			exit(1);
-		}
-		
-		if (IPC_GET_ARG1(charcall) == KEY_RELEASE)
-			goto again;
-		
-		lastchar = IPC_GET_ARG4(charcall);
-	}
-	
-	if (tvp) {
-		/* since there is input, we may not have timed out */
-		(void) gettimeofday(&endtv, NULL);
-		TV_SUB(&endtv, &starttv);
-		TV_SUB(tvp, &endtv);  /* adjust *tvp by elapsed time */
-	}
-	
-	return 1;
-}
-
-/*
- * `sleep' for the current turn time (using select).
- * Eat any input that might be available.
- */
-void tsleep(unsigned int sec)
-{
-	struct timeval tv;
-	
-	tv.tv_sec = 0;
-	tv.tv_usec = sec * USEC_COUNT;
-	while (TV_POS(&tv))
-		if (rwait(&tv)) {
-			lastchar = '\0';
-		} else
-			break;
-}
-
-/*
- * getchar with timeout.
- */
-int tgetchar(unsigned int sec)
-{
-	static struct timeval timeleft;
-	char c;
-	
-	/*
-	 * Reset timeleft to USEC_COUNT whenever it is not positive.
-	 * In any case, wait to see if there is any input.  If so,
-	 * take it, and update timeleft so that the next call to
-	 * tgetchar() will not wait as long.  If there is no input,
-	 * make timeleft zero or negative, and return -1.
-	 *
-	 * Most of the hard work is done by rwait().
-	 */
-	if (!TV_POS(&timeleft)) {
-		timeleft.tv_sec = 0;
-		timeleft.tv_usec = sec * USEC_COUNT;
-	}
-	
-	if (!rwait(&timeleft))
-		return -1;
-	
-	c = lastchar;
-	lastchar = '\0';
-	return ((int) (unsigned char) c);
-}
-
-/** @}
- */
Index: uspace/app/top/input.h
===================================================================
--- uspace/app/top/input.h	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ 	(revision )
@@ -1,56 +1,0 @@
-/*	$OpenBSD: input.h,v 1.5 2003/06/03 03:01:41 millert Exp $	*/
-/*	$NetBSD: input.h,v 1.2 1995/04/22 07:42:36 cgd Exp $	*/
-
-/*-
- * Copyright (c) 1992, 1993
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek and Darren F. Provine.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *	@(#)input.h	8.1 (Berkeley) 5/31/93
- */
-
-/** @addtogroup top
- * @{
- */
-/** @file
- */
-
-#ifndef TOP_INPUT_
-#define TOP_INPUT_
-
-#include <sys/time.h>
-
-extern int rwait(struct timeval *);
-extern int tgetchar(unsigned int sec);
-extern void tsleep(unsigned int sec);
-
-#endif
-
-/** @}
- */
Index: uspace/app/top/screen.c
===================================================================
--- uspace/app/top/screen.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/top/screen.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -46,35 +46,40 @@
 #include "top.h"
 
+#define USEC_COUNT  1000000
+
 static sysarg_t warn_col = 0;
 static sysarg_t warn_row = 0;
+static suseconds_t timeleft = 0;
+
+console_ctrl_t *console;
 
 static void screen_style_normal(void)
 {
-	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_NORMAL);
+	console_flush(console);
+	console_set_style(console, STYLE_NORMAL);
 }
 
 static void screen_style_inverted(void)
 {
-	fflush(stdout);
-	console_set_style(fphone(stdout), STYLE_INVERTED);
+	console_flush(console);
+	console_set_style(console, STYLE_INVERTED);
 }
 
 static void screen_moveto(sysarg_t col, sysarg_t row)
 {
-	fflush(stdout);
-	console_set_pos(fphone(stdout), col, row);
+	console_flush(console);
+	console_set_pos(console, col, row);
 }
 
 static void screen_get_pos(sysarg_t *col, sysarg_t *row)
 {
-	fflush(stdout);
-	console_get_pos(fphone(stdout), col, row);
+	console_flush(console);
+	console_get_pos(console, col, row);
 }
 
 static void screen_get_size(sysarg_t *col, sysarg_t *row)
 {
-	fflush(stdout);
-	console_get_size(fphone(stdout), col, row);
+	console_flush(console);
+	console_get_size(console, col, row);
 }
 
@@ -84,6 +89,6 @@
 	
 	if (clear) {
-		fflush(stdout);
-		console_clear(fphone(stdout));
+		console_flush(console);
+		console_clear(console);
 	}
 	
@@ -111,6 +116,8 @@
 void screen_init(void)
 {
-	fflush(stdout);
-	console_cursor_visibility(fphone(stdout), false);
+	console = console_init(stdin, stdout);
+	
+	console_flush(console);
+	console_cursor_visibility(console, false);
 	
 	screen_restart(true);
@@ -121,6 +128,6 @@
 	screen_restart(true);
 	
-	fflush(stdout);
-	console_cursor_visibility(fphone(stdout), true);
+	console_flush(console);
+	console_cursor_visibility(console, true);
 }
 
@@ -254,16 +261,16 @@
 	uint64_t used;
 	uint64_t free;
-	char total_suffix;
-	char unavail_suffix;
-	char used_suffix;
-	char free_suffix;
-	
-	order_suffix(data->physmem->total, &total, &total_suffix);
-	order_suffix(data->physmem->unavail, &unavail, &unavail_suffix);
-	order_suffix(data->physmem->used, &used, &used_suffix);
-	order_suffix(data->physmem->free, &free, &free_suffix);
-	
-	printf("memory: %" PRIu64 "%c total, %" PRIu64 "%c unavail, %"
-	    PRIu64 "%c used, %" PRIu64 "%c free", total, total_suffix,
+	const char *total_suffix;
+	const char *unavail_suffix;
+	const char *used_suffix;
+	const char *free_suffix;
+	
+	bin_order_suffix(data->physmem->total, &total, &total_suffix, false);
+	bin_order_suffix(data->physmem->unavail, &unavail, &unavail_suffix, false);
+	bin_order_suffix(data->physmem->used, &used, &used_suffix, false);
+	bin_order_suffix(data->physmem->free, &free, &free_suffix, false);
+	
+	printf("memory: %" PRIu64 "%s total, %" PRIu64 "%s unavail, %"
+	    PRIu64 "%s used, %" PRIu64 "%s free", total, total_suffix,
 	    unavail, unavail_suffix, used, used_suffix, free, free_suffix);
 	screen_newline();
@@ -295,15 +302,15 @@
 		
 		uint64_t resmem;
-		char resmem_suffix;
-		order_suffix(task->resmem, &resmem, &resmem_suffix);
+		const char *resmem_suffix;
+		bin_order_suffix(task->resmem, &resmem, &resmem_suffix, true);
 		
 		uint64_t virtmem;
-		char virtmem_suffix;
-		order_suffix(task->virtmem, &virtmem, &virtmem_suffix);
-		
-		printf("%-8" PRIu64 " %7zu %9" PRIu64 "%c ",
+		const char *virtmem_suffix;
+		bin_order_suffix(task->virtmem, &virtmem, &virtmem_suffix, true);
+		
+		printf("%-8" PRIu64 " %7zu %7" PRIu64 "%s ",
 		    task->task_id, task->threads, resmem, resmem_suffix);
 		print_percent(perc->resmem, 2);
-		printf(" %8" PRIu64 "%c ", virtmem, virtmem_suffix);
+		printf(" %6" PRIu64 "%s ", virtmem, virtmem_suffix);
 		print_percent(perc->virtmem, 2);
 		puts(" ");
@@ -508,5 +515,5 @@
 	}
 	
-	fflush(stdout);
+	console_flush(console);
 }
 
@@ -521,5 +528,41 @@
 	
 	screen_newline();
-	fflush(stdout);
+	console_flush(console);
+}
+
+/** Get char with timeout
+ *
+ */
+int tgetchar(unsigned int sec)
+{
+	/*
+	 * Reset timeleft whenever it is not positive.
+	 */
+	
+	if (timeleft <= 0)
+		timeleft = sec * USEC_COUNT;
+	
+	/*
+	 * Wait to see if there is any input. If so, take it and
+	 * update timeleft so that the next call to tgetchar()
+	 * will not wait as long. If there is no input,
+	 * make timeleft zero and return -1.
+	 */
+	
+	wchar_t c = 0;
+	
+	while (c == 0) {
+		kbd_event_t event;
+		
+		if (!console_get_kbd_event_timeout(console, &event, &timeleft)) {
+			timeleft = 0;
+			return -1;
+		}
+		
+		if (event.type == KEY_PRESS)
+			c = event.c;
+	}
+	
+	return (int) c;
 }
 
Index: uspace/app/top/screen.h
===================================================================
--- uspace/app/top/screen.h	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/top/screen.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -35,5 +35,8 @@
 #define TOP_SCREEN_H_
 
+#include <io/console.h>
 #include "top.h"
+
+extern console_ctrl_t *console;
 
 extern void screen_init(void);
@@ -42,4 +45,6 @@
 extern void print_warning(const char *, ...);
 
+extern int tgetchar(unsigned int);
+
 #endif
 
Index: uspace/app/top/top.c
===================================================================
--- uspace/app/top/top.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/top/top.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -46,5 +46,4 @@
 #include <sort.h>
 #include "screen.h"
-#include "input.h"
 #include "top.h"
 
Index: uspace/app/trace/ipc_desc.c
===================================================================
--- uspace/app/trace/ipc_desc.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/trace/ipc_desc.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -33,5 +33,6 @@
  */
 
-#include <ipc/common.h>
+#include <kernel/ipc/ipc.h>
+#include <kernel/ipc/ipc_methods.h>
 #include <stdlib.h>
 #include "ipc_desc.h"
@@ -39,16 +40,14 @@
 ipc_m_desc_t ipc_methods[] = {
 	/* System methods */
-	{ IPC_M_CONNECT_TO_ME,	"CONNECT_TO_ME" },
-	{ IPC_M_CONNECT_ME_TO,	"CONNECT_ME_TO" },
-	{ IPC_M_PHONE_HUNGUP,	"PHONE_HUNGUP" },
-	{ IPC_M_SHARE_OUT,	"SHARE_OUT" },
-	{ IPC_M_SHARE_IN,	"SHARE_IN" },
-	{ IPC_M_DATA_WRITE,	"DATA_WRITE" },
-	{ IPC_M_DATA_READ,	"DATA_READ" },
-	{ IPC_M_DEBUG_ALL,	"DEBUG_ALL" },
-
-	/* Well-known methods */
-	{ IPC_M_PING,		"PING" },
-
+	{ IPC_M_PHONE_HUNGUP,  "PHONE_HUNGUP" },
+	{ IPC_M_CONNECT_ME,    "CONNECT_ME" },
+	{ IPC_M_CONNECT_ME_TO, "CONNECT_ME_TO" },
+	{ IPC_M_CONNECT_TO_ME, "CONNECT_TO_ME" },
+	{ IPC_M_SHARE_OUT,     "SHARE_OUT" },
+	{ IPC_M_SHARE_IN,      "SHARE_IN" },
+	{ IPC_M_DATA_WRITE,    "DATA_WRITE" },
+	{ IPC_M_DATA_READ,     "DATA_READ" },
+	{ IPC_M_DEBUG,         "DEBUG" },
+	
 	/* Terminating entry */
 	{ 0, NULL }
Index: uspace/app/trace/ipcp.c
===================================================================
--- uspace/app/trace/ipcp.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/trace/ipcp.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -37,5 +37,5 @@
 #include <adt/hash_table.h>
 #include <sys/typefmt.h>
-
+#include <kernel/ipc/ipc_methods.h>
 #include "ipc_desc.h"
 #include "proto.h"
@@ -268,17 +268,15 @@
 	proto_t *proto;
 	int cphone;
-
+	
 	sysarg_t *resp;
 	oper_t *oper;
 	int i;
-
-//	printf("parse_answer\n");
-
+	
 	phone = pcall->phone_hash;
 	method = IPC_GET_IMETHOD(pcall->question);
 	retval = IPC_GET_RETVAL(*answer);
-
+	
 	resp = answer->args;
-
+	
 	if ((display_mask & DM_IPC) != 0) {
 		printf("Response to %p: retval=%" PRIdn ", args = (%" PRIun ", "
@@ -288,11 +286,12 @@
 		    IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
 	}
-
+	
 	if ((display_mask & DM_USER) != 0) {
 		oper = pcall->oper;
-
-		if (oper != NULL && (oper->rv_type != V_VOID || oper->respc > 0)) {
+		
+		if ((oper != NULL) &&
+		    ((oper->rv_type != V_VOID) || (oper->respc > 0))) {
 			printf("->");
-
+			
 			if (oper->rv_type != V_VOID) {
 				putchar(' ');
@@ -304,25 +303,29 @@
 				putchar('(');
 				for (i = 1; i <= oper->respc; ++i) {
-					if (i > 1) printf(", ");
+					if (i > 1)
+						printf(", ");
 					val_print(resp[i], oper->resp_type[i - 1]);
 				}
 				putchar(')');
 			}
-
+			
 			putchar('\n');
 		}
 	}
-
-	if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
+	
+	if ((phone == PHONE_NS) && (method == IPC_M_CONNECT_ME_TO) &&
+	    (retval == 0)) {
 		/* Connected to a service (through NS) */
 		service = IPC_GET_ARG1(pcall->question);
 		proto = proto_get_by_srv(service);
-		if (proto == NULL) proto = proto_unknown;
-
+		if (proto == NULL)
+			proto = proto_unknown;
+		
 		cphone = IPC_GET_ARG5(*answer);
 		if ((display_mask & DM_SYSTEM) != 0) {
 			printf("Registering connection (phone %d, protocol: %s)\n", cphone,
-		    		proto->name);
-		}
+		    proto->name);
+		}
+		
 		ipcp_connection_set(cphone, 0, proto);
 	}
@@ -334,7 +337,5 @@
 	pending_call_t *pcall;
 	unsigned long key[1];
-
-//	printf("ipcp_call_in()\n");
-
+	
 	if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
 		/* Not a response */
@@ -344,11 +345,12 @@
 		return;
 	}
-
+	
 	hash = hash & ~IPC_CALLID_ANSWERED;
 	key[0] = hash;
-
+	
 	item = hash_table_find(&pending_calls, key);
-	if (item == NULL) return; // No matching question found
-
+	if (item == NULL)
+		return; /* No matching question found */
+	
 	/*
 	 * Response matched to question.
@@ -357,5 +359,5 @@
 	pcall = hash_table_get_instance(item, pending_call_t, link);
 	hash_table_remove(&pending_calls, key, 1);
-
+	
 	parse_answer(hash, pcall, call);
 	free(pcall);
Index: uspace/app/trace/syscalls.c
===================================================================
--- uspace/app/trace/syscalls.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/trace/syscalls.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -40,4 +40,5 @@
     [SYS_KLOG] ={ "klog",				3,	V_INT_ERRNO },
     [SYS_TLS_SET] = { "tls_set",			1,	V_ERRNO },
+
     [SYS_THREAD_CREATE] = { "thread_create",		3,	V_ERRNO },
     [SYS_THREAD_EXIT] = { "thread_exit",		1,	V_ERRNO },
Index: uspace/app/trace/trace.c
===================================================================
--- uspace/app/trace/trace.c	(revision e686889ccfd9de736c9b43f5bba55aa065b36861)
+++ uspace/app/trace/trace.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -72,5 +72,5 @@
 ipc_call_t thread_ipc_req[THBUF_SIZE];
 
-int phoneid;
+async_sess_t *sess;
 bool abort_trace;
 
@@ -81,5 +81,5 @@
 
 static bool cev_valid;
-static console_event_t cev;
+static kbd_event_t cev;
 
 void thread_trace_start(uintptr_t thread_hash);
@@ -146,36 +146,33 @@
 static int connect_task(task_id_t task_id)
 {
-	int rc;
-
-	rc = async_connect_kbox(task_id);
-
-	if (rc == ENOTSUP) {
-		printf("You do not have userspace debugging support "
-		    "compiled in the kernel.\n");
-		printf("Compile kernel with 'Support for userspace debuggers' "
-		    "(CONFIG_UDEBUG) enabled.\n");
-		return rc;
-	}
-
-	if (rc < 0) {
+	async_sess_t *ksess = async_connect_kbox(task_id);
+	
+	if (!ksess) {
+		if (errno == ENOTSUP) {
+			printf("You do not have userspace debugging support "
+			    "compiled in the kernel.\n");
+			printf("Compile kernel with 'Support for userspace debuggers' "
+			    "(CONFIG_UDEBUG) enabled.\n");
+			return errno;
+		}
+		
 		printf("Error connecting\n");
-		printf("ipc_connect_task(%" PRIu64 ") -> %d ", task_id, rc);
-		return rc;
-	}
-
-	phoneid = rc;
-
-	rc = udebug_begin(phoneid);
+		printf("ipc_connect_task(%" PRIu64 ") -> %d ", task_id, errno);
+		return errno;
+	}
+	
+	int rc = udebug_begin(ksess);
 	if (rc < 0) {
 		printf("udebug_begin() -> %d\n", rc);
 		return rc;
 	}
-
-	rc = udebug_set_evmask(phoneid, UDEBUG_EM_ALL);
+	
+	rc = udebug_set_evmask(ksess, UDEBUG_EM_ALL);
 	if (rc < 0) {
 		printf("udebug_set_evmask(0x%x) -> %d\n ", UDEBUG_EM_ALL, rc);
 		return rc;
 	}
-
+	
+	sess = ksess;
 	return 0;
 }
@@ -188,5 +185,5 @@
 	int i;
 
-	rc = udebug_thread_read(phoneid, thread_hash_buf,
+	rc = udebug_thread_read(sess, thread_hash_buf,
 		THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
 	if (rc < 0) {
@@ -314,5 +311,5 @@
 
 	memset(&call, 0, sizeof(call));
-	rc = udebug_mem_read(phoneid, &call.args, sc_args[1], sizeof(call.args));
+	rc = udebug_mem_read(sess, &call.args, sc_args[1], sizeof(call.args));
 
 	if (rc >= 0) {
@@ -325,8 +322,7 @@
 	ipc_call_t question, reply;
 	int rc;
-	int phoneidx;
-
-//	printf("sc_ipc_call_sync_fast()\n");
-	phoneidx = sc_args[0];
+	int phoneid;
+
+	phoneid = sc_args[0];
 
 	IPC_SET_IMETHOD(question, sc_args[1]);
@@ -337,14 +333,10 @@
 	IPC_SET_ARG5(question, 0);
 
-//	printf("memset\n");
 	memset(&reply, 0, sizeof(reply));
-//	printf("udebug_mem_read(phone=%d, buffer_ptr=%u, src_addr=%d, n=%d\n",
-//		phoneid, &reply.args, sc_args[5], sizeof(reply.args));
-	rc = udebug_mem_read(phoneid, &reply.args, sc_args[5], sizeof(reply.args));
-//	printf("dmr->%d\n", rc);
-	if (rc < 0) return;
-
-//	printf("call ipc_call_sync\n");
-	ipcp_call_sync(phoneidx, &question, &reply);
+	rc = udebug_mem_read(sess, &reply.args, sc_args[5], sizeof(reply.args));
+	if (rc < 0)
+		return;
+	
+	ipcp_call_sync(phoneid, &question, &reply);
 }
 
@@ -355,5 +347,5 @@
 
 	memset(&question, 0, sizeof(question));
-	rc = udebug_mem_read(phoneid, &question.args, sc_args[1],
+	rc = udebug_mem_read(sess, &question.args, sc_args[1],
 	    sizeof(question.args));
 
@@ -372,5 +364,5 @@
 
 	memset(&reply, 0, sizeof(reply));
-	rc = udebug_mem_read(phoneid, &reply.args, sc_args[2],
+	rc = udebug_mem_read(sess, &reply.args, sc_args[2],
 	    sizeof(reply.args));
 
@@ -391,11 +383,8 @@
 
 	memset(&call, 0, sizeof(call));
-	rc = udebug_mem_read(phoneid, &call, sc_args[0], sizeof(call));
-//	printf("udebug_mem_read(phone %d, dest %d, app-mem src %d, size %d -> %d\n",
-//		phoneid, (int)&call, sc_args[0], sizeof(call), rc);
-
-	if (rc >= 0) {
+	rc = udebug_mem_read(sess, &call, sc_args[0], sizeof(call));
+	
+	if (rc >= 0)
 		ipcp_call_in(&call, sc_rc);
-	}
 }
 
@@ -407,13 +396,8 @@
 
 	/* Read syscall arguments */
-	rc = udebug_args_read(phoneid, thread_hash, sc_args);
-
-	async_serialize_start();
-
-//	printf("[%d] ", thread_id);
+	rc = udebug_args_read(sess, thread_hash, sc_args);
 
 	if (rc < 0) {
 		printf("error\n");
-		async_serialize_end();
 		return;
 	}
@@ -432,6 +416,4 @@
 		break;
 	}
-
-	async_serialize_end();
 }
 
@@ -444,7 +426,5 @@
 
 	/* Read syscall arguments */
-	rc = udebug_args_read(phoneid, thread_hash, sc_args);
-
-	async_serialize_start();
+	rc = udebug_args_read(sess, thread_hash, sc_args);
 
 //	printf("[%d] ", thread_id);
@@ -452,5 +432,4 @@
 	if (rc < 0) {
 		printf("error\n");
-		async_serialize_end();
 		return;
 	}
@@ -481,14 +460,9 @@
 		break;
 	}
-
-	async_serialize_end();
 }
 
 static void event_thread_b(uintptr_t hash)
 {
-	async_serialize_start();
 	printf("New thread, hash %p\n", (void *) hash);
-	async_serialize_end();
-
 	thread_trace_start(hash);
 }
@@ -527,5 +501,5 @@
 
 		/* Run thread until an event occurs */
-		rc = udebug_go(phoneid, thread_hash,
+		rc = udebug_go(sess, thread_hash,
 		    &ev_type, &val0, &val1);
 
@@ -656,5 +630,7 @@
 {
 	(void) arg;
-
+	
+	console_ctrl_t *console = console_init(stdin, stdout);
+	
 	while (true) {
 		fibril_mutex_lock(&state_lock);
@@ -662,12 +638,12 @@
 			fibril_condvar_wait(&state_cv, &state_lock);
 		fibril_mutex_unlock(&state_lock);
-
-		if (!console_get_event(fphone(stdin), &cev))
+		
+		if (!console_get_kbd_event(console, &cev))
 			return -1;
-
+		
 		fibril_mutex_lock(&state_lock);
 		cev_valid = true;
 		fibril_condvar_broadcast(&state_cv);
-		fibril_mutex_unlock(&state_lock);		
+		fibril_mutex_unlock(&state_lock);
 	}
 }
@@ -675,5 +651,5 @@
 static void trace_task(task_id_t task_id)
 {
-	console_event_t ev;
+	kbd_event_t ev;
 	bool done;
 	int i;
@@ -727,5 +703,5 @@
 		case KC_P:
 			printf("Pause...\n");
-			rc = udebug_stop(phoneid, thash);
+			rc = udebug_stop(sess, thash);
 			if (rc != EOK)
 				printf("Error: stop -> %d\n", rc);
@@ -743,6 +719,6 @@
 	printf("\nTerminate debugging session...\n");
 	abort_trace = true;
-	udebug_end(phoneid);
-	async_hangup(phoneid);
+	udebug_end(sess);
+	async_hangup(sess);
 
 	ipcp_cleanup();
Index: uspace/app/usbinfo/Makefile
===================================================================
--- uspace/app/usbinfo/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/usbinfo/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2010 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+BINARY = usbinfo
+
+LIBS = \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a \
+	$(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS = \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+SOURCES = \
+	desctree.c \
+	dev.c \
+	dump.c \
+	info.c \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/usbinfo/desctree.c
===================================================================
--- uspace/app/usbinfo/desctree.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/usbinfo/desctree.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbinfo
+ * @{
+ */
+/**
+ * @file
+ * Descriptor tree dump.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+
+#include "usbinfo.h"
+#include <usb/dev/dp.h>
+
+static void browse_descriptor_tree_internal(usb_dp_parser_t *parser,
+    usb_dp_parser_data_t *data, uint8_t *root, size_t depth,
+    dump_descriptor_in_tree_t callback, void *arg)
+{
+	if (root == NULL) {
+		return;
+	}
+	callback(root, depth, arg);
+	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	do {
+		browse_descriptor_tree_internal(parser, data, child, depth + 1,
+		    callback, arg);
+		child = usb_dp_get_sibling_descriptor(parser, data,
+		    root, child);
+	} while (child != NULL);
+}
+
+void browse_descriptor_tree(uint8_t *descriptors, size_t descriptors_size,
+    usb_dp_descriptor_nesting_t *descriptor_nesting,
+    dump_descriptor_in_tree_t callback, size_t initial_depth, void *arg)
+{
+	usb_dp_parser_data_t data = {
+		.data = descriptors,
+		.size = descriptors_size,
+		.arg = NULL
+	};
+
+	usb_dp_parser_t parser = {
+		.nesting = descriptor_nesting
+	};
+
+	browse_descriptor_tree_internal(&parser, &data, descriptors,
+	    initial_depth, callback, arg);
+}
+
+/** @}
+ */
Index: uspace/app/usbinfo/dev.c
===================================================================
--- uspace/app/usbinfo/dev.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/usbinfo/dev.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbinfo
+ * @{
+ */
+/**
+ * @file
+ * Representation of queried device.
+ */
+#include <usb/dev/pipes.h>
+#include <errno.h>
+#include <str_error.h>
+#include <usb/dev/request.h>
+#include "usbinfo.h"
+
+usbinfo_device_t *prepare_device(const char *name,
+    devman_handle_t hc_handle, usb_address_t dev_addr)
+{
+	usbinfo_device_t *dev = malloc(sizeof(usbinfo_device_t));
+	if (dev == NULL) {
+		fprintf(stderr, NAME ": memory allocation failed.\n");
+		return NULL;
+	}
+
+	int rc;
+	bool transfer_started = false;
+
+	rc = usb_device_connection_initialize(&dev->wire, hc_handle, dev_addr);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to create connection to device %s: %s.\n",
+		    name, str_error(rc));
+		goto leave;
+	}
+
+	rc = usb_pipe_initialize_default_control(&dev->ctrl_pipe,
+	    &dev->wire);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to create default control pipe to %s: %s.\n",
+		    name, str_error(rc));
+		goto leave;
+	}
+
+	rc = usb_pipe_probe_default_control(&dev->ctrl_pipe);
+	if (rc != EOK) {
+		if (rc == ENOENT) {
+			fprintf(stderr, NAME ": " \
+			    "device %s not present or malfunctioning.\n",
+			    name);
+		} else {
+			fprintf(stderr, NAME ": " \
+			    "probing default control pipe of %s failed: %s.\n",
+			    name, str_error(rc));
+		}
+		goto leave;
+	}
+
+	usb_pipe_start_long_transfer(&dev->ctrl_pipe);
+	transfer_started = true;
+
+	rc = usb_request_get_device_descriptor(&dev->ctrl_pipe,
+	    &dev->device_descriptor);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to retrieve device descriptor of %s: %s.\n",
+		    name, str_error(rc));
+		goto leave;
+	}
+
+	rc = usb_request_get_full_configuration_descriptor_alloc(
+	    &dev->ctrl_pipe, 0, (void **)&dev->full_configuration_descriptor,
+	    &dev->full_configuration_descriptor_size);
+	if (rc != EOK) {
+		fprintf(stderr, NAME ": " \
+		    "failed to retrieve configuration descriptor of %s: %s.\n",
+		    name, str_error(rc));
+		goto leave;
+	}
+
+	return dev;
+
+
+leave:
+	if (transfer_started) {
+		usb_pipe_end_long_transfer(&dev->ctrl_pipe);
+	}
+
+	free(dev);
+
+	return NULL;
+}
+
+void destroy_device(usbinfo_device_t *dev)
+{
+	usb_pipe_end_long_transfer(&dev->ctrl_pipe);
+	free(dev);
+}
+
+/** @}
+ */
Index: uspace/app/usbinfo/dump.c
===================================================================
--- uspace/app/usbinfo/dump.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/usbinfo/dump.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbinfo
+ * @{
+ */
+/**
+ * @file
+ * USB querying.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+
+#include "usbinfo.h"
+#include <usb/dev/dp.h>
+
+#define INDENT "  "
+#define BYTES_PER_LINE 12
+
+
+const char *get_indent(size_t level)
+{
+	static const char *indents[] = {
+		INDENT,
+		INDENT INDENT,
+		INDENT INDENT INDENT,
+		INDENT INDENT INDENT INDENT,
+		INDENT INDENT INDENT INDENT INDENT
+	};
+	static size_t indents_count = sizeof(indents)/sizeof(indents[0]);
+	if (level >= indents_count) {
+		return indents[indents_count - 1];
+	}
+	return indents[level];
+}
+
+void dump_buffer(const char *msg, size_t indent,
+    const uint8_t *buffer, size_t length)
+{
+	if (msg != NULL) {
+		printf("%s\n", msg);
+	}
+
+	size_t i;
+	if (length > 0) {
+		printf("%s", get_indent(indent));
+	}
+	for (i = 0; i < length; i++) {
+		printf("0x%02X", buffer[i]);
+		if (((i > 0) && (((i+1) % BYTES_PER_LINE) == 0))
+		    || (i + 1 == length)) {
+			printf("\n");
+			if (i + 1 < length) {
+				printf("%s", get_indent(indent));
+			}
+		} else {
+			printf("  ");
+		}
+	}
+}
+
+void dump_usb_descriptor(uint8_t *descriptor, size_t size)
+{
+	printf("Device descriptor:\n");
+	usb_dump_standard_descriptor(stdout, get_indent(0), "\n",
+	    descriptor, size);
+}
+
+void dump_match_ids(match_id_list_t *matches, const char *line_prefix)
+{
+	link_t *link;
+	for (link = matches->ids.next;
+	    link != &matches->ids;
+	    link = link->next) {
+		match_id_t *match = list_get_instance(link, match_id_t, link);
+
+		printf("%s%3d %s\n", line_prefix, match->score, match->id);
+	}
+}
+
+static void dump_tree_descriptor(uint8_t *descriptor, size_t depth)
+{
+	if (descriptor == NULL) {
+		return;
+	}
+	int type = (int) *(descriptor + 1);
+	const char *name = "unknown";
+	switch (type) {
+#define _TYPE(descriptor_type) \
+		case USB_DESCTYPE_##descriptor_type: name = #descriptor_type; break
+		_TYPE(DEVICE);
+		_TYPE(CONFIGURATION);
+		_TYPE(STRING);
+		_TYPE(INTERFACE);
+		_TYPE(ENDPOINT);
+		_TYPE(HID);
+		_TYPE(HID_REPORT);
+		_TYPE(HID_PHYSICAL);
+		_TYPE(HUB);
+#undef _TYPE
+	}
+	printf("%s%s (0x%02X):\n", get_indent(depth), name, type);
+	usb_dump_standard_descriptor(stdout, get_indent(depth), "\n",
+	    descriptor, descriptor[0]);
+}
+
+static void dump_tree_internal(usb_dp_parser_t *parser, usb_dp_parser_data_t *data,
+    uint8_t *root, size_t depth)
+{
+	if (root == NULL) {
+		return;
+	}
+	dump_tree_descriptor(root, depth);
+	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	do {
+		dump_tree_internal(parser, data, child, depth + 1);
+		child = usb_dp_get_sibling_descriptor(parser, data, root, child);
+	} while (child != NULL);
+}
+
+static void dump_tree(usb_dp_parser_t *parser, usb_dp_parser_data_t *data)
+{
+	uint8_t *ptr = data->data;
+	printf("Descriptor tree:\n");
+	dump_tree_internal(parser, data, ptr, 0);
+}
+
+#define NESTING(parentname, childname) \
+	{ \
+		.child = USB_DESCTYPE_##childname, \
+		.parent = USB_DESCTYPE_##parentname, \
+	}
+#define LAST_NESTING { -1, -1 }
+
+static usb_dp_descriptor_nesting_t descriptor_nesting[] = {
+	NESTING(CONFIGURATION, INTERFACE),
+	NESTING(INTERFACE, ENDPOINT),
+	NESTING(INTERFACE, HUB),
+	NESTING(INTERFACE, HID),
+	NESTING(HID, HID_REPORT),
+	LAST_NESTING
+};
+
+static usb_dp_parser_t parser = {
+	.nesting = descriptor_nesting
+};
+
+void dump_descriptor_tree(uint8_t *descriptors, size_t length)
+{
+	usb_dp_parser_data_t data = {
+		.data = descriptors,
+		.size = length,
+		.arg = NULL
+	};
+
+	dump_tree(&parser, &data);
+}
+
+/** @}
+ */
Index: uspace/app/usbinfo/info.c
===================================================================
--- uspace/app/usbinfo/info.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/usbinfo/info.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbinfo
+ * @{
+ */
+/**
+ * @file
+ * Dumping of generic device properties.
+ */
+#include <stdio.h>
+#include <str_error.h>
+#include <errno.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/recognise.h>
+#include <usb/dev/request.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/hub.h>
+#include "usbinfo.h"
+
+void dump_short_device_identification(usbinfo_device_t *dev)
+{
+	printf("%sDevice 0x%04x by vendor 0x%04x\n", get_indent(0),
+	    (int) dev->device_descriptor.product_id,
+	    (int) dev->device_descriptor.vendor_id);
+}
+
+static void dump_match_ids_from_interface(uint8_t *descriptor, size_t depth,
+    void *arg)
+{
+	if (depth != 1) {
+		return;
+	}
+	size_t descr_size = descriptor[0];
+	if (descr_size < sizeof(usb_standard_interface_descriptor_t)) {
+		return;
+	}
+	int descr_type = descriptor[1];
+	if (descr_type != USB_DESCTYPE_INTERFACE) {
+		return;
+	}
+
+	usbinfo_device_t *dev = (usbinfo_device_t *) arg;
+
+	usb_standard_interface_descriptor_t *iface
+	    = (usb_standard_interface_descriptor_t *) descriptor;
+
+	printf("%sInterface #%d match ids (%s, 0x%02x, 0x%02x)\n",
+	    get_indent(0),
+	    (int) iface->interface_number,
+	    usb_str_class(iface->interface_class),
+	    (int) iface->interface_subclass,
+	    (int) iface->interface_protocol);
+
+	match_id_list_t matches;
+	init_match_ids(&matches);
+	usb_device_create_match_ids_from_interface(&dev->device_descriptor,
+	    iface, &matches);
+	dump_match_ids(&matches, get_indent(1));
+	clean_match_ids(&matches);
+}
+
+void dump_device_match_ids(usbinfo_device_t *dev)
+{
+	match_id_list_t matches;
+	init_match_ids(&matches);
+	usb_device_create_match_ids_from_device_descriptor(
+	    &dev->device_descriptor, &matches);
+	printf("%sDevice match ids (0x%04x by 0x%04x, %s)\n", get_indent(0),
+	    (int) dev->device_descriptor.product_id,
+	    (int) dev->device_descriptor.vendor_id,
+	    usb_str_class(dev->device_descriptor.device_class));
+	dump_match_ids(&matches, get_indent(1));
+	clean_match_ids(&matches);
+
+	usb_dp_walk_simple(dev->full_configuration_descriptor,
+	    dev->full_configuration_descriptor_size,
+	    usb_dp_standard_descriptor_nesting,
+	    dump_match_ids_from_interface,
+	    dev);
+}
+
+static void dump_descriptor_tree_brief_device(const char *prefix,
+    usb_standard_device_descriptor_t *descriptor)
+{
+	printf("%sDevice (0x%04x by 0x%04x, %s, %zu configurations)\n", prefix,
+	    (int) descriptor->product_id,
+	    (int) descriptor->vendor_id,
+	    usb_str_class(descriptor->device_class),
+	    (size_t) descriptor->configuration_count);
+}
+
+static void dump_descriptor_tree_brief_configuration(const char *prefix,
+    usb_standard_configuration_descriptor_t *descriptor)
+{
+	printf("%sConfiguration #%d (%zu interfaces, total %zuB)\n", prefix,
+	    (int) descriptor->configuration_number,
+	    (size_t) descriptor->interface_count,
+	    (size_t) descriptor->total_length);
+}
+
+static void dump_descriptor_tree_brief_interface(const char *prefix,
+    usb_standard_interface_descriptor_t *descriptor)
+{
+	printf("%sInterface #%d (%s, 0x%02x, 0x%02x), alternate %d\n", prefix,
+	    (int) descriptor->interface_number,
+	    usb_str_class(descriptor->interface_class),
+	    (int) descriptor->interface_subclass,
+	    (int) descriptor->interface_protocol,
+	    (int) descriptor->alternate_setting);
+}
+
+static void dump_descriptor_tree_brief_endpoint(const char *prefix,
+    usb_standard_endpoint_descriptor_t *descriptor)
+{
+	usb_endpoint_t endpoint_no = descriptor->endpoint_address & 0xF;
+	usb_transfer_type_t transfer = descriptor->attributes & 0x3;
+	usb_direction_t direction = descriptor->endpoint_address & 0x80
+	    ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
+	printf("%sEndpoint #%d (%s %s, %zu)\n", prefix,
+	    endpoint_no, usb_str_transfer_type(transfer),
+	    direction == USB_DIRECTION_IN ? "in" : "out",
+	    (size_t) descriptor->max_packet_size);
+}
+
+static void dump_descriptor_tree_brief_hid(const char *prefix,
+    usb_standard_hid_descriptor_t *descriptor)
+{
+	printf("%sHID (country %d, %d descriptors)\n", prefix,
+	    (int) descriptor->country_code,
+	    (int) descriptor->class_desc_count);
+}
+
+static void dump_descriptor_tree_brief_hub(const char *prefix,
+    usb_hub_descriptor_header_t *descriptor)
+{
+	printf("%shub (%d ports)\n", prefix,
+	    (int) descriptor->port_count);
+}
+
+
+static void dump_descriptor_tree_callback(uint8_t *descriptor,
+    size_t depth, void *arg)
+{
+	const char *indent = get_indent(depth + 1);
+
+	int descr_type = -1;
+	size_t descr_size = descriptor[0];
+	if (descr_size > 0) {
+		descr_type = descriptor[1];
+	}
+
+	switch (descr_type) {
+
+#define _BRANCH(type_enum, descriptor_type, callback) \
+	case type_enum: \
+		if (descr_size >= sizeof(descriptor_type)) { \
+			callback(indent, (descriptor_type *) descriptor); \
+			if (arg != NULL) { \
+				usb_dump_standard_descriptor(stdout, \
+				    get_indent(depth +2), "\n", \
+				    descriptor, descr_size); \
+			} \
+		} else { \
+			descr_type = -1; \
+		} \
+		break;
+
+		_BRANCH(USB_DESCTYPE_DEVICE,
+		    usb_standard_device_descriptor_t,
+		    dump_descriptor_tree_brief_device);
+		_BRANCH(USB_DESCTYPE_CONFIGURATION,
+		    usb_standard_configuration_descriptor_t,
+		    dump_descriptor_tree_brief_configuration);
+		_BRANCH(USB_DESCTYPE_INTERFACE,
+		    usb_standard_interface_descriptor_t,
+		    dump_descriptor_tree_brief_interface);
+		_BRANCH(USB_DESCTYPE_ENDPOINT,
+		    usb_standard_endpoint_descriptor_t,
+		    dump_descriptor_tree_brief_endpoint);
+		_BRANCH(USB_DESCTYPE_HID,
+		    usb_standard_hid_descriptor_t,
+		    dump_descriptor_tree_brief_hid);
+		/*
+		 * Probably useless, hub descriptor shall not be part of
+		 * configuration descriptor.
+		 */
+		_BRANCH(USB_DESCTYPE_HUB,
+		    usb_hub_descriptor_header_t,
+		    dump_descriptor_tree_brief_hub);
+
+		default:
+			break;
+	}
+
+	if (descr_type == -1) {
+		printf("%sInvalid descriptor.\n", indent);
+	}
+}
+
+void dump_descriptor_tree_brief(usbinfo_device_t *dev)
+{
+	dump_descriptor_tree_callback((uint8_t *)&dev->device_descriptor,
+	    (size_t) -1, NULL);
+	usb_dp_walk_simple(dev->full_configuration_descriptor,
+	    dev->full_configuration_descriptor_size,
+	    usb_dp_standard_descriptor_nesting,
+	    dump_descriptor_tree_callback,
+	    NULL);
+}
+
+void dump_descriptor_tree_full(usbinfo_device_t *dev)
+{
+	dump_descriptor_tree_callback((uint8_t *)&dev->device_descriptor,
+	    (size_t) -1, dev);
+	usb_dp_walk_simple(dev->full_configuration_descriptor,
+	    dev->full_configuration_descriptor_size,
+	    usb_dp_standard_descriptor_nesting,
+	    dump_descriptor_tree_callback,
+	    dev);
+}
+
+static void find_string_indexes_callback(uint8_t *descriptor,
+    size_t depth, void *arg)
+{
+	size_t descriptor_length = descriptor[0];
+	if (descriptor_length <= 1) {
+		return;
+	}
+
+	/*printf("Found string in %s->%s: %zu\n",
+	    #descr_struct, #descr_item, __str_index); */
+#define SET_STRING_INDEX(descr, mask, descr_type, descr_struct, descr_item) \
+	do { \
+		if ((descr)[1] == (descr_type)) { \
+			descr_struct *__type_descr = (descr_struct *) (descr); \
+			size_t __str_index = __type_descr->descr_item; \
+			if ((__str_index > 0) && (__str_index < 64)) { \
+				mask = (mask) | (1 << __str_index); \
+			} \
+		} \
+	} while (0)
+
+	uint64_t *mask = arg;
+
+#define SET_STR(descr_type, descr_struct, descr_item) \
+	SET_STRING_INDEX(descriptor, (*mask), descr_type, descr_struct, descr_item)
+
+	SET_STR(USB_DESCTYPE_DEVICE, usb_standard_device_descriptor_t,
+	    str_manufacturer);
+	SET_STR(USB_DESCTYPE_DEVICE, usb_standard_device_descriptor_t,
+	    str_product);
+	SET_STR(USB_DESCTYPE_DEVICE, usb_standard_device_descriptor_t,
+	    str_serial_number);
+	SET_STR(USB_DESCTYPE_CONFIGURATION, usb_standard_configuration_descriptor_t,
+	    str_configuration);
+	SET_STR(USB_DESCTYPE_INTERFACE, usb_standard_interface_descriptor_t,
+	    str_interface);
+}
+
+
+void dump_strings(usbinfo_device_t *dev)
+{
+	/* Get supported languages. */
+	l18_win_locales_t *langs;
+	size_t langs_count;
+	int rc = usb_request_get_supported_languages(&dev->ctrl_pipe,
+	    &langs, &langs_count);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to get list of supported languages: %s.\n",
+		    str_error(rc));
+		return;
+	}
+
+	printf("%sString languages (%zu):", get_indent(0), langs_count);
+	size_t i;
+	for (i = 0; i < langs_count; i++) {
+		printf(" 0x%04x", (int) langs[i]);
+	}
+	printf(".\n");
+
+	/* Find used indexes. Device with more than 64 strings are very rare.
+	 */
+	uint64_t str_mask = 0;
+	find_string_indexes_callback((uint8_t *)&dev->device_descriptor, 0,
+	    &str_mask);
+	usb_dp_walk_simple(dev->full_configuration_descriptor,
+	    dev->full_configuration_descriptor_size,
+	    usb_dp_standard_descriptor_nesting,
+	    find_string_indexes_callback,
+	    &str_mask);
+
+	/* Get all strings and dump them. */
+	for (i = 0; i < langs_count; i++) {
+		l18_win_locales_t lang = langs[i];
+
+		printf("%sStrings in %s:\n", get_indent(0),
+		    str_l18_win_locale(lang));
+
+		size_t idx;
+		for (idx = 1; idx < 64; idx++) {
+			if ((str_mask & ((uint64_t)1 << idx)) == 0) {
+				continue;
+			}
+			char *string = NULL;
+			rc = usb_request_get_string(&dev->ctrl_pipe, idx, lang,
+			    &string);
+			if ((rc != EOK) && (rc != EEMPTY)) {
+				printf("%sWarn: failed to retrieve string #%zu: %s.\n",
+				    get_indent(1), idx, str_error(rc));
+				continue;
+			}
+			printf("%sString #%zu: \"%s\"\n", get_indent(1),
+			    idx, rc == EOK ? string : "");
+			if (string != NULL) {
+				free(string);
+			}
+		}
+	}
+}
+
+
+void dump_status(usbinfo_device_t *dev)
+{
+	int rc;
+	uint16_t device_status = 0;
+	uint16_t ctrl_pipe_status = 0;
+
+	/* Device status first. */
+	rc = usb_request_get_status(&dev->ctrl_pipe,
+	    USB_REQUEST_RECIPIENT_DEVICE, 0,
+	    &device_status);
+	if (rc != EOK) {
+		printf("%sFailed to get device status: %s.\n",
+		    get_indent(0), str_error(rc));
+		goto try_ctrl_pipe_status;
+	}
+
+	printf("%sDevice status 0x%04x: power=%s, remote-wakeup=%s.\n",
+	    get_indent(0),
+	    device_status,
+	    device_status & USB_DEVICE_STATUS_SELF_POWERED ? "self" : "bus",
+	    device_status & USB_DEVICE_STATUS_REMOTE_WAKEUP ? "yes" : "no");
+
+	/* Interface is not interesting, skipping ;-). */
+
+	/* Control endpoint zero. */
+try_ctrl_pipe_status:
+	rc = usb_request_get_status(&dev->ctrl_pipe,
+	    USB_REQUEST_RECIPIENT_ENDPOINT, 0,
+	    &ctrl_pipe_status);
+	if (rc != EOK) {
+		printf("%sFailed to get control endpoint status: %s.\n",
+		    get_indent(0), str_error(rc));
+		goto leave;
+	}
+
+	printf("%sControl endpoint zero status %04X: halted=%s.\n",
+	    get_indent(0),
+	    ctrl_pipe_status,
+	    ctrl_pipe_status & USB_ENDPOINT_STATUS_HALTED ? "yes" : "no");
+
+leave:
+	return;
+}
+
+/** @}
+ */
Index: uspace/app/usbinfo/main.c
===================================================================
--- uspace/app/usbinfo/main.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/usbinfo/main.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2010-2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbinfo
+ * @{
+ */
+/**
+ * @file
+ * USB querying.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+#include <getopt.h>
+#include <devman.h>
+#include <devmap.h>
+#include <usb/hc.h>
+#include <usb/dev/pipes.h>
+#include "usbinfo.h"
+
+static void print_usage(char *app_name)
+{
+#define _INDENT "      "
+#define _OPTION(opt, description) \
+	printf(_INDENT opt "\n" _INDENT _INDENT description "\n")
+
+	printf(NAME ": query USB devices for descriptors\n\n");
+	printf("Usage: %s [options] device [device [device [ ... ]]]\n",
+	    app_name);
+	printf(_INDENT "The device is a devman path to the device.\n");
+
+	_OPTION("-h --help", "Print this help and exit.");
+	_OPTION("-i --identification", "Brief device identification.");
+	_OPTION("-m --match-ids", "Print match ids generated for the device.");
+	_OPTION("-t --descriptor-tree", "Print descriptor tree.");
+	_OPTION("-T --descriptor-tree-full", "Print detailed descriptor tree");
+	_OPTION("-s --strings", "Try to print all string descriptors.");
+	_OPTION("-S --status", "Get status of the device.");
+
+	printf("\n");
+	printf("If no option is specified, `-i' is considered default.\n");
+	printf("\n");
+
+#undef _OPTION
+#undef _INDENT
+}
+
+static struct option long_options[] = {
+	{"help", no_argument, NULL, 'h'},
+	{"identification", no_argument, NULL, 'i'},
+	{"match-ids", no_argument, NULL, 'm'},
+	{"descriptor-tree", no_argument, NULL, 't'},
+	{"descriptor-tree-full", no_argument, NULL, 'T'},
+	{"strings", no_argument, NULL, 's'},
+	{"status", no_argument, NULL, 'S'},
+	{0, 0, NULL, 0}
+};
+static const char *short_options = "himtTsS";
+
+static usbinfo_action_t actions[] = {
+	{
+		.opt = 'i',
+		.action = dump_short_device_identification,
+		.active = false
+	},
+	{
+		.opt = 'm',
+		.action = dump_device_match_ids,
+		.active = false
+	},
+	{
+		.opt = 't',
+		.action = dump_descriptor_tree_brief,
+		.active = false
+	},
+	{
+		.opt = 'T',
+		.action = dump_descriptor_tree_full,
+		.active = false
+	},
+	{
+		.opt = 's',
+		.action = dump_strings,
+		.active = false
+	},
+	{
+		.opt = 'S',
+		.action = dump_status,
+		.active = false
+	},
+	{
+		.opt = 0
+	}
+};
+
+int main(int argc, char *argv[])
+{
+	if (argc <= 1) {
+		print_usage(argv[0]);
+		return -1;
+	}
+
+	/*
+	 * Process command-line options. They determine what shall be
+	 * done with the device.
+	 */
+	int opt;
+	do {
+		opt = getopt_long(argc, argv,
+		    short_options, long_options, NULL);
+		switch (opt) {
+			case -1:
+				break;
+			case '?':
+				print_usage(argv[0]);
+				return 1;
+			case 'h':
+				print_usage(argv[0]);
+				return 0;
+			default: {
+				int idx = 0;
+				while (actions[idx].opt != 0) {
+					if (actions[idx].opt == opt) {
+						actions[idx].active = true;
+						break;
+					}
+					idx++;
+				}
+				break;
+			}
+		}
+	} while (opt > 0);
+
+	/* Set the default action. */
+	int idx = 0;
+	bool something_active = false;
+	while (actions[idx].opt != 0) {
+		if (actions[idx].active) {
+			something_active = true;
+			break;
+		}
+		idx++;
+	}
+	if (!something_active) {
+		actions[0].active = true;
+	}
+
+	/*
+	 * Go through all devices given on the command line and run the
+	 * specified actions.
+	 */
+	int i;
+	for (i = optind; i < argc; i++) {
+		char *devpath = argv[i];
+
+		/* The initialization is here only to make compiler happy. */
+		devman_handle_t hc_handle = 0;
+		usb_address_t dev_addr = 0;
+		int rc = usb_resolve_device_handle(devpath,
+		    &hc_handle, &dev_addr, NULL);
+		if (rc != EOK) {
+			fprintf(stderr, NAME ": device `%s' not found "
+			    "or not of USB kind, skipping.\n",
+			    devpath);
+			continue;
+		}
+
+		usbinfo_device_t *dev = prepare_device(devpath,
+		    hc_handle, dev_addr);
+		if (dev == NULL) {
+			continue;
+		}
+
+		/* Run actions the user specified. */
+		printf("%s\n", devpath);
+
+		int action = 0;
+		while (actions[action].opt != 0) {
+			if (actions[action].active) {
+				actions[action].action(dev);
+			}
+			action++;
+		}
+
+		/* Destroy the control pipe (close the session etc.). */
+		destroy_device(dev);
+	}
+
+	return 0;
+}
+
+
+/** @}
+ */
Index: uspace/app/usbinfo/usbinfo.h
===================================================================
--- uspace/app/usbinfo/usbinfo.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/usbinfo/usbinfo.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbinfo
+ * @{
+ */
+/** @file
+ * Common header for usbinfo application.
+ */
+#ifndef USBINFO_USBINFO_H_
+#define USBINFO_USBINFO_H_
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/dev/pipes.h>
+#include <usb/debug.h>
+#include <usb/dev/dp.h>
+#include <ipc/devman.h>
+
+typedef struct {
+	usb_pipe_t ctrl_pipe;
+	usb_device_connection_t wire;
+	usb_standard_device_descriptor_t device_descriptor;
+	uint8_t *full_configuration_descriptor;
+	size_t full_configuration_descriptor_size;
+} usbinfo_device_t;
+
+typedef struct {
+	int opt;
+	void (*action)(usbinfo_device_t *dev);
+	bool active;
+} usbinfo_action_t;
+
+
+#define NAME "usbinfo"
+
+void dump_buffer(const char *, size_t, const uint8_t *, size_t);
+const char *get_indent(size_t);
+void dump_match_ids(match_id_list_t *, const char *);
+void dump_usb_descriptor(uint8_t *, size_t);
+void dump_descriptor_tree(uint8_t *, size_t);
+
+static inline void internal_error(int err)
+{
+	fprintf(stderr, NAME ": internal error (%s).\n", str_error(err));
+}
+
+usbinfo_device_t *prepare_device(const char *, devman_handle_t, usb_address_t);
+void destroy_device(usbinfo_device_t *);
+
+typedef void (*dump_descriptor_in_tree_t)(uint8_t *, size_t, void *);
+void browse_descriptor_tree(uint8_t *, size_t, usb_dp_descriptor_nesting_t *,
+    dump_descriptor_in_tree_t, size_t, void *);
+
+
+void dump_short_device_identification(usbinfo_device_t *);
+void dump_device_match_ids(usbinfo_device_t *);
+void dump_descriptor_tree_brief(usbinfo_device_t *);
+void dump_descriptor_tree_full(usbinfo_device_t *);
+void dump_strings(usbinfo_device_t *);
+void dump_status(usbinfo_device_t *);
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/vuhid/Makefile
===================================================================
--- uspace/app/vuhid/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/vuhid/Makefile	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,58 @@
+#
+# Copyright (c) 2011 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+# acronym for virtual USB human input device
+# (it is really annoying to write long names)
+BINARY = vuh
+
+LIBS = \
+	$(LIBUSBVIRT_PREFIX)/libusbvirt.a \
+	$(LIBUSBHID_PREFIX)/libusbhid.a \
+	$(LIBUSBDEV_PREFIX)/libusbdev.a \
+	$(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS = \
+	-I$(LIBUSB_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
+	-I$(LIBUSBHID_PREFIX)/include \
+	-I$(LIBUSBVIRT_PREFIX)/include \
+	-I$(LIBDRV_PREFIX)/include
+
+
+SOURCES_INTERFACES = \
+	hids/bootkbd.c
+
+SOURCES = \
+	main.c \
+	device.c \
+	ifaces.c \
+	stdreq.c \
+	$(SOURCES_INTERFACES)
+	
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/vuhid/device.c
===================================================================
--- uspace/app/vuhid/device.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/vuhid/device.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbvirthid
+ * @{
+ */
+/**
+ * @file
+ * Virtual USB HID device.
+ */
+#include "virthid.h"
+#include <errno.h>
+#include <stdio.h>
+#include <str.h>
+#include <assert.h>
+#include <usb/classes/classes.h>
+
+static int on_data_from_device(usbvirt_device_t *dev,
+    usb_endpoint_t ep, usb_transfer_type_t tr_type,
+    void *data, size_t data_size, size_t *actual_size)
+{
+	vuhid_data_t *vuhid = dev->device_data;
+	vuhid_interface_t *iface = vuhid->in_endpoints_mapping[ep];
+	if (iface == NULL) {
+		return ESTALL;
+	}
+
+	if (iface->on_data_in == NULL) {
+		return EBADCHECKSUM;
+	}
+
+	return iface->on_data_in(iface, data, data_size, actual_size);
+}
+
+static int on_data_to_device(usbvirt_device_t *dev,
+    usb_endpoint_t ep, usb_transfer_type_t tr_type,
+    void *data, size_t data_size)
+{
+	vuhid_data_t *vuhid = dev->device_data;
+	vuhid_interface_t *iface = vuhid->out_endpoints_mapping[ep];
+	if (iface == NULL) {
+		return ESTALL;
+	}
+
+	if (iface->on_data_out == NULL) {
+		return EBADCHECKSUM;
+	}
+
+	return iface->on_data_out(iface, data, data_size);
+}
+
+static int interface_life_fibril(void *arg)
+{
+	vuhid_interface_t *iface = arg;
+	vuhid_data_t *hid_data = iface->vuhid_data;
+
+	if (iface->live != NULL) {
+		iface->live(iface);
+	}
+
+	fibril_mutex_lock(&hid_data->iface_count_mutex);
+	hid_data->iface_died_count++;
+	fibril_condvar_broadcast(&hid_data->iface_count_cv);
+	fibril_mutex_unlock(&hid_data->iface_count_mutex);
+
+	return EOK;
+}
+
+
+static vuhid_interface_t *find_interface_by_id(vuhid_interface_t **ifaces,
+    const char *id)
+{
+	if ((ifaces == NULL) || (id == NULL)) {
+		return NULL;
+	}
+	while (*ifaces != NULL) {
+		if (str_cmp((*ifaces)->id, id) == 0) {
+			return *ifaces;
+		}
+		ifaces++;
+	}
+
+	return NULL;
+}
+
+int add_interface_by_id(vuhid_interface_t **interfaces, const char *id,
+    usbvirt_device_t *dev)
+{
+	vuhid_interface_t *iface = find_interface_by_id(interfaces, id);
+	if (iface == NULL) {
+		return ENOENT;
+	}
+
+	if ((iface->in_data_size == 0) && (iface->out_data_size == 0)) {
+		return EEMPTY;
+	}
+
+	/* Already used interface. */
+	if (iface->vuhid_data != NULL) {
+		return EEXISTS;
+	}
+
+	vuhid_data_t *hid_data = dev->device_data;
+
+	/* Check that we have not run out of available endpoints. */
+	if ((iface->in_data_size > 0)
+	    && (hid_data->in_endpoint_first_free >= VUHID_ENDPOINT_MAX)) {
+		return ELIMIT;
+	}
+	if ((iface->out_data_size > 0)
+	    && (hid_data->out_endpoint_first_free >= VUHID_ENDPOINT_MAX)) {
+		return ELIMIT;
+	}
+
+	if (dev->descriptors->configuration->descriptor->interface_count >=
+	    VUHID_INTERFACE_MAX) {
+		return ELIMIT;
+	}
+
+	/*
+	 * How may descriptors we would add?
+	 */
+	/* Start with interface descriptor. */
+	size_t new_descriptor_count = 1;
+	/* Having in/out data size positive means we would need endpoint. */
+	if (iface->in_data_size > 0) {
+		new_descriptor_count++;
+	}
+	if (iface->out_data_size > 0) {
+		new_descriptor_count++;
+	}
+	/* Having report descriptor means adding the HID descriptor. */
+	if (iface->report_descriptor != NULL) {
+		new_descriptor_count++;
+	}
+
+	/* From now on, in case of errors, we goto to error_leave */
+	int rc;
+
+	/*
+	 * Prepare new descriptors.
+	 */
+	size_t descr_count = 0;
+	size_t total_descr_size = 0;
+	usb_standard_interface_descriptor_t *descr_iface = NULL;
+	hid_descriptor_t *descr_hid = NULL;
+	usb_standard_endpoint_descriptor_t *descr_ep_in = NULL;
+	usb_standard_endpoint_descriptor_t *descr_ep_out = NULL;
+
+	size_t ep_count = 0;
+	if (iface->in_data_size > 0) {
+		ep_count++;
+	}
+	if (iface->out_data_size > 0) {
+		ep_count++;
+	}
+	assert(ep_count > 0);
+
+	/* Interface would be needed always. */
+	descr_iface = malloc(sizeof(usb_standard_interface_descriptor_t));
+	if (descr_iface == NULL) {
+		rc = ENOMEM;
+		goto error_leave;
+	}
+	descr_count++;
+	total_descr_size += sizeof(usb_standard_interface_descriptor_t);
+	descr_iface->length = sizeof(usb_standard_interface_descriptor_t);
+	descr_iface->descriptor_type = USB_DESCTYPE_INTERFACE;
+	descr_iface->interface_number
+	    = dev->descriptors->configuration->descriptor->interface_count;
+	descr_iface->alternate_setting = 0;
+	descr_iface->endpoint_count = ep_count;
+	descr_iface->interface_class = USB_CLASS_HID;
+	descr_iface->interface_subclass = iface->usb_subclass;
+	descr_iface->interface_protocol = iface->usb_protocol;
+	descr_iface->str_interface = 0;
+
+	/* Create the HID descriptor. */
+	if (iface->report_descriptor != NULL) {
+		descr_hid = malloc(sizeof(hid_descriptor_t));
+		if (descr_hid == NULL) {
+			rc = ENOMEM;
+			goto error_leave;
+		}
+		descr_count++;
+		total_descr_size += sizeof(hid_descriptor_t);
+		descr_hid->length = sizeof(hid_descriptor_t);
+		descr_hid->type = USB_DESCTYPE_HID;
+		descr_hid->hid_spec_release = 0x101;
+		descr_hid->country_code = 0;
+		descr_hid->descriptor_count = 1;
+		descr_hid->descriptor1_type = USB_DESCTYPE_HID_REPORT;
+		descr_hid->descriptor1_length = iface->report_descriptor_size;
+	}
+
+	/* Prepare the endpoint descriptors. */
+	if (iface->in_data_size > 0) {
+		descr_ep_in = malloc(sizeof(usb_standard_endpoint_descriptor_t));
+		if (descr_ep_in == NULL) {
+			rc = ENOMEM;
+			goto error_leave;
+		}
+		descr_count++;
+		total_descr_size += sizeof(usb_standard_endpoint_descriptor_t);
+		descr_ep_in->length = sizeof(usb_standard_endpoint_descriptor_t);
+		descr_ep_in->descriptor_type = USB_DESCTYPE_ENDPOINT;
+		descr_ep_in->endpoint_address
+		    = 0x80 | hid_data->in_endpoint_first_free;
+		descr_ep_in->attributes = 3;
+		descr_ep_in->max_packet_size = iface->in_data_size;
+		descr_ep_in->poll_interval = 10;
+	}
+	if (iface->out_data_size > 0) {
+		descr_ep_out = malloc(sizeof(usb_standard_endpoint_descriptor_t));
+		if (descr_ep_out == NULL) {
+			rc = ENOMEM;
+			goto error_leave;
+		}
+		descr_count++;
+		total_descr_size += sizeof(usb_standard_endpoint_descriptor_t);
+		descr_ep_out->length = sizeof(usb_standard_endpoint_descriptor_t);
+		descr_ep_out->descriptor_type = USB_DESCTYPE_ENDPOINT;
+		descr_ep_out->endpoint_address
+		    = 0x00 | hid_data->out_endpoint_first_free;
+		descr_ep_out->attributes = 3;
+		descr_ep_out->max_packet_size = iface->out_data_size;
+		descr_ep_out->poll_interval = 10;
+	}
+
+	/* Extend existing extra descriptors with these ones. */
+	usbvirt_device_configuration_extras_t *extra_descriptors
+	    = dev->descriptors->configuration->extra;
+	extra_descriptors = realloc(extra_descriptors,
+	    sizeof(usbvirt_device_configuration_extras_t)
+	    * (dev->descriptors->configuration->extra_count + descr_count));
+	if (extra_descriptors == NULL) {
+		rc = ENOMEM;
+		goto error_leave;
+	}
+
+	/* Launch the "life" fibril. */
+	iface->vuhid_data = hid_data;
+	fid_t life_fibril = fibril_create(interface_life_fibril, iface);
+	if (life_fibril == 0) {
+		rc = ENOMEM;
+		goto error_leave;
+	}
+
+	/* Allocation is okay, we can (actually have to now) overwrite the
+	 * original pointer.
+	 */
+	dev->descriptors->configuration->extra = extra_descriptors;
+	extra_descriptors += dev->descriptors->configuration->extra_count;
+
+	/* Initialize them. */
+#define _APPEND_DESCRIPTOR(descriptor) \
+	do { \
+		if ((descriptor) != NULL) { \
+			extra_descriptors->data = (uint8_t *) (descriptor); \
+			extra_descriptors->length = (descriptor)->length; \
+			extra_descriptors++; \
+		} \
+	} while (0)
+
+	_APPEND_DESCRIPTOR(descr_iface);
+	_APPEND_DESCRIPTOR(descr_hid);
+	_APPEND_DESCRIPTOR(descr_ep_in);
+	_APPEND_DESCRIPTOR(descr_ep_out);
+#undef _APPEND_DESCRIPTOR
+	dev->descriptors->configuration->extra_count += descr_count;
+
+	/*
+	 * Final changes.
+	 * Increase the necessary counters, make endpoint mapping.
+	 *
+	 */
+	if (iface->in_data_size > 0) {
+		hid_data->in_endpoints_mapping[hid_data->in_endpoint_first_free]
+		    = iface;
+		dev->ops->data_in[hid_data->in_endpoint_first_free]
+		    = on_data_from_device;
+		hid_data->in_endpoint_first_free++;
+	}
+	if (iface->out_data_size > 0) {
+		hid_data->out_endpoints_mapping[hid_data->out_endpoint_first_free]
+		    = iface;
+		dev->ops->data_out[hid_data->out_endpoint_first_free]
+		    = on_data_to_device;
+		hid_data->out_endpoint_first_free++;
+	}
+
+	hid_data->interface_mapping[
+	    dev->descriptors->configuration->descriptor->interface_count]
+	    = iface;
+
+	dev->descriptors->configuration->descriptor->interface_count++;
+	dev->descriptors->configuration->descriptor->total_length
+	    += total_descr_size;
+
+	hid_data->iface_count++;
+	fibril_add_ready(life_fibril);
+
+	return EOK;
+
+error_leave:
+	if (descr_iface != NULL) {
+		free(descr_iface);
+	}
+	if (descr_hid != NULL) {
+		free(descr_hid);
+	}
+	if (descr_ep_in != NULL) {
+		free(descr_ep_in);
+	}
+	if (descr_ep_out != NULL) {
+		free(descr_ep_out);
+	}
+
+	return rc;
+}
+
+void wait_for_interfaces_death(usbvirt_device_t *dev)
+{
+	vuhid_data_t *hid_data = dev->device_data;
+
+	fibril_mutex_lock(&hid_data->iface_count_mutex);
+	while (hid_data->iface_died_count < hid_data->iface_count) {
+		fibril_condvar_wait(&hid_data->iface_count_cv,
+		    &hid_data->iface_count_mutex);
+	}
+	fibril_mutex_unlock(&hid_data->iface_count_mutex);
+}
+
+/** @}
+ */
Index: uspace/app/vuhid/hids/bootkbd.c
===================================================================
--- uspace/app/vuhid/hids/bootkbd.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/vuhid/hids/bootkbd.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbvirthid
+ * @{
+ */
+/** @file
+ *
+ */
+#include "../virthid.h"
+#include <errno.h>
+#include <usb/debug.h>
+#include <usb/hid/hid.h>
+#include <usb/hid/usages/core.h>
+
+#include "../report.h"
+
+uint8_t report_descriptor[] = {
+	STD_USAGE_PAGE(USB_HIDUT_PAGE_GENERIC_DESKTOP),
+	USAGE1(USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD),
+	START_COLLECTION(COLLECTION_APPLICATION),
+		STD_USAGE_PAGE(USB_HIDUT_PAGE_KEYBOARD),
+		USAGE_MINIMUM1(224),
+		USAGE_MAXIMUM1(231),
+		LOGICAL_MINIMUM1(0),
+		LOGICAL_MAXIMUM1(1),
+		REPORT_SIZE1(1),
+		REPORT_COUNT1(8),
+		/* Modifiers */
+		INPUT(IOF_DATA | IOF_VARIABLE | IOF_ABSOLUTE),
+		REPORT_COUNT1(1),
+		REPORT_SIZE1(8),
+		/* Reserved */
+		INPUT(IOF_CONSTANT),
+		REPORT_COUNT1(5),
+		REPORT_SIZE1(1),
+		STD_USAGE_PAGE(USB_HIDUT_PAGE_LED),
+		USAGE_MINIMUM1(1),
+		USAGE_MAXIMUM1(5),
+		/* LED states */
+		OUTPUT(IOF_DATA | IOF_VARIABLE | IOF_ABSOLUTE),
+		REPORT_COUNT1(1),
+		REPORT_SIZE1(3),
+		/* LED states padding */
+		OUTPUT(IOF_CONSTANT),
+		REPORT_COUNT1(6),
+		REPORT_SIZE1(8),
+		LOGICAL_MINIMUM1(0),
+		LOGICAL_MAXIMUM1(101),
+		STD_USAGE_PAGE(USB_HIDUT_PAGE_KEYBOARD),
+		USAGE_MINIMUM1(0),
+		USAGE_MAXIMUM1(101),
+		/* Key array */
+		INPUT(IOF_DATA | IOF_ARRAY),
+	END_COLLECTION()
+};
+
+#define INPUT_SIZE 8
+
+static uint8_t in_data[] = {
+	     0, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	     0, 0, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, // Caps Lock
+	     0, 0, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, // Num Lock
+	     0, 0, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, // Caps Lock
+	1 << 2, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	1 << 2, 0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,
+	1 << 2, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	     0, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+static size_t in_data_count = sizeof(in_data)/INPUT_SIZE;
+// FIXME - locking
+static size_t in_data_position = 0;
+
+static int on_data_in(vuhid_interface_t *iface,
+    void *buffer, size_t buffer_size, size_t *act_buffer_size)
+{
+	static size_t last_pos = (size_t) -1;
+	size_t pos = in_data_position;
+	if (pos >= in_data_count) {
+		return EBADCHECKSUM;
+	}
+
+	if (last_pos == pos) {
+		return ENAK;
+	}
+
+	if (buffer_size > INPUT_SIZE) {
+		buffer_size = INPUT_SIZE;
+	}
+
+	if (act_buffer_size != NULL) {
+		*act_buffer_size = buffer_size;
+	}
+
+	memcpy(buffer, in_data + pos * INPUT_SIZE, buffer_size);
+	last_pos = pos;
+
+	return EOK;
+}
+
+static int on_data_out(vuhid_interface_t *iface,
+    void *buffer, size_t buffer_size)
+{
+	if (buffer_size == 0) {
+		return EEMPTY;
+	}
+	uint8_t leds = ((uint8_t *) buffer)[0];
+#define _GET_LED(index, signature) \
+	(((leds) & (1 << index)) ? (signature) : '-')
+	usb_log_info("%s: LEDs = %c%c%c%c%c\n",
+	    iface->name,
+	    _GET_LED(0, '0'), _GET_LED(1, 'A'), _GET_LED(2, 's'),
+	    _GET_LED(3, 'c'), _GET_LED(4, 'k'));
+#undef _GET_LED
+	return EOK;
+}
+
+
+static void live(vuhid_interface_t *iface)
+{
+	async_usleep(1000 * 1000 * 5);
+	usb_log_debug("Boot keyboard comes to life...\n");
+	while (in_data_position < in_data_count) {
+		async_usleep(1000 * 500);
+		in_data_position++;
+	}
+	usb_log_debug("Boot keyboard died.\n");
+}
+
+
+vuhid_interface_t vuhid_interface_bootkbd = {
+	.id = "boot",
+	.name = "boot keyboard",
+	.usb_subclass = USB_HID_SUBCLASS_BOOT,
+	.usb_protocol = USB_HID_PROTOCOL_KEYBOARD,
+
+	.report_descriptor = report_descriptor,
+	.report_descriptor_size = sizeof(report_descriptor),
+
+	.in_data_size = INPUT_SIZE,
+	.on_data_in = on_data_in,
+
+	.out_data_size = 1,
+	.on_data_out = on_data_out,
+
+	.live = live,
+
+	.vuhid_data = NULL
+};
+
+/**
+ * @}
+ */
Index: uspace/app/vuhid/ifaces.c
===================================================================
--- uspace/app/vuhid/ifaces.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/vuhid/ifaces.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbvirthid
+ * @{
+ */
+/**
+ * @file
+ * List of known interfaces.
+ */
+#include <stdlib.h>
+#include "ifaces.h"
+
+extern vuhid_interface_t vuhid_interface_bootkbd;
+
+vuhid_interface_t *available_hid_interfaces[] = {
+	&vuhid_interface_bootkbd,
+	NULL
+};
+
+
+/** @}
+ */
Index: uspace/app/vuhid/ifaces.h
===================================================================
--- uspace/app/vuhid/ifaces.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/vuhid/ifaces.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbvirthid
+ * @{
+ */
+/** @file
+ *
+ */
+#ifndef VUHID_IFACES_H_
+#define VUHID_IFACES_H_
+
+#include "virthid.h"
+
+extern vuhid_interface_t *available_hid_interfaces[];
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/vuhid/items.h
===================================================================
--- uspace/app/vuhid/items.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/vuhid/items.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbvirtkbd
+ * @{
+ */
+/** @file
+ * @brief HID Item related functions.
+ */
+#ifndef VUK_ITEM_H_
+#define VUK_ITEM_H_
+
+#include <sys/types.h>
+
+typedef uint8_t report_descriptor_data_t[];
+
+/* Item types. */
+#define ITEM_MAIN 0
+#define ITEM_GLOBAL 1
+#define ITEM_LOCAL 2
+
+
+
+/* Item tags. */
+
+/* Main item tags. */
+#define TAG_INPUT 8
+#define TAG_OUTPUT 9
+#define TAG_FEATURE 11
+#define TAG_COLLECTION 10
+#define TAG_END_COLLECTION 12
+
+/* Global item tags. */
+#define TAG_USAGE_PAGE 0
+#define TAG_LOGICAL_MINIMUM 1
+#define TAG_LOGICAL_MAXIMUM 2
+#define TAG_REPORT_SIZE 7
+#define TAG_REPORT_COUNT 9
+
+/* Local item tags. */
+#define TAG_USAGE 0
+#define TAG_USAGE_MINIMUM 1
+#define TAG_USAGE_MAXIMUM 2
+
+
+/* Bits for Input, Output and Feature items. */
+#define _IOF(value, shift) ((value) << (shift))
+#define IOF_DATA _IOF(0, 0)
+#define IOF_CONSTANT _IOF(1, 0)
+#define IOF_ARRAY _IOF(0, 1)
+#define IOF_VARIABLE _IOF(1, 1)
+#define IOF_ABSOLUTE _IOF(0, 2)
+#define IOF_RELATIVE _IOF(1, 2)
+/* ... */
+
+/* Collection types. */
+#define COLLECTION_PHYSICAL 0x00
+#define COLLECTION_APPLICATION 0x01
+
+
+/** Creates item prefix.
+ * @param size Item size.
+ * @param type Item type.
+ * @param tag Item tag.
+ */
+#define BUILD_ITEM_PREFIX(size, type, tag) \
+	((size) | ((type) << 2) | ((tag) << 4))
+
+/** Create no-data item.
+ * @param type Item type.
+ * @param tag Item tag.
+ */
+#define ITEM_CREATE0(type, tag) \
+	BUILD_ITEM_PREFIX(0, type, tag)
+
+/** Create item with 1-byte data.
+ * @param type Item type.
+ * @param tag Item tag.
+ * @param data Item data (single byte).
+ */
+#define ITEM_CREATE1(type, tag, data) \
+	BUILD_ITEM_PREFIX(1, type, tag), data
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/vuhid/main.c
===================================================================
--- uspace/app/vuhid/main.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/vuhid/main.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbvirthid
+ * @{
+ */
+/**
+ * @file
+ * Virtual USB HID device.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/hid/hid.h>
+#include <usbvirt/device.h>
+
+#include "virthid.h"
+#include "ifaces.h"
+#include "stdreq.h"
+
+static usbvirt_control_request_handler_t endpoint_zero_handlers[] = {
+	{
+		.req_direction = USB_DIRECTION_IN,
+		.req_type = USB_REQUEST_TYPE_STANDARD,
+		.req_recipient = USB_REQUEST_RECIPIENT_INTERFACE,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.name = "Get_Descriptor",
+		.callback = req_get_descriptor
+	},
+	{
+		.req_direction = USB_DIRECTION_OUT,
+		.req_recipient = USB_REQUEST_RECIPIENT_INTERFACE,
+		.req_type = USB_REQUEST_TYPE_CLASS,
+		.request = USB_HIDREQ_SET_PROTOCOL,
+		.name = "Set_Protocol",
+		.callback = req_set_protocol
+	},
+	{
+		.req_direction = USB_DIRECTION_OUT,
+		.req_recipient = USB_REQUEST_RECIPIENT_INTERFACE,
+		.req_type = USB_REQUEST_TYPE_CLASS,
+		.request = USB_HIDREQ_SET_REPORT,
+		.name = "Set_Report",
+		.callback = req_set_report
+	},
+	{
+		.callback = NULL
+	}
+};
+
+/** Keyboard callbacks.
+ * We abuse the fact that static variables are zero-filled.
+ */
+static usbvirt_device_ops_t hid_ops = {
+	.control = endpoint_zero_handlers,
+};
+
+/** Standard configuration descriptor. */
+static usb_standard_configuration_descriptor_t std_configuration_descriptor = {
+	.length = sizeof(usb_standard_configuration_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
+	/* Will be patched at runtime. */
+	.total_length = sizeof(usb_standard_configuration_descriptor_t),
+	.interface_count = 0,
+	.configuration_number = 1,
+	.str_configuration = 0,
+	.attributes = 128, /* denotes bus-powered device */
+	.max_power = 50
+};
+
+/** Standard device descriptor. */
+static usb_standard_device_descriptor_t std_device_descriptor = {
+	.length = sizeof(usb_standard_device_descriptor_t),
+	.descriptor_type = USB_DESCTYPE_DEVICE,
+	.usb_spec_version = 0x110,
+	.device_class = USB_CLASS_USE_INTERFACE,
+	.device_subclass = 0,
+	.device_protocol = 0,
+	.max_packet_size = 64,
+	.configuration_count = 1
+};
+
+/** HID configuration. */
+usbvirt_device_configuration_t configuration = {
+	.descriptor = &std_configuration_descriptor,
+	.extra = NULL,
+	.extra_count = 0
+};
+
+/** HID standard descriptors. */
+usbvirt_descriptors_t descriptors = {
+	.device = &std_device_descriptor,
+	.configuration = &configuration,
+	.configuration_count = 1,
+};
+
+static vuhid_data_t vuhid_data = {
+	.in_endpoints_mapping = { NULL },
+	.in_endpoint_first_free = 1,
+	.out_endpoints_mapping = { NULL },
+	.out_endpoint_first_free = 1,
+
+	.iface_count = 0,
+	.iface_died_count = 0
+	// mutex and CV must be initialized elsewhere
+};
+
+
+/** Keyboard device.
+ * Rest of the items will be initialized later.
+ */
+static usbvirt_device_t hid_dev = {
+	.ops = &hid_ops,
+	.descriptors = &descriptors,
+	.name = "HID",
+	.device_data = &vuhid_data
+};
+
+
+int main(int argc, char * argv[])
+{
+	int rc;
+
+	usb_log_enable(USB_LOG_LEVEL_DEBUG2, "vusbhid");
+
+	fibril_mutex_initialize(&vuhid_data.iface_count_mutex);
+	fibril_condvar_initialize(&vuhid_data.iface_count_cv);
+
+	/* Determine which interfaces to initialize. */
+	int i;
+	for (i = 1; i < argc; i++) {
+		rc = add_interface_by_id(available_hid_interfaces, argv[i],
+		    &hid_dev);
+		if (rc != EOK) {
+			fprintf(stderr, "Failed to add device `%s': %s.\n",
+			    argv[i], str_error(rc));
+		} else {
+			printf("Added device `%s'.\n", argv[i]);
+		}
+	}
+
+	for (i = 0; i < (int) hid_dev.descriptors->configuration->extra_count; i++) {
+		usb_log_debug("Found extra descriptor: %s.\n",
+		    usb_debug_str_buffer(
+		        hid_dev.descriptors->configuration->extra[i].data,
+		        hid_dev.descriptors->configuration->extra[i].length,
+		        0));
+	}
+
+	rc = usbvirt_device_plug(&hid_dev, "/virt/usbhc/hc");
+	if (rc != EOK) {
+		printf("Unable to start communication with VHCD: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	printf("Connected to VHCD...\n");
+
+	wait_for_interfaces_death(&hid_dev);
+	
+	printf("Terminating...\n");
+	
+	usbvirt_device_unplug(&hid_dev);
+
+	return 0;
+}
+
+
+/** @}
+ */
Index: uspace/app/vuhid/report.h
===================================================================
--- uspace/app/vuhid/report.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/vuhid/report.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbvirtkbd
+ * @{
+ */
+/** @file
+ * @brief HID Report Descriptor.
+ */
+#ifndef VUK_REPORT_H_
+#define VUK_REPORT_H_
+
+#include "items.h"
+
+/** Use standard Usage Page. */
+#define STD_USAGE_PAGE(page) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_USAGE_PAGE, page)
+
+/** Usage with one byte usage ID. */
+#define USAGE1(usage_id) \
+	ITEM_CREATE1(ITEM_LOCAL, TAG_USAGE, usage_id)
+
+/** Start a collection. */
+#define START_COLLECTION(collection) \
+	ITEM_CREATE1(ITEM_MAIN, TAG_COLLECTION, collection)
+
+/** End a collection. */
+#define END_COLLECTION() \
+	ITEM_CREATE0(ITEM_MAIN, TAG_END_COLLECTION)
+
+
+#define USAGE_MINIMUM1(value) \
+	ITEM_CREATE1(ITEM_LOCAL, TAG_USAGE_MINIMUM, value)
+	
+#define USAGE_MAXIMUM1(value) \
+	ITEM_CREATE1(ITEM_LOCAL, TAG_USAGE_MAXIMUM, value)
+	
+#define LOGICAL_MINIMUM1(value) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_LOGICAL_MINIMUM, value)
+
+#define LOGICAL_MAXIMUM1(value) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_LOGICAL_MAXIMUM, value)
+
+#define REPORT_SIZE1(size) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_REPORT_SIZE, size)
+
+#define REPORT_COUNT1(count) \
+	ITEM_CREATE1(ITEM_GLOBAL, TAG_REPORT_COUNT, count)
+	
+#define INPUT(modifiers) \
+	ITEM_CREATE1(ITEM_MAIN, TAG_INPUT, modifiers)
+
+#define OUTPUT(modifiers) \
+	ITEM_CREATE1(ITEM_MAIN, TAG_OUTPUT, modifiers)
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/vuhid/stdreq.c
===================================================================
--- uspace/app/vuhid/stdreq.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/vuhid/stdreq.c	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbvirthid
+ * @{
+ */
+/**
+ * @file
+ *
+ */
+#include <errno.h>
+#include <usb/debug.h>
+#include <usb/descriptor.h>
+#include "stdreq.h"
+#include "virthid.h"
+
+#define VUHID_DATA(vuhid, device) \
+	vuhid_data_t *vuhid = device->device_data
+
+int req_get_descriptor(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size)
+{
+	VUHID_DATA(vuhid, device);
+
+	if (setup_packet->value_high == USB_DESCTYPE_HID_REPORT) {
+		vuhid_interface_t *iface
+		    = vuhid->interface_mapping[setup_packet->index];
+		if (iface == NULL) {
+			return EFORWARD;
+		}
+		if (iface->report_descriptor != NULL) {
+			usbvirt_control_reply_helper(setup_packet,
+			    data, act_size,
+			    iface->report_descriptor,
+			    iface->report_descriptor_size);
+			return EOK;
+		} else {
+			return ENOENT;
+		}
+	}
+	
+	/* Let the framework handle all the rest. */
+	return EFORWARD;
+}
+
+int req_set_protocol(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size)
+{
+	VUHID_DATA(vuhid, device);
+
+	size_t iface_index = setup_packet->index;
+	int protocol = setup_packet->value;
+
+	// FIXME - check ranges
+	vuhid_interface_t *iface = vuhid->interface_mapping[iface_index];
+	if (iface == NULL) {
+		return ENOENT;
+	}
+	iface->set_protocol = protocol;
+
+	return EOK;
+}
+
+int req_set_report(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size)
+{
+	VUHID_DATA(vuhid, device);
+
+	size_t iface_index = setup_packet->index;
+
+	// FIXME - check ranges
+	vuhid_interface_t *iface = vuhid->interface_mapping[iface_index];
+	if (iface == NULL) {
+		return ENOENT;
+	}
+
+	size_t data_length = setup_packet->length;
+	if (iface->on_data_out == NULL) {
+		return ENOTSUP;
+	}
+
+	/* SET_REPORT is translated to data out */
+	int rc = iface->on_data_out(iface, data, data_length);
+
+	return rc;
+}
+
+
+
+/** @}
+ */
Index: uspace/app/vuhid/stdreq.h
===================================================================
--- uspace/app/vuhid/stdreq.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/vuhid/stdreq.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbvirthid
+ * @{
+ */
+/** @file
+ * Device request handlers.
+ */
+#ifndef VUHID_STDREQ_H_
+#define VUHID_STDREQ_H_
+
+#include <usbvirt/device.h>
+
+int req_get_descriptor(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size);
+
+int req_set_protocol(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size);
+
+int req_set_report(usbvirt_device_t *device,
+    const usb_device_request_setup_packet_t *setup_packet,
+    uint8_t *data, size_t *act_size);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/vuhid/virthid.h
===================================================================
--- uspace/app/vuhid/virthid.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
+++ uspace/app/vuhid/virthid.h	(revision 2af29ed7c9c717445d7e7c17955fdb597d7ce3c8)
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup usbvirthid
+ * @{
+ */
+/** @file
+ *
+ */
+#ifndef VUHID_VIRTHID_H_
+#define VUHID_VIRTHID_H_
+
+#include <usb/usb.h>
+#include <usbvirt/device.h>
+#include <fibril_synch.h>
+
+#define VUHID_ENDPOINT_MAX USB11_ENDPOINT_MAX
+#define VUHID_INTERFACE_MAX 8
+
+typedef struct vuhid_interface vuhid_interface_t;
+
+typedef struct {
+	vuhid_interface_t *in_endpoints_mapping[VUHID_ENDPOINT_MAX];
+	size_t in_endpoint_first_free;
+	vuhid_interface_t *out_endpoints_mapping[VUHID_ENDPOINT_MAX];
+	size_t out_endpoint_first_free;
+	vuhid_interface_t *interface_mapping[VUHID_INTERFACE_MAX];
+
+	fibril_mutex_t iface_count_mutex;
+	fibril_condvar_t iface_count_cv;
+	size_t iface_count;
+	size_t iface_died_count;
+} vuhid_data_t;
+
+struct vuhid_interface {
+	const char *name;
+	const char *id;
+	int usb_subclass;
+	int usb_protocol;
+
+	uint8_t *report_descriptor;
+	size_t report_descriptor_size;
+
+	size_t in_data_size;
+	size_t out_data_size;
+
+	int (*on_data_in)(vuhid_interface_t *, void *, size_t, size_t *);
+	int (*on_data_out)(vuhid_interface_t *, void *, size_t);
+	void (*live)(vuhid_interface_t *);
+
+	int set_protocol;
+
+	void *interface_data;
+
+	vuhid_data_t *vuhid_data;
+};
+
+typedef struct {
+	uint8_t length;
+	uint8_t type;
+	uint16_t hid_spec_release;
+	uint8_t country_code;
+	uint8_t descriptor_count;
+	uint8_t descriptor1_type;
+	uint16_t descriptor1_length;
+} __attribute__ ((packed)) hid_descriptor_t;
+
+int add_interface_by_id(vuhid_interface_t **, const char *, usbvirt_device_t *);
+void wait_for_interfaces_death(usbvirt_device_t *);
+
+#endif
+/**
+ * @}
+ */
