Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ HelenOS.config	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -573,5 +573,7 @@
 ! CONFIG_RUN_VIRTUAL_USB_HC (n/y)
 
-% Polling UHCI & OHCI (no interrupts)
-! [PLATFORM=ia32|PLATFORM=amd64] CONFIG_USBHC_NO_INTERRUPTS (n/y)
-
+% OHCI root hub port power switching
+@ "no" All root hub ports are always powered.
+@ "ganged" Root hub ports are all powered or all off.
+@ "per_port" Powered status of every root hub port is independent.
+![PLATFORM=ia32|PLATFORM=amd64] OHCI_POWER_SWITCH (choice)
Index: defaults/amd64/Makefile.config
===================================================================
--- defaults/amd64/Makefile.config	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ defaults/amd64/Makefile.config	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -65,2 +65,4 @@
 CONFIG_MOUNT_DATA = n
 
+# OHCI root hub power switch, ganged is enough
+OHCI_POWER_SWITCH = ganged
Index: defaults/ia32/Makefile.config
===================================================================
--- defaults/ia32/Makefile.config	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ defaults/ia32/Makefile.config	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -71,2 +71,4 @@
 CONFIG_MOUNT_DATA = n
 
+# OHCI root hub power switch, ganged is enough
+OHCI_POWER_SWITCH = ganged
Index: uspace/app/bdsh/Makefile
===================================================================
--- uspace/app/bdsh/Makefile	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/app/bdsh/Makefile	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -54,4 +54,5 @@
 	cmds/mod_cmds.c \
 	cmds/builtin_cmds.c \
+	compl.c \
 	errors.c \
 	input.c \
Index: uspace/app/bdsh/compl.c
===================================================================
--- uspace/app/bdsh/compl.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
+++ uspace/app/bdsh/compl.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <bool.h>
+#include <dirent.h>
+#include <errno.h>
+#include <macros.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "cmds/cmds.h"
+#include "compl.h"
+#include "exec.h"
+
+static int compl_init(wchar_t *text, size_t pos, size_t *cstart, void **state);
+static int compl_get_next(void *state, char **compl);
+static void compl_fini(void *state);
+
+/** Bdsh implementation of completion ops. */
+tinput_compl_ops_t compl_ops = {
+	.init = compl_init,
+	.get_next = compl_get_next,
+	.fini = compl_fini
+};
+
+/** Completion state object.
+ *
+ * The state object contains 'iterators' for modules, builtins and
+ * executables in directories.
+ */
+typedef struct {
+	/** String prefix which we are trying to complete. */
+	char *prefix;
+	/** Length of string prefix (number of characters) */
+	size_t prefix_len;
+
+	/** Pointer inside list of modules */
+	module_t *module;
+	/** Pointer inside list of builtins */
+	builtin_t *builtin;
+
+	/** Pointer inside list of directories */
+	const char **path;
+	/** If not @c NULL, should be freed in the end. */
+	const char **path_list;
+	/** Current open directory */
+	DIR *dir;
+
+	char *last_compl;
+
+	/**
+	 * @c true if we are completing a command, @c false if we are
+	 * completing an argument
+	 */
+	bool is_command;
+} compl_t;
+
+/** Init completion.
+ *
+ * Set up iterators in completion object, based on current token.
+ */
+static int compl_init(wchar_t *text, size_t pos, size_t *cstart, void **state)
+{
+	compl_t *cs = NULL;
+	size_t p;
+	size_t pref_size;
+	char *stext = NULL;
+	char *prefix = NULL;
+	char *dirname = NULL;
+	char *rpath_sep;
+	static const char *dirlist_arg[] = { ".", NULL };
+	int retval;
+
+	cs = calloc(1, sizeof(compl_t));
+	if (!cs) {
+		retval = ENOMEM;
+		goto error;
+	}
+
+	/*
+	 * Copy token pointed to by caret from start up to the caret.
+	 * XXX Ideally we would use the standard tokenizer.
+	 */
+	p = pos;
+	while (p > 0 && text[p - 1] != (wchar_t) ' ')
+		--p;
+	*cstart = p;
+
+	/* Convert text buffer to string */
+	stext = wstr_to_astr(text + *cstart);
+	if (stext == NULL) {
+		retval = ENOMEM;
+		goto error;
+	}
+
+	/* Extract the prefix being completed */
+	pref_size = str_lsize(stext, pos - *cstart);
+	prefix = malloc(pref_size + 1);
+	if (prefix == NULL) {
+		retval = ENOMEM;
+		goto error;
+	}
+
+	str_ncpy(prefix, pref_size + 1, stext, pref_size);
+
+	/*
+	 * Determine if the token being completed is a command or argument.
+	 * We look at the previous token. If there is none or it is a pipe
+	 * ('|'), it is a command, otherwise it is an argument.
+	 * XXX Again we should use the standard tokenizer/parser.
+	 */
+
+	/* Skip any whitespace before current token */
+	while (p > 0 && text[p - 1] == (wchar_t) ' ')
+		--p;
+
+	/*
+	 * It is a command if it is the first token or if it immediately
+	 * follows a pipe token.
+	 */
+	if (p == 0 || text[p - 1] == '|')
+		cs->is_command = true;
+	else
+		cs->is_command = false;
+
+	rpath_sep = str_rchr(prefix, '/');
+	if (rpath_sep != NULL) {
+		/* Extract path. For path beginning with '/' keep the '/'. */
+		dirname = str_ndup(prefix, max(1, rpath_sep - prefix));
+		if (dirname == NULL) {
+			retval = ENOMEM;
+			goto error;
+		}
+
+		/* Extract name prefix */
+		cs->prefix = str_dup(rpath_sep + 1);
+		if (cs->prefix == NULL) {
+			retval = ENOMEM;
+			goto error;
+		}
+		*cstart += rpath_sep + 1 - prefix;
+		free(prefix);
+
+		cs->path_list = malloc(sizeof(char *) * 2);
+		if (cs->path_list == NULL) {
+			retval = ENOMEM;
+			goto error;
+		}
+		cs->path_list[0] = dirname;
+		cs->path_list[1] = NULL;
+		cs->path = cs->path_list;
+
+	} else if (cs->is_command) {
+		/* Command without path */
+		cs->module = modules;
+		cs->builtin = builtins;
+		cs->prefix = prefix;
+		cs->path = &search_dir[0];
+	} else {
+		/* Argument without path */
+		cs->prefix = prefix;
+		cs->path = &dirlist_arg[0];
+	}
+
+	cs->prefix_len = str_length(cs->prefix);
+
+	*state = cs;
+	return EOK;
+
+error:
+	/* Error cleanup */
+
+	if (cs != NULL && cs->path_list != NULL) {
+		size_t i = 0;
+		while (cs->path_list[i] != NULL) {
+			free(cs->path_list[i]);
+			++i;
+		}
+		free(cs->path_list);
+	}
+
+	if (cs != NULL && cs->prefix != NULL)
+		free(cs->prefix);
+	if (dirname != NULL)
+		free(dirname);
+	if (prefix != NULL)
+		free(prefix);
+	if (stext != NULL)
+		free(stext);
+	if (cs != NULL)
+		free(cs);
+
+	return retval;
+}
+
+/** Determine if completion matches the required prefix.
+ *
+ * Required prefix is stored in @a cs->prefix.
+ *
+ * @param cs	Completion state object
+ * @param compl	Completion string
+ * @return	@c true when @a compl matches, @c false otherwise
+ */
+static bool compl_match_prefix(compl_t *cs, const char *compl)
+{
+	return str_lcmp(compl, cs->prefix, cs->prefix_len) == 0;
+}
+
+/** Get next match. */
+static int compl_get_next(void *state, char **compl)
+{
+	compl_t *cs = (compl_t *) state;
+	struct dirent *dent;
+
+	*compl = NULL;
+
+	if (cs->last_compl != NULL) {
+		free(cs->last_compl);
+		cs->last_compl = NULL;
+	}
+
+	/* Modules */
+	if (cs->module != NULL) {
+		while (*compl == NULL && cs->module->name != NULL) {
+			if (compl_match_prefix(cs, cs->module->name)) {
+				asprintf(compl, "%s ", cs->module->name);
+				cs->last_compl = *compl;
+				if (*compl == NULL)
+					return ENOMEM;
+			}
+			cs->module++;
+		}
+	}
+
+	/* Builtins */
+	if (cs->builtin != NULL) {
+		while (*compl == NULL && cs->builtin->name != NULL) {
+			if (compl_match_prefix(cs, cs->builtin->name)) {
+				asprintf(compl, "%s ", cs->builtin->name);
+				cs->last_compl = *compl;
+				if (*compl == NULL)
+					return ENOMEM;
+			}
+			cs->builtin++;
+		}
+	}
+
+	/* Files and directories. We scan entries from a set of directories. */
+	if (cs->path != NULL) {
+		while (*compl == NULL) {
+			/* Open next directory */
+			while (cs->dir == NULL) {
+				if (*cs->path == NULL)
+					break;
+
+				cs->dir = opendir(*cs->path);
+			}
+
+			/* If it was the last one, we are done */
+			if (cs->dir == NULL)
+				break;
+
+			/* Read next directory entry */
+			dent = readdir(cs->dir);
+			if (dent == NULL) {
+				/* Error. Close directory, go to next one */
+				closedir(cs->dir);
+				cs->dir = NULL;
+				cs->path++;
+				continue;
+			}
+
+			if (compl_match_prefix(cs, dent->d_name)) {
+				/* Construct pathname */
+				char *ent_path;
+				asprintf(&ent_path, "%s/%s", *cs->path, dent->d_name);
+				struct stat ent_stat;
+				if (stat(ent_path, &ent_stat) != EOK) {
+					/* Error */
+					free(ent_path);
+					continue;
+				}
+
+				free(ent_path);
+
+				/* If completing command, do not match directories. */
+				if (!ent_stat.is_directory || !cs->is_command) {
+					asprintf(compl, "%s%c", dent->d_name,
+					    ent_stat.is_directory ? '/' : ' ');
+					cs->last_compl = *compl;
+					if (*compl == NULL)
+						return ENOMEM;
+				}
+			}
+		}
+	}
+
+	if (*compl == NULL)
+		return ENOENT;
+
+	return EOK;
+}
+
+/** Finish completion operation. */
+static void compl_fini(void *state)
+{
+	compl_t *cs = (compl_t *) state;
+
+	if (cs->path_list != NULL) {
+		size_t i = 0;
+		while (cs->path_list[i] != NULL) {
+			free(cs->path_list[i]);
+			++i;
+		}
+		free(cs->path_list);
+	}
+
+	if (cs->last_compl != NULL)
+		free(cs->last_compl);
+	if (cs->dir != NULL)
+		closedir(cs->dir);
+
+	free(cs->prefix);
+	free(cs);
+}
Index: uspace/app/bdsh/compl.h
===================================================================
--- uspace/app/bdsh/compl.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
+++ uspace/app/bdsh/compl.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2008 Tim Post
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef COMPL_H
+#define COMPL_H
+
+#include <tinput.h>
+
+extern tinput_compl_ops_t compl_ops;
+
+#endif
Index: uspace/app/bdsh/config.h
===================================================================
--- uspace/app/bdsh/config.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/app/bdsh/config.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -40,8 +40,4 @@
 #endif
 
-/* Work around for getenv() */
-#define PATH "/srv:/app"
-#define PATH_DELIM ":"
-
 /* Used in many places */
 #define SMALL_BUFLEN 256
Index: uspace/app/bdsh/exec.c
===================================================================
--- uspace/app/bdsh/exec.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/app/bdsh/exec.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -52,4 +52,6 @@
 static int try_access(const char *);
 
+const char *search_dir[] = { "app", "srv", NULL };
+
 /* work-around for access() */
 static int try_access(const char *f)
@@ -69,8 +71,5 @@
 static char *find_command(char *cmd)
 {
-	char *path_tok;
-	char *path[PATH_MAX];
-	int n = 0, i = 0;
-	size_t x = str_size(cmd) + 2;
+	size_t i;
 
 	found = (char *)malloc(PATH_MAX);
@@ -81,24 +80,9 @@
 	}
 
-	path_tok = str_dup(PATH);
-
-	/* Extract the PATH env to a path[] array */
-	path[n] = strtok(path_tok, PATH_DELIM);
-	while (NULL != path[n]) {
-		if ((str_size(path[n]) + x ) > PATH_MAX) {
-			cli_error(CL_ENOTSUP,
-				"Segment %d of path is too large, search ends at segment %d",
-				n, n-1);
-			break;
-		}
-		path[++n] = strtok(NULL, PATH_DELIM);
-	}
-
 	/* We now have n places to look for the command */
-	for (i=0; path[i]; i++) {
+	for (i = 0; search_dir[i] != NULL; i++) {
 		memset(found, 0, sizeof(found));
-		snprintf(found, PATH_MAX, "%s/%s", path[i], cmd);
+		snprintf(found, PATH_MAX, "%s/%s", search_dir[i], cmd);
 		if (-1 != try_access(found)) {
-			free(path_tok);
 			return (char *) found;
 		}
@@ -106,5 +90,4 @@
 
 	/* We didn't find it, just give it back as-is. */
-	free(path_tok);
 	return (char *) cmd;
 }
Index: uspace/app/bdsh/exec.h
===================================================================
--- uspace/app/bdsh/exec.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/app/bdsh/exec.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -33,4 +33,6 @@
 #include "scli.h"
 
+extern const char *search_dir[];
+
 extern unsigned int try_exec(char *, char **, iostate_t *);
 
Index: uspace/app/bdsh/input.c
===================================================================
--- uspace/app/bdsh/input.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/app/bdsh/input.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2008 Tim Post
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -43,4 +44,5 @@
 
 #include "config.h"
+#include "compl.h"
 #include "util.h"
 #include "scli.h"
@@ -226,9 +228,5 @@
 	int rc;
 	
-	console_flush(tinput->console);
-	console_set_style(tinput->console, STYLE_EMPHASIS);
-	printf("%s", usr->prompt);
-	console_flush(tinput->console);
-	console_set_style(tinput->console, STYLE_NORMAL);
+	tinput_set_prompt(tinput, usr->prompt);
 
 	rc = tinput_read(tinput, &str);
@@ -263,4 +261,6 @@
 	}
 
+	tinput_set_compl_ops(tinput, &compl_ops);
+
 	return 0;
 }
Index: uspace/app/bdsh/scli.h
===================================================================
--- uspace/app/bdsh/scli.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/app/bdsh/scli.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -32,4 +32,5 @@
 #include "config.h"
 #include <stdint.h>
+#include <stdio.h>
 
 typedef struct {
Index: uspace/app/sbi/src/input.c
===================================================================
--- uspace/app/sbi/src/input.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/app/sbi/src/input.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -176,4 +176,5 @@
 int input_get_line(input_t *input, char **line)
 {
+	const char *prompt;
 	const char *sp;
 	char *dp;
@@ -212,10 +213,10 @@
 		/* Interactive mode */
 		if (input->line_no == 0)
-			printf("sbi> ");
+			prompt = "sbi> ";
 		else
-			printf("...  ");
+			prompt = "...  ";
 
 		fflush(stdout);
-		if (os_input_line(&line_p) != EOK)
+		if (os_input_line(prompt, &line_p) != EOK)
 			return EIO;
 
Index: uspace/app/sbi/src/os/helenos.c
===================================================================
--- uspace/app/sbi/src/os/helenos.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/app/sbi/src/os/helenos.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -210,5 +210,5 @@
  * @param ptr	Place to store pointer to new string.
  */
-int os_input_line(char **ptr)
+int os_input_line(const char *prompt, char **ptr)
 {
 	char *line;
@@ -219,4 +219,6 @@
 		if (tinput == NULL)
 			return EIO;
+
+		tinput_set_prompt(tinput, prompt);
 	}
 
Index: uspace/app/sbi/src/os/os.h
===================================================================
--- uspace/app/sbi/src/os/os.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/app/sbi/src/os/os.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -38,5 +38,5 @@
 char *os_chr_to_astr(wchar_t chr);
 void os_input_disp_help(void);
-int os_input_line(char **ptr);
+int os_input_line(const char *prompt, char **ptr);
 int os_exec(char * const cmd[]);
 
Index: uspace/app/sbi/src/os/posix.c
===================================================================
--- uspace/app/sbi/src/os/posix.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/app/sbi/src/os/posix.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -193,6 +193,8 @@
  * @param ptr	Place to store pointer to new string.
  */
-int os_input_line(char **ptr)
-{
+int os_input_line(const char *prompt, char **ptr)
+{
+	printf("%s", prompt);
+
 	if (fgets(os_input_buffer, OS_INPUT_BUFFER_SIZE, stdin) == NULL)
 		os_input_buffer[0] = '\0';
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/isa/isa.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -352,4 +352,6 @@
 		    str_error(rc));
 	}
+
+	free(id);
 }
 
Index: uspace/drv/bus/pci/pciintel/pci.c
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -342,4 +342,6 @@
 	}
 	
+	free(match_id_str);
+	
 	/* TODO add more ids (with subsys ids, using class id etc.) */
 }
Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -46,8 +46,73 @@
 #define OHCI_USED_INTERRUPTS \
     (I_SO | I_WDH | I_UE | I_RHSC)
-static int interrupt_emulator(hc_t *instance);
+
+static const irq_cmd_t ohci_irq_commands[] =
+{
+	{ .cmd = CMD_MEM_READ_32, .dstarg = 1, .addr = NULL /*filled later*/ },
+	{ .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, .value = OHCI_USED_INTERRUPTS },
+	{ .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 },
+	{ .cmd = CMD_MEM_WRITE_A_32, .srcarg = 1, .addr = NULL /*filled later*/ },
+	{ .cmd = CMD_ACCEPT },
+};
+
 static void hc_gain_control(hc_t *instance);
+static void hc_start(hc_t *instance);
 static int hc_init_transfer_lists(hc_t *instance);
 static int hc_init_memory(hc_t *instance);
+static int interrupt_emulator(hc_t *instance);
+
+/*----------------------------------------------------------------------------*/
+/** Get number of commands used in IRQ code.
+ * @return Number of commands.
+ */
+size_t hc_irq_cmd_count(void)
+{
+	return sizeof(ohci_irq_commands) / sizeof(irq_cmd_t);
+}
+/*----------------------------------------------------------------------------*/
+/** Generate IRQ code commands.
+ * @param[out] cmds Place to store the commands.
+ * @param[in] cmd_size Size of the place (bytes).
+ * @param[in] regs Physical address of device's registers.
+ * @param[in] reg_size Size of the register area (bytes).
+ *
+ * @return Error code.
+ */
+int hc_get_irq_commands(
+    irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size)
+{
+	if (cmd_size < sizeof(ohci_irq_commands)
+	    || reg_size < sizeof(ohci_regs_t))
+		return EOVERFLOW;
+
+	/* Create register mapping to use in IRQ handler.
+	 * This mapping should be present in kernel only.
+	 * Remove it from here when kernel knows how to create mappings
+	 * and accepts physical addresses in IRQ code.
+	 * TODO: remove */
+	ohci_regs_t *registers;
+	const int ret = pio_enable((void*)regs, reg_size, (void**)&registers);
+	if (ret != EOK)
+		return ret;
+
+	/* Some bogus access to force create mapping. DO NOT remove,
+	 * unless whole virtual addresses in irq is replaced
+	 * NOTE: Compiler won't remove this as ohci_regs_t members
+	 * are declared volatile.
+	 *
+	 * Introducing CMD_MEM set of IRQ code commands broke
+	 * assumption that IRQ code does not cause page faults.
+	 * If this happens during idling (THREAD == NULL)
+	 * it causes kernel panic.
+	 */
+	registers->revision;
+
+	memcpy(cmds, ohci_irq_commands, sizeof(ohci_irq_commands));
+
+	void *address = (void*)&registers->interrupt_status;
+	cmds[0].addr = address;
+	cmds[3].addr = address;
+	return EOK;
+}
 /*----------------------------------------------------------------------------*/
 /** Announce OHCI root hub to the DDF
@@ -83,17 +148,14 @@
 	int ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,
 	    USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);
-	CHECK_RET_RELEASE(ret, "Failed(%d) to add OHCI rh endpoint 0.\n", ret);
-
-	char *match_str = NULL;
-	/* DDF needs heap allocated string */
-	ret = asprintf(&match_str, "usb&class=hub");
-	ret = ret > 0 ? 0 : ret;
-	CHECK_RET_RELEASE(ret, "Failed(%d) to create match-id string.\n", ret);
-
-	ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
-	CHECK_RET_RELEASE(ret, "Failed(%d) add root hub match-id.\n", ret);
+	CHECK_RET_RELEASE(ret,
+	    "Failed to add OHCI root hub endpoint 0: %s.\n", str_error(ret));
+
+	ret = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100);
+	CHECK_RET_RELEASE(ret,
+	    "Failed to add root hub match-id: %s.\n", str_error(ret));
 
 	ret = ddf_fun_bind(hub_fun);
-	CHECK_RET_RELEASE(ret, "Failed(%d) to bind root hub function.\n", ret);
+	CHECK_RET_RELEASE(ret,
+	    "Failed to bind root hub function: %s.\n", str_error(ret));
 
 	return EOK;
@@ -112,5 +174,5 @@
 {
 	assert(instance);
-	int ret = EOK;
+
 #define CHECK_RET_RETURN(ret, message...) \
 if (ret != EOK) { \
@@ -119,11 +181,12 @@
 } else (void)0
 
-	ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers);
+	int ret =
+	    pio_enable((void*)regs, reg_size, (void**)&instance->registers);
 	CHECK_RET_RETURN(ret,
-	    "Failed(%d) to gain access to device registers: %s.\n",
-	    ret, str_error(ret));
+	    "Failed to gain access to device registers: %s.\n", str_error(ret));
 
 	list_initialize(&instance->pending_batches);
 	usb_device_keeper_init(&instance->manager);
+
 	ret = usb_endpoint_manager_init(&instance->ep_manager,
 	    BANDWIDTH_AVAILABLE_USB11);
@@ -137,7 +200,6 @@
 
 	fibril_mutex_initialize(&instance->guard);
+
 	hc_gain_control(instance);
-
-	rh_init(&instance->rh, instance->registers);
 
 	if (!interrupts) {
@@ -147,8 +209,11 @@
 	}
 
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Create end register endpoint structures
+	rh_init(&instance->rh, instance->registers);
+	hc_start(instance);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Create and register endpoint structures.
  *
  * @param[in] instance OHCI driver structure.
@@ -168,13 +233,8 @@
     size_t mps, size_t size, unsigned interval)
 {
-	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	endpoint_t *ep =
+	    endpoint_get(address, endpoint, direction, type, speed, mps);
 	if (ep == NULL)
 		return ENOMEM;
-	int ret =
-	    endpoint_init(ep, address, endpoint, direction, type, speed, mps);
-	if (ret != EOK) {
-		free(ep);
-		return ret;
-	}
 
 	hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
@@ -184,5 +244,6 @@
 	}
 
-	ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
+	int ret =
+	    usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
 	if (ret != EOK) {
 		hcd_endpoint_clear(ep);
@@ -212,6 +273,4 @@
 		    &instance->lists[ep->transfer_type], hcd_ep);
 		instance->registers->control |= C_PLE | C_IE;
-		break;
-	default:
 		break;
 	}
@@ -312,5 +371,6 @@
 	/* Check for root hub communication */
 	if (batch->ep->address == instance->rh.address) {
-		return rh_request(&instance->rh, batch);
+		rh_request(&instance->rh, batch);
+		return EOK;
 	}
 
@@ -374,5 +434,5 @@
 
 	if (status & I_UE) {
-		hc_start_hw(instance);
+		hc_start(instance);
 	}
 
@@ -399,4 +459,7 @@
 /** Turn off any (BIOS)driver that might be in control of the device.
  *
+ * This function implements routines described in chapter 5.1.1.3 of the OHCI
+ * specification (page 40, pdf page 54).
+ *
  * @param[in] instance OHCI hc driver structure.
  */
@@ -404,14 +467,22 @@
 {
 	assert(instance);
+
 	usb_log_debug("Requesting OHCI control.\n");
-	/* Turn off legacy emulation */
-	volatile uint32_t *ohci_emulation_reg =
-	    (uint32_t*)((char*)instance->registers + 0x100);
-	usb_log_debug("OHCI legacy register %p: %x.\n",
-	    ohci_emulation_reg, *ohci_emulation_reg);
-	/* Do not change A20 state */
-	*ohci_emulation_reg &= 0x100;
-	usb_log_debug("OHCI legacy register %p: %x.\n",
-	    ohci_emulation_reg, *ohci_emulation_reg);
+	if (instance->registers->revision & R_LEGACY_FLAG) {
+		/* Turn off legacy emulation, it should be enough to zero
+		 * the lowest bit, but it caused problems. Thus clear all
+		 * except GateA20 (causes restart on some hw).
+		 * See page 145 of the specs for details.
+		 */
+		volatile uint32_t *ohci_emulation_reg =
+		(uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
+		usb_log_debug("OHCI legacy register %p: %x.\n",
+		    ohci_emulation_reg, *ohci_emulation_reg);
+		/* Zero everything but A20State */
+		*ohci_emulation_reg &= 0x100;
+		usb_log_debug(
+		    "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
+		    ohci_emulation_reg, *ohci_emulation_reg);
+	}
 
 	/* Interrupt routing enabled => smm driver is active */
@@ -419,15 +490,15 @@
 		usb_log_debug("SMM driver: request ownership change.\n");
 		instance->registers->command_status |= CS_OCR;
+		/* Hope that SMM actually knows its stuff or we can hang here */
 		while (instance->registers->control & C_IR) {
 			async_usleep(1000);
 		}
 		usb_log_info("SMM driver: Ownership taken.\n");
-		instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);
+		C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
 		async_usleep(50000);
 		return;
 	}
 
-	const unsigned hc_status =
-	    (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK;
+	const unsigned hc_status = C_HCFS_GET(instance->registers->control);
 	/* Interrupt routing disabled && status != USB_RESET => BIOS active */
 	if (hc_status != C_HCFS_RESET) {
@@ -437,6 +508,6 @@
 			return;
 		}
-		/* HC is suspended assert resume for 20ms */
-		instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
+		/* HC is suspended assert resume for 20ms, */
+		C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
 		async_usleep(20000);
 		usb_log_info("BIOS driver: HC resumed.\n");
@@ -454,5 +525,5 @@
  * @param[in] instance OHCI hc driver structure.
  */
-void hc_start_hw(hc_t *instance)
+void hc_start(hc_t *instance)
 {
 	/* OHCI guide page 42 */
@@ -516,5 +587,5 @@
 	    instance->registers->periodic_start, frame_length);
 
-	instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
+	C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
 	usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
 	    instance->registers->control);
@@ -534,6 +605,6 @@
 	int ret = endpoint_list_init(&instance->lists[type], name); \
 	if (ret != EOK) { \
-		usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
-		    ret, name); \
+		usb_log_error("Failed to setup %s endpoint list: %s.\n", \
+		    name, str_error(ret)); \
 		endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
 		endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
@@ -587,38 +658,7 @@
 	    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
 
-	/* Init interrupt code */
-	instance->interrupt_code.cmds = instance->interrupt_commands;
-	instance->interrupt_code.cmdcount = OHCI_NEEDED_IRQ_COMMANDS;
-	{
-		/* Read status register */
-		instance->interrupt_commands[0].cmd = CMD_MEM_READ_32;
-		instance->interrupt_commands[0].dstarg = 1;
-		instance->interrupt_commands[0].addr =
-		    (void*)&instance->registers->interrupt_status;
-
-		/* Test whether we are the interrupt cause */
-		instance->interrupt_commands[1].cmd = CMD_BTEST;
-		instance->interrupt_commands[1].value =
-		    OHCI_USED_INTERRUPTS;
-		instance->interrupt_commands[1].srcarg = 1;
-		instance->interrupt_commands[1].dstarg = 2;
-
-		/* Predicate cleaning and accepting */
-		instance->interrupt_commands[2].cmd = CMD_PREDICATE;
-		instance->interrupt_commands[2].value = 2;
-		instance->interrupt_commands[2].srcarg = 2;
-
-		/* Write-clean status register */
-		instance->interrupt_commands[3].cmd = CMD_MEM_WRITE_A_32;
-		instance->interrupt_commands[3].srcarg = 1;
-		instance->interrupt_commands[3].addr =
-		    (void*)&instance->registers->interrupt_status;
-
-		/* Accept interrupt */
-		instance->interrupt_commands[4].cmd = CMD_ACCEPT;
-	}
-
-	return EOK;
-}
+	return EOK;
+}
+
 /**
  * @}
Index: uspace/drv/bus/usb/ohci/hc.h
===================================================================
--- uspace/drv/bus/usb/ohci/hc.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/ohci/hc.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -51,7 +51,5 @@
 #include "hw_struct/hcca.h"
 
-#define OHCI_NEEDED_IRQ_COMMANDS 5
-
-/** Main OHCI drier structure */
+/** Main OHCI driver structure */
 typedef struct hc {
 	/** USB bus driver, devices and addresses */
@@ -76,17 +74,13 @@
 	fibril_mutex_t guard;
 
-	/** Code to be executed in kernel interrupt handler */
-	irq_code_t interrupt_code;
-
-	/** Commands that form interrupt code */
-	irq_cmd_t interrupt_commands[OHCI_NEEDED_IRQ_COMMANDS];
-
 	/** USB hub emulation structure */
 	rh_t rh;
 } hc_t;
 
+size_t hc_irq_cmd_count(void);
+int hc_get_irq_commands(
+    irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size);
+int hc_init(hc_t *instance, uintptr_t regs, size_t reg_size, bool interrupts);
 int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun);
-int hc_init(hc_t *instance, uintptr_t regs, size_t reg_size, bool interrupts);
-void hc_start_hw(hc_t *instance);
 
 /** Safely dispose host controller internal structures
Index: uspace/drv/bus/usb/ohci/ohci.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/ohci/ohci.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -58,8 +58,6 @@
 {
 	assert(dev);
-	assert(dev->driver_data);
 	return dev->driver_data;
 }
-
 /** IRQ handling callback, identifies device
  *
@@ -70,8 +68,13 @@
 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
 {
-	hc_t *hc = &dev_to_ohci(dev)->hc;
-	assert(hc);
+	assert(dev);
+
+	ohci_t *ohci = dev_to_ohci(dev);
+	if (!ohci) {
+		usb_log_warning("Interrupt on device that is not ready.\n");
+		return;
+	}
 	const uint16_t status = IPC_GET_ARG1(*call);
-	hc_interrupt(hc, status);
+	hc_interrupt(&ohci->hc, status);
 }
 /*----------------------------------------------------------------------------*/
@@ -166,4 +169,5 @@
 	} \
 	free(instance); \
+	device->driver_data = NULL; \
 	usb_log_error(message); \
 	return ret; \
@@ -173,5 +177,6 @@
 	instance->hc_fun = ddf_fun_create(device, fun_exposed, "ohci_hc");
 	int ret = instance->hc_fun ? EOK : ENOMEM;
-	CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create OHCI HC function.\n");
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed to create OHCI HC function: %s.\n", str_error(ret));
 	instance->hc_fun->ops = &hc_ops;
 	instance->hc_fun->driver_data = &instance->hc;
@@ -179,5 +184,6 @@
 	instance->rh_fun = ddf_fun_create(device, fun_inner, "ohci_rh");
 	ret = instance->rh_fun ? EOK : ENOMEM;
-	CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create OHCI RH function.\n");
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed to create OHCI RH function: %s.\n", str_error(ret));
 	instance->rh_fun->ops = &rh_ops;
 
@@ -193,40 +199,48 @@
 	    (void *) reg_base, reg_size, irq);
 
+	const size_t cmd_count = hc_irq_cmd_count();
+	irq_cmd_t irq_cmds[cmd_count];
+	ret =
+	    hc_get_irq_commands(irq_cmds, sizeof(irq_cmds), reg_base, reg_size);
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed to generate IRQ commands: %s.\n", str_error(ret));
+
+	irq_code_t irq_code = { .cmdcount = cmd_count, .cmds = irq_cmds };
+
+	/* Register handler to avoid interrupt lockup */
+	ret = register_interrupt_handler(device, irq, irq_handler, &irq_code);
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed to register interrupt handler: %s.\n", str_error(ret));
+
+	/* Try to enable interrupts */
 	bool interrupts = false;
-#ifdef CONFIG_USBHC_NO_INTERRUPTS
-	usb_log_warning("Interrupts disabled in OS config, "
-	    "falling back to polling.\n");
-#else
 	ret = pci_enable_interrupts(device);
 	if (ret != EOK) {
-		usb_log_warning("Failed to enable interrupts: %s.\n",
-		    str_error(ret));
-		usb_log_info("HW interrupts not available, "
-		    "falling back to polling.\n");
+		usb_log_warning("Failed to enable interrupts: %s."
+		    " Falling back to polling\n", str_error(ret));
+		/* We don't need that handler */
+		unregister_interrupt_handler(device, irq);
 	} else {
 		usb_log_debug("Hw interrupts enabled.\n");
 		interrupts = true;
 	}
-#endif
 
 	ret = hc_init(&instance->hc, reg_base, reg_size, interrupts);
-	CHECK_RET_DEST_FREE_RETURN(ret, "Failed(%d) to init ohci_hcd.\n", ret);
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed to init ohci_hcd: %s.\n", str_error(ret));
+
+	device->driver_data = instance;
 
 #define CHECK_RET_FINI_RETURN(ret, message...) \
 if (ret != EOK) { \
+	unregister_interrupt_handler(device, irq); \
 	hc_fini(&instance->hc); \
 	CHECK_RET_DEST_FREE_RETURN(ret, message); \
 } else (void)0
 
-	/* It does no harm if we register this on polling */
-	ret = register_interrupt_handler(device, irq, irq_handler,
-	    &instance->hc.interrupt_code);
-	CHECK_RET_FINI_RETURN(ret,
-	    "Failed(%d) to register interrupt handler.\n", ret);
 
 	ret = ddf_fun_bind(instance->hc_fun);
 	CHECK_RET_FINI_RETURN(ret,
-	    "Failed(%d) to bind OHCI device function: %s.\n",
-	    ret, str_error(ret));
+	    "Failed to bind OHCI device function: %s.\n", str_error(ret));
 
 	ret = ddf_fun_add_to_class(instance->hc_fun, USB_HC_DDF_CLASS_NAME);
@@ -234,7 +248,4 @@
 	    "Failed to add OHCI to HC class: %s.\n", str_error(ret));
 
-	device->driver_data = instance;
-
-	hc_start_hw(&instance->hc);
 	hc_register_hub(&instance->hc, instance->rh_fun);
 	return EOK;
Index: uspace/drv/bus/usb/ohci/ohci_regs.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_regs.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/ohci/ohci_regs.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -34,16 +34,22 @@
 #ifndef DRV_OHCI_OHCI_REGS_H
 #define DRV_OHCI_OHCI_REGS_H
-#include <stdint.h>
+#include <sys/types.h>
+
+#define LEGACY_REGS_OFFSET 0x100
 
 /** OHCI memory mapped registers structure */
 typedef struct ohci_regs {
-	const volatile uint32_t revision;
-	volatile uint32_t control;
-#define C_CSBR_MASK (0x3) /* Control-bulk service ratio */
-#define C_CSBR_1_1  (0x0)
-#define C_CSBR_1_2  (0x1)
-#define C_CSBR_1_3  (0x2)
-#define C_CSBR_1_4  (0x3)
-#define C_CSBR_SHIFT (0)
+	const ioport32_t revision;
+#define R_REVISION_MASK (0x3f)
+#define R_REVISION_SHIFT (0)
+#define R_LEGACY_FLAG   (0x80)
+
+	ioport32_t control;
+#define C_CBSR_MASK (0x3) /* Control-bulk service ratio */
+#define C_CBSR_1_1  (0x0)
+#define C_CBSR_1_2  (0x1)
+#define C_CBSR_1_3  (0x2)
+#define C_CBSR_1_4  (0x3)
+#define C_CBSR_SHIFT (0)
 
 #define C_PLE (1 << 2)   /* Periodic list enable */
@@ -59,9 +65,18 @@
 #define C_HCFS_SHIFT       (6)
 
+#define C_HCFS_GET(reg) \
+	((reg >> C_HCFS_SHIFT) & C_HCFS_MASK)
+#define C_HCFS_SET(reg, hcfs_state) \
+do { \
+	reg = (reg & ~(C_HCFS_MASK << C_HCFS_SHIFT)) \
+	    | ((hcfs_state & C_HCFS_MASK) << C_HCFS_SHIFT); \
+} while (0)
+
+
 #define C_IR  (1 << 8)   /* Interrupt routing, make sure it's 0 */
 #define C_RWC (1 << 9)   /* Remote wakeup connected, host specific */
 #define C_RWE (1 << 10)  /* Remote wakeup enable */
 
-	volatile uint32_t command_status;
+	ioport32_t command_status;
 #define CS_HCR (1 << 0)   /* Host controller reset */
 #define CS_CLF (1 << 1)   /* Control list filled */
@@ -75,7 +90,7 @@
 	 * writing causes enable/disable,
 	 * status is write-clean (writing 1 clears the bit*/
-	volatile uint32_t interrupt_status;
-	volatile uint32_t interrupt_enable;
-	volatile uint32_t interrupt_disable;
+	ioport32_t interrupt_status;
+	ioport32_t interrupt_enable;
+	ioport32_t interrupt_disable;
 #define I_SO   (1 << 0)   /* Scheduling overrun */
 #define I_WDH  (1 << 1)   /* Done head write-back */
@@ -89,27 +104,27 @@
 
 	/** HCCA pointer (see hw_struct hcca.h) */
-	volatile uint32_t hcca;
+	ioport32_t hcca;
 #define HCCA_PTR_MASK 0xffffff00 /* HCCA is 256B aligned */
 
 	/** Currently executed periodic endpoint */
-	const volatile uint32_t periodic_current;
+	const ioport32_t periodic_current;
 
 	/** The first control endpoint */
-	volatile uint32_t control_head;
+	ioport32_t control_head;
 
 	/** Currently executed control endpoint */
-	volatile uint32_t control_current;
+	ioport32_t control_current;
 
 	/** The first bulk endpoint */
-	volatile uint32_t bulk_head;
+	ioport32_t bulk_head;
 
 	/** Currently executed bulk endpoint */
-	volatile uint32_t bulk_current;
+	ioport32_t bulk_current;
 
 	/** Done TD list, this value is periodically written to HCCA */
-	const volatile uint32_t done_head;
+	const ioport32_t done_head;
 
 	/** Frame time and max packet size for all transfers */
-	volatile uint32_t fm_interval;
+	ioport32_t fm_interval;
 #define FMI_FI_MASK (0x3fff) /* Frame interval in bit times (should be 11999)*/
 #define FMI_FI_SHIFT (0)
@@ -119,5 +134,5 @@
 
 	/** Bit times remaining in current frame */
-	const volatile uint32_t fm_remaining;
+	const ioport32_t fm_remaining;
 #define FMR_FR_MASK FMI_FI_MASK
 #define FMR_FR_SHIFT FMI_FI_SHIFT
@@ -125,17 +140,17 @@
 
 	/** Frame number */
-	const volatile uint32_t fm_number;
+	const ioport32_t fm_number;
 #define FMN_NUMBER_MASK (0xffff)
 
 	/** Remaining bit time in frame to start periodic transfers */
-	volatile uint32_t periodic_start;
+	ioport32_t periodic_start;
 #define PS_PS_MASK (0x3fff) /* bit time when periodic get priority (0x3e67) */
 
 	/** Threshold for starting LS transaction */
-	volatile uint32_t ls_threshold;
+	ioport32_t ls_threshold;
 #define LST_LST_MASK (0x7fff)
 
 	/** The first root hub control register */
-	volatile uint32_t rh_desc_a;
+	ioport32_t rh_desc_a;
 #define RHDA_NDS_MASK (0xff) /* Number of downstream ports, max 15 */
 #define RHDA_NDS_SHIFT (0)
@@ -144,10 +159,10 @@
 #define RHDA_DT_FLAG   (1 << 10) /* 1-Compound device, must be 0 */
 #define RHDA_OCPM_FLAG (1 << 11) /* Over-current mode: 0-global, 1-per port */
-#define RHDA_NOCP      (1 << 12) /* OC control: 0-use OCPM, 1-OC off */
+#define RHDA_NOCP_FLAG (1 << 12) /* OC control: 0-use OCPM, 1-OC off */
 #define RHDA_POTPGT_MASK (0xff)  /* Power on to power good time */
 #define RHDA_POTPGT_SHIFT (24)
 
 	/** The other root hub control register */
-	volatile uint32_t rh_desc_b;
+	ioport32_t rh_desc_b;
 #define RHDB_DR_MASK (0xffff) /* Device removable mask */
 #define RHDB_DR_SHIFT (0)
@@ -161,5 +176,5 @@
 
 	/** Root hub status register */
-	volatile uint32_t rh_status;
+	ioport32_t rh_status;
 #define RHS_LPS_FLAG  (1 <<  0)/* read: 0,
                                 * write: 0-no effect,
@@ -167,5 +182,5 @@
                                 *        specified in PPCM(RHDB), or all ports,
                                 *        if power is set globally */
-#define RHS_CLEAR_PORT_POWER RHS_LPS_FLAG /* synonym for the above */
+#define RHS_CLEAR_GLOBAL_POWER RHS_LPS_FLAG /* synonym for the above */
 #define RHS_OCI_FLAG  (1 <<  1)/* Over-current indicator, if per-port: 0 */
 #define RHS_DRWE_FLAG (1 << 15)/* read: 0-connect status change does not wake HC
@@ -178,10 +193,10 @@
                                 *        specified in PPCM(RHDB), or all ports,
                                 *        if power is set globally */
-#define RHS_SET_PORT_POWER RHS_LPSC_FLAG /* synonym for the above */
+#define RHS_SET_GLOBAL_POWER RHS_LPSC_FLAG /* synonym for the above */
 #define RHS_OCIC_FLAG (1 << 17)/* Over-current indicator change   */
 #define RHS_CLEAR_DRWE (1 << 31)
 
 	/** Root hub per port status */
-	volatile uint32_t rh_port_status[];
+	ioport32_t rh_port_status[];
 #define RHPS_CCS_FLAG (1 << 0) /* r: current connect status,
                                 * w: 1-clear port enable, 0-nothing */
Index: uspace/drv/bus/usb/ohci/root_hub.c
===================================================================
--- uspace/drv/bus/usb/ohci/root_hub.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/ohci/root_hub.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -40,4 +40,5 @@
 #include "root_hub.h"
 #include <usb/classes/classes.h>
+#include <usb/classes/hub.h>
 #include <usb/dev/driver.h>
 #include "ohci_regs.h"
@@ -56,7 +57,7 @@
 	.device_subclass = 0,
 	.device_version = 0,
-	.length = sizeof (usb_standard_device_descriptor_t),
-	.max_packet_size = 8,
-	.vendor_id = 0x16db,
+	.length = sizeof(usb_standard_device_descriptor_t),
+	.max_packet_size = 64,
+	.vendor_id = 0x16db, /* HelenOS does not have USB vendor ID assigned.*/
 	.product_id = 0x0001,
 	.str_serial_number = 0,
@@ -73,6 +74,6 @@
 	.descriptor_type = USB_DESCTYPE_CONFIGURATION,
 	.interface_count = 1,
-	.length = sizeof (usb_standard_configuration_descriptor_t),
-	.max_power = 100,
+	.length = sizeof(usb_standard_configuration_descriptor_t),
+	.max_power = 0, /* root hubs don't need no power */
 	.str_configuration = 0,
 };
@@ -89,5 +90,5 @@
 	.interface_protocol = 0,
 	.interface_subclass = 0,
-	.length = sizeof (usb_standard_interface_descriptor_t),
+	.length = sizeof(usb_standard_interface_descriptor_t),
 	.str_interface = 0,
 };
@@ -100,345 +101,268 @@
 	.descriptor_type = USB_DESCTYPE_ENDPOINT,
 	.endpoint_address = 1 + (1 << 7),
-	.length = sizeof (usb_standard_endpoint_descriptor_t),
-	.max_packet_size = 8,
+	.length = sizeof(usb_standard_endpoint_descriptor_t),
+	.max_packet_size = 2,
 	.poll_interval = 255,
 };
 
-/**
- * bitmask of hub features that are valid to be cleared
- */
-static const uint32_t hub_clear_feature_valid_mask =
-    RHS_OCIC_FLAG |
-    RHS_CLEAR_PORT_POWER;
-
-/**
- * bitmask of hub features that are cleared by writing 1 (and not 0)
- */
-static const uint32_t hub_clear_feature_by_writing_one_mask =
-    RHS_CLEAR_PORT_POWER;
-
-/**
- * bitmask of hub features that are valid to be set
- */
-static const uint32_t hub_set_feature_valid_mask =
-    RHS_LPSC_FLAG |
-    RHS_OCIC_FLAG;
-
-/**
- * bitmask of hub features that are set by writing 1 and cleared by writing 0
- */
-static const uint32_t hub_set_feature_direct_mask =
-    RHS_SET_PORT_POWER;
-
-/**
- * bitmask of port features that are valid to be set
- */
-static const uint32_t port_set_feature_valid_mask =
-    RHPS_SET_PORT_ENABLE |
-    RHPS_SET_PORT_SUSPEND |
-    RHPS_SET_PORT_RESET |
-    RHPS_SET_PORT_POWER;
-
-/**
- * bitmask of port features that can be cleared
- */
-static const uint32_t port_clear_feature_valid_mask =
-    RHPS_CCS_FLAG |
-    RHPS_SET_PORT_SUSPEND |
-    RHPS_POCI_FLAG |
-    RHPS_SET_PORT_POWER |
-    RHPS_CSC_FLAG |
-    RHPS_PESC_FLAG |
-    RHPS_PSSC_FLAG |
-    RHPS_OCIC_FLAG |
-    RHPS_PRSC_FLAG;
-
-//note that USB_HUB_FEATURE_PORT_POWER bit is translated into
-//USB_HUB_FEATURE_PORT_LOW_SPEED for port set feature request
-
-/**
- * bitmask with port status changes
- */
-static const uint32_t port_status_change_mask = RHPS_CHANGE_WC_MASK;
-
-static int create_serialized_hub_descriptor(rh_t *instance);
-
-static int rh_init_descriptors(rh_t *instance);
-
-static int process_get_port_status_request(rh_t *instance, uint16_t port,
-    usb_transfer_batch_t * request);
-
-static int process_get_hub_status_request(rh_t *instance,
-    usb_transfer_batch_t * request);
-
-static int process_get_status_request(rh_t *instance,
-    usb_transfer_batch_t * request);
-
-static void create_interrupt_mask_in_instance(rh_t *instance);
-
-static int process_get_descriptor_request(rh_t *instance,
-    usb_transfer_batch_t *request);
-
-static int process_get_configuration_request(rh_t *instance,
-    usb_transfer_batch_t *request);
-
-static int process_hub_feature_set_request(rh_t *instance, uint16_t feature);
-
-static int process_hub_feature_clear_request(rh_t *instance,
-    uint16_t feature);
-
-static int process_port_feature_set_request(rh_t *instance,
-    uint16_t feature, uint16_t port);
-
-static int process_port_feature_clear_request(rh_t *instance,
-    uint16_t feature, uint16_t port);
-
-static int process_address_set_request(rh_t *instance,
-    uint16_t address);
-
-static int process_request_with_output(rh_t *instance,
-    usb_transfer_batch_t *request);
-
-static int process_request_with_input(rh_t *instance,
-    usb_transfer_batch_t *request);
-
-static int process_request_without_data(rh_t *instance,
-    usb_transfer_batch_t *request);
-
-static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request);
-
-static int process_interrupt_mask_in_instance(rh_t *instance, usb_transfer_batch_t * request);
-
-static bool is_zeros(void * buffer, size_t size);
-
-/** Root hub initialization
- * @return Error code.
- */
-int rh_init(rh_t *instance, ohci_regs_t *regs) {
-	assert(instance);
+static void create_serialized_hub_descriptor(rh_t *instance);
+static void rh_init_descriptors(rh_t *instance);
+static uint16_t create_interrupt_mask(rh_t *instance);
+static int get_status(rh_t *instance, usb_transfer_batch_t *request);
+static int get_descriptor(rh_t *instance, usb_transfer_batch_t *request);
+static int set_feature(rh_t *instance, usb_transfer_batch_t *request);
+static int clear_feature(rh_t *instance, usb_transfer_batch_t *request);
+static int set_feature_port(rh_t *instance, uint16_t feature, uint16_t port);
+static int clear_feature_port(rh_t *instance, uint16_t feature, uint16_t port);
+static int control_request(rh_t *instance, usb_transfer_batch_t *request);
+static inline void interrupt_request(
+    usb_transfer_batch_t *request, uint16_t mask, size_t size)
+{
+	assert(request);
+
+	memcpy(request->data_buffer, &mask, size);
+	request->transfered_size = size;
+	usb_transfer_batch_finish_error(request, EOK);
+}
+
+#define TRANSFER_OK(bytes) \
+do { \
+	request->transfered_size = bytes; \
+	return EOK; \
+} while (0)
+
+/** Root Hub driver structure initialization.
+ *
+ * Reads info registers and prepares descriptors. Sets power mode.
+ */
+void rh_init(rh_t *instance, ohci_regs_t *regs)
+{
+	assert(instance);
+	assert(regs);
+
 	instance->registers = regs;
 	instance->port_count =
 	    (instance->registers->rh_desc_a >> RHDA_NDS_SHIFT) & RHDA_NDS_MASK;
-	int opResult = rh_init_descriptors(instance);
-	if (opResult != EOK) {
-		return opResult;
-	}
-	// set port power mode to no-power-switching
+	if (instance->port_count > 15) {
+		usb_log_warning("OHCI specification does not allow more than 15"
+		    " ports. Max 15 ports will be used");
+		instance->port_count = 15;
+	}
+
+	/* Don't forget the hub status bit and round up */
+	instance->interrupt_mask_size = 1 + (instance->port_count / 8);
+	instance->unfinished_interrupt_transfer = NULL;
+
+#ifdef OHCI_POWER_SWITCH_no
+	/* Set port power mode to no power-switching. (always on) */
 	instance->registers->rh_desc_a |= RHDA_NPS_FLAG;
-	instance->unfinished_interrupt_transfer = NULL;
-	instance->interrupt_mask_size = (instance->port_count + 8) / 8;
-	instance->interrupt_buffer = malloc(instance->interrupt_mask_size);
-	if (!instance->interrupt_buffer)
-		return ENOMEM;
+	/* Set to no over-current reporting */
+	instance->registers->rh_desc_a |= RHDA_NOCP_FLAG;
+#elif defined OHCI_POWER_SWITCH_ganged
+	/* Set port power mode to no ganged power-switching. */
+	instance->registers->rh_desc_a &= ~RHDA_NPS_FLAG;
+	instance->registers->rh_desc_a &= ~RHDA_PSM_FLAG;
+	instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER;
+	/* Set to global over-current */
+	instance->registers->rh_desc_a &= ~RHDA_NOCP_FLAG;
+	instance->registers->rh_desc_a &= ~RHDA_OCPM_FLAG;
+#else
+	/* Set port power mode to no per port power-switching. */
+	instance->registers->rh_desc_a &= ~RHDA_NPS_FLAG;
+	instance->registers->rh_desc_a |= RHDA_PSM_FLAG;
+
+	/* Control all ports by global switch and turn them off */
+	instance->registers->rh_desc_b &= (RHDB_PCC_MASK << RHDB_PCC_SHIFT);
+	instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER;
+	/* Return control to per port state */
+	instance->registers->rh_desc_b |=
+		((1 << (instance->port_count + 1)) - 1) << RHDB_PCC_SHIFT;
+	/* Set per port over-current */
+	instance->registers->rh_desc_a &= ~RHDA_NOCP_FLAG;
+	instance->registers->rh_desc_a |= RHDA_OCPM_FLAG;
+#endif
+
+	rh_init_descriptors(instance);
 
 	usb_log_info("Root hub (%zu ports) initialized.\n",
 	    instance->port_count);
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * process root hub request
- *
- * @param instance root hub instance
- * @param request structure containing both request and response information
- * @return error code
- */
-int rh_request(rh_t *instance, usb_transfer_batch_t *request) {
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Process root hub request.
+ *
+ * @param instance Root hub instance
+ * @param request Structure containing both request and response information
+ * @return Error code
+ */
+void rh_request(rh_t *instance, usb_transfer_batch_t *request)
+{
 	assert(instance);
 	assert(request);
-	int opResult;
-	if (request->ep->transfer_type == USB_TRANSFER_CONTROL) {
+
+	switch (request->ep->transfer_type)
+	{
+	case USB_TRANSFER_CONTROL:
 		usb_log_debug("Root hub got CONTROL packet\n");
-		opResult = process_ctrl_request(instance, request);
-		usb_transfer_batch_finish_error(request, opResult);
-	} else if (request->ep->transfer_type == USB_TRANSFER_INTERRUPT) {
+		const int ret = control_request(instance, request);
+		usb_transfer_batch_finish_error(request, ret);
+		break;
+	case USB_TRANSFER_INTERRUPT:
 		usb_log_debug("Root hub got INTERRUPT packet\n");
-		create_interrupt_mask_in_instance(instance);
-		if (is_zeros(instance->interrupt_buffer,
-		    instance->interrupt_mask_size)) {
+		const uint16_t mask = create_interrupt_mask(instance);
+		if (mask == 0) {
 			usb_log_debug("No changes..\n");
+			assert(instance->unfinished_interrupt_transfer == NULL);
 			instance->unfinished_interrupt_transfer = request;
-			//will be finished later
-		} else {
-			usb_log_debug("Processing changes..\n");
-			process_interrupt_mask_in_instance(instance, request);
+			break;
 		}
-		opResult = EOK;
-	} else {
-
-		opResult = EINVAL;
-		usb_transfer_batch_finish_error(request, opResult);
-	}
-	return EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-
-/**
- * process interrupt on a hub
+		usb_log_debug("Processing changes...\n");
+		interrupt_request(request, mask, instance->interrupt_mask_size);
+		break;
+
+	default:
+		usb_log_error("Root hub got unsupported request.\n");
+		usb_transfer_batch_finish_error(request, EINVAL);
+	}
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Process interrupt on a hub device.
  *
  * If there is no pending interrupt transfer, nothing happens.
  * @param instance
  */
-void rh_interrupt(rh_t *instance) {
-	if (!instance->unfinished_interrupt_transfer) {
+void rh_interrupt(rh_t *instance)
+{
+	assert(instance);
+
+	if (!instance->unfinished_interrupt_transfer)
 		return;
-	}
+
 	usb_log_debug("Finalizing interrupt transfer\n");
-	create_interrupt_mask_in_instance(instance);
-	process_interrupt_mask_in_instance(instance,
-	    instance->unfinished_interrupt_transfer);
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * Create hub descriptor used in hub-driver <-> hub communication
- *
- * This means creating byt array from data in root hub registers. For more
- * info see usb hub specification.
- *
+	const uint16_t mask = create_interrupt_mask(instance);
+	interrupt_request(instance->unfinished_interrupt_transfer,
+	    mask, instance->interrupt_mask_size);
+
+	instance->unfinished_interrupt_transfer = NULL;
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Create hub descriptor.
+ *
+ * For descriptor format see USB hub specification (chapter 11.15.2.1, pg. 263)
+ *
+ * @param instance Root hub instance
+ * @return Error code
+ */
+void create_serialized_hub_descriptor(rh_t *instance)
+{
+	assert(instance);
+
+	/* 7 bytes + 2 port bit fields (port count + global bit) */
+	const size_t size = 7 + (instance->interrupt_mask_size * 2);
+	assert(size <= HUB_DESCRIPTOR_MAX_SIZE);
+	instance->hub_descriptor_size = size;
+
+	const uint32_t hub_desc = instance->registers->rh_desc_a;
+	const uint32_t port_desc = instance->registers->rh_desc_b;
+
+	/* bDescLength */
+	instance->descriptors.hub[0] = size;
+	/* bDescriptorType */
+	instance->descriptors.hub[1] = USB_DESCTYPE_HUB;
+	/* bNmbrPorts */
+	instance->descriptors.hub[2] = instance->port_count;
+	/* wHubCharacteristics */
+	instance->descriptors.hub[3] = 0 |
+	    /* The lowest 2 bits indicate power switching mode */
+	    (((hub_desc & RHDA_PSM_FLAG)  ? 1 : 0) << 0) |
+	    (((hub_desc & RHDA_NPS_FLAG)  ? 1 : 0) << 1) |
+	    /* Bit 3 indicates device type (compound device) */
+	    (((hub_desc & RHDA_DT_FLAG)   ? 1 : 0) << 2) |
+	    /* Bits 4,5 indicate over-current protection mode */
+	    (((hub_desc & RHDA_OCPM_FLAG) ? 1 : 0) << 3) |
+	    (((hub_desc & RHDA_NOCP_FLAG) ? 1 : 0) << 4);
+
+	/* Reserved */
+	instance->descriptors.hub[4] = 0;
+	/* bPwrOn2PwrGood */
+	instance->descriptors.hub[5] =
+	    (hub_desc >> RHDA_POTPGT_SHIFT) & RHDA_POTPGT_MASK;
+	/* bHubContrCurrent, root hubs don't need no power. */
+	instance->descriptors.hub[6] = 0;
+
+	/* Device Removable and some legacy 1.0 stuff*/
+	instance->descriptors.hub[7] =
+	    (port_desc >> RHDB_DR_SHIFT) & RHDB_DR_MASK & 0xff;
+	instance->descriptors.hub[8] = 0xff;
+	if (instance->interrupt_mask_size == 2) {
+		instance->descriptors.hub[8] =
+		    (port_desc >> RHDB_DR_SHIFT) & RHDB_DR_MASK >> 8;
+		instance->descriptors.hub[9]  = 0xff;
+		instance->descriptors.hub[10] = 0xff;
+	}
+}
+/*----------------------------------------------------------------------------*/
+/** Initialize hub descriptors.
+ *
+ * A full configuration descriptor is assembled. The configuration and endpoint
+ * descriptors have local modifications.
+ * @param instance Root hub instance
+ * @return Error code
+ */
+void rh_init_descriptors(rh_t *instance)
+{
+	assert(instance);
+
+	instance->descriptors.configuration = ohci_rh_conf_descriptor;
+	instance->descriptors.interface = ohci_rh_iface_descriptor;
+	instance->descriptors.endpoint = ohci_rh_ep_descriptor;
+	create_serialized_hub_descriptor(instance);
+
+	instance->descriptors.endpoint.max_packet_size =
+	    instance->interrupt_mask_size;
+
+	instance->descriptors.configuration.total_length =
+	    sizeof(usb_standard_configuration_descriptor_t) +
+	    sizeof(usb_standard_endpoint_descriptor_t) +
+	    sizeof(usb_standard_interface_descriptor_t) +
+	    instance->hub_descriptor_size;
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Create bitmap of changes to answer status interrupt.
+ *
+ * Result contains bitmap where bit 0 indicates change on hub and
+ * bit i indicates change on i`th port (i>0). For more info see
+ * Hub and Port status bitmap specification in USB specification
+ * (chapter 11.13.4).
  * @param instance root hub instance
- * @return error code
- */
-static int create_serialized_hub_descriptor(rh_t *instance) {
-	size_t size = 7 +
-	    ((instance->port_count + 7) / 8) * 2;
-	size_t var_size = (instance->port_count + 7) / 8;
-	uint8_t * result = (uint8_t*) malloc(size);
-	if (!result) return ENOMEM;
-
-	bzero(result, size);
-	//size
-	result[0] = size;
-	//descriptor type
-	result[1] = USB_DESCTYPE_HUB;
-	result[2] = instance->port_count;
-	uint32_t hub_desc_reg = instance->registers->rh_desc_a;
-	result[3] =
-	    ((hub_desc_reg >> 8) % 2) +
-	    (((hub_desc_reg >> 9) % 2) << 1) +
-	    (((hub_desc_reg >> 10) % 2) << 2) +
-	    (((hub_desc_reg >> 11) % 2) << 3) +
-	    (((hub_desc_reg >> 12) % 2) << 4);
-	result[4] = 0;
-	result[5] = /*descriptor->pwr_on_2_good_time*/ 50;
-	result[6] = 50;
-
-	size_t port;
-	for (port = 1; port <= instance->port_count; ++port) {
-		uint8_t is_non_removable =
-		    instance->registers->rh_desc_b >> port % 2;
-		result[7 + port / 8] +=
-		    is_non_removable << (port % 8);
-	}
-	size_t i;
-	for (i = 0; i < var_size; ++i) {
-		result[7 + var_size + i] = 255;
-	}
-	instance->hub_descriptor = result;
-	instance->descriptor_size = size;
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-/** initialize hub descriptors
- *
- * Initialized are device and full configuration descriptor. These need to
- * be initialized only once per hub.
- * @instance root hub instance
- * @return error code
- */
-static int rh_init_descriptors(rh_t *instance) {
-	memcpy(&instance->descriptors.device, &ohci_rh_device_descriptor,
-	    sizeof (ohci_rh_device_descriptor)
-	    );
-	usb_standard_configuration_descriptor_t descriptor;
-	memcpy(&descriptor, &ohci_rh_conf_descriptor,
-	    sizeof (ohci_rh_conf_descriptor));
-
-	int opResult = create_serialized_hub_descriptor(instance);
-	if (opResult != EOK) {
-		return opResult;
-	}
-	descriptor.total_length =
-	    sizeof (usb_standard_configuration_descriptor_t) +
-	    sizeof (usb_standard_endpoint_descriptor_t) +
-	    sizeof (usb_standard_interface_descriptor_t) +
-	    instance->descriptor_size;
-
-	uint8_t * full_config_descriptor =
-	    (uint8_t*) malloc(descriptor.total_length);
-	if (!full_config_descriptor) {
-		return ENOMEM;
-	}
-	memcpy(full_config_descriptor, &descriptor, sizeof (descriptor));
-	memcpy(full_config_descriptor + sizeof (descriptor),
-	    &ohci_rh_iface_descriptor, sizeof (ohci_rh_iface_descriptor));
-	memcpy(full_config_descriptor + sizeof (descriptor) +
-	    sizeof (ohci_rh_iface_descriptor),
-	    &ohci_rh_ep_descriptor, sizeof (ohci_rh_ep_descriptor));
-	memcpy(full_config_descriptor + sizeof (descriptor) +
-	    sizeof (ohci_rh_iface_descriptor) +
-	    sizeof (ohci_rh_ep_descriptor),
-	    instance->hub_descriptor, instance->descriptor_size);
-
-	instance->descriptors.configuration = full_config_descriptor;
-	instance->descriptors.configuration_size = descriptor.total_length;
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * create answer to port status_request
- *
- * Copy content of corresponding port status register to answer buffer. The
- * format of the port status register and port status data is the same (
- * see OHCI root hub and USB hub documentation).
- *
- * @param instance root hub instance
- * @param port port number, counted from 1
- * @param request structure containing both request and response information
- * @return error code
- */
-static int process_get_port_status_request(rh_t *instance, uint16_t port,
-    usb_transfer_batch_t * request) {
-	if (port < 1 || port > instance->port_count)
-		return EINVAL;
-	request->transfered_size = 4;
-	uint32_t data = instance->registers->rh_port_status[port - 1];
-	memcpy(request->data_buffer, &data, 4);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * create answer to port status_request
- *
- * This copies flags in hub status register into the buffer. The format of the
- * status register and status message is the same, according to USB hub
- * specification and OHCI root hub specification.
- *
- * @param instance root hub instance
- * @param request structure containing both request and response information
- * @return error code
- */
-static int process_get_hub_status_request(rh_t *instance,
-    usb_transfer_batch_t * request) {
-	request->transfered_size = 4;
-	//bits, 0,1,16,17
-	uint32_t mask = 1 | (1 << 1) | (1 << 16) | (1 << 17);
-	uint32_t data = mask & instance->registers->rh_status;
-	memcpy(request->data_buffer, &data, 4);
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * create answer to status request
+ * @return Mask of changes.
+ */
+uint16_t create_interrupt_mask(rh_t *instance)
+{
+	assert(instance);
+	uint16_t mask = 0;
+
+	/* Only local power source change and over-current change can happen */
+	if (instance->registers->rh_status & (RHS_LPSC_FLAG | RHS_OCIC_FLAG)) {
+		mask |= 1;
+	}
+	size_t port = 1;
+	for (; port <= instance->port_count; ++port) {
+		/* Write-clean bits are those that indicate change */
+		if (RHPS_CHANGE_WC_MASK
+		    & instance->registers->rh_port_status[port - 1]) {
+
+			mask |= (1 << port);
+		}
+	}
+	/* USB is little endian */
+	return host2uint32_t_le(mask);
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Create answer to status request.
  *
  * This might be either hub status or port status request. If neither,
@@ -448,204 +372,119 @@
  * @return error code
  */
-static int process_get_status_request(rh_t *instance,
-    usb_transfer_batch_t * request) {
-	size_t buffer_size = request->buffer_size;
-	usb_device_request_setup_packet_t * request_packet =
-	    (usb_device_request_setup_packet_t*)
-	    request->setup_buffer;
-
-	usb_hub_bm_request_type_t request_type = request_packet->request_type;
-	if (buffer_size < 4) {
-		usb_log_warning("Requested more data than buffer size\n");
-		return EINVAL;
-	}
-
-	if (request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS)
-		return process_get_hub_status_request(instance, request);
-	if (request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS)
-		return process_get_port_status_request(instance,
-	    request_packet->index,
-	    request);
+int get_status(rh_t *instance, usb_transfer_batch_t *request)
+{
+	assert(instance);
+	assert(request);
+
+	const usb_device_request_setup_packet_t *request_packet =
+	    (usb_device_request_setup_packet_t*)request->setup_buffer;
+
+	if (request->buffer_size < 4) {
+		usb_log_error("Buffer too small for get status request.\n");
+		return EOVERFLOW;
+	}
+
+	/* Hub status: just filter relevant info from rh_status reg */
+	if (request_packet->request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS) {
+		const uint32_t data = instance->registers->rh_status &
+		    (RHS_LPS_FLAG | RHS_LPSC_FLAG | RHS_OCI_FLAG | RHS_OCIC_FLAG);
+		memcpy(request->data_buffer, &data, 4);
+		TRANSFER_OK(4);
+	}
+
+	/* Copy appropriate rh_port_status register, OHCI designers were
+	 * kind enough to make those bit values match USB specification */
+	if (request_packet->request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS) {
+		const unsigned port = request_packet->index;
+		if (port < 1 || port > instance->port_count)
+			return EINVAL;
+
+		const uint32_t data =
+		    instance->registers->rh_port_status[port - 1];
+		memcpy(request->data_buffer, &data, 4);
+		TRANSFER_OK(4);
+	}
 
 	return ENOTSUP;
 }
 /*----------------------------------------------------------------------------*/
-
-/**
- * create answer to status interrupt consisting of change bitmap
- *
- * Result contains bitmap where bit 0 indicates change on hub and
- * bit i indicates change on i`th port (i>0). For more info see
- * Hub and Port status bitmap specification in USB specification
- * (chapter 11.13.4).
- * Uses instance`s interrupt buffer to store the interrupt information.
- * @param instance root hub instance
- */
-static void create_interrupt_mask_in_instance(rh_t * instance) {
-	uint8_t * bitmap = (uint8_t*) (instance->interrupt_buffer);
-	uint32_t mask = (1 << (USB_HUB_FEATURE_C_HUB_LOCAL_POWER + 16))
-	    | (1 << (USB_HUB_FEATURE_C_HUB_OVER_CURRENT + 16));
-	bzero(bitmap, instance->interrupt_mask_size);
-	if ((instance->registers->rh_status & mask) != 0) {
-		bitmap[0] = 1;
-	}
-	size_t port;
-	mask = port_status_change_mask;
-	for (port = 1; port <= instance->port_count; ++port) {
-		if ((mask & instance->registers->rh_port_status[port - 1]) != 0) {
-
-			bitmap[(port) / 8] += 1 << (port % 8);
-		}
-	}
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * create answer to a descriptor request
+/**
+ * Create answer to a descriptor request.
  *
  * This might be a request for standard (configuration, device, endpoint or
  * interface) or device specific (hub) descriptor.
- * @param instance root hub instance
- * @param request structure containing both request and response information
- * @return error code
- */
-static int process_get_descriptor_request(rh_t *instance,
-    usb_transfer_batch_t *request) {
-	usb_device_request_setup_packet_t * setup_request =
-	    (usb_device_request_setup_packet_t*) request->setup_buffer;
+ * @param instance Root hub instance
+ * @param request Structure containing both request and response information
+ * @return Error code
+ */
+int get_descriptor(rh_t *instance, usb_transfer_batch_t *request)
+{
+	assert(instance);
+	assert(request);
+
+	const usb_device_request_setup_packet_t *setup_request =
+	    (usb_device_request_setup_packet_t *) request->setup_buffer;
 	size_t size;
-	const void * result_descriptor = NULL;
+	const void *descriptor = NULL;
 	const uint16_t setup_request_value = setup_request->value_high;
 	//(setup_request->value_low << 8);
-	switch (setup_request_value) {
-		case USB_DESCTYPE_HUB:
-		{
-			usb_log_debug2("USB_DESCTYPE_HUB\n");
-			result_descriptor = instance->hub_descriptor;
-			size = instance->descriptor_size;
-			break;
-		}
-		case USB_DESCTYPE_DEVICE:
-		{
-			usb_log_debug2("USB_DESCTYPE_DEVICE\n");
-			result_descriptor = &ohci_rh_device_descriptor;
-			size = sizeof (ohci_rh_device_descriptor);
-			break;
-		}
-		case USB_DESCTYPE_CONFIGURATION:
-		{
-			usb_log_debug2("USB_DESCTYPE_CONFIGURATION\n");
-			result_descriptor = instance->descriptors.configuration;
-			size = instance->descriptors.configuration_size;
-			break;
-		}
-		case USB_DESCTYPE_INTERFACE:
-		{
-			usb_log_debug2("USB_DESCTYPE_INTERFACE\n");
-			result_descriptor = &ohci_rh_iface_descriptor;
-			size = sizeof (ohci_rh_iface_descriptor);
-			break;
-		}
-		case USB_DESCTYPE_ENDPOINT:
-		{
-			usb_log_debug2("USB_DESCTYPE_ENDPOINT\n");
-			result_descriptor = &ohci_rh_ep_descriptor;
-			size = sizeof (ohci_rh_ep_descriptor);
-			break;
-		}
-		default:
-		{
-			usb_log_debug2("USB_DESCTYPE_EINVAL %d \n",
-			    setup_request->value);
-			usb_log_debug2("\ttype %d\n\trequest %d\n\tvalue "
-			    "%d\n\tindex %d\n\tlen %d\n ",
-			    setup_request->request_type,
-			    setup_request->request,
-			    setup_request_value,
-			    setup_request->index,
-			    setup_request->length
-			    );
-			return EINVAL;
-		}
+	switch (setup_request_value)
+	{
+	case USB_DESCTYPE_HUB:
+		usb_log_debug2("USB_DESCTYPE_HUB\n");
+		/* Hub descriptor was generated locally */
+		descriptor = instance->descriptors.hub;
+		size = instance->hub_descriptor_size;
+		break;
+
+	case USB_DESCTYPE_DEVICE:
+		usb_log_debug2("USB_DESCTYPE_DEVICE\n");
+		/* Device descriptor is shared (No one should ask for it)*/
+		descriptor = &ohci_rh_device_descriptor;
+		size = sizeof(ohci_rh_device_descriptor);
+		break;
+
+	case USB_DESCTYPE_CONFIGURATION:
+		usb_log_debug2("USB_DESCTYPE_CONFIGURATION\n");
+		/* Start with configuration and add others depending on
+		 * request size */
+		descriptor = &instance->descriptors;
+		size = instance->descriptors.configuration.total_length;
+		break;
+
+	case USB_DESCTYPE_INTERFACE:
+		usb_log_debug2("USB_DESCTYPE_INTERFACE\n");
+		/* Use local interface descriptor. There is one and it
+		 * might be modified */
+		descriptor = &instance->descriptors.interface;
+		size = sizeof(instance->descriptors.interface);
+		break;
+
+	case USB_DESCTYPE_ENDPOINT:
+		/* Use local endpoint descriptor. There is one
+		 * it might have max_packet_size field modified*/
+		usb_log_debug2("USB_DESCTYPE_ENDPOINT\n");
+		descriptor = &instance->descriptors.endpoint;
+		size = sizeof(instance->descriptors.endpoint);
+		break;
+
+	default:
+		usb_log_debug2("USB_DESCTYPE_EINVAL %d \n"
+		    "\ttype %d\n\trequest %d\n\tvalue "
+		    "%d\n\tindex %d\n\tlen %d\n ",
+		    setup_request->value,
+		    setup_request->request_type, setup_request->request,
+		    setup_request_value, setup_request->index,
+		    setup_request->length);
+		return EINVAL;
 	}
 	if (request->buffer_size < size) {
 		size = request->buffer_size;
 	}
-	request->transfered_size = size;
-	memcpy(request->data_buffer, result_descriptor, size);
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * answer to get configuration request
- *
- * Root hub works independently on the configuration.
- * @param instance root hub instance
- * @param request structure containing both request and response information
- * @return error code
- */
-static int process_get_configuration_request(rh_t *instance,
-    usb_transfer_batch_t *request) {
-	//set and get configuration requests do not have any meaning, only dummy
-	//values are returned
-	if (request->buffer_size != 1)
-		return EINVAL;
-	request->data_buffer[0] = 1;
-	request->transfered_size = 1;
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * process feature-enabling request on hub
- *
- * @param instance root hub instance
- * @param feature feature selector
- * @return error code
- */
-static int process_hub_feature_set_request(rh_t *instance,
-    uint16_t feature) {
-	if (!((1 << feature) & hub_set_feature_valid_mask))
-		return EINVAL;
-	if (feature == USB_HUB_FEATURE_C_HUB_LOCAL_POWER)
-		feature = USB_HUB_FEATURE_C_HUB_LOCAL_POWER << 16;
-	instance->registers->rh_status =
-	    (instance->registers->rh_status | (1 << feature))
-	    & (~hub_clear_feature_by_writing_one_mask);
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * process feature-disabling request on hub
- *
- * @param instance root hub instance
- * @param feature feature selector
- * @return error code
- */
-static int process_hub_feature_clear_request(rh_t *instance,
-    uint16_t feature) {
-	if (!((1 << feature) & hub_clear_feature_valid_mask))
-		return EINVAL;
-	//is the feature cleared directly?
-	if ((1 << feature) & hub_set_feature_direct_mask) {
-		instance->registers->rh_status =
-		    (instance->registers->rh_status & (~(1 << feature)))
-		    & (~hub_clear_feature_by_writing_one_mask);
-	} else {//the feature is cleared by writing '1'
-
-		instance->registers->rh_status =
-		    (instance->registers->rh_status
-		    & (~hub_clear_feature_by_writing_one_mask))
-		    | (1 << feature);
-	}
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
+
+	memcpy(request->data_buffer, descriptor, size);
+	TRANSFER_OK(size);
+}
+/*----------------------------------------------------------------------------*/
 /**
  * process feature-enabling request on hub
@@ -657,19 +496,36 @@
  * @return error code
  */
-static int process_port_feature_set_request(rh_t *instance,
-    uint16_t feature, uint16_t port) {
-	if (!((1 << feature) & port_set_feature_valid_mask))
-		return EINVAL;
+int set_feature_port(rh_t *instance, uint16_t feature, uint16_t port)
+{
+	assert(instance);
+
 	if (port < 1 || port > instance->port_count)
 		return EINVAL;
-	instance->registers->rh_port_status[port - 1] =
-	    (instance->registers->rh_port_status[port - 1] | (1 << feature))
-	    & (~port_clear_feature_valid_mask);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * process feature-disabling request on hub
+
+	switch (feature)
+	{
+	case USB_HUB_FEATURE_PORT_POWER:   //8
+		/* No power switching */
+		if (instance->registers->rh_desc_a & RHDA_NPS_FLAG)
+			return EOK;
+		/* Ganged power switching */
+		if (!(instance->registers->rh_desc_a & RHDA_PSM_FLAG)) {
+			instance->registers->rh_status = RHS_SET_GLOBAL_POWER;
+			return EOK;
+		}
+	case USB_HUB_FEATURE_PORT_ENABLE:  //1
+	case USB_HUB_FEATURE_PORT_SUSPEND: //2
+	case USB_HUB_FEATURE_PORT_RESET:   //4
+		/* Nice thing is that these shifts correspond to the position
+		 * of control bits in register */
+		instance->registers->rh_port_status[port - 1] = (1 << feature);
+		return EOK;
+	default:
+		return ENOTSUP;
+	}
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Process feature clear request.
  *
  * @param instance root hub instance
@@ -679,93 +535,52 @@
  * @return error code
  */
-static int process_port_feature_clear_request(rh_t *instance,
-    uint16_t feature, uint16_t port) {
-	if (!((1 << feature) & port_clear_feature_valid_mask))
-		return EINVAL;
+int clear_feature_port(rh_t *instance, uint16_t feature, uint16_t port)
+{
+	assert(instance);
+
 	if (port < 1 || port > instance->port_count)
 		return EINVAL;
-	if (feature == USB_HUB_FEATURE_PORT_POWER)
-		feature = USB_HUB_FEATURE_PORT_LOW_SPEED;
-	if (feature == USB_HUB_FEATURE_PORT_SUSPEND)
-		feature = USB_HUB_FEATURE_PORT_OVER_CURRENT;
-	instance->registers->rh_port_status[port - 1] =
-	    (instance->registers->rh_port_status[port - 1]
-	    & (~port_clear_feature_valid_mask))
-	    | (1 << feature);
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * register address to this device
- *
- * @param instance root hub instance
- * @param address new address
- * @return error code
- */
-static int process_address_set_request(rh_t *instance,
-    uint16_t address) {
-	return ENOTSUP;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * process one of requests that requere output data
- *
- * Request can be one of USB_DEVREQ_GET_STATUS, USB_DEVREQ_GET_DESCRIPTOR or
- * USB_DEVREQ_GET_CONFIGURATION.
- * @param instance root hub instance
- * @param request structure containing both request and response information
- * @return error code
- */
-static int process_request_with_output(rh_t *instance,
-    usb_transfer_batch_t *request) {
-	usb_device_request_setup_packet_t * setup_request =
-	    (usb_device_request_setup_packet_t*) request->setup_buffer;
-	if (setup_request->request == USB_DEVREQ_GET_STATUS) {
-		usb_log_debug("USB_DEVREQ_GET_STATUS\n");
-		return process_get_status_request(instance, request);
-	}
-	if (setup_request->request == USB_DEVREQ_GET_DESCRIPTOR) {
-		usb_log_debug("USB_DEVREQ_GET_DESCRIPTOR\n");
-		return process_get_descriptor_request(instance, request);
-	}
-	if (setup_request->request == USB_DEVREQ_GET_CONFIGURATION) {
-		usb_log_debug("USB_DEVREQ_GET_CONFIGURATION\n");
-
-		return process_get_configuration_request(instance, request);
-	}
-	return ENOTSUP;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * process one of requests that carry input data
- *
- * Request can be one of USB_DEVREQ_SET_DESCRIPTOR or
- * USB_DEVREQ_SET_CONFIGURATION.
- * @param instance root hub instance
- * @param request structure containing both request and response information
- * @return error code
- */
-static int process_request_with_input(rh_t *instance,
-    usb_transfer_batch_t *request) {
-	usb_device_request_setup_packet_t * setup_request =
-	    (usb_device_request_setup_packet_t*) request->setup_buffer;
-	request->transfered_size = 0;
-	if (setup_request->request == USB_DEVREQ_SET_DESCRIPTOR) {
+
+	/* Enabled features to clear: see page 269 of USB specs */
+	switch (feature)
+	{
+	case USB_HUB_FEATURE_PORT_POWER:          //8
+		/* No power switching */
+		if (instance->registers->rh_desc_a & RHDA_NPS_FLAG)
+			return ENOTSUP;
+		/* Ganged power switching */
+		if (!(instance->registers->rh_desc_a & RHDA_PSM_FLAG)) {
+			instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER;
+			return EOK;
+		}
+		instance->registers->rh_port_status[port - 1] =
+			RHPS_CLEAR_PORT_POWER;
+		return EOK;
+
+	case USB_HUB_FEATURE_PORT_ENABLE:         //1
+		instance->registers->rh_port_status[port - 1] =
+			RHPS_CLEAR_PORT_ENABLE;
+		return EOK;
+
+	case USB_HUB_FEATURE_PORT_SUSPEND:        //2
+		instance->registers->rh_port_status[port - 1] =
+			RHPS_CLEAR_PORT_SUSPEND;
+		return EOK;
+
+	case USB_HUB_FEATURE_C_PORT_CONNECTION:   //16
+	case USB_HUB_FEATURE_C_PORT_ENABLE:       //17
+	case USB_HUB_FEATURE_C_PORT_SUSPEND:      //18
+	case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: //19
+	case USB_HUB_FEATURE_C_PORT_RESET:        //20
+		/* Nice thing is that these shifts correspond to the position
+		 * of control bits in register */
+		instance->registers->rh_port_status[port - 1] = (1 << feature);
+		return EOK;
+
+	default:
 		return ENOTSUP;
 	}
-	if (setup_request->request == USB_DEVREQ_SET_CONFIGURATION) {
-		//set and get configuration requests do not have any meaning,
-		//only dummy values are returned
-
-		return EOK;
-	}
-	return ENOTSUP;
-}
-/*----------------------------------------------------------------------------*/
-
+}
+/*----------------------------------------------------------------------------*/
 /**
  * process one of requests that do not request nor carry additional data
@@ -777,55 +592,76 @@
  * @return error code
  */
-static int process_request_without_data(rh_t *instance,
-    usb_transfer_batch_t *request) {
-	usb_device_request_setup_packet_t * setup_request =
-	    (usb_device_request_setup_packet_t*) request->setup_buffer;
-	request->transfered_size = 0;
-	if (setup_request->request == USB_DEVREQ_CLEAR_FEATURE) {
-		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
-			usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
-			return process_hub_feature_clear_request(instance,
-			    setup_request->value);
-		}
-		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
-			usb_log_debug2("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
-			return process_port_feature_clear_request(instance,
-			    setup_request->value,
-			    setup_request->index);
-		}
-		usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
+int set_feature(rh_t *instance, usb_transfer_batch_t *request)
+{
+	assert(instance);
+	assert(request);
+
+	const usb_device_request_setup_packet_t *setup_request =
+	    (usb_device_request_setup_packet_t *) request->setup_buffer;
+	switch (setup_request->request_type)
+	{
+	case USB_HUB_REQ_TYPE_SET_PORT_FEATURE:
+		usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
+		return set_feature_port(instance,
+		    setup_request->value, setup_request->index);
+
+	case USB_HUB_REQ_TYPE_SET_HUB_FEATURE:
+		/* Chapter 11.16.2 specifies that hub can be recipient
+		 * only for C_HUB_LOCAL_POWER and C_HUB_OVER_CURRENT
+		 * features. It makes no sense to SET either. */
+		usb_log_error("Invalid HUB set feature request.\n");
+		return ENOTSUP;
+	default:
+		usb_log_error("Invalid set feature request type: %d\n",
 		    setup_request->request_type);
 		return EINVAL;
 	}
-	if (setup_request->request == USB_DEVREQ_SET_FEATURE) {
-		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
-			usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
-			return process_hub_feature_set_request(instance,
-			    setup_request->value);
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * process one of requests that do not request nor carry additional data
+ *
+ * Request can be one of USB_DEVREQ_CLEAR_FEATURE, USB_DEVREQ_SET_FEATURE or
+ * USB_DEVREQ_SET_ADDRESS.
+ * @param instance root hub instance
+ * @param request structure containing both request and response information
+ * @return error code
+ */
+int clear_feature(rh_t *instance, usb_transfer_batch_t *request)
+{
+	assert(instance);
+	assert(request);
+
+	const usb_device_request_setup_packet_t *setup_request =
+	    (usb_device_request_setup_packet_t *) request->setup_buffer;
+	request->transfered_size = 0;
+	switch (setup_request->request_type)
+	{
+	case USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE:
+		usb_log_debug("USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE\n");
+		return clear_feature_port(instance,
+		    setup_request->value, setup_request->index);
+
+	case USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE:
+		usb_log_debug("USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE\n");
+		/*
+		 * Chapter 11.16.2 specifies that only C_HUB_LOCAL_POWER and
+		 * C_HUB_OVER_CURRENT are supported. C_HUB_OVER_CURRENT is represented
+		 * by OHCI RHS_OCIC_FLAG. C_HUB_LOCAL_POWER is not supported
+		 * as root hubs do not support local power status feature.
+		 * (OHCI pg. 127) */
+		if (setup_request->value == USB_HUB_FEATURE_C_HUB_OVER_CURRENT) {
+			instance->registers->rh_status = RHS_OCIC_FLAG;
+			TRANSFER_OK(0);
 		}
-		if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
-			usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
-			return process_port_feature_set_request(instance,
-			    setup_request->value,
-			    setup_request->index);
-		}
-		usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
+	default:
+		usb_log_error("Invalid clear feature request type: %d\n",
 		    setup_request->request_type);
 		return EINVAL;
 	}
-	if (setup_request->request == USB_DEVREQ_SET_ADDRESS) {
-		usb_log_debug("USB_DEVREQ_SET_ADDRESS\n");
-		return process_address_set_request(instance,
-		    setup_request->value);
-	}
-	usb_log_debug("USB_DEVREQ_SET_ENOTSUP %d\n",
-	    setup_request->request_type);
-
-	return ENOTSUP;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * process hub control request
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Process hub control request.
  *
  * If needed, writes answer into the request structure.
@@ -844,95 +680,65 @@
  * @return error code
  */
-static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request) {
+int control_request(rh_t *instance, usb_transfer_batch_t *request)
+{
+	assert(instance);
+	assert(request);
+
 	if (!request->setup_buffer) {
-		usb_log_error("root hub received empty transaction?");
+		usb_log_error("Root hub received empty transaction!");
 		return EINVAL;
 	}
-	int opResult;
-	if (sizeof (usb_device_request_setup_packet_t) > request->setup_size) {
+
+	if (sizeof(usb_device_request_setup_packet_t) > request->setup_size) {
 		usb_log_error("Setup packet too small\n");
-		return EINVAL;
-	}
-	usb_log_debug("CTRL packet: %s.\n",
-	    usb_debug_str_buffer(
-	    (const uint8_t *) request->setup_buffer, 8, 8));
-	usb_device_request_setup_packet_t * setup_request =
-	    (usb_device_request_setup_packet_t*)
-	    request->setup_buffer;
-	switch (setup_request->request) {
-		case USB_DEVREQ_GET_STATUS:
-		case USB_DEVREQ_GET_DESCRIPTOR:
-		case USB_DEVREQ_GET_CONFIGURATION:
-			usb_log_debug2("Processing request with output\n");
-			opResult = process_request_with_output(
-			    instance, request);
-			break;
-		case USB_DEVREQ_CLEAR_FEATURE:
-		case USB_DEVREQ_SET_FEATURE:
-		case USB_DEVREQ_SET_ADDRESS:
-			usb_log_debug2("Processing request without "
-			    "additional data\n");
-			opResult = process_request_without_data(
-			    instance, request);
-			break;
-		case USB_DEVREQ_SET_DESCRIPTOR:
-		case USB_DEVREQ_SET_CONFIGURATION:
-			usb_log_debug2("Processing request with input\n");
-			opResult = process_request_with_input(
-			    instance, request);
-
-			break;
-		default:
-			usb_log_warning("Received unsupported request: %d.\n",
-			    setup_request->request);
-			opResult = ENOTSUP;
-	}
-	return opResult;
-}
-/*----------------------------------------------------------------------------*/
-
-/**
- * process hanging interrupt request
- *
- * If an interrupt transfer has been received and there was no change,
- * the driver stores the transfer information and waits for change to occcur.
- * This routine is called when that happens and it finalizes the interrupt
- * transfer.
- *
- * @param instance hub instance
- * @param request batch request to be processed
- *
- * @return
- */
-static int process_interrupt_mask_in_instance(rh_t *instance,
-    usb_transfer_batch_t * request) {
-	memcpy(request->data_buffer, instance->interrupt_buffer,
-	    instance->interrupt_mask_size);
-	request->transfered_size = instance->interrupt_mask_size;
-	instance->unfinished_interrupt_transfer = NULL;
-	usb_transfer_batch_finish_error(request, EOK);
-
-	return EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-
-/**
- * return whether the buffer is full of zeros
- *
- * Convenience function.
- * @param buffer
- * @param size
- * @return
- */
-static bool is_zeros(void *buffer, size_t size) {
-	if (!buffer) return true;
-	if (!size) return true;
-	size_t i;
-	for (i = 0; i < size; ++i) {
-		if (((char*) buffer)[i])
-			return false;
-	}
-	return true;
+		return EOVERFLOW;
+	}
+
+	usb_log_debug2("CTRL packet: %s.\n",
+	    usb_debug_str_buffer((uint8_t *) request->setup_buffer, 8, 8));
+	const usb_device_request_setup_packet_t *setup_request =
+	    (usb_device_request_setup_packet_t *) request->setup_buffer;
+	switch (setup_request->request)
+	{
+	case USB_DEVREQ_GET_STATUS:
+		usb_log_debug("USB_DEVREQ_GET_STATUS\n");
+		return get_status(instance, request);
+
+	case USB_DEVREQ_GET_DESCRIPTOR:
+		usb_log_debug("USB_DEVREQ_GET_DESCRIPTOR\n");
+		return get_descriptor(instance, request);
+
+	case USB_DEVREQ_GET_CONFIGURATION:
+		usb_log_debug("USB_DEVREQ_GET_CONFIGURATION\n");
+		if (request->buffer_size != 1)
+			return EINVAL;
+		request->data_buffer[0] = 1;
+		TRANSFER_OK(1);
+
+	case USB_DEVREQ_CLEAR_FEATURE:
+		usb_log_debug2("Processing request without "
+		    "additional data\n");
+		return clear_feature(instance, request);
+	case USB_DEVREQ_SET_FEATURE:
+		usb_log_debug2("Processing request without "
+		    "additional data\n");
+		return set_feature(instance, request);
+
+	case USB_DEVREQ_SET_ADDRESS:
+		usb_log_debug("USB_DEVREQ_SET_ADDRESS\n");
+		instance->address = setup_request->value;
+		TRANSFER_OK(0);
+
+	case USB_DEVREQ_SET_CONFIGURATION:
+		usb_log_debug("USB_DEVREQ_SET_CONFIGURATION\n");
+		/* We don't need to do anything */
+		TRANSFER_OK(0);
+
+	case USB_DEVREQ_SET_DESCRIPTOR: /* Not supported by OHCI RH */
+	default:
+		usb_log_error("Received unsupported request: %d.\n",
+		    setup_request->request);
+		return ENOTSUP;
+	}
 }
 
Index: uspace/drv/bus/usb/ohci/root_hub.h
===================================================================
--- uspace/drv/bus/usb/ohci/root_hub.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/ohci/root_hub.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -41,4 +41,6 @@
 #include "batch.h"
 
+#define HUB_DESCRIPTOR_MAX_SIZE (7 + 2 + 2)
+
 /**
  * ohci root hub representation
@@ -51,28 +53,23 @@
 	/** hub port count */
 	size_t port_count;
-	/** hubs descriptors */
-	usb_device_descriptors_t descriptors;
 	/** interrupt transfer waiting for an actual interrupt to occur */
-	usb_transfer_batch_t * unfinished_interrupt_transfer;
-	/** pre-allocated interrupt mask
-	 *
-	 * This is allocated when initializing instance, so that memory
-	 * allocation is not needed when processing request. Buffer is used for
-	 * interrupt bitmask.
-	 */
-	uint8_t * interrupt_buffer;
+	usb_transfer_batch_t *unfinished_interrupt_transfer;
 	/** size of interrupt buffer */
 	size_t interrupt_mask_size;
-	/** instance`s descriptor*/
-	uint8_t * hub_descriptor;
+	/** Descriptors */
+	struct {
+		usb_standard_configuration_descriptor_t configuration;
+		usb_standard_interface_descriptor_t interface;
+		usb_standard_endpoint_descriptor_t endpoint;
+		uint8_t hub[HUB_DESCRIPTOR_MAX_SIZE];
+	} __attribute__ ((packed)) descriptors;
 	/** size of hub descriptor */
-	size_t descriptor_size;
-
+	size_t hub_descriptor_size;
 
 } rh_t;
 
-int rh_init(rh_t *instance, ohci_regs_t *regs);
+void rh_init(rh_t *instance, ohci_regs_t *regs);
 
-int rh_request(rh_t *instance, usb_transfer_batch_t *request);
+void rh_request(rh_t *instance, usb_transfer_batch_t *request);
 
 void rh_interrupt(rh_t *instance);
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -47,4 +47,13 @@
     (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)
 
+static const irq_cmd_t uhci_irq_commands[] =
+{
+	{ .cmd = CMD_PIO_READ_16, .dstarg = 1, .addr = NULL/*filled later*/},
+	{ .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2,
+	  .value = UHCI_STATUS_USED_INTERRUPTS | UHCI_STATUS_NM_INTERRUPTS },
+	{ .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 },
+	{ .cmd = CMD_PIO_WRITE_A_16, .srcarg = 1, .addr = NULL/*filled later*/},
+	{ .cmd = CMD_ACCEPT },
+};
 
 static int hc_init_transfer_lists(hc_t *instance);
@@ -54,4 +63,37 @@
 static int hc_interrupt_emulator(void *arg);
 static int hc_debug_checker(void *arg);
+
+/*----------------------------------------------------------------------------*/
+/** Get number of commands used in IRQ code.
+ * @return Number of commands.
+ */
+size_t hc_irq_cmd_count(void)
+{
+	return sizeof(uhci_irq_commands) / sizeof(irq_cmd_t);
+}
+/*----------------------------------------------------------------------------*/
+/** Generate IRQ code commands.
+ * @param[out] cmds Place to store the commands.
+ * @param[in] cmd_size Size of the place (bytes).
+ * @param[in] regs Physical address of device's registers.
+ * @param[in] reg_size Size of the register area (bytes).
+ *
+ * @return Error code.
+ */
+int hc_get_irq_commands(
+    irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size)
+{
+	if (cmd_size < sizeof(uhci_irq_commands)
+	    || reg_size < sizeof(uhci_regs_t))
+		return EOVERFLOW;
+
+	uhci_regs_t *registers = (uhci_regs_t*)regs;
+
+	memcpy(cmds, uhci_irq_commands, sizeof(uhci_irq_commands));
+
+	cmds[0].addr = (void*)&registers->usbsts;
+	cmds[3].addr = (void*)&registers->usbsts;
+	return EOK;
+}
 /*----------------------------------------------------------------------------*/
 /** Initialize UHCI hc driver structure
@@ -69,5 +111,5 @@
 int hc_init(hc_t *instance, void *regs, size_t reg_size, bool interrupts)
 {
-	assert(reg_size >= sizeof(regs_t));
+	assert(reg_size >= sizeof(uhci_regs_t));
 	int ret;
 
@@ -82,17 +124,16 @@
 
 	/* allow access to hc control registers */
-	regs_t *io;
+	uhci_regs_t *io;
 	ret = pio_enable(regs, reg_size, (void **)&io);
-	CHECK_RET_RETURN(ret,
-	    "Failed(%d) to gain access to registers at %p: %s.\n",
-	    ret, io, str_error(ret));
+	CHECK_RET_RETURN(ret, "Failed to gain access to registers at %p: %s.\n",
+	    io, str_error(ret));
 	instance->registers = io;
-	usb_log_debug("Device registers at %p (%zuB) accessible.\n",
-	    io, reg_size);
+	usb_log_debug(
+	    "Device registers at %p (%zuB) accessible.\n", io, reg_size);
 
 	ret = hc_init_mem_structures(instance);
 	CHECK_RET_RETURN(ret,
-	    "Failed(%d) to initialize UHCI memory structures: %s.\n",
-	    ret, str_error(ret));
+	    "Failed to initialize UHCI memory structures: %s.\n",
+	    str_error(ret));
 
 	hc_init_hw(instance);
@@ -116,12 +157,12 @@
 {
 	assert(instance);
-	regs_t *registers = instance->registers;
+	uhci_regs_t *registers = instance->registers;
 
 	/* Reset everything, who knows what touched it before us */
 	pio_write_16(&registers->usbcmd, UHCI_CMD_GLOBAL_RESET);
-	async_usleep(10000); /* 10ms according to USB spec */
+	async_usleep(50000); /* 50ms according to USB spec(root hub reset) */
 	pio_write_16(&registers->usbcmd, 0);
 
-	/* Reset hc, all states and counters */
+	/* Reset hc, all states and counters. Hope that hw is not broken */
 	pio_write_16(&registers->usbcmd, UHCI_CMD_HCRESET);
 	do { async_usleep(10); }
@@ -141,7 +182,7 @@
 	}
 
-	const uint16_t status = pio_read_16(&registers->usbcmd);
-	if (status != 0)
-		usb_log_warning("Previous command value: %x.\n", status);
+	const uint16_t cmd = pio_read_16(&registers->usbcmd);
+	if (cmd != 0)
+		usb_log_warning("Previous command value: %x.\n", cmd);
 
 	/* Start the hc with large(64B) packet FSBR */
@@ -170,60 +211,12 @@
 	} else (void) 0
 
-	/* Init interrupt code */
-	instance->interrupt_code.cmds = instance->interrupt_commands;
-	{
-		/* Read status register */
-		instance->interrupt_commands[0].cmd = CMD_PIO_READ_16;
-		instance->interrupt_commands[0].dstarg = 1;
-		instance->interrupt_commands[0].addr =
-		    &instance->registers->usbsts;
-
-		/* Test whether we are the interrupt cause */
-		instance->interrupt_commands[1].cmd = CMD_BTEST;
-		instance->interrupt_commands[1].value =
-		    UHCI_STATUS_USED_INTERRUPTS | UHCI_STATUS_NM_INTERRUPTS;
-		instance->interrupt_commands[1].srcarg = 1;
-		instance->interrupt_commands[1].dstarg = 2;
-
-		/* Predicate cleaning and accepting */
-		instance->interrupt_commands[2].cmd = CMD_PREDICATE;
-		instance->interrupt_commands[2].value = 2;
-		instance->interrupt_commands[2].srcarg = 2;
-
-		/* Write clean status register */
-		instance->interrupt_commands[3].cmd = CMD_PIO_WRITE_A_16;
-		instance->interrupt_commands[3].srcarg = 1;
-		instance->interrupt_commands[3].addr =
-		    &instance->registers->usbsts;
-
-		/* Accept interrupt */
-		instance->interrupt_commands[4].cmd = CMD_ACCEPT;
-
-		instance->interrupt_code.cmdcount = UHCI_NEEDED_IRQ_COMMANDS;
-	}
-
 	/* Init transfer lists */
 	int ret = hc_init_transfer_lists(instance);
-	CHECK_RET_RETURN(ret, "Failed to init transfer lists.\n");
+	CHECK_RET_RETURN(ret, "Failed to initialize transfer lists.\n");
 	usb_log_debug("Initialized transfer lists.\n");
-
-	/* Init USB frame list page*/
-	instance->frame_list = get_page();
-	ret = instance->frame_list ? EOK : ENOMEM;
-	CHECK_RET_RETURN(ret, "Failed to get frame list page.\n");
-	usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
-
-	/* Set all frames to point to the first queue head */
-	const uint32_t queue = LINK_POINTER_QH(
-	        addr_to_phys(instance->transfers_interrupt.queue_head));
-
-	unsigned i = 0;
-	for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
-		instance->frame_list[i] = queue;
-	}
 
 	/* Init device keeper */
 	usb_device_keeper_init(&instance->manager);
-	usb_log_debug("Initialized device manager.\n");
+	usb_log_debug("Initialized device keeper.\n");
 
 	ret = usb_endpoint_manager_init(&instance->ep_manager,
@@ -232,4 +225,21 @@
 	    str_error(ret));
 
+	/* Init USB frame list page*/
+	instance->frame_list = get_page();
+	if (!instance->frame_list) {
+		usb_log_error("Failed to get frame list page.\n");
+		usb_endpoint_manager_destroy(&instance->ep_manager);
+		return ENOMEM;
+	}
+	usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
+
+	/* Set all frames to point to the first queue head */
+	const uint32_t queue = LINK_POINTER_QH(
+	        addr_to_phys(instance->transfers_interrupt.queue_head));
+	unsigned i = 0;
+	for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
+		instance->frame_list[i] = queue;
+	}
+
 	return EOK;
 #undef CHECK_RET_RETURN
@@ -252,6 +262,6 @@
 	int ret = transfer_list_init(&instance->transfers_##type, name); \
 	if (ret != EOK) { \
-		usb_log_error("Failed(%d) to setup %s transfer list: %s.\n", \
-		    ret, name, str_error(ret)); \
+		usb_log_error("Failed to setup %s transfer list: %s.\n", \
+		    name, str_error(ret)); \
 		transfer_list_fini(&instance->transfers_bulk_full); \
 		transfer_list_fini(&instance->transfers_control_full); \
Index: uspace/drv/bus/usb/uhci/hc.h
===================================================================
--- uspace/drv/bus/usb/uhci/hc.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/uhci/hc.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -84,5 +84,5 @@
 	/** SOF modification to match external timers */
 	uint8_t sofmod;
-} regs_t;
+} uhci_regs_t;
 
 #define UHCI_FRAME_LIST_COUNT 1024
@@ -100,5 +100,5 @@
 
 	/** Addresses of I/O registers */
-	regs_t *registers;
+	uhci_regs_t *registers;
 
 	/** Frame List contains 1024 link pointers */
@@ -116,14 +116,6 @@
 	/** Pointer table to the above lists, helps during scheduling */
 	transfer_list_t *transfers[2][4];
-
-	/** Code to be executed in kernel interrupt handler */
-	irq_code_t interrupt_code;
-
-	/** Commands that form interrupt code */
-	irq_cmd_t interrupt_commands[UHCI_NEEDED_IRQ_COMMANDS];
-
 	/** Fibril periodically checking status register*/
 	fid_t interrupt_emulator;
-
 	/** Indicator of hw interrupts availability */
 	bool hw_interrupts;
@@ -132,9 +124,9 @@
 	unsigned hw_failures;
 } hc_t;
-
+size_t hc_irq_cmd_count(void);
+int hc_get_irq_commands(
+    irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size);
 int hc_init(hc_t *instance, void *regs, size_t reg_size, bool interupts);
-
 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);
-
 void hc_interrupt(hc_t *instance, uint16_t status);
 
Index: uspace/drv/bus/usb/uhci/root_hub.c
===================================================================
--- uspace/drv/bus/usb/uhci/root_hub.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/uhci/root_hub.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -50,21 +50,12 @@
 int rh_init(rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size)
 {
+	int ret;
+
 	assert(fun);
 
-	char *match_str = NULL;
-	int ret = asprintf(&match_str, "usb&uhci&root-hub");
-	if (ret < 0) {
-		usb_log_error(
-		    "Failed(%d) to create root hub match string: %s.\n",
-		    ret, str_error(ret));
-		return ret;
-	}
-	assert(match_str);
-
-	ret = ddf_fun_add_match_id(fun, match_str, 100);
+	ret = ddf_fun_add_match_id(fun, "usb&uhci&root-hub", 100);
 	if (ret != EOK) {
-		free(match_str);
-		usb_log_error("Failed(%d) to add root hub match id: %s\n",
-		    ret, str_error(ret));
+		usb_log_error("Failed to add root hub match id: %s\n",
+		    str_error(ret));
 		return ret;
 	}
Index: uspace/drv/bus/usb/uhci/uhci.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/uhci/uhci.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -64,5 +64,4 @@
 {
 	assert(dev);
-	assert(dev->driver_data);
 	return dev->driver_data;
 }
@@ -78,8 +77,10 @@
 	assert(dev);
 	uhci_t *uhci = dev_to_uhci(dev);
-	hc_t *hc = &uhci->hc;
+	if (!uhci) {
+		usb_log_error("Interrupt on not yet initialized device.\n");
+		return;
+	}
 	const uint16_t status = IPC_GET_ARG1(*call);
-	assert(hc);
-	hc_interrupt(hc, status);
+	hc_interrupt(&uhci->hc, status);
 }
 /*----------------------------------------------------------------------------*/
@@ -192,4 +193,5 @@
 	} \
 	free(instance); \
+	device->driver_data = NULL; \
 	usb_log_error(message); \
 	return ret; \
@@ -222,27 +224,35 @@
 	ret = pci_disable_legacy(device);
 	CHECK_RET_DEST_FREE_RETURN(ret,
-	    "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret));
+	    "Failed to disable legacy USB: %s.\n", str_error(ret));
+
+	const size_t cmd_count = hc_irq_cmd_count();
+	irq_cmd_t irq_cmds[cmd_count];
+	ret =
+	    hc_get_irq_commands(irq_cmds, sizeof(irq_cmds), reg_base, reg_size);
+	CHECK_RET_DEST_FREE_RETURN(ret,
+	    "Failed to generate IRQ commands: %s.\n", str_error(ret));
+
+	irq_code_t irq_code = { .cmdcount = cmd_count, .cmds = irq_cmds };
+
+        /* Register handler to avoid interrupt lockup */
+        ret = register_interrupt_handler(device, irq, irq_handler, &irq_code);
+        CHECK_RET_DEST_FREE_RETURN(ret,
+            "Failed to register interrupt handler: %s.\n", str_error(ret));
 
 	bool interrupts = false;
-#ifdef CONFIG_USBHC_NO_INTERRUPTS
-	usb_log_warning("Interrupts disabled in OS config, " \
-	    "falling back to polling.\n");
-#else
 	ret = pci_enable_interrupts(device);
 	if (ret != EOK) {
-		usb_log_warning("Failed to enable interrupts: %s.\n",
-		    str_error(ret));
-		usb_log_info("HW interrupts not available, " \
-		    "falling back to polling.\n");
+		usb_log_warning("Failed to enable interrupts: %s."
+		    " Falling back to polling.\n", str_error(ret));
 	} else {
 		usb_log_debug("Hw interrupts enabled.\n");
 		interrupts = true;
 	}
-#endif
-
 
 	ret = hc_init(&instance->hc, (void*)reg_base, reg_size, interrupts);
 	CHECK_RET_DEST_FREE_RETURN(ret,
-	    "Failed(%d) to init uhci_hcd: %s.\n", ret, str_error(ret));
+	    "Failed to init uhci_hcd: %s.\n", str_error(ret));
+
+	device->driver_data = instance;
 
 #define CHECK_RET_FINI_RETURN(ret, message...) \
@@ -253,15 +263,7 @@
 } else (void)0
 
-	/* It does no harm if we register this on polling */
-	ret = register_interrupt_handler(device, irq, irq_handler,
-	    &instance->hc.interrupt_code);
-	CHECK_RET_FINI_RETURN(ret,
-	    "Failed(%d) to register interrupt handler: %s.\n",
-	    ret, str_error(ret));
-
 	ret = ddf_fun_bind(instance->hc_fun);
-	CHECK_RET_FINI_RETURN(ret,
-	    "Failed(%d) to bind UHCI device function: %s.\n",
-	    ret, str_error(ret));
+	CHECK_RET_FINI_RETURN(ret, "Failed to bind UHCI device function: %s.\n",
+	    str_error(ret));
 
 	ret = ddf_fun_add_to_class(instance->hc_fun, USB_HC_DDF_CLASS_NAME);
@@ -272,11 +274,10 @@
 	    (uintptr_t)instance->hc.registers + 0x10, 4);
 	CHECK_RET_FINI_RETURN(ret,
-	    "Failed(%d) to setup UHCI root hub: %s.\n", ret, str_error(ret));
+	    "Failed to setup UHCI root hub: %s.\n", str_error(ret));
 
 	ret = ddf_fun_bind(instance->rh_fun);
 	CHECK_RET_FINI_RETURN(ret,
-	    "Failed(%d) to register UHCI root hub: %s.\n", ret, str_error(ret));
-
-	device->driver_data = instance;
+	    "Failed to register UHCI root hub: %s.\n", str_error(ret));
+
 	return EOK;
 #undef CHECK_RET_FINI_RETURN
Index: uspace/drv/bus/usb/usbhub/usbhub.c
===================================================================
--- uspace/drv/bus/usb/usbhub/usbhub.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/usbhub/usbhub.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -220,9 +220,9 @@
  * @return error code
  */
-static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info) {
+int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info)
+{
 	// get hub descriptor
-	usb_log_debug("Creating serialized descriptor\n");
+	usb_log_debug("Retrieving descriptor\n");
 	uint8_t serialized_descriptor[USB_HUB_MAX_DESCRIPTOR_SIZE];
-	usb_hub_descriptor_t * descriptor;
 	int opResult;
 
@@ -234,47 +234,53 @@
 
 	if (opResult != EOK) {
-		usb_log_error("Failed when receiving hub descriptor, "
-		    "%s\n",
-		    str_error(opResult));
-		free(serialized_descriptor);
+		usb_log_error("Failed to receive hub descriptor: %s.\n",
+		    str_error(opResult));
 		return opResult;
 	}
-	usb_log_debug2("Deserializing descriptor\n");
-	descriptor = usb_create_deserialized_hub_desriptor(
-	    serialized_descriptor);
-	if (descriptor == NULL) {
-		usb_log_warning("could not deserialize descriptor \n");
-		return ENOMEM;
-	}
-	usb_log_debug("setting port count to %d\n", descriptor->ports_count);
-	hub_info->port_count = descriptor->ports_count;
-	bool is_power_switched =
-	    ((descriptor->hub_characteristics & 1) == 0);
-	bool has_individual_port_powering =
-	    ((descriptor->hub_characteristics & 1) != 0);
-	hub_info->ports = malloc(
-	    sizeof (usb_hub_port_t) * (hub_info->port_count + 1));
+	usb_log_debug2("Parsing descriptor\n");
+	usb_hub_descriptor_t descriptor;
+	opResult = usb_deserialize_hub_desriptor(
+	        serialized_descriptor, received_size, &descriptor);
+	if (opResult != EOK) {
+		usb_log_error("Could not parse descriptor: %s\n",
+		    str_error(opResult));
+		return opResult;
+	}
+	usb_log_debug("Setting port count to %d.\n", descriptor.ports_count);
+	hub_info->port_count = descriptor.ports_count;
+
+	hub_info->ports =
+	    malloc(sizeof(usb_hub_port_t) * (hub_info->port_count + 1));
 	if (!hub_info->ports) {
 		return ENOMEM;
 	}
+
 	size_t port;
 	for (port = 0; port < hub_info->port_count + 1; ++port) {
 		usb_hub_port_init(&hub_info->ports[port]);
 	}
+
+	const bool is_power_switched =
+	    !(descriptor.hub_characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG);
 	if (is_power_switched) {
 		usb_log_debug("Hub power switched\n");
-
-		if (!has_individual_port_powering) {
-			//this setting actually makes no difference
-			usb_log_debug("Hub has global powering\n");
-		}
+		const bool per_port_power = descriptor.hub_characteristics
+		    & HUB_CHAR_POWER_PER_PORT_FLAG;
 
 		for (port = 1; port <= hub_info->port_count; ++port) {
 			usb_log_debug("Powering port %zu.\n", port);
-			opResult = usb_hub_set_port_feature(hub_info->control_pipe,
+			opResult = usb_hub_set_port_feature(
+			    hub_info->control_pipe,
 			    port, USB_HUB_FEATURE_PORT_POWER);
 			if (opResult != EOK) {
 				usb_log_error("Cannot power on port %zu: %s.\n",
 				    port, str_error(opResult));
+			} else {
+				if (!per_port_power) {
+					usb_log_debug(
+					    "Ganged power switching mode, "
+					    "one port is enough.\n");
+					break;
+				}
 			}
 		}
@@ -283,6 +289,4 @@
 		usb_log_debug("Power not switched, not going to be powered\n");
 	}
-	usb_log_debug2("Freeing data\n");
-	free(descriptor);
 	return EOK;
 }
Index: uspace/drv/bus/usb/usbhub/usbhub_private.h
===================================================================
--- uspace/drv/bus/usb/usbhub/usbhub_private.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/usbhub/usbhub_private.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -171,9 +171,6 @@
     void * serialized_descriptor);
 
-usb_hub_descriptor_t * usb_create_deserialized_hub_desriptor(
-    void * serialized_descriptor);
-
-void usb_deserialize_hub_desriptor(void * serialized_descriptor,
-    usb_hub_descriptor_t * descriptor);
+int usb_deserialize_hub_desriptor(
+    void *serialized_descriptor, size_t size, usb_hub_descriptor_t *descriptor);
 
 
Index: uspace/drv/bus/usb/usbhub/utils.c
===================================================================
--- uspace/drv/bus/usb/usbhub/utils.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/usbhub/utils.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -110,53 +110,45 @@
 }
 
+/*----------------------------------------------------------------------------*/
 /**
- * create deserialized desriptor structure out of serialized descriptor
+ * Deserialize descriptor into given pointer
  *
- * The serialized descriptor must be proper usb hub descriptor,
- * otherwise an eerror might occur.
- *
- * @param sdescriptor serialized descriptor
- * @return newly created deserialized descriptor pointer
- */
-usb_hub_descriptor_t * usb_create_deserialized_hub_desriptor(
-    void *serialized_descriptor) {
-	uint8_t * sdescriptor = serialized_descriptor;
-
-	if (sdescriptor[1] != USB_DESCTYPE_HUB) {
-		usb_log_warning("trying to deserialize wrong descriptor %x\n",
-		    sdescriptor[1]);
-		return NULL;
-	}
-
-	usb_hub_descriptor_t * result = malloc(sizeof (usb_hub_descriptor_t));
-	if (result)
-		usb_deserialize_hub_desriptor(serialized_descriptor, result);
-	return result;
-}
-
-/**
- * deserialize descriptor into given pointer
- * 
  * @param serialized_descriptor
  * @param descriptor
  * @return
  */
-void usb_deserialize_hub_desriptor(
-    void * serialized_descriptor, usb_hub_descriptor_t *descriptor) {
+int usb_deserialize_hub_desriptor(
+    void *serialized_descriptor, size_t size, usb_hub_descriptor_t *descriptor)
+{
 	uint8_t * sdescriptor = serialized_descriptor;
+
+	if (sdescriptor[1] != USB_DESCTYPE_HUB) {
+		usb_log_error("Trying to deserialize wrong descriptor %x\n",
+		    sdescriptor[1]);
+		return EINVAL;
+	}
+	if (size < 7) {
+		usb_log_error("Serialized descriptor too small.\n");
+		return EOVERFLOW;
+	}
+
 	descriptor->ports_count = sdescriptor[2];
-	/// @fixme handling of endianness??
-	descriptor->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3];
+	descriptor->hub_characteristics = sdescriptor[3] + 256 * sdescriptor[4];
 	descriptor->pwr_on_2_good_time = sdescriptor[5];
 	descriptor->current_requirement = sdescriptor[6];
-	size_t var_size = (descriptor->ports_count + 7) / 8;
+	const size_t var_size = (descriptor->ports_count + 7) / 8;
 	//descriptor->devices_removable = (uint8_t*) malloc(var_size);
 
-	size_t i;
-	for (i = 0; i < var_size; ++i) {
+	if (size < (7 + var_size)) {
+		usb_log_error("Serialized descriptor too small.\n");
+		return EOVERFLOW;
+	}
+	size_t i = 0;
+	for (; i < var_size; ++i) {
 		descriptor->devices_removable[i] = sdescriptor[7 + i];
 	}
+	return EOK;
 }
-
+/*----------------------------------------------------------------------------*/
 /**
  * @}
Index: uspace/drv/bus/usb/usbmast/Makefile
===================================================================
--- uspace/drv/bus/usb/usbmast/Makefile	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/usbmast/Makefile	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -44,7 +44,7 @@
 
 SOURCES = \
-	cmds.c \
+	bo_trans.c \
+	cmdw.c \
 	main.c \
-	mast.c \
 	scsi_ms.c
 
Index: uspace/drv/bus/usb/usbmast/bo_trans.c
===================================================================
--- uspace/drv/bus/usb/usbmast/bo_trans.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
+++ uspace/drv/bus/usb/usbmast/bo_trans.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -0,0 +1,286 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * USB mass storage bulk-only transport.
+ */
+#include <bool.h>
+#include <errno.h>
+#include <str_error.h>
+#include <usb/debug.h>
+#include <usb/dev/request.h>
+
+#include "bo_trans.h"
+#include "cmdw.h"
+#include "usbmast.h"
+
+bool usb_mast_verbose = false;
+
+#define MASTLOG(format, ...) \
+	do { \
+		if (usb_mast_verbose) { \
+			usb_log_debug2("USB cl08: " format, ##__VA_ARGS__); \
+		} \
+	} while (false)
+
+/** Send command via bulk-only transport.
+ *
+ * @param mfun		Mass storage function
+ * @param tag		Command block wrapper tag (automatically compared
+ *			with answer)
+ * @param cmd		Command block
+ * @param cmd_size	Command block size in bytes
+ * @param ddir		Direction in which data will be transferred
+ * @param dbuf		Data send/receive buffer
+ * @param dbuf_size	Size of the data buffer
+ * @param xferred_size	Number of bytes actually transferred
+ *
+ * @return		Error code
+ */
+static int usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, const void *cmd,
+    size_t cmd_size, usb_direction_t ddir, void *dbuf, size_t dbuf_size,
+    size_t *xferred_size)
+{
+	int rc;
+	size_t act_size;
+	usb_pipe_t *bulk_in_pipe = mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe;
+	usb_pipe_t *bulk_out_pipe = mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe;
+
+	/* Prepare CBW - command block wrapper */
+	usb_massstor_cbw_t cbw;
+	usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, mfun->lun,
+	    cmd_size, cmd);
+
+	/* Send the CBW. */
+	rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
+	MASTLOG("CBW '%s' sent: %s.\n",
+	    usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
+	    str_error(rc));
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if (ddir == USB_DIRECTION_IN) {
+		/* Recieve data from the device. */
+		rc = usb_pipe_read(bulk_in_pipe, dbuf, dbuf_size, &act_size);
+		MASTLOG("Received %zu bytes (%s): %s.\n", act_size,
+		    usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
+		    str_error(rc));
+	} else {
+		/* Send data to the device. */
+		rc = usb_pipe_write(bulk_out_pipe, dbuf, dbuf_size);
+		MASTLOG("Sent %zu bytes (%s): %s.\n", act_size,
+		    usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
+		    str_error(rc));
+	}
+
+	if (rc != EOK) {
+		/*
+		 * XXX If the pipe is stalled, we should clear it
+		 * and read CSW.
+		 */
+		return rc;
+	}
+
+	/* Read CSW. */
+	usb_massstor_csw_t csw;
+	size_t csw_size;
+	rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
+	MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
+	    usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
+	    str_error(rc));
+	if (rc != EOK) {
+		MASTLOG("rc != EOK\n");
+		return rc;
+	}
+
+	if (csw_size != sizeof(csw)) {
+		MASTLOG("csw_size != sizeof(csw)\n");
+		return ERANGE;
+	}
+
+	if (csw.dCSWTag != tag) {
+		MASTLOG("csw.dCSWTag != tag\n");
+		return EBADCHECKSUM;
+	}
+
+	/*
+	 * Determine the actual return value from the CSW.
+	 */
+	if (csw.dCSWStatus != 0) {
+		MASTLOG("csw.dCSWStatus != 0\n");
+		// FIXME: better error code
+		// FIXME: distinguish 0x01 and 0x02
+		return EXDEV;
+	}
+
+	size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
+	if (residue > dbuf_size) {
+		MASTLOG("residue > dbuf_size\n");
+		return ERANGE;
+	}
+
+	/*
+	 * When the device has less data to send than requested (or cannot
+	 * receive moredata), it can either stall the pipe or send garbage
+	 * (ignore data) and indicate that via the residue field in CSW.
+	 * That means dbuf_size - residue is the authoritative size of data
+	 * received (sent).
+	 */
+
+	if (xferred_size != NULL)
+		*xferred_size = dbuf_size - residue;
+
+	return EOK;
+}
+
+/** Perform data-in command.
+ *
+ * @param mfun		Mass storage function
+ * @param tag		Command block wrapper tag (automatically compared with
+ *			answer)
+ * @param cmd		CDB (Command Descriptor)
+ * @param cmd_size	CDB length in bytes
+ * @param dbuf		Data receive buffer
+ * @param dbuf_size	Data receive buffer size in bytes
+ * @param proc_size	Number of bytes actually processed by device
+ *
+ * @return Error code
+ */
+int usb_massstor_data_in(usbmast_fun_t *mfun, uint32_t tag, const void *cmd,
+    size_t cmd_size, void *dbuf, size_t dbuf_size, size_t *proc_size)
+{
+	return usb_massstor_cmd(mfun, tag, cmd, cmd_size, USB_DIRECTION_IN,
+	    dbuf, dbuf_size, proc_size);
+}
+
+/** Perform data-out command.
+ *
+ * @param mfun		Mass storage function
+ * @param tag		Command block wrapper tag (automatically compared with
+ *			answer)
+ * @param cmd		CDB (Command Descriptor)
+ * @param cmd_size	CDB length in bytes
+ * @param data		Command data
+ * @param data_size	Size of @a data in bytes
+ * @param proc_size	Number of bytes actually processed by device
+ *
+ * @return Error code
+ */
+int usb_massstor_data_out(usbmast_fun_t *mfun, uint32_t tag, const void *cmd,
+    size_t cmd_size, const void *data, size_t data_size, size_t *proc_size)
+{
+	return usb_massstor_cmd(mfun, tag, cmd, cmd_size, USB_DIRECTION_OUT,
+	    (void *) data, data_size, proc_size);
+}
+
+/** Perform bulk-only mass storage reset.
+ *
+ * @param mfun		Mass storage function
+ * @return		Error code
+ */
+int usb_massstor_reset(usbmast_dev_t *mdev)
+{
+	return usb_control_request_set(&mdev->usb_dev->ctrl_pipe,
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
+	    0xFF, 0, mdev->usb_dev->interface_no, NULL, 0);
+}
+
+/** Perform complete reset recovery of bulk-only mass storage.
+ *
+ * Notice that no error is reported because if this fails, the error
+ * would reappear on next transaction somehow.
+ *
+ * @param mfun		Mass storage function
+ */
+void usb_massstor_reset_recovery(usbmast_dev_t *mdev)
+{
+	/* We would ignore errors here because if this fails
+	 * we are doomed anyway and any following transaction would fail.
+	 */
+	usb_massstor_reset(mdev);
+	usb_pipe_clear_halt(&mdev->usb_dev->ctrl_pipe,
+	    mdev->usb_dev->pipes[BULK_IN_EP].pipe);
+	usb_pipe_clear_halt(&mdev->usb_dev->ctrl_pipe,
+	    mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
+}
+
+/** Get max LUN of a mass storage device.
+ *
+ * @see usb_masstor_get_lun_count
+ *
+ * @warning Error from this command does not necessarily indicate malfunction
+ * of the device. Device does not need to support this request.
+ * You shall rather use usb_masstor_get_lun_count.
+ *
+ * @param mfun		Mass storage function
+ * @return		Error code of maximum LUN (index, not count)
+ */
+int usb_massstor_get_max_lun(usbmast_dev_t *mdev)
+{
+	uint8_t max_lun;
+	size_t data_recv_len;
+	int rc = usb_control_request_get(&mdev->usb_dev->ctrl_pipe,
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
+	    0xFE, 0, mdev->usb_dev->interface_no, &max_lun, 1, &data_recv_len);
+	if (rc != EOK) {
+		return rc;
+	}
+	if (data_recv_len != 1) {
+		return EEMPTY;
+	}
+	return (int) max_lun;
+}
+
+/** Get number of LUNs supported by mass storage device.
+ *
+ * @warning This function hides any error during the request
+ * (typically that shall not be a problem).
+ *
+ * @param mfun		Mass storage function
+ * @return		Number of LUNs
+ */
+size_t usb_masstor_get_lun_count(usbmast_dev_t *mdev)
+{
+	int max_lun = usb_massstor_get_max_lun(mdev);
+	if (max_lun < 0) {
+		max_lun = 1;
+	} else {
+		max_lun++;
+	}
+
+	return (size_t) max_lun;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/usbmast/bo_trans.h
===================================================================
--- uspace/drv/bus/usb/usbmast/bo_trans.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
+++ uspace/drv/bus/usb/usbmast/bo_trans.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -0,0 +1,62 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * USB mass storage bulk-only transport.
+ */
+
+#ifndef BO_TRANS_H_
+#define BO_TRANS_H_
+
+#include <scsi/spc.h>
+#include <sys/types.h>
+#include <usb/usb.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/driver.h>
+#include "usbmast.h"
+
+#define BULK_IN_EP 0
+#define BULK_OUT_EP 1
+
+extern int usb_massstor_data_in(usbmast_fun_t *, uint32_t, const void *,
+    size_t, void *, size_t, size_t *);
+extern int usb_massstor_data_out(usbmast_fun_t *, uint32_t, const void *,
+    size_t, const void *, size_t, size_t *);
+extern int usb_massstor_reset(usbmast_dev_t *);
+extern void usb_massstor_reset_recovery(usbmast_dev_t *);
+extern int usb_massstor_get_max_lun(usbmast_dev_t *);
+extern size_t usb_masstor_get_lun_count(usbmast_dev_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: pace/drv/bus/usb/usbmast/cmds.c
===================================================================
--- uspace/drv/bus/usb/usbmast/cmds.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ 	(revision )
@@ -1,66 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbmast
- * @{
- */
-/** @file
- * USB mass storage commands.
- */
-
-#include <byteorder.h>
-#include <mem.h>
-#include <sys/types.h>
-#include <usb/usb.h>
-#include "cmds.h"
-
-void usb_massstor_cbw_prepare(usb_massstor_cbw_t *cbw,
-    uint32_t tag, uint32_t transfer_length, usb_direction_t dir,
-    uint8_t lun, uint8_t cmd_len, const uint8_t *cmd)
-{
-	cbw->dCBWSignature = uint32_host2usb(0x43425355);
-	cbw->dCBWTag = tag;
-	cbw->dCBWDataTransferLength = transfer_length;
-
-	cbw->bmCBWFlags = 0;
-	if (dir == USB_DIRECTION_IN) {
-		cbw->bmCBWFlags |= (1 << 7);
-	}
-
-	/* Only lowest 4 bits. */
-	cbw->bCBWLUN = lun & 0x0F;
-
-	/* Only lowest 5 bits. */
-	cbw->bCBWBLength = cmd_len & 0x1F;
-
-	memcpy(cbw->CBWCB, cmd, cbw->bCBWBLength);
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbmast/cmds.h
===================================================================
--- uspace/drv/bus/usb/usbmast/cmds.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ 	(revision )
@@ -1,66 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbmast
- * @{
- */
-/** @file
- * USB mass storage commands.
- */
-
-#ifndef USB_USBMAST_CMDS_H_
-#define USB_USBMAST_CMDS_H_
-
-#include <sys/types.h>
-#include <usb/usb.h>
-
-typedef struct {
-	uint32_t dCBWSignature;
-	uint32_t dCBWTag;
-	uint32_t dCBWDataTransferLength;
-	uint8_t bmCBWFlags;
-	uint8_t bCBWLUN;
-	uint8_t bCBWBLength;
-	uint8_t CBWCB[16];
-} __attribute__((packed)) usb_massstor_cbw_t;
-
-typedef struct {
-	uint32_t dCSWSignature;
-	uint32_t dCSWTag;
-	uint32_t dCSWDataResidue;
-	uint8_t dCSWStatus;
-} __attribute__((packed)) usb_massstor_csw_t;
-
-extern void usb_massstor_cbw_prepare(usb_massstor_cbw_t *, uint32_t, uint32_t,
-    usb_direction_t, uint8_t, uint8_t, const uint8_t *);
-
-#endif
-
-/**
- * @}
- */
Index: uspace/drv/bus/usb/usbmast/cmdw.c
===================================================================
--- uspace/drv/bus/usb/usbmast/cmdw.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
+++ uspace/drv/bus/usb/usbmast/cmdw.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -0,0 +1,66 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * USB mass storage commands.
+ */
+
+#include <byteorder.h>
+#include <mem.h>
+#include <sys/types.h>
+#include <usb/usb.h>
+#include "cmdw.h"
+
+void usb_massstor_cbw_prepare(usb_massstor_cbw_t *cbw,
+    uint32_t tag, uint32_t transfer_length, usb_direction_t dir,
+    uint8_t lun, uint8_t cmd_len, const uint8_t *cmd)
+{
+	cbw->dCBWSignature = uint32_host2usb(0x43425355);
+	cbw->dCBWTag = tag;
+	cbw->dCBWDataTransferLength = transfer_length;
+
+	cbw->bmCBWFlags = 0;
+	if (dir == USB_DIRECTION_IN) {
+		cbw->bmCBWFlags |= (1 << 7);
+	}
+
+	/* Only lowest 4 bits. */
+	cbw->bCBWLUN = lun & 0x0F;
+
+	/* Only lowest 5 bits. */
+	cbw->bCBWBLength = cmd_len & 0x1F;
+
+	memcpy(cbw->CBWCB, cmd, cbw->bCBWBLength);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/usbmast/cmdw.h
===================================================================
--- uspace/drv/bus/usb/usbmast/cmdw.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
+++ uspace/drv/bus/usb/usbmast/cmdw.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -0,0 +1,66 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * USB mass storage commands.
+ */
+
+#ifndef CMDW_H_
+#define CMDW_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+
+typedef struct {
+	uint32_t dCBWSignature;
+	uint32_t dCBWTag;
+	uint32_t dCBWDataTransferLength;
+	uint8_t bmCBWFlags;
+	uint8_t bCBWLUN;
+	uint8_t bCBWBLength;
+	uint8_t CBWCB[16];
+} __attribute__((packed)) usb_massstor_cbw_t;
+
+typedef struct {
+	uint32_t dCSWSignature;
+	uint32_t dCSWTag;
+	uint32_t dCSWDataResidue;
+	uint8_t dCSWStatus;
+} __attribute__((packed)) usb_massstor_csw_t;
+
+extern void usb_massstor_cbw_prepare(usb_massstor_cbw_t *, uint32_t, uint32_t,
+    usb_direction_t, uint8_t, uint8_t, const uint8_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/usbmast/main.c
===================================================================
--- uspace/drv/bus/usb/usbmast/main.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/usbmast/main.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -45,7 +45,8 @@
 #include <errno.h>
 #include <str_error.h>
-#include "cmds.h"
-#include "mast.h"
+#include "cmdw.h"
+#include "bo_trans.h"
 #include "scsi_ms.h"
+#include "usbmast.h"
 
 #define NAME "usbmast"
@@ -77,19 +78,5 @@
 };
 
-/** Mass storage function.
- *
- * Serves as soft state for function/LUN.
- */
-typedef struct {
-	/** DDF function */
-	ddf_fun_t *ddf_fun;
-	/** Total number of blocks. */
-	uint64_t nblocks;
-	/** Block size in bytes. */
-	size_t block_size;
-	/** USB device function belongs to */
-	usb_device_t *usb_dev;
-} usbmast_fun_t;
-
+static int usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun);
 static void usbmast_bd_connection(ipc_callid_t iid, ipc_call_t *icall,
     void *arg);
@@ -103,11 +90,10 @@
 {
 	int rc;
-	const char *fun_name = "a";
-	ddf_fun_t *fun = NULL;
-	usbmast_fun_t *msfun = NULL;
+	usbmast_dev_t *mdev = NULL;
+	unsigned i;
 
 	/* Allocate softstate */
-	msfun = calloc(1, sizeof(usbmast_fun_t));
-	if (msfun == NULL) {
+	mdev = calloc(1, sizeof(usbmast_dev_t));
+	if (mdev == NULL) {
 		usb_log_error("Failed allocating softstate.\n");
 		rc = ENOMEM;
@@ -115,14 +101,6 @@
 	}
 
-	fun = ddf_fun_create(dev->ddf_dev, fun_exposed, fun_name);
-	if (fun == NULL) {
-		usb_log_error("Failed to create DDF function %s.\n", fun_name);
-		rc = ENOMEM;
-		goto error;
-	}
-
-	/* Set up a connection handler. */
-	fun->conn_handler = usbmast_bd_connection;
-	fun->driver_data = msfun;
+	mdev->ddf_dev = dev->ddf_dev;
+	mdev->usb_dev = dev;
 
 	usb_log_info("Initializing mass storage `%s'.\n",
@@ -136,38 +114,92 @@
 
 	usb_log_debug("Get LUN count...\n");
-	size_t lun_count = usb_masstor_get_lun_count(dev);
-
-	/* XXX Handle more than one LUN properly. */
-	if (lun_count > 1) {
-		usb_log_warning ("Mass storage has %zu LUNs. Ignoring all "
-		    "but first.\n", lun_count);
-	}
+	mdev->luns = usb_masstor_get_lun_count(mdev);
+
+	for (i = 0; i < mdev->luns; i++) {
+		rc = usbmast_fun_create(mdev, i);
+		if (rc != EOK)
+			goto error;
+	}
+
+	return EOK;
+error:
+	/* XXX Destroy functions */
+	if (mdev != NULL)
+		free(mdev);
+	return rc;
+}
+
+/** Create mass storage function.
+ *
+ * Called once for each LUN.
+ *
+ * @param mdev		Mass storage device
+ * @param lun		LUN
+ * @return		EOK on success or negative error code.
+ */
+static int usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun)
+{
+	int rc;
+	char *fun_name = NULL;
+	ddf_fun_t *fun = NULL;
+	usbmast_fun_t *mfun = NULL;
+
+	/* Allocate softstate */
+	mfun = calloc(1, sizeof(usbmast_fun_t));
+	if (mfun == NULL) {
+		usb_log_error("Failed allocating softstate.\n");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	mfun->mdev = mdev;
+	mfun->lun = lun;
+
+	if (asprintf(&fun_name, "l%u", lun) < 0) {
+		usb_log_error("Out of memory.\n");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	fun = ddf_fun_create(mdev->ddf_dev, fun_exposed, fun_name);
+	if (fun == NULL) {
+		usb_log_error("Failed to create DDF function %s.\n", fun_name);
+		rc = ENOMEM;
+		goto error;
+	}
+
+	free(fun_name);
+	fun_name = NULL;
+
+	/* Set up a connection handler. */
+	fun->conn_handler = usbmast_bd_connection;
+	fun->driver_data = mfun;
 
 	usb_log_debug("Inquire...\n");
 	usbmast_inquiry_data_t inquiry;
-	rc = usbmast_inquiry(dev, &inquiry);
+	rc = usbmast_inquiry(mfun, &inquiry);
 	if (rc != EOK) {
 		usb_log_warning("Failed to inquire device `%s': %s.\n",
-		    dev->ddf_dev->name, str_error(rc));
+		    mdev->ddf_dev->name, str_error(rc));
 		rc = EIO;
 		goto error;
 	}
 
-	usb_log_info("Mass storage `%s': " \
-	    "%s by %s rev. %s is %s (%s), %zu LUN(s).\n",
-	    dev->ddf_dev->name,
+	usb_log_info("Mass storage `%s' LUN %u: " \
+	    "%s by %s rev. %s is %s (%s).\n",
+	    mdev->ddf_dev->name,
+	    lun,
 	    inquiry.product,
 	    inquiry.vendor,
 	    inquiry.revision,
 	    usbmast_scsi_dev_type_str(inquiry.device_type),
-	    inquiry.removable ? "removable" : "non-removable",
-	    lun_count);
+	    inquiry.removable ? "removable" : "non-removable");
 
 	uint32_t nblocks, block_size;
 
-	rc = usbmast_read_capacity(dev, &nblocks, &block_size);
+	rc = usbmast_read_capacity(mfun, &nblocks, &block_size);
 	if (rc != EOK) {
 		usb_log_warning("Failed to read capacity, device `%s': %s.\n",
-		    dev->ddf_dev->name, str_error(rc));
+		    mdev->ddf_dev->name, str_error(rc));
 		rc = EIO;
 		goto error;
@@ -177,7 +209,6 @@
 	    "block_size=%" PRIu32 "\n", nblocks, block_size);
 
-	msfun->nblocks = nblocks;
-	msfun->block_size = block_size;
-	msfun->usb_dev = dev;
+	mfun->nblocks = nblocks;
+	mfun->block_size = block_size;
 
 	rc = ddf_fun_bind(fun);
@@ -194,6 +225,8 @@
 	if (fun != NULL)
 		ddf_fun_destroy(fun);
-	if (msfun != NULL)
-		free(msfun);
+	if (fun_name != NULL)
+		free(fun_name);
+	if (mfun != NULL)
+		free(mfun);
 	return rc;
 }
@@ -203,5 +236,5 @@
     void *arg)
 {
-	usbmast_fun_t *msfun;
+	usbmast_fun_t *mfun;
 	void *comm_buf = NULL;
 	size_t comm_size;
@@ -229,5 +262,5 @@
 	(void) async_share_out_finalize(callid, comm_buf);
 
-	msfun = (usbmast_fun_t *) ((ddf_fun_t *)arg)->driver_data;
+	mfun = (usbmast_fun_t *) ((ddf_fun_t *)arg)->driver_data;
 
 	while (true) {
@@ -243,15 +276,14 @@
 		switch (method) {
 		case BD_GET_BLOCK_SIZE:
-			async_answer_1(callid, EOK, msfun->block_size);
+			async_answer_1(callid, EOK, mfun->block_size);
 			break;
 		case BD_GET_NUM_BLOCKS:
-			async_answer_2(callid, EOK, LOWER32(msfun->nblocks),
-			    UPPER32(msfun->nblocks));
+			async_answer_2(callid, EOK, LOWER32(mfun->nblocks),
+			    UPPER32(mfun->nblocks));
 			break;
 		case BD_READ_BLOCKS:
 			ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
 			cnt = IPC_GET_ARG3(call);
-			retval = usbmast_read(msfun->usb_dev, ba, cnt,
-			    msfun->block_size, comm_buf);
+			retval = usbmast_read(mfun, ba, cnt, comm_buf);
 			async_answer_0(callid, retval);
 			break;
@@ -259,6 +291,5 @@
 			ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
 			cnt = IPC_GET_ARG3(call);
-			retval = usbmast_write(msfun->usb_dev, ba, cnt,
-			    msfun->block_size, comm_buf);
+			retval = usbmast_write(mfun, ba, cnt, comm_buf);
 			async_answer_0(callid, retval);
 			break;
Index: pace/drv/bus/usb/usbmast/mast.c
===================================================================
--- uspace/drv/bus/usb/usbmast/mast.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ 	(revision )
@@ -1,283 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbmast
- * @{
- */
-/**
- * @file
- * Generic functions for USB mass storage (implementation).
- */
-#include "mast.h"
-#include "cmds.h"
-#include <bool.h>
-#include <errno.h>
-#include <str_error.h>
-#include <usb/debug.h>
-#include <usb/dev/request.h>
-
-bool usb_mast_verbose = false;
-
-#define MASTLOG(format, ...) \
-	do { \
-		if (usb_mast_verbose) { \
-			usb_log_debug2("USB cl08: " format, ##__VA_ARGS__); \
-		} \
-	} while (false)
-
-/** Send command via bulk-only transport.
- *
- * @param tag		Command block wrapper tag (automatically compared
- *			with answer)
- * @param lun		LUN
- * @param cmd		Command block
- * @param cmd_size	Command block size in bytes
- * @param ddir		Direction in which data will be transferred
- * @param dbuf		Data send/receive buffer
- * @param dbuf_size	Size of the data buffer
- * @param xferred_size	Number of bytes actually transferred
- *
- * @return		Error code
- */
-static int usb_massstor_cmd(usb_device_t *dev, uint32_t tag, uint8_t lun,
-    const void *cmd, size_t cmd_size, usb_direction_t ddir, void *dbuf,
-    size_t dbuf_size, size_t *xferred_size)
-{
-	int rc;
-	size_t act_size;
-	usb_pipe_t *bulk_in_pipe = dev->pipes[BULK_IN_EP].pipe;
-	usb_pipe_t *bulk_out_pipe = dev->pipes[BULK_OUT_EP].pipe;
-
-	/* Prepare CBW - command block wrapper */
-	usb_massstor_cbw_t cbw;
-	usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, lun, cmd_size,
-	    cmd);
-
-	/* Send the CBW. */
-	rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
-	MASTLOG("CBW '%s' sent: %s.\n",
-	    usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
-	    str_error(rc));
-	if (rc != EOK) {
-		return rc;
-	}
-
-	if (ddir == USB_DIRECTION_IN) {
-		/* Recieve data from the device. */
-		rc = usb_pipe_read(bulk_in_pipe, dbuf, dbuf_size, &act_size);
-		MASTLOG("Received %zu bytes (%s): %s.\n", act_size,
-		    usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
-		    str_error(rc));
-	} else {
-		/* Send data to the device. */
-		rc = usb_pipe_write(bulk_out_pipe, dbuf, dbuf_size);
-		MASTLOG("Sent %zu bytes (%s): %s.\n", act_size,
-		    usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
-		    str_error(rc));
-	}
-
-	if (rc != EOK) {
-		/*
-		 * XXX If the pipe is stalled, we should clear it
-		 * and read CSW.
-		 */
-		return rc;
-	}
-
-	/* Read CSW. */
-	usb_massstor_csw_t csw;
-	size_t csw_size;
-	rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
-	MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
-	    usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
-	    str_error(rc));
-	if (rc != EOK) {
-		MASTLOG("rc != EOK\n");
-		return rc;
-	}
-
-	if (csw_size != sizeof(csw)) {
-		MASTLOG("csw_size != sizeof(csw)\n");
-		return ERANGE;
-	}
-
-	if (csw.dCSWTag != tag) {
-		MASTLOG("csw.dCSWTag != tag\n");
-		return EBADCHECKSUM;
-	}
-
-	/*
-	 * Determine the actual return value from the CSW.
-	 */
-	if (csw.dCSWStatus != 0) {
-		MASTLOG("csw.dCSWStatus != 0\n");
-		// FIXME: better error code
-		// FIXME: distinguish 0x01 and 0x02
-		return EXDEV;
-	}
-
-	size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
-	if (residue > dbuf_size) {
-		MASTLOG("residue > dbuf_size\n");
-		return ERANGE;
-	}
-
-	/*
-	 * When the device has less data to send than requested (or cannot
-	 * receive moredata), it can either stall the pipe or send garbage
-	 * (ignore data) and indicate that via the residue field in CSW.
-	 * That means dbuf_size - residue is the authoritative size of data
-	 * received (sent).
-	 */
-
-	if (xferred_size != NULL)
-		*xferred_size = dbuf_size - residue;
-
-	return EOK;
-}
-
-/** Perform data-in command.
- *
- * @param tag		Command block wrapper tag (automatically compared with
- *			answer)
- * @param lun		LUN
- * @param cmd		CDB (Command Descriptor)
- * @param cmd_size	CDB length in bytes
- * @param dbuf		Data receive buffer
- * @param dbuf_size	Data receive buffer size in bytes
- * @param proc_size	Number of bytes actually processed by device
- *
- * @return Error code
- */
-int usb_massstor_data_in(usb_device_t *dev, uint32_t tag, uint8_t lun,
-    const void *cmd, size_t cmd_size, void *dbuf, size_t dbuf_size, size_t *proc_size)
-{
-	return usb_massstor_cmd(dev, tag, lun, cmd, cmd_size, USB_DIRECTION_IN,
-	    dbuf, dbuf_size, proc_size);
-}
-
-/** Perform data-out command.
- *
- * @param tag		Command block wrapper tag (automatically compared with
- *			answer)
- * @param lun		LUN
- * @param cmd		CDB (Command Descriptor)
- * @param cmd_size	CDB length in bytes
- * @param data		Command data
- * @param data_size	Size of @a data in bytes
- * @param proc_size	Number of bytes actually processed by device
- *
- * @return Error code
- */
-int usb_massstor_data_out(usb_device_t *dev, uint32_t tag, uint8_t lun,
-    const void *cmd, size_t cmd_size, const void *data, size_t data_size,
-    size_t *proc_size)
-{
-	return usb_massstor_cmd(dev, tag, lun, cmd, cmd_size, USB_DIRECTION_OUT,
-	    (void *) data, data_size, proc_size);
-}
-
-/** Perform bulk-only mass storage reset.
- *
- * @param dev Device to be reseted.
- * @return Error code.
- */
-int usb_massstor_reset(usb_device_t *dev)
-{
-	return usb_control_request_set(&dev->ctrl_pipe,
-	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
-	    0xFF, 0, dev->interface_no, NULL, 0);
-}
-
-/** Perform complete reset recovery of bulk-only mass storage.
- *
- * Notice that no error is reported because if this fails, the error
- * would reappear on next transaction somehow.
- *
- * @param dev Device to be reseted.
- */
-void usb_massstor_reset_recovery(usb_device_t *dev)
-{
-	/* We would ignore errors here because if this fails
-	 * we are doomed anyway and any following transaction would fail.
-	 */
-	usb_massstor_reset(dev);
-	usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[BULK_IN_EP].pipe);
-	usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[BULK_OUT_EP].pipe);
-}
-
-/** Get max LUN of a mass storage device.
- *
- * @see usb_masstor_get_lun_count
- *
- * @warning Error from this command does not necessarily indicate malfunction
- * of the device. Device does not need to support this request.
- * You shall rather use usb_masstor_get_lun_count.
- *
- * @param dev Mass storage device.
- * @return Error code of maximum LUN (index, not count).
- */
-int usb_massstor_get_max_lun(usb_device_t *dev)
-{
-	uint8_t max_lun;
-	size_t data_recv_len;
-	int rc = usb_control_request_get(&dev->ctrl_pipe,
-	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
-	    0xFE, 0, dev->interface_no, &max_lun, 1, &data_recv_len);
-	if (rc != EOK) {
-		return rc;
-	}
-	if (data_recv_len != 1) {
-		return EEMPTY;
-	}
-	return (int) max_lun;
-}
-
-/** Get number of LUNs supported by mass storage device.
- *
- * @warning This function hides any error during the request
- * (typically that shall not be a problem).
- *
- * @param dev Mass storage device.
- * @return Number of LUNs.
- */
-size_t usb_masstor_get_lun_count(usb_device_t *dev)
-{
-	int max_lun = usb_massstor_get_max_lun(dev);
-	if (max_lun < 0) {
-		max_lun = 1;
-	} else {
-		max_lun++;
-	}
-
-	return (size_t) max_lun;
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbmast/mast.h
===================================================================
--- uspace/drv/bus/usb/usbmast/mast.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ 	(revision )
@@ -1,61 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbmast
- * @{
- */
-/** @file
- * Generic functions for USB mass storage.
- */
-
-#ifndef USB_USBMAST_MAST_H_
-#define USB_USBMAST_MAST_H_
-
-#include <scsi/spc.h>
-#include <sys/types.h>
-#include <usb/usb.h>
-#include <usb/dev/pipes.h>
-#include <usb/dev/driver.h>
-
-#define BULK_IN_EP 0
-#define BULK_OUT_EP 1
-
-extern int usb_massstor_data_in(usb_device_t *, uint32_t, uint8_t, const void *,
-    size_t, void *, size_t, size_t *);
-extern int usb_massstor_data_out(usb_device_t *, uint32_t, uint8_t, const void *,
-    size_t, const void *, size_t, size_t *);
-extern int usb_massstor_reset(usb_device_t *);
-extern void usb_massstor_reset_recovery(usb_device_t *);
-extern int usb_massstor_get_max_lun(usb_device_t *);
-extern size_t usb_masstor_get_lun_count(usb_device_t *);
-
-#endif
-
-/**
- * @}
- */
Index: uspace/drv/bus/usb/usbmast/scsi_ms.c
===================================================================
--- uspace/drv/bus/usb/usbmast/scsi_ms.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/usbmast/scsi_ms.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -46,7 +46,8 @@
 #include <scsi/sbc.h>
 #include <scsi/spc.h>
-#include "cmds.h"
-#include "mast.h"
+#include "cmdw.h"
+#include "bo_trans.h"
 #include "scsi_ms.h"
+#include "usbmast.h"
 
 /** Get string representation for SCSI peripheral device type.
@@ -62,9 +63,9 @@
 /** Perform SCSI Inquiry command on USB mass storage device.
  *
- * @param dev		USB device.
- * @param inquiry_result Where to store parsed inquiry result.
- * @return		Error code.
- */
-int usbmast_inquiry(usb_device_t *dev, usbmast_inquiry_data_t *inq_res)
+ * @param mfun		Mass storage function
+ * @param inquiry_result Where to store parsed inquiry result
+ * @return		Error code
+ */
+int usbmast_inquiry(usbmast_fun_t *mfun, usbmast_inquiry_data_t *inq_res)
 {
 	scsi_std_inquiry_data_t inq_data;
@@ -77,10 +78,10 @@
 	cdb.alloc_len = host2uint16_t_be(sizeof(inq_data));
 
-	rc = usb_massstor_data_in(dev, 0xDEADBEEF, 0, (uint8_t *) &cdb,
+	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
 	    sizeof(cdb), &inq_data, sizeof(inq_data), &response_len);
 
 	if (rc != EOK) {
 		usb_log_error("Inquiry failed, device %s: %s.\n",
-		   dev->ddf_dev->name, str_error(rc));
+		   mfun->mdev->ddf_dev->name, str_error(rc));
 		return rc;
 	}
@@ -118,5 +119,5 @@
 /** Perform SCSI Request Sense command on USB mass storage device.
  *
- * @param dev		USB device
+ * @param mfun		Mass storage function
  * @param buf		Destination buffer
  * @param size		Size of @a buf
@@ -124,5 +125,5 @@
  * @return		Error code.
  */
-int usbmast_request_sense(usb_device_t *dev, void *buf, size_t size)
+int usbmast_request_sense(usbmast_fun_t *mfun, void *buf, size_t size)
 {
 	scsi_cdb_request_sense_t cdb;
@@ -134,10 +135,10 @@
 	cdb.alloc_len = min(size, SCSI_SENSE_DATA_MAX_SIZE);
 
-	rc = usb_massstor_data_in(dev, 0xDEADBEEF, 0, (uint8_t *) &cdb,
+	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
 	    sizeof(cdb), buf, size, &data_len);
 
         if (rc != EOK) {
 		usb_log_error("Request Sense failed, device %s: %s.\n",
-		   dev->ddf_dev->name, str_error(rc));
+		   mfun->mdev->ddf_dev->name, str_error(rc));
 		return rc;
 	}
@@ -154,11 +155,11 @@
 /** Perform SCSI Read Capacity command on USB mass storage device.
  *
- * @param dev		USB device.
- * @param nblocks	Output, number of blocks.
- * @param block_size	Output, block size in bytes.
+ * @param mfun		Mass storage function
+ * @param nblocks	Output, number of blocks
+ * @param block_size	Output, block size in bytes
  *
  * @return		Error code.
  */
-int usbmast_read_capacity(usb_device_t *dev, uint32_t *nblocks,
+int usbmast_read_capacity(usbmast_fun_t *mfun, uint32_t *nblocks,
     uint32_t *block_size)
 {
@@ -171,10 +172,10 @@
 	cdb.op_code = SCSI_CMD_READ_CAPACITY_10;
 
-	rc = usb_massstor_data_in(dev, 0xDEADBEEF, 0, (uint8_t *) &cdb,
+	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
 	    sizeof(cdb), &data, sizeof(data), &data_len);
 
         if (rc != EOK) {
 		usb_log_error("Read Capacity (10) failed, device %s: %s.\n",
-		   dev->ddf_dev->name, str_error(rc));
+		   mfun->mdev->ddf_dev->name, str_error(rc));
 		return rc;
 	}
@@ -194,13 +195,11 @@
 /** Perform SCSI Read command on USB mass storage device.
  *
- * @param dev		USB device.
- * @param ba		Address of first block.
- * @param nblocks	Number of blocks to read.
- * @param bsize		Block size.
- *
- * @return		Error code.
- */
-int usbmast_read(usb_device_t *dev, uint64_t ba, size_t nblocks, size_t bsize,
-    void *buf)
+ * @param mfun		Mass storage function
+ * @param ba		Address of first block
+ * @param nblocks	Number of blocks to read
+ *
+ * @return		Error code
+ */
+int usbmast_read(usbmast_fun_t *mfun, uint64_t ba, size_t nblocks, void *buf)
 {
 	scsi_cdb_read_12_t cdb;
@@ -213,5 +212,5 @@
 		return ELIMIT;
 
-	if ((uint64_t)nblocks * bsize > UINT32_MAX)
+	if ((uint64_t)nblocks * mfun->block_size > UINT32_MAX)
 		return ELIMIT;
 
@@ -221,14 +220,14 @@
 	cdb.xfer_len = host2uint32_t_be(nblocks);
 
-	rc = usb_massstor_data_in(dev, 0xDEADBEEF, 0, (uint8_t *) &cdb,
-	    sizeof(cdb), buf, nblocks * bsize, &data_len);
+	rc = usb_massstor_data_in(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
+	    sizeof(cdb), buf, nblocks * mfun->block_size, &data_len);
 
         if (rc != EOK) {
 		usb_log_error("Read (12) failed, device %s: %s.\n",
-		   dev->ddf_dev->name, str_error(rc));
-		return rc;
-	}
-
-	if (data_len < nblocks * bsize) {
+		   mfun->mdev->ddf_dev->name, str_error(rc));
+		return rc;
+	}
+
+	if (data_len < nblocks * mfun->block_size) {
 		usb_log_error("SCSI Read response too short (%zu).\n",
 		    data_len);
@@ -241,13 +240,12 @@
 /** Perform SCSI Write command on USB mass storage device.
  *
- * @param dev		USB device
+ * @param mfun		Mass storage function
  * @param ba		Address of first block
  * @param nblocks	Number of blocks to read
- * @param bsize		Block size
  * @param data		Data to write
  *
  * @return		Error code
  */
-int usbmast_write(usb_device_t *dev, uint64_t ba, size_t nblocks, size_t bsize,
+int usbmast_write(usbmast_fun_t *mfun, uint64_t ba, size_t nblocks,
     const void *data)
 {
@@ -256,10 +254,8 @@
 	int rc;
 
-	/* XXX Need softstate to store block size. */
-
 	if (ba > UINT32_MAX)
 		return ELIMIT;
 
-	if ((uint64_t)nblocks * bsize > UINT32_MAX)
+	if ((uint64_t)nblocks * mfun->block_size > UINT32_MAX)
 		return ELIMIT;
 
@@ -269,14 +265,14 @@
 	cdb.xfer_len = host2uint32_t_be(nblocks);
 
-	rc = usb_massstor_data_out(dev, 0xDEADBEEF, 0, (uint8_t *) &cdb,
-	    sizeof(cdb), data, nblocks * bsize, &sent_len);
+	rc = usb_massstor_data_out(mfun, 0xDEADBEEF, (uint8_t *) &cdb,
+	    sizeof(cdb), data, nblocks * mfun->block_size, &sent_len);
 
         if (rc != EOK) {
 		usb_log_error("Write (12) failed, device %s: %s.\n",
-		   dev->ddf_dev->name, str_error(rc));
-		return rc;
-	}
-
-	if (sent_len < nblocks * bsize) {
+		   mfun->mdev->ddf_dev->name, str_error(rc));
+		return rc;
+	}
+
+	if (sent_len < nblocks * mfun->block_size) {
 		usb_log_error("SCSI Write not all bytes transferred (%zu).\n",
 		    sent_len);
Index: uspace/drv/bus/usb/usbmast/scsi_ms.h
===================================================================
--- uspace/drv/bus/usb/usbmast/scsi_ms.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/usbmast/scsi_ms.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -59,10 +59,9 @@
 } usbmast_inquiry_data_t;
 
-extern int usbmast_inquiry(usb_device_t *, usbmast_inquiry_data_t *);
-extern int usbmast_request_sense(usb_device_t *, void *, size_t);
-extern int usbmast_read_capacity(usb_device_t *, uint32_t *, uint32_t *);
-extern int usbmast_read(usb_device_t *, uint64_t, size_t, size_t, void *);
-extern int usbmast_write(usb_device_t *, uint64_t, size_t, size_t,
-    const void *);
+extern int usbmast_inquiry(usbmast_fun_t *, usbmast_inquiry_data_t *);
+extern int usbmast_request_sense(usbmast_fun_t *, void *, size_t);
+extern int usbmast_read_capacity(usbmast_fun_t *, uint32_t *, uint32_t *);
+extern int usbmast_read(usbmast_fun_t *, uint64_t, size_t, void *);
+extern int usbmast_write(usbmast_fun_t *, uint64_t, size_t, const void *);
 extern const char *usbmast_scsi_dev_type_str(unsigned);
 
Index: uspace/drv/bus/usb/usbmast/usbmast.h
===================================================================
--- uspace/drv/bus/usb/usbmast/usbmast.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
+++ uspace/drv/bus/usb/usbmast/usbmast.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup drvusbmast
+ * @{
+ */
+/** @file
+ * USB mass storage commands.
+ */
+
+#ifndef USBMAST_H_
+#define USBMAST_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+
+/** Mass storage device. */
+typedef struct {
+	/** DDF device */
+	ddf_dev_t *ddf_dev;
+	/** USB device */
+	usb_device_t *usb_dev;
+	/** Number of LUNs */
+	unsigned luns;
+} usbmast_dev_t;
+
+/** Mass storage function.
+ *
+ * Serves as soft state for function/LUN.
+ */
+typedef struct {
+	/** Mass storage device the function belongs to */
+	usbmast_dev_t *mdev;
+	/** DDF function */
+	ddf_fun_t *ddf_fun;
+	/** LUN */
+	unsigned lun;
+	/** Total number of blocks */
+	uint64_t nblocks;
+	/** Block size in bytes */
+	size_t block_size;
+} usbmast_fun_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/vhc/connhost.c
===================================================================
--- uspace/drv/bus/usb/vhc/connhost.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/bus/usb/vhc/connhost.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -141,19 +141,14 @@
     size_t max_packet_size, unsigned int interval)
 {
-	VHC_DATA(vhc, fun);
-
-	endpoint_t *ep = malloc(sizeof(endpoint_t));
+	/* TODO: Use usb_endpoint_manager_add_ep */
+	VHC_DATA(vhc, fun);
+
+	endpoint_t *ep = endpoint_get(
+	    address, endpoint, direction, transfer_type, USB_SPEED_FULL, 1);
 	if (ep == NULL) {
 		return ENOMEM;
 	}
 
-	int rc = endpoint_init(ep, address, endpoint, direction, transfer_type,
-	    USB_SPEED_FULL, 1);
-	if (rc != EOK) {
-		free(ep);
-		return rc;
-	}
-
-	rc = usb_endpoint_manager_register_ep(&vhc->ep_manager, ep, 1);
+	int rc = usb_endpoint_manager_register_ep(&vhc->ep_manager, ep, 1);
 	if (rc != EOK) {
 		endpoint_destroy(ep);
Index: uspace/drv/infrastructure/root/root.c
===================================================================
--- uspace/drv/infrastructure/root/root.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/infrastructure/root/root.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -176,4 +176,6 @@
 	}
 
+	free(match_id);
+
 	rc = ddf_fun_bind(fun);
 	if (rc != EOK) {
Index: uspace/drv/test/test1/test1.c
===================================================================
--- uspace/drv/test/test1/test1.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/drv/test/test1/test1.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -74,5 +74,5 @@
 	}
 
-	rc = ddf_fun_add_match_id(fun, str_dup(match_id), match_score);
+	rc = ddf_fun_add_match_id(fun, match_id, match_score);
 	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed adding match IDs to function %s",
Index: uspace/lib/c/generic/io/io.c
===================================================================
--- uspace/lib/c/generic/io/io.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/c/generic/io/io.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -714,4 +714,5 @@
 off64_t ftell(FILE *stream)
 {
+	_fflushbuf(stream);
 	return lseek(stream->fd, 0, SEEK_CUR);
 }
Index: uspace/lib/clui/tinput.c
===================================================================
--- uspace/lib/clui/tinput.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/clui/tinput.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -27,4 +27,5 @@
  */
 
+#include <sort.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -42,4 +43,7 @@
 #include <tinput.h>
 
+#define LIN_TO_COL(ti, lpos) ((lpos) % ((ti)->con_cols))
+#define LIN_TO_ROW(ti, lpos) ((lpos) / ((ti)->con_cols))
+
 /** Seek direction */
 typedef enum {
@@ -61,4 +65,10 @@
 static void tinput_post_seek(tinput_t *, bool);
 
+static void tinput_console_set_lpos(tinput_t *ti, unsigned lpos)
+{
+	console_set_pos(ti->console, LIN_TO_COL(ti, lpos),
+	    LIN_TO_ROW(ti, lpos));
+}
+
 /** Create a new text input field. */
 tinput_t *tinput_new(void)
@@ -66,5 +76,5 @@
 	tinput_t *ti;
 	
-	ti = malloc(sizeof(tinput_t));
+	ti = calloc(1, sizeof(tinput_t));
 	if (ti == NULL)
 		return NULL;
@@ -77,5 +87,17 @@
 void tinput_destroy(tinput_t *ti)
 {
+	if (ti->prompt != NULL)
+		free(ti->prompt);
 	free(ti);
+}
+
+static void tinput_display_prompt(tinput_t *ti)
+{
+	tinput_console_set_lpos(ti, ti->prompt_coord);
+
+	console_set_style(ti->console, STYLE_EMPHASIS);
+	printf("%s", ti->prompt);
+	console_flush(ti->console);
+	console_set_style(ti->console, STYLE_NORMAL);
 }
 
@@ -88,6 +110,5 @@
 	tinput_sel_get_bounds(ti, &sa, &sb);
 	
-	console_set_pos(ti->console, (ti->col0 + start) % ti->con_cols,
-	    ti->row0 + (ti->col0 + start) / ti->con_cols);
+	tinput_console_set_lpos(ti, ti->text_coord + start);
 	console_set_style(ti->console, STYLE_NORMAL);
 	
@@ -134,17 +155,45 @@
 static void tinput_position_caret(tinput_t *ti)
 {
-	console_set_pos(ti->console, (ti->col0 + ti->pos) % ti->con_cols,
-	    ti->row0 + (ti->col0 + ti->pos) / ti->con_cols);
-}
-
-/** Update row0 in case the screen could have scrolled. */
+	tinput_console_set_lpos(ti, ti->text_coord + ti->pos);
+}
+
+/** Update text_coord, prompt_coord in case the screen could have scrolled. */
 static void tinput_update_origin(tinput_t *ti)
 {
-	sysarg_t width = ti->col0 + ti->nc;
-	sysarg_t rows = (width / ti->con_cols) + 1;
-	
-	/* Update row0 if the screen scrolled. */
-	if (ti->row0 + rows > ti->con_rows)
-		ti->row0 = ti->con_rows - rows;
+	unsigned end_coord = ti->text_coord + ti->nc;
+	unsigned end_row = LIN_TO_ROW(ti, end_coord);
+
+	unsigned scroll_rows;
+
+	/* Update coords if the screen scrolled. */
+	if (end_row >= ti->con_rows) {
+		scroll_rows = end_row - ti->con_rows + 1;
+		ti->text_coord -= ti->con_cols * scroll_rows;
+		ti->prompt_coord -= ti->con_cols * scroll_rows;
+	}
+}
+
+static void tinput_jump_after(tinput_t *ti)
+{
+	tinput_console_set_lpos(ti, ti->text_coord + ti->nc);
+	console_flush(ti->console);
+	putchar('\n');
+}
+
+static int tinput_display(tinput_t *ti)
+{
+	sysarg_t col0, row0;
+	
+	if (console_get_pos(ti->console, &col0, &row0) != EOK)
+		return EIO;
+	
+	ti->prompt_coord = row0 * ti->con_cols + col0;
+	ti->text_coord = ti->prompt_coord + str_length(ti->prompt);
+
+	tinput_display_prompt(ti);
+	tinput_display_tail(ti, 0, 0);
+	tinput_position_caret(ti);
+
+	return EOK;
 }
 
@@ -154,5 +203,5 @@
 		return;
 	
-	sysarg_t new_width = ti->col0 + ti->nc + 1;
+	unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + 1;
 	if (new_width % ti->con_cols == 0) {
 		/* Advancing to new line. */
@@ -185,6 +234,6 @@
 		return;
 	
-	sysarg_t new_width = ti->col0 + ti->nc + ilen;
-	sysarg_t new_height = (new_width / ti->con_cols) + 1;
+	unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + ilen;
+	unsigned new_height = (new_width / ti->con_cols) + 1;
 	if (new_height >= ti->con_rows) {
 		/* Disallow text longer than 1 page for now. */
@@ -511,4 +560,141 @@
 }
 
+/** Compare two entries in array of completions. */
+static int compl_cmp(void *va, void *vb, void *arg)
+{
+	const char *a = *(const char **) va;
+	const char *b = *(const char **) vb;
+
+	return str_cmp(a, b);
+}
+
+static size_t common_pref_len(const char *a, const char *b)
+{
+	size_t i;
+	size_t a_off, b_off;
+	wchar_t ca, cb;
+
+	i = 0;
+	a_off = 0;
+	b_off = 0;
+
+	while (true) {
+		ca = str_decode(a, &a_off, STR_NO_LIMIT);
+		cb = str_decode(b, &b_off, STR_NO_LIMIT);
+
+		if (ca == '\0' || cb == '\0' || ca != cb)
+			break;
+		++i;
+	}
+
+	return i;
+}
+
+static void tinput_text_complete(tinput_t *ti)
+{
+	void *state;
+	size_t cstart;
+	char *ctmp;
+	char **compl;     	/* Array of completions */
+	size_t compl_len;	/* Current length of @c compl array */
+	size_t cnum;
+	size_t i;
+	int rc;
+
+	if (ti->compl_ops == NULL)
+		return;
+
+	/*
+	 * Obtain list of all possible completions (growing array).
+	 */
+
+	rc = (*ti->compl_ops->init)(ti->buffer, ti->pos, &cstart, &state);
+	if (rc != EOK)
+		return;
+
+	cnum = 0;
+
+	compl_len = 1;
+	compl = malloc(compl_len * sizeof(char *));
+	if (compl == NULL) {
+		printf("Error: Out of memory.\n");
+		return;
+	}
+
+	while (true) {
+		rc = (*ti->compl_ops->get_next)(state, &ctmp);
+		if (rc != EOK)
+			break;
+
+		if (cnum >= compl_len) {
+			/* Extend array */
+			compl_len = 2 * compl_len;
+			compl = realloc(compl, compl_len * sizeof(char *));
+			if (compl == NULL) {
+				printf("Error: Out of memory.\n");
+				break;
+			}
+		}
+
+		compl[cnum] = str_dup(ctmp);
+		if (compl[cnum] == NULL) {
+			printf("Error: Out of memory.\n");
+			break;
+		}
+		cnum++;
+	}
+
+	(*ti->compl_ops->fini)(state);
+
+	if (cnum > 1) {
+		/*
+		 * More than one match. Determine maximum common prefix.
+		 */
+		size_t cplen;
+
+		cplen = str_length(compl[0]);
+		for (i = 1; i < cnum; i++)
+			cplen = min(cplen, common_pref_len(compl[0], compl[i]));
+
+		/* Compute how many bytes we should skip. */
+		size_t istart = str_lsize(compl[0], ti->pos - cstart);
+
+		if (cplen > istart) {
+			/* Insert common prefix. */
+
+			/* Copy remainder of common prefix. */
+			char *cpref = str_ndup(compl[0] + istart,
+			    str_lsize(compl[0], cplen - istart));
+
+			/* Insert it. */
+			tinput_insert_string(ti, cpref);
+			free(cpref);
+		} else {
+			/* No common prefix. Sort and display all entries. */
+
+			qsort(compl, cnum, sizeof(char *), compl_cmp, NULL);
+
+			tinput_jump_after(ti);
+			for (i = 0; i < cnum; i++)
+				printf("%s\n", compl[i]);
+			tinput_display(ti);
+		}
+	} else if (cnum == 1) {
+		/*
+		 * We have exactly one match. Insert it.
+		 */
+
+		/* Compute how many bytes of completion string we should skip. */
+		size_t istart = str_lsize(compl[0], ti->pos - cstart);
+
+		/* Insert remainder of completion string at current position. */
+		tinput_insert_string(ti, compl[0] + istart);
+	}
+
+	for (i = 0; i < cnum; i++)
+		free(compl[i]);
+	free(compl);
+}
+
 /** Initialize text input field.
  *
@@ -521,4 +707,33 @@
 	ti->hpos = 0;
 	ti->history[0] = NULL;
+}
+
+/** Set prompt string.
+ *
+ * @param ti		Text input
+ * @param prompt	Prompt string
+ *
+ * @return		EOK on success, ENOMEM if out of memory.
+ */
+int tinput_set_prompt(tinput_t *ti, const char *prompt)
+{
+	if (ti->prompt != NULL)
+		free(ti->prompt);
+	
+	ti->prompt = str_dup(prompt);
+	if (ti->prompt == NULL)
+		return ENOMEM;
+	
+	return EOK;
+}
+
+/** Set completion ops.
+ *
+ * Set pointer to completion ops structure that will be used for text
+ * completion.
+ */
+void tinput_set_compl_ops(tinput_t *ti, tinput_compl_ops_t *compl_ops)
+{
+	ti->compl_ops = compl_ops;
 }
 
@@ -539,7 +754,4 @@
 		return EIO;
 	
-	if (console_get_pos(ti->console, &ti->col0, &ti->row0) != EOK)
-		return EIO;
-	
 	ti->pos = 0;
 	ti->sel_start = 0;
@@ -549,4 +761,7 @@
 	ti->exit_clui = false;
 	
+	if (tinput_display(ti) != EOK)
+		return EIO;
+	
 	while (!ti->done) {
 		console_flush(ti->console);
@@ -714,4 +929,7 @@
 		tinput_history_seek(ti, -1);
 		break;
+	case KC_TAB:
+		tinput_text_complete(ti);
+		break;
 	default:
 		break;
Index: uspace/lib/clui/tinput.h
===================================================================
--- uspace/lib/clui/tinput.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/clui/tinput.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -37,11 +37,65 @@
 #define LIBCLUI_TINPUT_H_
 
-#include <stdio.h>
+#include <adt/list.h>
 #include <async.h>
 #include <inttypes.h>
 #include <io/console.h>
+#include <stdio.h>
 
 #define HISTORY_LEN     10
 #define INPUT_MAX_SIZE  1024
+
+/** Begin enumeration of text completions.
+ *
+ * When user requests text completion, tinput will call this function to start
+ * text completion operation. @a *cstart should be set to the position
+ * (character index) of the first character of the 'word' that is being
+ * completed. The resulting text is obtained by replacing the range of text
+ * starting at @a *cstart and ending at @a pos with the completion text.
+ *
+ * The function can pass information to the get_next and fini functions
+ * via @a state. The init function allocates the state object and stores
+ * a pointer to it to @a *state. The fini function destroys the state object.
+ *
+ * @param text		Current contents of edit buffer (null-terminated).
+ * @param pos		Current caret position.
+ * @param cstart	Output, position in text where completion begins from.
+ * @param state		Output, pointer to a client state object.
+ *
+ * @return		EOK on success, negative error code on failure.
+ */
+typedef int (*tinput_compl_init_fn)(wchar_t *text, size_t pos, size_t *cstart,
+    void **state);
+
+/** Obtain one text completion alternative.
+ *
+ * Upon success the function sets @a *compl to point to a string, the
+ * completion text. The caller (Tinput) should not modify or free the text.
+ * The pointer is only valid until the next invocation of any completion
+ * function.
+ *
+ * @param state		Pointer to state object created by the init funtion.
+ * @param compl		Output, the completion text, ownership retained.
+ *
+ * @return		EOK on success, negative error code on failure.
+ */
+typedef int (*tinput_compl_get_next_fn)(void *state, char **compl);
+
+
+/** Finish enumeration of text completions.
+ *
+ * The function must deallocate any state information allocated by the init
+ * function or temporary data allocated by the get_next function.
+ *
+ * @param state		Pointer to state object created by the init funtion.
+ */
+typedef void (*tinput_compl_fini_fn)(void *state);
+
+/** Text completion ops. */
+typedef struct {
+	tinput_compl_init_fn init;
+	tinput_compl_get_next_fn get_next;
+	tinput_compl_fini_fn fini;
+} tinput_compl_ops_t;
 
 /** Text input field (command line).
@@ -53,10 +107,17 @@
 	console_ctrl_t *console;
 	
+	/** Prompt string */
+	char *prompt;
+	
+	/** Completion ops. */
+	tinput_compl_ops_t *compl_ops;
+	
 	/** Buffer holding text currently being edited */
 	wchar_t buffer[INPUT_MAX_SIZE + 1];
 	
-	/** Screen coordinates of the top-left corner of the text field */
-	sysarg_t col0;
-	sysarg_t row0;
+	/** Linear position on screen where the prompt starts */
+	unsigned prompt_coord;
+	/** Linear position on screen where the text field starts */
+	unsigned text_coord;
 	
 	/** Screen dimensions */
@@ -90,4 +151,6 @@
 
 extern tinput_t *tinput_new(void);
+extern int tinput_set_prompt(tinput_t *, const char *);
+extern void tinput_set_compl_ops(tinput_t *, tinput_compl_ops_t *);
 extern void tinput_destroy(tinput_t *);
 extern int tinput_read(tinput_t *, char **);
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/drv/generic/driver.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -620,5 +620,5 @@
 		return ENOMEM;
 	
-	match_id->id = match_id_str;
+	match_id->id = str_dup(match_id_str);
 	match_id->score = 90;
 	
Index: uspace/lib/posix/Makefile
===================================================================
--- uspace/lib/posix/Makefile	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/Makefile	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -63,3 +63,2 @@
 $(INCLUDE_LIBC): ../c/include
 	ln -s -f -n $^ $@
-
Index: uspace/lib/posix/assert.h
===================================================================
--- uspace/lib/posix/assert.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/assert.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Program assertion.
  */
 
@@ -52,3 +52,2 @@
 /** @}
  */
-
Index: uspace/lib/posix/ctype.c
===================================================================
--- uspace/lib/posix/ctype.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/ctype.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Character classification.
  */
 
@@ -43,6 +43,6 @@
  * Checks whether character is a hexadecimal digit.
  *
- * @param c
- * @return
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
  */
 int posix_isxdigit(int c)
@@ -56,6 +56,6 @@
  * Checks whether character is a word separator.
  *
- * @param c
- * @return
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
  */
 int posix_isblank(int c)
@@ -67,6 +67,6 @@
  * Checks whether character is a control character.
  *
- * @param c
- * @return
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
  */
 int posix_iscntrl(int c)
@@ -78,6 +78,6 @@
  * Checks whether character is any printing character except space.
  *
- * @param c
- * @return
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
  */
 int posix_isgraph(int c)
@@ -89,6 +89,6 @@
  * Checks whether character is a printing character.
  *
- * @param c
- * @return
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
  */
 int posix_isprint(int c)
@@ -100,10 +100,10 @@
  * Checks whether character is a punctuation.
  *
- * @param c
- * @return
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
  */
 int posix_ispunct(int c)
 {
-	return !isspace(c) && !isalnum(c);
+	return !isspace(c) && !isalnum(c) && posix_isprint(c);
 }
 
@@ -111,6 +111,6 @@
  * Checks whether character is ASCII. (obsolete)
  *
- * @param c
- * @return
+ * @param c Character to inspect.
+ * @return Non-zero if character match the definition, zero otherwise.
  */
 extern int posix_isascii(int c)
@@ -122,6 +122,6 @@
  * Converts argument to a 7-bit ASCII character. (obsolete)
  *
- * @param c
- * @return
+ * @param c Character to convert.
+ * @return Coverted character.
  */
 extern int posix_toascii(int c)
Index: uspace/lib/posix/ctype.h
===================================================================
--- uspace/lib/posix/ctype.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/ctype.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Character classification.
  */
 
Index: uspace/lib/posix/errno.c
===================================================================
--- uspace/lib/posix/errno.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/errno.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file System error numbers.
  */
 
@@ -51,3 +51,2 @@
 /** @}
  */
-
Index: uspace/lib/posix/errno.h
===================================================================
--- uspace/lib/posix/errno.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/errno.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file System error numbers.
  */
 
@@ -325,3 +325,2 @@
 /** @}
  */
-
Index: uspace/lib/posix/fcntl.c
===================================================================
--- uspace/lib/posix/fcntl.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/fcntl.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file File control.
  */
 
Index: uspace/lib/posix/fcntl.h
===================================================================
--- uspace/lib/posix/fcntl.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/fcntl.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file File control.
  */
 
Index: uspace/lib/posix/float.h
===================================================================
--- uspace/lib/posix/float.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/float.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Floating type support.
  */
 
Index: uspace/lib/posix/fnmatch.c
===================================================================
--- uspace/lib/posix/fnmatch.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/fnmatch.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Filename-matching.
  */
 
@@ -45,4 +45,6 @@
 #include "internal/common.h"
 #include "fnmatch.h"
+
+// TODO: documentation
 
 #define INVALID_PATTERN -1
@@ -169,4 +171,10 @@
 };
 
+/**
+ * 
+ * @param key
+ * @param elem
+ * @return
+ */
 static int _class_compare(const void *key, const void *elem)
 {
@@ -175,4 +183,10 @@
 }
 
+/**
+ * 
+ * @param cname
+ * @param c
+ * @return
+ */
 static bool _is_in_class (const char *cname, int c)
 {
@@ -191,4 +205,11 @@
 }
 
+/**
+ * 
+ * @param pattern
+ * @param str
+ * @param flags
+ * @return
+ */
 static int _match_char_class(const char **pattern, const char *str, int flags)
 {
@@ -204,4 +225,10 @@
 /************** END CHARACTER CLASSES ****************/
 
+/**
+ * 
+ * @param pattern
+ * @param flags
+ * @return
+ */
 static _coll_elm_t _next_coll_elm(const char **pattern, int flags)
 {
@@ -240,5 +267,9 @@
 
 /**
- *
+ * 
+ * @param pattern
+ * @param str
+ * @param flags
+ * @return
  */
 static int _match_bracket_expr(const char **pattern, const char *str, int flags)
@@ -327,5 +358,9 @@
 
 /**
- *
+ * 
+ * @param pattern
+ * @param string
+ * @param flags
+ * @return
  */
 static bool _partial_match(const char **pattern, const char **string, int flags)
@@ -421,4 +456,11 @@
 }
 
+/**
+ * 
+ * @param pattern
+ * @param string
+ * @param flags
+ * @return
+ */
 static bool _full_match(const char *pattern, const char *string, int flags)
 {
@@ -476,4 +518,9 @@
 }
 
+/**
+ * 
+ * @param s
+ * @return
+ */
 static char *_casefold(const char *s)
 {
@@ -506,6 +553,10 @@
 
 	if ((flags & FNM_CASEFOLD) != 0) {
-		free((char *) pattern);
-		free((char *) string);
+		if (pattern) {
+			free((char *) pattern);
+		}
+		if (string) {
+			free((char *) string);
+		}
 	}
 
@@ -604,3 +655,2 @@
 /** @}
  */
-
Index: uspace/lib/posix/fnmatch.h
===================================================================
--- uspace/lib/posix/fnmatch.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/fnmatch.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Filename-matching.
  */
 
@@ -36,5 +36,5 @@
 #define POSIX_FNMATCH_H_
 
-/* Error Values. */
+/* Error Values */
 #undef FNM_NOMATCH
 #define FNM_NOMATCH 1
@@ -66,3 +66,2 @@
 /** @}
  */
-
Index: uspace/lib/posix/internal/common.h
===================================================================
--- uspace/lib/posix/internal/common.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/internal/common.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Helper definitions common for all libposix files.
  */
 
Index: uspace/lib/posix/inttypes.h
===================================================================
--- uspace/lib/posix/inttypes.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/inttypes.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Fixed size integer types.
  */
 
@@ -39,4 +39,14 @@
 #include "libc/inttypes.h"
 
+extern posix_intmax_t posix_strtoimax(const char *restrict nptr,
+    char **restrict endptr, int base);
+extern posix_uintmax_t posix_strtoumax(const char *restrict nptr,
+    char **restrict endptr, int base);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define strtoimax posix_strtoimax
+	#define strtoumax posix_strtoumax
+#endif
+
 #endif /* POSIX_INTTYPES_H_ */
 
Index: uspace/lib/posix/iso646.h
===================================================================
--- uspace/lib/posix/iso646.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/iso646.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -1,7 +1,34 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * 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 libposix
  * @{
  */
-/** @file
+/** @file Alternative spellings.
  */
 
@@ -25,3 +52,2 @@
 /** @}
  */
-
Index: uspace/lib/posix/limits.h
===================================================================
--- uspace/lib/posix/limits.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/limits.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Implementation-defined limit constants.
  */
 
Index: uspace/lib/posix/locale.c
===================================================================
--- uspace/lib/posix/locale.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/locale.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Locale-specific definitions.
  */
 
@@ -41,4 +41,6 @@
 #include "limits.h"
 #include "string.h"
+
+// TODO: documentation
 
 struct __posix_locale {
@@ -73,4 +75,10 @@
 };
 
+/**
+ * 
+ * @param category
+ * @param locale
+ * @return
+ */
 char *posix_setlocale(int category, const char *locale)
 {
@@ -83,4 +91,8 @@
 }
 
+/**
+ * 
+ * @return
+ */
 struct posix_lconv *posix_localeconv(void)
 {
@@ -89,4 +101,9 @@
 }
 
+/**
+ * 
+ * @param locobj
+ * @return
+ */
 posix_locale_t posix_duplocale(posix_locale_t locobj)
 {
@@ -104,9 +121,22 @@
 }
 
+/**
+ * 
+ * @param locobj
+ */
 void posix_freelocale(posix_locale_t locobj)
 {
-	free(locobj);
+	if (locobj) {
+		free(locobj);
+	}
 }
 
+/**
+ * 
+ * @param category_mask
+ * @param locale
+ * @param base
+ * @return
+ */
 posix_locale_t posix_newlocale(int category_mask, const char *locale,
     posix_locale_t base)
@@ -129,5 +159,10 @@
 }
 
-posix_locale_t posix_uselocale (posix_locale_t newloc)
+/**
+ * 
+ * @param newloc
+ * @return
+ */
+posix_locale_t posix_uselocale(posix_locale_t newloc)
 {
 	// TODO
Index: uspace/lib/posix/locale.h
===================================================================
--- uspace/lib/posix/locale.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/locale.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,9 +30,11 @@
  * @{
  */
-/** @file
+/** @file Locale-specific definitions.
  */
 
 #ifndef POSIX_LOCALE_H_
 #define POSIX_LOCALE_H_
+
+// TODO: documentation
 
 #ifndef NULL
@@ -83,28 +85,28 @@
 
 struct posix_lconv {
-	char    *currency_symbol;
-	char    *decimal_point;
-	char     frac_digits;
-	char    *grouping;
-	char    *int_curr_symbol;
-	char     int_frac_digits;
-	char     int_n_cs_precedes;
-	char     int_n_sep_by_space;
-	char     int_n_sign_posn;
-	char     int_p_cs_precedes;
-	char     int_p_sep_by_space;
-	char     int_p_sign_posn;
-	char    *mon_decimal_point;
-	char    *mon_grouping;
-	char    *mon_thousands_sep;
-	char    *negative_sign;
-	char     n_cs_precedes;
-	char     n_sep_by_space;
-	char     n_sign_posn;
-	char    *positive_sign;
-	char     p_cs_precedes;
-	char     p_sep_by_space;
-	char     p_sign_posn;
-	char    *thousands_sep;
+	char *currency_symbol;
+	char *decimal_point;
+	char  frac_digits;
+	char *grouping;
+	char *int_curr_symbol;
+	char  int_frac_digits;
+	char  int_n_cs_precedes;
+	char  int_n_sep_by_space;
+	char  int_n_sign_posn;
+	char  int_p_cs_precedes;
+	char  int_p_sep_by_space;
+	char  int_p_sign_posn;
+	char *mon_decimal_point;
+	char *mon_grouping;
+	char *mon_thousands_sep;
+	char *negative_sign;
+	char  n_cs_precedes;
+	char  n_sep_by_space;
+	char  n_sign_posn;
+	char *positive_sign;
+	char  p_cs_precedes;
+	char  p_sep_by_space;
+	char  p_sign_posn;
+	char *thousands_sep;
 };
 
@@ -117,5 +119,5 @@
 extern posix_locale_t posix_newlocale(int category_mask, const char *locale,
     posix_locale_t base);
-extern posix_locale_t posix_uselocale (posix_locale_t newloc);
+extern posix_locale_t posix_uselocale(posix_locale_t newloc);
 
 #ifndef LIBPOSIX_INTERNAL
@@ -131,5 +133,4 @@
 #endif
 
-
 #endif /* POSIX_LOCALE_H_ */
 
Index: uspace/lib/posix/math.c
===================================================================
--- uspace/lib/posix/math.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/math.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Mathematical operations.
  */
 
Index: uspace/lib/posix/math.h
===================================================================
--- uspace/lib/posix/math.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/math.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Mathematical operations.
  */
 
Index: uspace/lib/posix/pwd.c
===================================================================
--- uspace/lib/posix/pwd.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/pwd.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,12 +30,14 @@
  * @{
  */
-/** @file
+/** @file Password handling.
  */
 
 #define LIBPOSIX_INTERNAL
+
 #include "pwd.h"
 #include "string.h"
 #include "errno.h"
 
+// TODO: documentation
 
 static bool entry_read = false;
@@ -53,4 +55,6 @@
  * Since HelenOS doesn't have user accounts, this always returns
  * the same made-up entry.
+ *
+ * @return
  */
 struct posix_passwd *posix_getpwent(void)
@@ -178,3 +182,2 @@
 /** @}
  */
-
Index: uspace/lib/posix/pwd.h
===================================================================
--- uspace/lib/posix/pwd.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/pwd.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,9 +30,11 @@
  * @{
  */
-/** @file
+/** @file Password handling.
  */
 
 #ifndef POSIX_PWD_H_
 #define POSIX_PWD_H_
+
+// TODO: documentation
 
 #include "sys/types.h"
@@ -76,3 +78,2 @@
 /** @}
  */
-
Index: uspace/lib/posix/signal.c
===================================================================
--- uspace/lib/posix/signal.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/signal.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Signal handling.
  */
 
@@ -45,4 +45,6 @@
 #include "libc/task.h"
 
+// TODO: documentation
+
 /* Used to serialize signal handling. */
 static FIBRIL_MUTEX_INITIALIZE(_signal_mutex);
@@ -63,4 +65,8 @@
 };
 
+/**
+ * 
+ * @param signo
+ */
 void __posix_default_signal_handler(int signo)
 {
@@ -118,4 +124,8 @@
 }
 
+/**
+ *
+ * @param signo
+ */
 void __posix_hold_signal_handler(int signo)
 {
@@ -123,4 +133,8 @@
 }
 
+/**
+ * 
+ * @param signo
+ */
 void __posix_ignore_signal_handler(int signo)
 {
@@ -128,5 +142,9 @@
 }
 
-
+/**
+ * 
+ * @param set
+ * @return
+ */
 int posix_sigemptyset(posix_sigset_t *set)
 {
@@ -137,4 +155,9 @@
 }
 
+/**
+ * 
+ * @param set
+ * @return
+ */
 int posix_sigfillset(posix_sigset_t *set)
 {
@@ -145,4 +168,10 @@
 }
 
+/**
+ * 
+ * @param set
+ * @param signo
+ * @return
+ */
 int posix_sigaddset(posix_sigset_t *set, int signo)
 {
@@ -153,4 +182,10 @@
 }
 
+/**
+ * 
+ * @param set
+ * @param signo
+ * @return
+ */
 int posix_sigdelset(posix_sigset_t *set, int signo)
 {
@@ -161,4 +196,10 @@
 }
 
+/**
+ * 
+ * @param set
+ * @param signo
+ * @return
+ */
 int posix_sigismember(const posix_sigset_t *set, int signo)
 {
@@ -168,4 +209,10 @@
 }
 
+/**
+ * 
+ * @param sig
+ * @param act
+ * @param oact
+ */
 static void _sigaction_unsafe(int sig, const struct posix_sigaction *restrict act,
     struct posix_sigaction *restrict oact)
@@ -182,4 +229,11 @@
 }
 
+/**
+ * 
+ * @param sig
+ * @param act
+ * @param oact
+ * @return
+ */
 int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
     struct posix_sigaction *restrict oact)
@@ -206,4 +260,10 @@
 }
 
+/**
+ * 
+ * @param sig
+ * @param func
+ * @return
+ */
 void (*posix_signal(int sig, void (*func)(int)))(int)
 {
@@ -222,4 +282,10 @@
 }
 
+/**
+ * 
+ * @param signo
+ * @param siginfo
+ * @return
+ */
 static int _raise_sigaction(int signo, posix_siginfo_t *siginfo)
 {
@@ -259,4 +325,9 @@
 }
 
+/**
+ * 
+ * @param sig
+ * @return
+ */
 int posix_raise(int sig)
 {
@@ -273,4 +344,10 @@
 }
 
+/**
+ * 
+ * @param pid
+ * @param signo
+ * @return
+ */
 int posix_kill(posix_pid_t pid, int signo)
 {
@@ -303,4 +380,10 @@
 }
 
+/**
+ * 
+ * @param pid
+ * @param sig
+ * @return
+ */
 int posix_killpg(posix_pid_t pid, int sig)
 {
@@ -309,4 +392,9 @@
 }
 
+/**
+ * 
+ * @param pinfo
+ * @param message
+ */
 void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message)
 {
@@ -316,4 +404,9 @@
 }
 
+/**
+ * 
+ * @param signum
+ * @param message
+ */
 void posix_psignal(int signum, const char *message)
 {
@@ -326,4 +419,11 @@
 }
 
+/**
+ * 
+ * @param how
+ * @param set
+ * @param oset
+ * @return
+ */
 int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
     posix_sigset_t *restrict oset)
@@ -358,4 +458,11 @@
 }
 
+/**
+ * 
+ * @param how
+ * @param set
+ * @param oset
+ * @return
+ */
 int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
     posix_sigset_t *restrict oset)
@@ -371,3 +478,2 @@
 /** @}
  */
-
Index: uspace/lib/posix/signal.h
===================================================================
--- uspace/lib/posix/signal.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/signal.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,9 +30,11 @@
  * @{
  */
-/** @file
+/** @file Signal handling.
  */
 
 #ifndef POSIX_SIGNAL_H_
 #define POSIX_SIGNAL_H_
+
+// TODO: documentation
 
 #include "libc/errno.h"
@@ -107,5 +109,4 @@
 	posix_mcontext_t uc_mcontext;
 } posix_ucontext_t;
-
 
 /* Values of posix_sigevent::sigev_notify */
@@ -154,5 +155,5 @@
 #define SIGSTKSZ 0
 
-/* full POSIX set */
+/* Full POSIX set */
 enum {
 	/* Termination Signals */
@@ -214,5 +215,4 @@
 
 /* Values for sigaction field si_code. */
-
 enum {
 	SI_USER,
@@ -287,9 +287,10 @@
 		#define sigevent posix_sigevent
 	#endif
-	#define sigaction posix_sigaction
 	#define mcontext_t posix_mcontext_t
 	#define ucontext_t posix_ucontext_t
 	#define stack_t posix_stack_t
 	#define siginfo_t posix_siginfo_t
+
+	#define sigaction posix_sigaction
 
 	#define signal posix_signal
Index: uspace/lib/posix/stdbool.h
===================================================================
--- uspace/lib/posix/stdbool.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/stdbool.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Boolean type and values.
  */
 
@@ -50,3 +50,2 @@
 
 #endif /* POSIX_STDBOOL_H_ */
-
Index: uspace/lib/posix/stddef.h
===================================================================
--- uspace/lib/posix/stddef.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/stddef.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Standard type definitions.
  */
 
Index: uspace/lib/posix/stdint.h
===================================================================
--- uspace/lib/posix/stdint.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/stdint.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Integer types.
  */
 
@@ -88,4 +88,14 @@
 #define AOFF64_MIN  UINT64_MIN
 
+#undef INTMAX_MIN
+#undef INTMAX_MAX
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+
+#undef UINTMAX_MIN
+#undef UINTMAX_MAX
+#define UINTMAX_MIN UINT64_MIN
+#define UINTMAX_MAX UINT64_MAX
+
 #include "libc/sys/types.h"
 
Index: uspace/lib/posix/stdio.c
===================================================================
--- uspace/lib/posix/stdio.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/stdio.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Standard buffered input/output.
  */
 
@@ -355,9 +355,10 @@
 {
 	off64_t ret = ftell(stream);
-	if (ret == -1) {
-		return errno;
-	}
-	pos->offset = ret;
-	return 0;
+	if (ret != -1) {
+		pos->offset = ret;
+		return 0;
+	} else {
+		return -1;
+	}
 }
 
Index: uspace/lib/posix/stdio.h
===================================================================
--- uspace/lib/posix/stdio.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/stdio.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Standard buffered input/output.
  */
 
Index: uspace/lib/posix/stdio/scanf.c
===================================================================
--- uspace/lib/posix/stdio/scanf.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/stdio/scanf.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -303,6 +303,8 @@
 	self->fetched = 0;
 	self->cursor = NULL;
-	free(self->window);
-	self->window = NULL;
+	if (self->window) {
+		free(self->window);
+		self->window = NULL;
+	}
 	self->window_size = 0;
 	self->state = _PROV_CONSTRUCTED;
@@ -653,5 +655,5 @@
 				/* Update the cursor so it can be returned to the provider. */
 				cur_borrowed += cur_updated - cur_limited;
-				if (width != -1) {
+				if (width != -1 && cur_limited != NULL) {
 					/* Deallocate duplicated part of the cursor view. */
 					free(cur_limited);
@@ -833,5 +835,5 @@
 				/* Update the cursor so it can be returned to the provider. */
 				cur_borrowed += cur_updated - cur_limited;
-				if (width != -1) {
+				if (width != -1 && cur_limited != NULL) {
 					/* Deallocate duplicated part of the cursor view. */
 					free(cur_limited);
Index: uspace/lib/posix/stdlib.c
===================================================================
--- uspace/lib/posix/stdlib.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/stdlib.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Standard library definitions.
  */
 
@@ -40,4 +40,5 @@
 
 #include "errno.h"
+#include "limits.h"
 
 #include "libc/sort.h"
@@ -59,4 +60,5 @@
 
 /**
+ * Integer absolute value.
  * 
  * @param i Input value.
@@ -69,4 +71,5 @@
 
 /**
+ * Long integer absolute value.
  * 
  * @param i Input value.
@@ -79,4 +82,5 @@
 
 /**
+ * Long long integer absolute value.
  * 
  * @param i Input value.
@@ -88,4 +92,11 @@
 }
 
+/**
+ * Compute the quotient and remainder of an integer division.
+ *
+ * @param numer Numerator.
+ * @param denom Denominator.
+ * @return Quotient and remainder packed into structure.
+ */
 posix_div_t posix_div(int numer, int denom)
 {
@@ -93,4 +104,11 @@
 }
 
+/**
+ * Compute the quotient and remainder of a long integer division.
+ *
+ * @param numer Numerator.
+ * @param denom Denominator.
+ * @return Quotient and remainder packed into structure.
+ */
 posix_ldiv_t posix_ldiv(long numer, long denom)
 {
@@ -98,4 +116,11 @@
 }
 
+/**
+ * Compute the quotient and remainder of a long long integer division.
+ *
+ * @param numer Numerator.
+ * @param denom Denominator.
+ * @return Quotient and remainder packed into structure.
+ */
 posix_lldiv_t posix_lldiv(long long numer, long long denom)
 {
@@ -109,5 +134,4 @@
  * @param elem2 Second element to compare.
  * @param compare Comparison function without userdata parameter.
- *
  * @return Relative ordering of the elements.
  */
@@ -115,5 +139,14 @@
 {
 	int (*compare)(const void *, const void *) = userdata;
-	return compare(elem1, elem2);
+	int ret = compare(elem1, elem2);
+	
+	/* Native qsort internals expect this. */
+	if (ret < 0) {
+		return -1;
+	} else if (ret > 0) {
+		return 1;
+	} else {
+		return 0;
+	}
 }
 
@@ -121,8 +154,8 @@
  * Array sorting utilizing the quicksort algorithm.
  *
- * @param array
- * @param count
- * @param size
- * @param compare
+ * @param array Array of elements to sort.
+ * @param count Number of elements in the array.
+ * @param size Width of each element.
+ * @param compare Decides relative ordering of two elements.
  */
 void posix_qsort(void *array, size_t count, size_t size,
@@ -171,9 +204,10 @@
 /**
  * Retrieve a value of the given environment variable.
+ *
  * Since HelenOS doesn't support env variables at the moment,
  * this function always returns NULL.
  *
- * @param name
- * @return Always NULL.
+ * @param name Name of the variable.
+ * @return Value of the variable or NULL if such variable does not exist.
  */
 char *posix_getenv(const char *name)
@@ -195,7 +229,10 @@
 
 /**
- *
- * @param string String to be passed to a command interpreter.
- * @return
+ * Issue a command.
+ *
+ * @param string String to be passed to a command interpreter or NULL.
+ * @return Termination status of the command if the command is not NULL,
+ *     otherwise indicate whether there is a command interpreter (non-zero)
+ *     or not (zero).
  */
 int posix_system(const char *string) {
@@ -205,10 +242,14 @@
 
 /**
- * 
- * @param name
- * @param resolved
- * @return
- */
-char *posix_realpath(const char *name, char *resolved)
+ * Resolve absolute pathname.
+ * 
+ * @param name Pathname to be resolved.
+ * @param resolved Either buffer for the resolved absolute pathname or NULL.
+ * @return On success, either resolved (if it was not NULL) or pointer to the
+ *     newly allocated buffer containing the absolute pathname (if resolved was
+ *     NULL). Otherwise NULL.
+ *
+ */
+char *posix_realpath(const char *restrict name, char *restrict resolved)
 {
 	#ifndef PATH_MAX
@@ -254,6 +295,6 @@
  * its native representation. See posix_strtold().
  *
- * @param nptr
- * @return
+ * @param nptr String representation of a floating-point number.
+ * @return Double-precision number resulting from the string conversion.
  */
 double posix_atof(const char *nptr)
@@ -266,7 +307,8 @@
  * its native representation. See posix_strtold().
  *
- * @param nptr
- * @param endptr
- * @return
+ * @param nptr String representation of a floating-point number.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @return Single-precision number resulting from the string conversion.
  */
 float posix_strtof(const char *restrict nptr, char **restrict endptr)
@@ -279,7 +321,8 @@
  * its native representation. See posix_strtold().
  *
- * @param nptr
- * @param endptr
- * @return
+ * @param nptr String representation of a floating-point number.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @return Double-precision number resulting from the string conversion.
  */
 double posix_strtod(const char *restrict nptr, char **restrict endptr)
@@ -289,7 +332,8 @@
 
 /**
- *
- * @param size
- * @return
+ * Allocate memory chunk.
+ *
+ * @param size Size of the chunk to allocate.
+ * @return Either pointer to the allocated chunk or NULL if not possible.
  */
 void *posix_malloc(size_t size)
@@ -299,8 +343,9 @@
 
 /**
- *
- * @param nelem
- * @param elsize
- * @return
+ * Allocate memory for an array of elements.
+ *
+ * @param nelem Number of elements in the array.
+ * @param elsize Size of each element.
+ * @return Either pointer to the allocated array or NULL if not possible.
  */
 void *posix_calloc(size_t nelem, size_t elsize)
@@ -310,21 +355,31 @@
 
 /**
- *
- * @param ptr
- * @param size
- * @return
+ * Reallocate memory chunk to a new size.
+ *
+ * @param ptr Memory chunk to reallocate. Might be NULL.
+ * @param size Size of the reallocated chunk. Might be zero.
+ * @return Either NULL or the pointer to the newly reallocated chunk.
  */
 void *posix_realloc(void *ptr, size_t size)
 {
-	return realloc(ptr, size);
-}
-
-/**
- *
- * @param ptr
+	if (ptr != NULL && size == 0) {
+		/* Native realloc does not handle this special case. */
+		free(ptr);
+		return NULL;
+	} else {
+		return realloc(ptr, size);
+	}
+}
+
+/**
+ * Free allocated memory chunk.
+ *
+ * @param ptr Memory chunk to be freed.
  */
 void posix_free(void *ptr)
 {
-	free(ptr);
+	if (ptr) {
+		free(ptr);
+	}
 }
 
@@ -341,9 +396,11 @@
 
 /**
- * Should read system load statistics. Not supported. Always returns -1.
- *
- * @param loadavg
- * @param nelem
- * @return
+ * Get system load average statistics.
+ *
+ * Not supported. Always returns -1.
+ *
+ * @param loadavg Array where the load averages shall be placed.
+ * @param nelem Maximum number of elements to be placed into the array.
+ * @return Number of elements placed into the array on success, -1 otherwise.
  */
 int bsd_getloadavg(double loadavg[], int nelem)
Index: uspace/lib/posix/stdlib.h
===================================================================
--- uspace/lib/posix/stdlib.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/stdlib.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Standard library definitions.
  */
 
@@ -56,5 +56,5 @@
 extern long long posix_llabs(long long i);
 
-/* Integer division */
+/* Integer Division */
 
 typedef struct {
@@ -80,11 +80,8 @@
     size_t nmemb, size_t size, int (*compar)(const void *, const void *));
 
-
 /* Environment Access */
 extern char *posix_getenv(const char *name);
 extern int posix_putenv(char *string);
-
 extern int posix_system(const char *string);
-
 
 /* Symbolic Links */
@@ -101,5 +98,4 @@
 extern long int posix_atol(const char *nptr);
 extern long long int posix_atoll(const char *nptr);
-
 extern long int posix_strtol(const char *restrict nptr,
     char **restrict endptr, int base);
@@ -110,5 +106,4 @@
 extern unsigned long long int posix_strtoull(
     const char *restrict nptr, char **restrict endptr, int base);
-
 
 /* Memory Allocation */
Index: uspace/lib/posix/stdlib/strtol.c
===================================================================
--- uspace/lib/posix/stdlib/strtol.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/stdlib/strtol.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Backend for integer conversions.
  */
 
@@ -38,10 +38,19 @@
 #include "../stdlib.h"
 
-#include "../limits.h"
 #include "../ctype.h"
 #include "../errno.h"
-
-// TODO: documentation
-
+#include "../inttypes.h"
+#include "../limits.h"
+
+#define intmax_t posix_intmax_t
+#define uintmax_t posix_uintmax_t
+
+/**
+ * Decides whether a digit belongs to a particular base.
+ *
+ * @param c Character representation of the digit.
+ * @param base Base against which the digit shall be tested.
+ * @return True if the digit belongs to the base, false otherwise.
+ */
 static inline bool is_digit_in_base(int c, int base)
 {
@@ -54,5 +63,11 @@
 }
 
-static inline int get_digit_in_base(int c, int base)
+/**
+ * Derive a digit from its character representation.
+ *
+ * @param c Character representation of the digit.
+ * @return Digit value represented by an integer.
+ */
+static inline int digit_value(int c)
 {
 	if (c <= '9') {
@@ -63,7 +78,30 @@
 }
 
-static inline unsigned long long internal_strtol(
+/**
+ * Generic function for parsing an integer from it's string representation.
+ * Different variants differ in lower and upper bounds.
+ * The parsed string returned by this function is always positive, sign
+ * information is provided via a dedicated parameter.
+ *
+ * @param nptr Input string.
+ * @param endptr If non-NULL, *endptr is set to the position of the first
+ *     unrecognized character. If no digit has been parsed, value of
+ *     nptr is stored there (regardless of any skipped characters at the
+ *     beginning).
+ * @param base Expected base of the string representation. If 0, base is
+ *    determined to be decimal, octal or hexadecimal using the same rules
+ *    as C syntax. Otherwise, value must be between 2 and 36, inclusive.
+ * @param min_value Lower bound for the resulting conversion.
+ * @param max_value Upper bound for the resulting conversion.
+ * @param out_negative Either NULL for unsigned conversion or a pointer to the
+ *     bool variable into which shall be placed the negativity of the resulting
+ *     converted value.
+ * @return The absolute value of the parsed value, or the closest in-range value
+ *     if the parsed value is out of range. If the input is invalid, zero is
+ *     returned and errno is set to EINVAL.
+ */
+static inline uintmax_t internal_strtol(
     const char *restrict nptr, char **restrict endptr, int base,
-    const long long min_value, const unsigned long long max_value,
+    const intmax_t min_value, const uintmax_t max_value,
     bool *restrict out_negative)
 {
@@ -78,8 +116,11 @@
 	}
 	
-	unsigned long long real_max_value = max_value;
+	/* The maximal absolute value that can be returned in this run.
+	 * Depends on sign.
+	 */
+	uintmax_t real_max_value = max_value;
 	
 	/* Current index in the input string. */
-	int i = 0;
+	size_t i = 0;
 	bool negative = false;
 	
@@ -93,5 +134,14 @@
 	case '-':
 		negative = true;
-		real_max_value = -min_value;
+		
+		/* The strange computation is are there to avoid a corner case
+		 * where -min_value can't be represented in intmax_t.
+		 * (I'm not exactly sure what the semantics are in such a
+		 *  case, but this should be safe for any case.)
+		 */
+		real_max_value = (min_value == 0)
+		    ? 0
+		    :(((uintmax_t) -(min_value + 1)) + 1);
+		
 		/* fallthrough */
 	case '+':
@@ -104,14 +154,18 @@
 		if (nptr[i] == '0') {
 			if (tolower(nptr[i + 1]) == 'x') {
+				/* 0x... is hex. */
 				base = 16;
 				i += 2;
 			} else {
+				/* 0... is octal. */
 				base = 8;
 			}
 		} else {
+			/* Anything else is decimal by default. */
 			base = 10;
 		}
 		break;
 	case 16:
+		/* Allow hex number to be prefixed with "0x". */
 		if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x') {
 			i += 2;
@@ -133,7 +187,7 @@
 	 * of overflow.
 	 */
-	unsigned long long max_safe_value = (real_max_value - base + 1) / base;
-	
-	unsigned long long result = 0;
+	uintmax_t max_safe_value = (real_max_value - base + 1) / base;
+	
+	uintmax_t result = 0;
 	
 	if (real_max_value == 0) {
@@ -145,5 +199,5 @@
 			if (nptr[i] != '0') {
 				errno = ERANGE;
-				result = max_value;
+				result = 0;
 			}
 			i++;
@@ -152,16 +206,15 @@
 	
 	while (is_digit_in_base(nptr[i], base)) {
-		int digit = get_digit_in_base(nptr[i], base);
+		int digit = digit_value(nptr[i]);
 		
 		if (result > max_safe_value) {
 			/* corner case, check for overflow */
 			
-			unsigned long long
-			    boundary = (real_max_value - digit) / base;
+			uintmax_t boundary = (real_max_value - digit) / base;
 			
 			if (result > boundary) {
 				/* overflow */
 				errno = ERANGE;
-				result = max_value;
+				result = real_max_value;
 				break;
 			}
@@ -188,54 +241,118 @@
 }
 
+/**
+ * Convert a string to an integer.
+ *
+ * @param nptr Input string.
+ * @return Result of the conversion.
+ */
 int posix_atoi(const char *nptr)
 {
 	bool neg = false;
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, NULL, 10, INT_MIN, INT_MAX, &neg);
 
-	return (int) (neg ? -result : result);
-}
-
+	return (neg ? ((int) -result) : (int) result);
+}
+
+/**
+ * Convert a string to a long integer.
+ *
+ * @param nptr Input string.
+ * @return Result of the conversion.
+ */
 long posix_atol(const char *nptr)
 {
 	bool neg = false;
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, NULL, 10, LONG_MIN, LONG_MAX, &neg);
 
-	return (long) (neg ? -result : result);
-}
-
+	return (neg ? ((long) -result) : (long) result);
+}
+
+/**
+ * Convert a string to a long long integer.
+ *
+ * @param nptr Input string.
+ * @return Result of the conversion.
+ */
 long long posix_atoll(const char *nptr)
 {
 	bool neg = false;
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, NULL, 10, LLONG_MIN, LLONG_MAX, &neg);
 
-	return (long long) (neg ? -result : result);
-}
-
+	return (neg ? ((long long) -result) : (long long) result);
+}
+
+/**
+ * Convert a string to a long integer.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
 long posix_strtol(const char *restrict nptr, char **restrict endptr, int base)
 {
 	bool neg = false;
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, endptr, base, LONG_MIN, LONG_MAX, &neg);
 
-	return (long) (neg ? -result : result);
-}
-
+	return (neg ? ((long) -result) : ((long) result));
+}
+
+/**
+ * Convert a string to a long long integer.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
 long long posix_strtoll(
     const char *restrict nptr, char **restrict endptr, int base)
 {
 	bool neg = false;
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, endptr, base, LLONG_MIN, LLONG_MAX, &neg);
 
-	return (long long) (neg ? -result : result);
-}
-
+	return (neg ? ((long long) -result) : (long long) result);
+}
+
+/**
+ * Convert a string to a largest signed integer type.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
+intmax_t posix_strtoimax(
+    const char *restrict nptr, char **restrict endptr, int base)
+{
+	bool neg = false;
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, INTMAX_MIN, INTMAX_MAX, &neg);
+
+	return (neg ? ((intmax_t) -result) : (intmax_t) result);
+}
+
+/**
+ * Convert a string to an unsigned long integer.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
 unsigned long posix_strtoul(
     const char *restrict nptr, char **restrict endptr, int base)
 {
-	unsigned long long result =
+	uintmax_t result =
 	    internal_strtol(nptr, endptr, base, 0, ULONG_MAX, NULL);
 
@@ -243,12 +360,40 @@
 }
 
+/**
+ * Convert a string to an unsigned long long integer.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
 unsigned long long posix_strtoull(
     const char *restrict nptr, char **restrict endptr, int base)
 {
-	return internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
-}
-
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, 0, ULLONG_MAX, NULL);
+
+	return (unsigned long long) result;
+}
+
+/**
+ * Convert a string to a largest unsigned integer type.
+ *
+ * @param nptr Input string.
+ * @param endptr Pointer to the final part of the string which
+ *     was not used for conversion.
+ * @param base Expected base of the string representation.
+ * @return Result of the conversion.
+ */
+uintmax_t posix_strtoumax(
+    const char *restrict nptr, char **restrict endptr, int base)
+{
+	uintmax_t result =
+	    internal_strtol(nptr, endptr, base, 0, UINTMAX_MAX, NULL);
+
+	return result;
+}
 
 /** @}
  */
-
Index: uspace/lib/posix/stdlib/strtold.c
===================================================================
--- uspace/lib/posix/stdlib/strtold.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/stdlib/strtold.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Backend for floating point conversions.
  */
 
@@ -46,4 +46,7 @@
 #include "../strings.h"
 #include "../errno.h"
+#include "../limits.h"
+
+// FIXME: #include <float.h>
 
 #ifndef HUGE_VALL
@@ -52,49 +55,56 @@
 
 #ifndef abs
-	#define abs(x) ((x < 0) ? -x : x)
-#endif
-
-// TODO: clean up, documentation
-
-// FIXME: ensure it builds and works on all platforms
-
-const int max_small_pow5 = 15;
-
-/* The value at index i is approximately 5**i. */
-long double small_pow5[] = {
-	0x1P0,
-	0x5P0,
-	0x19P0,
-	0x7dP0,
-	0x271P0,
-	0xc35P0,
-	0x3d09P0,
-	0x1312dP0,
-	0x5f5e1P0,
-	0x1dcd65P0,
-	0x9502f9P0,
-	0x2e90eddP0,
-	0xe8d4a51P0,
-	0x48c27395P0,
-	0x16bcc41e9P0,
-	0x71afd498dP0
+	#define abs(x) (((x) < 0) ? -(x) : (x))
+#endif
+
+/* If the constants are not defined, use double precision as default. */
+#ifndef LDBL_MANT_DIG
+	#define LDBL_MANT_DIG 53
+#endif
+#ifndef LDBL_MAX_EXP
+	#define LDBL_MAX_EXP 1024
+#endif
+#ifndef LDBL_MIN_EXP
+	#define LDBL_MIN_EXP (-1021)
+#endif
+#ifndef LDBL_DIG
+	#define LDBL_DIG 15
+#endif
+#ifndef LDBL_MIN
+	#define LDBL_MIN 2.2250738585072014E-308
+#endif
+
+/* power functions ************************************************************/
+
+#if LDBL_MAX_EXP >= 16384
+const int MAX_POW5 = 12;
+#else
+const int MAX_POW5 = 8;
+#endif
+
+/* The value at index i is approximately 5**(2**i). */
+long double pow5[] = {
+	0x5p0l,
+	0x19p0l,
+	0x271p0l,
+	0x5F5E1p0l,
+	0x2386F26FC1p0l,
+	0x4EE2D6D415B85ACEF81p0l,
+	0x184F03E93FF9F4DAA797ED6E38ED6p36l,
+	0x127748F9301D319BF8CDE66D86D62p185l,
+	0x154FDD7F73BF3BD1BBB77203731FDp482l,
+#if LDBL_MAX_EXP >= 16384
+	0x1C633415D4C1D238D98CAB8A978A0p1076l,
+	0x192ECEB0D02EA182ECA1A7A51E316p2265l,
+	0x13D1676BB8A7ABBC94E9A519C6535p4643l,
+	0x188C0A40514412F3592982A7F0094p9398l,
+#endif
 };
 
-/* The value at index i is approximately 5**(2**i). */
-long double large_pow5[] = {
-	0x5P0l,
-	0x19P0l,
-	0x271P0l,
-	0x5f5e1P0l,
-	0x2386f26fc1P0l,
-	0x4ee2d6d415b85acef81P0l,
-	0x184f03e93ff9f4daa797ed6e38ed64bf6a1f01P0l,
-	0x24ee91f2603a6337f19bccdb0dac404dc08d3cff5ecP128l,
-	0x553f75fdcefcef46eeddcP512l,
-	0x1c633415d4c1d238d98cab8a978a0b1f138cb07303P1024l,
-	0x325d9d61a05d4305d9434f4a3c62d433949ae6209d492P2200l,
-	0x9e8b3b5dc53d5de4a74d28ce329ace526a3197bbebe3034f77154ce2bcba1964P4500l,
-	0x6230290145104bcd64a60a9fc025254932bb0fd922271133eeae7P9300l
-};
+#if LDBL_MAX_EXP >= 16384
+const int MAX_POW2 = 15;
+#else
+const int MAX_POW2 = 9;
+#endif
 
 /* Powers of two. */
@@ -110,41 +120,41 @@
 	0x1P256l,
 	0x1P512l,
+#if LDBL_MAX_EXP >= 16384
 	0x1P1024l,
 	0x1P2048l,
 	0x1P4096l,
-	0x1P8192l
+	0x1P8192l,
+#endif
 };
 
-static inline bool out_of_range(long double num)
-{
-	return num == 0.0l || num == HUGE_VALL;
-}
-
 /**
  * Multiplies a number by a power of five.
- * The result is not exact and may not be the best possible approximation.
- *
- * @param base Number to be multiplied.
- * @param exponent Base 5 exponent.
- * @return base multiplied by 5**exponent
- */
-static long double mul_pow5(long double base, int exponent)
-{
-	if (out_of_range(base)) {
-		return base;
-	}
-	
-	if (abs(exponent) >> 13 != 0) {
+ * The result may be inexact and may not be the best possible approximation.
+ *
+ * @param mant Number to be multiplied.
+ * @param exp Base 5 exponent.
+ * @return mant multiplied by 5**exp
+ */
+static long double mul_pow5(long double mant, int exp)
+{
+	if (mant == 0.0l || mant == HUGE_VALL) {
+		return mant;
+	}
+	
+	if (abs(exp) >> (MAX_POW5 + 1) != 0) {
+		/* Too large exponent. */
 		errno = ERANGE;
-		return exponent < 0 ? 0.0l : HUGE_VALL;
-	}
-	
-	if (exponent < 0) {
-		exponent = -exponent;
-		base /= small_pow5[exponent & 0xF];
-		for (int i = 4; i < 13; ++i) {
-			if (((exponent >> i) & 1) != 0) {
-				base /= large_pow5[i];
-				if (out_of_range(base)) {
+		return exp < 0 ? LDBL_MIN : HUGE_VALL;
+	}
+	
+	if (exp < 0) {
+		exp = abs(exp);
+		for (int bit = 0; bit <= MAX_POW5; ++bit) {
+			/* Multiply by powers of five bit-by-bit. */
+			if (((exp >> bit) & 1) != 0) {
+				mant /= pow5[bit];
+				if (mant == 0.0l) {
+					/* Underflow. */
+					mant = LDBL_MIN;
 					errno = ERANGE;
 					break;
@@ -153,9 +163,10 @@
 		}
 	} else {
-		base *= small_pow5[exponent & 0xF];
-		for (int i = 4; i < 13; ++i) {
-			if (((exponent >> i) & 1) != 0) {
-				base *= large_pow5[i];
-				if (out_of_range(base)) {
+		for (int bit = 0; bit <= MAX_POW5; ++bit) {
+			/* Multiply by powers of five bit-by-bit. */
+			if (((exp >> bit) & 1) != 0) {
+				mant *= pow5[bit];
+				if (mant == HUGE_VALL) {
+					/* Overflow. */
 					errno = ERANGE;
 					break;
@@ -165,31 +176,32 @@
 	}
 	
-	return base;
-}
-
-/**
- * Multiplies a number by a power of two.
- *
- * @param base Number to be multiplied.
- * @param exponent Base 2 exponent.
- * @return base multiplied by 2**exponent
- */
-static long double mul_pow2(long double base, int exponent)
-{
-	if (out_of_range(base)) {
-		return base;
-	}
-	
-	if (abs(exponent) >> 14 != 0) {
+	return mant;
+}
+
+/**
+ * Multiplies a number by a power of two. This is always exact.
+ *
+ * @param mant Number to be multiplied.
+ * @param exp Base 2 exponent.
+ * @return mant multiplied by 2**exp.
+ */
+static long double mul_pow2(long double mant, int exp)
+{
+	if (mant == 0.0l || mant == HUGE_VALL) {
+		return mant;
+	}
+	
+	if (exp > LDBL_MAX_EXP || exp < LDBL_MIN_EXP) {
 		errno = ERANGE;
-		return exponent < 0 ? 0.0l : HUGE_VALL;
-	}
-	
-	if (exponent < 0) {
-		exponent = -exponent;
-		for (int i = 0; i < 14; ++i) {
-			if (((exponent >> i) & 1) != 0) {
-				base /= pow2[i];
-				if (out_of_range(base)) {
+		return exp < 0 ? LDBL_MIN : HUGE_VALL;
+	}
+	
+	if (exp < 0) {
+		exp = abs(exp);
+		for (int i = 0; i <= MAX_POW2; ++i) {
+			if (((exp >> i) & 1) != 0) {
+				mant /= pow2[i];
+				if (mant == 0.0l) {
+					mant = LDBL_MIN;
 					errno = ERANGE;
 					break;
@@ -198,8 +210,8 @@
 		}
 	} else {
-		for (int i = 0; i < 14; ++i) {
-			if (((exponent >> i) & 1) != 0) {
-				base *= pow2[i];
-				if (out_of_range(base)) {
+		for (int i = 0; i <= MAX_POW2; ++i) {
+			if (((exp >> i) & 1) != 0) {
+				mant *= pow2[i];
+				if (mant == HUGE_VALL) {
 					errno = ERANGE;
 					break;
@@ -209,40 +221,49 @@
 	}
 	
-	return base;
-}
-
-
+	return mant;
+}
+
+/* end power functions ********************************************************/
+
+
+
+/**
+ * Convert decimal string representation of the floating point number.
+ * Function expects the string pointer to be already pointed at the first
+ * digit (i.e. leading optional sign was already consumed by the caller).
+ * 
+ * @param sptr Pointer to the storage of the string pointer. Upon successful
+ *     conversion, the string pointer is updated to point to the first
+ *     unrecognized character.
+ * @return An approximate representation of the input floating-point number.
+ */
 static long double parse_decimal(const char **sptr)
 {
-	// TODO: Use strtol(), at least for exponent.
+	assert(sptr != NULL);
+	assert (*sptr != NULL);
 	
 	const int DEC_BASE = 10;
 	const char DECIMAL_POINT = '.';
 	const char EXPONENT_MARK = 'e';
-	/* The highest amount of digits that can be safely parsed
-	 * before an overflow occurs.
-	 */
-	const int PARSE_DECIMAL_DIGS = 19;
-	
-	/* significand */
-	uint64_t significand = 0;
-	
-	/* position in the input string */
-	int i = 0;
+	
+	const char *str = *sptr;
+	long double significand = 0;
+	long exponent = 0;
 	
 	/* number of digits parsed so far */
 	int parsed_digits = 0;
-	
-	int exponent = 0;
-	
-	const char *str = *sptr;
-	
-	/* digits before decimal point */
-	while (isdigit(str[i])) {
-		if (parsed_digits == 0 && str[i] == '0') {
+	bool after_decimal = false;
+	
+	while (isdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
+		if (*str == DECIMAL_POINT) {
+			after_decimal = true;
+			str++;
+			continue;
+		}
+		
+		if (parsed_digits == 0 && *str == '0') {
 			/* Nothing, just skip leading zeros. */
-		} else if (parsed_digits < PARSE_DECIMAL_DIGS) {
-			significand *= DEC_BASE;
-			significand += str[i] - '0';
+		} else if (parsed_digits < LDBL_DIG) {
+			significand = significand * DEC_BASE + (*str - '0');
 			parsed_digits++;
 		} else {
@@ -250,69 +271,40 @@
 		}
 		
-		i++;
-	}
-	
-	if (str[i] == DECIMAL_POINT) {
-		i++;
-		
-		/* digits after decimal point */
-		while (isdigit(str[i])) {
-			if (parsed_digits == 0 && str[i] == '0') {
-				/* Skip leading zeros and decrement exponent. */
-				exponent--;
-			} else if (parsed_digits < PARSE_DECIMAL_DIGS) {
-				significand *= DEC_BASE;
-				significand += str[i] - '0';
-				exponent--;
-				parsed_digits++;
-			} else {
-				/* ignore */
-			}
-			
-			i++;
-		}
+		if (after_decimal) {
+			/* Decrement exponent if we are parsing the fractional part. */
+			exponent--;
+		}
+		
+		str++;
 	}
 	
 	/* exponent */
-	if (tolower(str[i]) == EXPONENT_MARK) {
-		i++;
-		
-		bool negative = false;
-		int exp = 0;
-		
-		switch (str[i]) {
-		case '-':
-			negative = true;
-			/* fallthrough */
-		case '+':
-			i++;
-		}
-		
-		while (isdigit(str[i])) {
-			if (exp < 65536) {
-				exp *= DEC_BASE;
-				exp += str[i] - '0';
-			}
-			
-			i++;
-		}
-		
-		if (negative) {
-			exp = -exp;
-		}
-		
-		exponent += exp;
-	}
-	
-	long double result = (long double) significand;
-	result = mul_pow5(result, exponent);
-	if (result != HUGE_VALL) {
-		result = mul_pow2(result, exponent);
-	}
-	
-	*sptr = &str[i];
-	return result;
-}
-
+	if (tolower(*str) == EXPONENT_MARK) {
+		str++;
+		
+		/* Returns MIN/MAX value on error, which is ok. */
+		long exp = strtol(str, (char **) &str, DEC_BASE);
+		
+		if (exponent > 0 && exp > LONG_MAX - exponent) {
+			exponent = LONG_MAX;
+		} else if (exponent < 0 && exp < LONG_MIN - exponent) {
+			exponent = LONG_MIN;
+		} else {
+			exponent += exp;
+		}
+	}
+	
+	*sptr = str;
+	
+	/* Return multiplied by a power of ten. */
+	return mul_pow2(mul_pow5(significand, exponent), exponent);
+}
+
+/**
+ * Derive a hexadecimal digit from its character representation.
+ * 
+ * @param ch Character representation of the hexadecimal digit.
+ * @return Digit value represented by an integer.
+ */
 static inline int hex_value(char ch)
 {
@@ -325,24 +317,17 @@
 
 /**
- * @param val Integer value.
- * @return How many leading zero bits there are. (Maximum is 3)
- */
-static inline int leading_zeros(uint64_t val)
-{
-	for (int i = 3; i > 0; --i) {
-		if ((val >> (64 - i)) == 0) {
-			return i;
-		}
-	}
-	
-	return 0;
-}
-
+ * Convert hexadecimal string representation of the floating point number.
+ * Function expects the string pointer to be already pointed at the first
+ * digit (i.e. leading optional sign and 0x prefix were already consumed
+ * by the caller).
+ *
+ * @param sptr Pointer to the storage of the string pointer. Upon successful
+ *     conversion, the string pointer is updated to point to the first
+ *     unrecognized character.
+ * @return Representation of the input floating-point number.
+ */
 static long double parse_hexadecimal(const char **sptr)
 {
-	// TODO: Use strtol(), at least for exponent.
-	
-	/* this function currently always rounds to zero */
-	// TODO: honor rounding mode
+	assert(sptr != NULL && *sptr != NULL);
 	
 	const int DEC_BASE = 10;
@@ -350,118 +335,56 @@
 	const char DECIMAL_POINT = '.';
 	const char EXPONENT_MARK = 'p';
-	/* The highest amount of digits that can be safely parsed
-	 * before an overflow occurs.
-	 */
-	const int PARSE_HEX_DIGS = 16;
-	
-	/* significand */
-	uint64_t significand = 0;
-	
-	/* position in the input string */
-	int i = 0;
-	
-	/* number of digits parsed so far */
-	int parsed_digits = 0;
-	
-	int exponent = 0;
 	
 	const char *str = *sptr;
-	
-	/* digits before decimal point */
-	while (posix_isxdigit(str[i])) {
-		if (parsed_digits == 0 && str[i] == '0') {
+	long double significand = 0;
+	long exponent = 0;
+	
+	/* number of bits parsed so far */
+	int parsed_bits = 0;
+	bool after_decimal = false;
+	
+	while (posix_isxdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
+		if (*str == DECIMAL_POINT) {
+			after_decimal = true;
+			str++;
+			continue;
+		}
+		
+		if (parsed_bits == 0 && *str == '0') {
 			/* Nothing, just skip leading zeros. */
-		} else if (parsed_digits < PARSE_HEX_DIGS) {
-			significand *= HEX_BASE;
-			significand += hex_value(str[i]);
-			parsed_digits++;
-		} else if (parsed_digits == PARSE_HEX_DIGS) {
-			/* The first digit may have had leading zeros,
-			 * so we need to parse one more digit and shift
-			 * the value accordingly.
-			 */
-			
-			int zeros = leading_zeros(significand);
-			significand = (significand << zeros) |
-			    (hex_value(str[i]) >> (4 - zeros));
-			
-			exponent += (4 - zeros);
-			parsed_digits++;
+		} else if (parsed_bits <= LDBL_MANT_DIG) {
+			significand = significand * HEX_BASE + hex_value(*str);
+			parsed_bits += 4;
 		} else {
 			exponent += 4;
 		}
 		
-		i++;
-	}
-	
-	if (str[i] == DECIMAL_POINT) {
-		i++;
-		
-		/* digits after decimal point */
-		while (posix_isxdigit(str[i])) {
-			if (parsed_digits == 0 && str[i] == '0') {
-				/* Skip leading zeros and decrement exponent. */
-				exponent -= 4;
-			} else if (parsed_digits < PARSE_HEX_DIGS) {
-				significand *= HEX_BASE;
-				significand += hex_value(str[i]);
-				exponent -= 4;
-				parsed_digits++;
-			} else if (parsed_digits == PARSE_HEX_DIGS) {
-				/* The first digit may have had leading zeros,
-				 * so we need to parse one more digit and shift
-				 * the value accordingly.
-				 */
-				
-				int zeros = leading_zeros(significand);
-				significand = (significand << zeros) |
-				    (hex_value(str[i]) >> (4 - zeros));
-				
-				exponent -= zeros;
-				parsed_digits++;
-			} else {
-				/* ignore */
-			}
-			
-			i++;
-		}
+		if (after_decimal) {
+			exponent -= 4;
+		}
+		
+		str++;
 	}
 	
 	/* exponent */
-	if (tolower(str[i]) == EXPONENT_MARK) {
-		i++;
-		
-		bool negative = false;
-		int exp = 0;
-		
-		switch (str[i]) {
-		case '-':
-			negative = true;
-			/* fallthrough */
-		case '+':
-			i++;
-		}
-		
-		while (isdigit(str[i])) {
-			if (exp < 65536) {
-				exp *= DEC_BASE;
-				exp += str[i] - '0';
-			}
-			
-			i++;
-		}
-		
-		if (negative) {
-			exp = -exp;
-		}
-		
-		exponent += exp;
-	}
-	
-	long double result = (long double) significand;
-	result = mul_pow2(result, exponent);
-	
-	*sptr = &str[i];
-	return result;
+	if (tolower(*str) == EXPONENT_MARK) {
+		str++;
+		
+		/* Returns MIN/MAX value on error, which is ok. */
+		long exp = strtol(str, (char **) &str, DEC_BASE);
+		
+		if (exponent > 0 && exp > LONG_MAX - exponent) {
+			exponent = LONG_MAX;
+		} else if (exponent < 0 && exp < LONG_MIN - exponent) {
+			exponent = LONG_MIN;
+		} else {
+			exponent += exp;
+		}
+	}
+	
+	*sptr = str;
+	
+	/* Return multiplied by a power of two. */
+	return mul_pow2(significand, exponent);
 }
 
@@ -478,5 +401,5 @@
  * @param nptr Input string.
  * @param endptr If non-NULL, *endptr is set to the position of the first
- *    unrecognized character.
+ *     unrecognized character.
  * @return An approximate representation of the input floating-point number.
  */
@@ -512,8 +435,8 @@
 		
 		if (endptr != NULL) {
-			*endptr = (char *) &nptr[i + 3];
-		}
-		errno = ERANGE;
-		return negative ? -0.0l : +0.0l;
+			*endptr = (char *) nptr;
+		}
+		errno = EINVAL;
+		return 0;
 	}
 	
@@ -567,3 +490,2 @@
 /** @}
  */
-
Index: uspace/lib/posix/string.c
===================================================================
--- uspace/lib/posix/string.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/string.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file String manipulation.
  */
 
@@ -48,9 +48,9 @@
 
 /**
- * Returns true if s2 is a prefix of s1.
- *
- * @param s1
- * @param s2
- * @return
+ * Decides whether s2 is a prefix of s1.
+ *
+ * @param s1 String in which to look for a prefix.
+ * @param s2 Prefix string to look for.
+ * @return True if s2 is a prefix of s1, false otherwise.
  */
 static bool begins_with(const char *s1, const char *s2)
@@ -69,7 +69,8 @@
  * if no occurence is found.
  *
- * @param s1
- * @param s2
- * @return
+ * @param s1 String in which to look for the bytes.
+ * @param s2 String of bytes to look for.
+ * @return Pointer to the found byte on success, pointer to the
+ *     string terminator otherwise.
  */
 static char *strpbrk_null(const char *s1, const char *s2)
@@ -83,10 +84,11 @@
 
 /**
- *
- * @param dest
- * @param src
- * @return
- */
-char *posix_strcpy(char *dest, const char *src)
+ * Copy a string.
+ *
+ * @param dest Destination pre-allocated buffer.
+ * @param src Source string to be copied.
+ * @return Pointer to the destination buffer.
+ */
+char *posix_strcpy(char *restrict dest, const char *restrict src)
 {
 	posix_stpcpy(dest, src);
@@ -95,11 +97,12 @@
 
 /**
- *
- * @param dest
- * @param src
- * @param n
- * @return
- */
-char *posix_strncpy(char *dest, const char *src, size_t n)
+ * Copy fixed length string.
+ *
+ * @param dest Destination pre-allocated buffer.
+ * @param src Source string to be copied.
+ * @param n Number of bytes to be stored into destination buffer.
+ * @return Pointer to the destination buffer.
+ */
+char *posix_strncpy(char *restrict dest, const char *restrict src, size_t n)
 {
 	posix_stpncpy(dest, src, n);
@@ -108,8 +111,9 @@
 
 /**
- *
- * @param dest
- * @param src
- * @return Pointer to the nul character in the dest string
+ * Copy a string.
+ *
+ * @param dest Destination pre-allocated buffer.
+ * @param src Source string to be copied.
+ * @return Pointer to the nul character in the destination string.
  */
 char *posix_stpcpy(char *restrict dest, const char *restrict src)
@@ -132,9 +136,10 @@
 
 /**
- *
- * @param dest
- * @param src
- * @param n
- * @return Pointer to the first written nul character or &dest[n]
+ * Copy fixed length string.
+ *
+ * @param dest Destination pre-allocated buffer.
+ * @param src Source string to be copied.
+ * @param n Number of bytes to be stored into destination buffer.
+ * @return Pointer to the first written nul character or &dest[n].
  */
 char *posix_stpncpy(char *restrict dest, const char *restrict src, size_t n)
@@ -162,10 +167,11 @@
 
 /**
- *
- * @param dest
- * @param src
- * @return
- */
-char *posix_strcat(char *dest, const char *src)
+ * Concatenate two strings.
+ *
+ * @param dest String to which src shall be appended.
+ * @param src String to be appended after dest.
+ * @return Pointer to destination buffer.
+ */
+char *posix_strcat(char *restrict dest, const char *restrict src)
 {
 	assert(dest != NULL);
@@ -177,11 +183,12 @@
 
 /**
- *
- * @param dest
- * @param src
- * @param n
- * @return
- */
-char *posix_strncat(char *dest, const char *src, size_t n)
+ * Concatenate a string with part of another.
+ *
+ * @param dest String to which part of src shall be appended.
+ * @param src String whose part shall be appended after dest.
+ * @param n Number of bytes to append after dest.
+ * @return Pointer to destination buffer.
+ */
+char *posix_strncat(char *restrict dest, const char *restrict src, size_t n)
 {
 	assert(dest != NULL);
@@ -195,12 +202,13 @@
 
 /**
- *
- * @param dest
- * @param src
- * @param c
- * @param n
+ * Copy limited number of bytes in memory.
+ *
+ * @param dest Destination buffer.
+ * @param src Source buffer.
+ * @param c Character after which the copying shall stop.
+ * @param n Number of bytes that shall be copied if not stopped earlier by c.
  * @return Pointer to the first byte after c in dest if found, NULL otherwise.
  */
-void *posix_memccpy(void *dest, const void *src, int c, size_t n)
+void *posix_memccpy(void *restrict dest, const void *restrict src, int c, size_t n)
 {
 	assert(dest != NULL);
@@ -223,7 +231,8 @@
 
 /**
- *
- * @param s
- * @return Newly allocated string
+ * Duplicate a string.
+ *
+ * @param s String to be duplicated.
+ * @return Newly allocated copy of the string.
  */
 char *posix_strdup(const char *s)
@@ -233,8 +242,9 @@
 
 /**
- *
- * @param s
- * @param n
- * @return Newly allocated string of length at most n
+ * Duplicate a specific number of bytes from a string.
+ *
+ * @param s String to be duplicated.
+ * @param n Maximum length of the resulting string..
+ * @return Newly allocated string copy of length at most n.
  */
 char *posix_strndup(const char *s, size_t n)
@@ -255,10 +265,11 @@
 
 /**
- *
- * @param mem1
- * @param mem2
- * @param n
+ * Compare bytes in memory.
+ *
+ * @param mem1 First area of memory to be compared.
+ * @param mem2 Second area of memory to be compared.
+ * @param n Maximum number of bytes to be compared.
  * @return Difference of the first pair of inequal bytes,
- *     or 0 if areas have the same content
+ *     or 0 if areas have the same content.
  */
 int posix_memcmp(const void *mem1, const void *mem2, size_t n)
@@ -272,5 +283,5 @@
 	for (size_t i = 0; i < n; ++i) {
 		if (s1[i] != s2[i]) {
-			return s2[i] - s1[i];
+			return s1[i] - s2[i];
 		}
 	}
@@ -280,8 +291,10 @@
 
 /**
- *
- * @param s1
- * @param s2
- * @return
+ * Compare two strings.
+ *
+ * @param s1 First string to be compared.
+ * @param s2 Second string to be compared.
+ * @return Difference of the first pair of inequal characters,
+ *     or 0 if strings have the same content.
  */
 int posix_strcmp(const char *s1, const char *s2)
@@ -294,9 +307,11 @@
 
 /**
- *
- * @param s1
- * @param s2
- * @param n
- * @return
+ * Compare part of two strings.
+ *
+ * @param s1 First string to be compared.
+ * @param s2 Second string to be compared.
+ * @param n Maximum number of characters to be compared.
+ * @return Difference of the first pair of inequal characters,
+ *     or 0 if strings have the same content.
  */
 int posix_strncmp(const char *s1, const char *s2, size_t n)
@@ -307,5 +322,5 @@
 	for (size_t i = 0; i < n; ++i) {
 		if (s1[i] != s2[i]) {
-			return s2[i] - s1[i];
+			return s1[i] - s2[i];
 		}
 		if (s1[i] == '\0') {
@@ -318,9 +333,11 @@
 
 /**
- *
- * @param mem
- * @param c
- * @param n
- * @return
+ * Find byte in memory.
+ *
+ * @param mem Memory area in which to look for the byte.
+ * @param c Byte to look for.
+ * @param n Maximum number of bytes to be inspected.
+ * @return Pointer to the specified byte on success,
+ *     NULL pointer otherwise.
  */
 void *posix_memchr(const void *mem, int c, size_t n)
@@ -339,8 +356,10 @@
 
 /**
- *
- * @param s
- * @param c
- * @return
+ * Scan string for a first occurence of a character.
+ *
+ * @param s String in which to look for the character.
+ * @param c Character to look for.
+ * @return Pointer to the specified character on success,
+ *     NULL pointer otherwise.
  */
 char *posix_strchr(const char *s, int c)
@@ -353,8 +372,10 @@
 
 /**
- *
- * @param s
- * @param c
- * @return
+ * Scan string for a last occurence of a character.
+ *
+ * @param s String in which to look for the character.
+ * @param c Character to look for.
+ * @return Pointer to the specified character on success,
+ *     NULL pointer otherwise.
  */
 char *posix_strrchr(const char *s, int c)
@@ -376,4 +397,12 @@
 }
 
+/**
+ * Scan string for a first occurence of a character.
+ *
+ * @param s String in which to look for the character.
+ * @param c Character to look for.
+ * @return Pointer to the specified character on success, pointer to the
+ *     string terminator otherwise.
+ */
 char *gnu_strchrnul(const char *s, int c)
 {
@@ -388,8 +417,10 @@
 
 /**
- *
- * @param s1
- * @param s2
- * @return
+ * Scan a string for a first occurence of one of provided bytes.
+ *
+ * @param s1 String in which to look for the bytes.
+ * @param s2 String of bytes to look for.
+ * @return Pointer to the found byte on success,
+ *     NULL pointer otherwise.
  */
 char *posix_strpbrk(const char *s1, const char *s2)
@@ -403,8 +434,9 @@
 
 /**
- *
- * @param s1
- * @param s2
- * @return
+ * Get the length of a complementary substring.
+ *
+ * @param s1 String that shall be searched for complementary prefix.
+ * @param s2 String of bytes that shall not occur in the prefix.
+ * @return Length of the prefix.
  */
 size_t posix_strcspn(const char *s1, const char *s2)
@@ -418,8 +450,9 @@
 
 /**
- *
- * @param s1
- * @param s2
- * @return
+ * Get length of a substring.
+ *
+ * @param s1 String that shall be searched for prefix.
+ * @param s2 String of bytes that the prefix must consist of.
+ * @return Length of the prefix.
  */
 size_t posix_strspn(const char *s1, const char *s2)
@@ -438,8 +471,10 @@
 
 /**
- *
- * @param s1
- * @param s2
- * @return
+ * Find a substring.
+ *
+ * @param s1 String in which to look for a substring.
+ * @param s2 Substring to look for.
+ * @return Pointer to the first character of the substring in s1, or NULL if
+ *     not found.
  */
 char *posix_strstr(const char *s1, const char *s2)
@@ -467,9 +502,12 @@
 
 /**
+ * String comparison using collating information.
+ *
  * Currently ignores locale and just calls strcmp.
  *
- * @param s1
- * @param s2
- * @return
+ * @param s1 First string to be compared.
+ * @param s2 Second string to be compared.
+ * @return Difference of the first pair of inequal characters,
+ *     or 0 if strings have the same content.
  */
 int posix_strcoll(const char *s1, const char *s2)
@@ -482,12 +520,16 @@
 
 /**
- * strcoll is equal to strcmp here, so this just makes a copy.
- *
- * @param s1
- * @param s2
- * @param n
- * @return
- */
-size_t posix_strxfrm(char *s1, const char *s2, size_t n)
+ * Transform a string in such a way that the resulting string yields the same
+ * results when passed to the strcmp as if the original string is passed to
+ * the strcoll.
+ *
+ * Since strcoll is equal to strcmp here, this just makes a copy.
+ *
+ * @param s1 Transformed string.
+ * @param s2 Original string.
+ * @param n Maximum length of the transformed string.
+ * @return Length of the transformed string.
+ */
+size_t posix_strxfrm(char *restrict s1, const char *restrict s2, size_t n)
 {
 	assert(s1 != NULL || n == 0);
@@ -504,7 +546,8 @@
 
 /**
- *
- * @param errnum
- * @return
+ * Get error message string.
+ *
+ * @param errnum Error code for which to obtain human readable string.
+ * @return Error message.
  */
 char *posix_strerror(int errnum)
@@ -518,9 +561,10 @@
 
 /**
- *
- * @param errnum Error code
- * @param buf Buffer to store a human readable string to
- * @param bufsz Size of buffer pointed to by buf
- * @return
+ * Get error message string.
+ *
+ * @param errnum Error code for which to obtain human readable string.
+ * @param buf Buffer to store a human readable string to.
+ * @param bufsz Size of buffer pointed to by buf.
+ * @return Zero on success, errno otherwise.
  */
 int posix_strerror_r(int errnum, char *buf, size_t bufsz)
@@ -541,7 +585,8 @@
 
 /**
- *
- * @param s
- * @return
+ * Get length of the string.
+ *
+ * @param s String which length shall be determined.
+ * @return Length of the string.
  */
 size_t posix_strlen(const char *s)
@@ -553,8 +598,9 @@
 
 /**
- *
- * @param s
- * @param n
- * @return
+ * Get limited length of the string.
+ *
+ * @param s String which length shall be determined.
+ * @param n Maximum number of bytes that can be examined to determine length.
+ * @return The lower of either string length or n limit.
  */
 size_t posix_strnlen(const char *s, size_t n)
@@ -573,7 +619,8 @@
 
 /**
- *
- * @param signum
- * @return
+ * Get description of a signal.
+ *
+ * @param signum Signal number.
+ * @return Human readable signal description.
  */
 char *posix_strsignal(int signum)
Index: uspace/lib/posix/string.h
===================================================================
--- uspace/lib/posix/string.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/string.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file String manipulation.
  */
 
@@ -103,8 +103,8 @@
 extern size_t posix_strnlen(const char *s, size_t n);
 
-/* Signal messages */
+/* Signal Messages */
 extern char *posix_strsignal(int signum);
 
-/* Legacy declarations */
+/* Legacy Declarations */
 #ifndef POSIX_STRINGS_H_
 extern int posix_ffs(int i);
Index: uspace/lib/posix/strings.c
===================================================================
--- uspace/lib/posix/strings.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/strings.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Additional string manipulation.
  */
 
@@ -45,7 +45,8 @@
 
 /**
+ * Find first set bit (beginning with the least significant bit).
  *
- * @param i
- * @return
+ * @param i Integer in which to look for the first set bit.
+ * @return Index of first set bit. Bits are numbered starting at one.
  */
 int posix_ffs(int i)
@@ -82,8 +83,10 @@
 
 /**
+ * Compare two strings (case-insensitive).
  *
- * @param s1
- * @param s2
- * @return
+ * @param s1 First string to be compared.
+ * @param s2 Second string to be compared.
+ * @return Difference of the first pair of inequal characters,
+ *     or 0 if strings have the same content.
  */
 int posix_strcasecmp(const char *s1, const char *s2)
@@ -93,9 +96,11 @@
 
 /**
+ * Compare part of two strings (case-insensitive).
  *
- * @param s1
- * @param s2
- * @param n
- * @return
+ * @param s1 First string to be compared.
+ * @param s2 Second string to be compared.
+ * @param n Maximum number of characters to be compared.
+ * @return Difference of the first pair of inequal characters,
+ *     or 0 if strings have the same content.
  */
 int posix_strncasecmp(const char *s1, const char *s2, size_t n)
@@ -116,9 +121,11 @@
 
 /**
+ * Compare two memory areas.
  *
- * @param mem1
- * @param mem2
- * @param n
- * @return
+ * @param mem1 Pointer to the first area to compare.
+ * @param mem2 Pointer to the second area to compare.
+ * @param n Common size of both areas.
+ * @return If n is 0, return zero. If the areas match, return
+ *     zero. Otherwise return non-zero.
  */
 int posix_bcmp(const void *mem1, const void *mem2, size_t n)
@@ -128,19 +135,21 @@
 
 /**
+ * Copy bytes in memory with overlapping areas.
  *
- * @param dest
- * @param src
- * @param n
+ * @param src Source area.
+ * @param dest Destination area.
+ * @param n Number of bytes to copy.
  */
-void posix_bcopy(const void *dest, void *src, size_t n)
+void posix_bcopy(const void *src, void *dest, size_t n)
 {
 	/* Note that memmove has different order of arguments. */
-	memmove(src, dest, n);
+	memmove(dest, src, n);
 }
 
 /**
+ * Reset bytes in memory area to zero.
  *
- * @param mem
- * @param n
+ * @param mem Memory area to be zeroed.
+ * @param n Number of bytes to reset.
  */
 void posix_bzero(void *mem, size_t n)
@@ -150,8 +159,10 @@
 
 /**
+ * Scan string for a first occurence of a character.
  *
- * @param s
- * @param c
- * @return
+ * @param s String in which to look for the character.
+ * @param c Character to look for.
+ * @return Pointer to the specified character on success,
+ *     NULL pointer otherwise.
  */
 char *posix_index(const char *s, int c)
@@ -161,8 +172,10 @@
 
 /**
- * 
- * @param s
- * @param c
- * @return
+ * Scan string for a last occurence of a character.
+ *
+ * @param s String in which to look for the character.
+ * @param c Character to look for.
+ * @return Pointer to the specified character on success,
+ *     NULL pointer otherwise.
  */
 char *posix_rindex(const char *s, int c)
Index: uspace/lib/posix/strings.h
===================================================================
--- uspace/lib/posix/strings.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/strings.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Additional string manipulation.
  */
 
@@ -37,6 +37,6 @@
 #define POSIX_STRINGS_H_
 
+/* Search Functions */
 #ifndef POSIX_STRING_H_
-/* Search Functions */
 extern int posix_ffs(int i);
 #endif
@@ -56,5 +56,5 @@
 /* Legacy Functions */
 extern int posix_bcmp(const void *mem1, const void *mem2, size_t n);
-extern void posix_bcopy(const void *dest, void *src, size_t n);
+extern void posix_bcopy(const void *src, void *dest, size_t n);
 extern void posix_bzero(void *mem, size_t n);
 extern char *posix_index(const char *s, int c);
Index: uspace/lib/posix/sys/mman.h
===================================================================
--- uspace/lib/posix/sys/mman.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/sys/mman.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Memory management declarations.
  */
 
Index: uspace/lib/posix/sys/stat.c
===================================================================
--- uspace/lib/posix/sys/stat.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/sys/stat.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file File status handling.
  */
 
@@ -80,6 +80,5 @@
 	int rc = fstat(fd, &hst);
 	if (rc < 0) {
-		/* fstat() returns negative error code instead of using errno.
-		 */
+		/* fstat() returns negative error code instead of using errno. */
 		errno = -rc;
 		return -1;
@@ -96,5 +95,5 @@
  * @return Zero on success, -1 otherwise.
  */
-int posix_lstat(const char *path, struct posix_stat *st)
+int posix_lstat(const char *restrict path, struct posix_stat *restrict st)
 {
 	/* There are currently no symbolic links in HelenOS. */
@@ -109,11 +108,10 @@
  * @return Zero on success, -1 otherwise.
  */
-int posix_stat(const char *path, struct posix_stat *st)
+int posix_stat(const char *restrict path, struct posix_stat *restrict st)
 {
 	struct stat hst;
 	int rc = stat(path, &hst);
 	if (rc < 0) {
-		/* stat() returns negative error code instead of using errno.
-		 */
+		/* stat() returns negative error code instead of using errno. */
 		errno = -rc;
 		return -1;
Index: uspace/lib/posix/sys/stat.h
===================================================================
--- uspace/lib/posix/sys/stat.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/sys/stat.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file File status handling.
  */
 
Index: uspace/lib/posix/sys/types.h
===================================================================
--- uspace/lib/posix/sys/types.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/sys/types.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Data types definitions.
  */
 
@@ -49,8 +49,8 @@
 typedef sysarg_t posix_dev_t;
 
-/* PThread types */
+/* PThread Types */
 typedef struct posix_thread_attr posix_thread_attr_t;
 
-/* Clock types */
+/* Clock Types */
 typedef long posix_clock_t;
 typedef int posix_clockid_t;
Index: uspace/lib/posix/sys/wait.c
===================================================================
--- uspace/lib/posix/sys/wait.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/sys/wait.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Support for waiting.
  */
 
@@ -65,3 +65,2 @@
 /** @}
  */
-
Index: uspace/lib/posix/sys/wait.h
===================================================================
--- uspace/lib/posix/sys/wait.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/sys/wait.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file Support for waiting.
  */
 
Index: uspace/lib/posix/time.c
===================================================================
--- uspace/lib/posix/time.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/time.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Time measurement support.
  */
 
@@ -63,4 +63,9 @@
 #define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY)
 
+/**
+ *
+ * @param year
+ * @return
+ */
 static bool _is_leap_year(time_t year)
 {
@@ -76,4 +81,10 @@
 }
 
+/**
+ *
+ * @param year
+ * @param mon
+ * @return
+ */
 static int _days_in_month(time_t year, time_t mon)
 {
@@ -92,4 +103,11 @@
 }
 
+/**
+ *
+ * @param year
+ * @param mon
+ * @param mday
+ * @return
+ */
 static int _day_of_year(time_t year, time_t mon, time_t mday)
 {
@@ -102,5 +120,10 @@
 }
 
-/* Integer division that rounds to negative infinity.
+/**
+ * Integer division that rounds to negative infinity.
+ *
+ * @param op1
+ * @param op2
+ * @return
  */
 static time_t _floor_div(time_t op1, time_t op2)
@@ -113,5 +136,10 @@
 }
 
-/* Modulo that rounds to negative infinity.
+/**
+ * Modulo that rounds to negative infinity.
+ *
+ * @param op1
+ * @param op2
+ * @return
  */
 static time_t _floor_mod(time_t op1, time_t op2)
@@ -132,4 +160,11 @@
 }
 
+/**
+ *
+ * @param year
+ * @param mon
+ * @param mday
+ * @return
+ */
 static time_t _days_since_epoch(time_t year, time_t mon, time_t mday)
 {
@@ -139,5 +174,10 @@
 }
 
-/* Assumes normalized broken-down time. */
+/**
+ * Assumes normalized broken-down time.
+ *
+ * @param tm
+ * @return
+ */
 static time_t _secs_since_epoch(const struct posix_tm *tm)
 {
@@ -147,4 +187,11 @@
 }
 
+/**
+ * 
+ * @param year
+ * @param mon
+ * @param mday
+ * @return
+ */
 static int _day_of_week(time_t year, time_t mon, time_t mday)
 {
@@ -165,4 +212,9 @@
 };
 
+/**
+ *
+ * @param ltm
+ * @param ptm
+ */
 static void _posix_to_long_tm(struct _long_tm *ltm, struct posix_tm *ptm)
 {
@@ -179,4 +231,9 @@
 }
 
+/**
+ *
+ * @param ptm
+ * @param ltm
+ */
 static void _long_to_posix_tm(struct posix_tm *ptm, struct _long_tm *ltm)
 {
@@ -196,4 +253,8 @@
 }
 
+/**
+ * 
+ * @param tm
+ */
 static void _normalize_time(struct _long_tm *tm)
 {
@@ -241,6 +302,10 @@
 }
 
-/* Which day the week-based year starts on relative to the first calendar day.
+/**
+ * Which day the week-based year starts on relative to the first calendar day.
  * E.g. if the year starts on December 31st, the return value is -1.
+ *
+ * @param year
+ * @return
  */
 static int _wbyear_offset(int year)
@@ -250,6 +315,10 @@
 }
 
-/* Returns week-based year of the specified time.
+/**
+ * Returns week-based year of the specified time.
  * Assumes normalized broken-down time.
+ *
+ * @param tm
+ * @return
  */
 static int _wbyear(const struct posix_tm *tm)
@@ -268,7 +337,8 @@
 }
 
-/** Week number of the year, assuming weeks start on sunday.
- *  The first Sunday of January is the first day of week 1;
- *  days in the new year before this are in week 0.
+/**
+ * Week number of the year, assuming weeks start on sunday.
+ * The first Sunday of January is the first day of week 1;
+ * days in the new year before this are in week 0.
  *
  * @param tm Normalized broken-down time.
@@ -281,9 +351,10 @@
 }
 
-/** Week number of the year, assuming weeks start on monday.
- *  If the week containing January 1st has four or more days in the new year,
- *  then it is considered week 1. Otherwise, it is the last week of the previous
- *  year, and the next week is week 1. Both January 4th and the first Thursday
- *  of January are always in week 1.
+/**
+ * Week number of the year, assuming weeks start on monday.
+ * If the week containing January 1st has four or more days in the new year,
+ * then it is considered week 1. Otherwise, it is the last week of the previous
+ * year, and the next week is week 1. Both January 4th and the first Thursday
+ * of January are always in week 1.
  *
  * @param tm Normalized broken-down time.
@@ -305,7 +376,8 @@
 }
 
-/** Week number of the year, assuming weeks start on monday.
- *  The first Monday of January is the first day of week 1;
- *  days in the new year before this are in week 0. 
+/**
+ * Week number of the year, assuming weeks start on monday.
+ * The first Monday of January is the first day of week 1;
+ * days in the new year before this are in week 0. 
  *
  * @param tm Normalized broken-down time.
@@ -324,4 +396,7 @@
 char *posix_tzname[2];
 
+/**
+ * 
+ */
 void posix_tzset(void)
 {
@@ -333,4 +408,10 @@
 }
 
+/**
+ * 
+ * @param time1
+ * @param time0
+ * @return
+ */
 double posix_difftime(time_t time1, time_t time0)
 {
@@ -338,9 +419,10 @@
 }
 
-/** This function first normalizes the provided broken-down time
- *  (moves all values to their proper bounds) and then tries to
- *  calculate the appropriate time_t representation.
- *
- * @param timeptr Broken-down time.
+/**
+ * This function first normalizes the provided broken-down time
+ * (moves all values to their proper bounds) and then tries to
+ * calculate the appropriate time_t representation.
+ *
+ * @param tm Broken-down time.
  * @return time_t representation of the time, undefined value on overflow
  */
@@ -358,4 +440,9 @@
 }
 
+/**
+ *
+ * @param timer
+ * @return
+ */
 struct posix_tm *posix_gmtime(const time_t *timer)
 {
@@ -364,4 +451,10 @@
 }
 
+/**
+ * 
+ * @param timer
+ * @param result
+ * @return
+ */
 struct posix_tm *posix_gmtime_r(const time_t *restrict timer,
     struct posix_tm *restrict result)
@@ -394,5 +487,5 @@
 /**
  *
- * @param timep
+ * @param timer
  * @return
  */
@@ -403,4 +496,10 @@
 }
 
+/**
+ * 
+ * @param timer
+ * @param result
+ * @return
+ */
 struct posix_tm *posix_localtime_r(const time_t *restrict timer,
     struct posix_tm *restrict result)
@@ -413,5 +512,5 @@
 /**
  *
- * @param tm
+ * @param timeptr
  * @return
  */
@@ -422,4 +521,10 @@
 }
 
+/**
+ * 
+ * @param timeptr
+ * @param buf
+ * @return
+ */
 char *posix_asctime_r(const struct posix_tm *restrict timeptr,
     char *restrict buf)
@@ -448,5 +553,5 @@
 /**
  * 
- * @param timep
+ * @param timer
  * @return
  */
@@ -460,4 +565,10 @@
 }
 
+/**
+ * 
+ * @param timer
+ * @param buf
+ * @return
+ */
 char *posix_ctime_r(const time_t *timer, char *buf)
 {
@@ -477,6 +588,6 @@
  * @return
  */
-size_t posix_strftime(char *s, size_t maxsize,
-    const char *format, const struct posix_tm *tm)
+size_t posix_strftime(char *restrict s, size_t maxsize,
+    const char *restrict format, const struct posix_tm *restrict tm)
 {
 	// TODO: use locale
@@ -655,4 +766,27 @@
 }
 
+/**
+ * 
+ * @param s
+ * @param maxsize
+ * @param format
+ * @param tm
+ * @param loc
+ * @return
+ */
+extern size_t posix_strftime_l(char *restrict s, size_t maxsize,
+    const char *restrict format, const struct posix_tm *restrict tm,
+    posix_locale_t loc)
+{
+	// TODO
+	not_implemented();
+}
+
+/**
+ *
+ * @param clock_id
+ * @param res
+ * @return
+ */
 int posix_clock_getres(posix_clockid_t clock_id, struct posix_timespec *res)
 {
@@ -670,4 +804,10 @@
 }
 
+/**
+ * 
+ * @param clock_id
+ * @param tp
+ * @return
+ */
 int posix_clock_gettime(posix_clockid_t clock_id, struct posix_timespec *tp)
 {
@@ -688,4 +828,10 @@
 }
 
+/**
+ * 
+ * @param clock_id
+ * @param tp
+ * @return
+ */
 int posix_clock_settime(posix_clockid_t clock_id,
     const struct posix_timespec *tp)
@@ -706,4 +852,12 @@
 }
 
+/**
+ * 
+ * @param clock_id
+ * @param flags
+ * @param rqtp
+ * @param rmtp
+ * @return
+ */
 int posix_clock_nanosleep(posix_clockid_t clock_id, int flags,
     const struct posix_timespec *rqtp, struct posix_timespec *rmtp)
@@ -735,4 +889,11 @@
 };
 
+/**
+ * 
+ * @param clockid
+ * @param evp
+ * @param timerid
+ * @return
+ */
 int posix_timer_create(posix_clockid_t clockid,
     struct posix_sigevent *restrict evp,
@@ -743,4 +904,9 @@
 }
 
+/**
+ * 
+ * @param timerid
+ * @return
+ */
 int posix_timer_delete(posix_timer_t timerid)
 {
@@ -749,4 +915,9 @@
 }
 
+/**
+ * 
+ * @param timerid
+ * @return
+ */
 int posix_timer_getoverrun(posix_timer_t timerid)
 {
@@ -755,4 +926,10 @@
 }
 
+/**
+ * 
+ * @param timerid
+ * @param value
+ * @return
+ */
 int posix_timer_gettime(posix_timer_t timerid,
     struct posix_itimerspec *value)
@@ -762,4 +939,12 @@
 }
 
+/**
+ * 
+ * @param timerid
+ * @param flags
+ * @param value
+ * @param ovalue
+ * @return
+ */
 int posix_timer_settime(posix_timer_t timerid, int flags,
     const struct posix_itimerspec *restrict value,
@@ -783,7 +968,7 @@
 	if (task_stats) {
 		total_cycles = (posix_clock_t) (task_stats->kcycles + task_stats->ucycles);
-	}
-	free(task_stats);
-	task_stats = 0;
+		free(task_stats);
+		task_stats = 0;
+	}
 
 	return total_cycles;
Index: uspace/lib/posix/time.h
===================================================================
--- uspace/lib/posix/time.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/time.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Time measurement support.
  */
 
@@ -94,17 +94,14 @@
 
 /* Timezones */
-
 extern int posix_daylight;
 extern long posix_timezone;
 extern char *posix_tzname[2];
-
 extern void posix_tzset(void);
 
-/* time_t */
-
+/* Elapsed Time */
 extern double posix_difftime(time_t time1, time_t time0);
 
 /* Broken-down Time */
-extern time_t posix_mktime(struct posix_tm *timeptr);
+extern time_t posix_mktime(struct posix_tm *tm);
 extern struct posix_tm *posix_gmtime(const time_t *timer);
 extern struct posix_tm *posix_gmtime_r(const time_t *restrict timer,
@@ -120,14 +117,11 @@
 extern char *posix_ctime(const time_t *timer);
 extern char *posix_ctime_r(const time_t *timer, char *buf);
-
 extern size_t posix_strftime(char *restrict s, size_t maxsize,
     const char *restrict format, const struct posix_tm *restrict tm);
-
 extern size_t posix_strftime_l(char *restrict s, size_t maxsize,
     const char *restrict format, const struct posix_tm *restrict tm,
     posix_locale_t loc);
 
-/* Clocks. */
-
+/* Clocks */
 extern int posix_clock_getres(posix_clockid_t clock_id,
     struct posix_timespec *res);
@@ -139,8 +133,7 @@
     const struct posix_timespec *rqtp, struct posix_timespec *rmtp);
 
-/* Timers. */
-
 #if 0
 
+/* Timers */
 extern int posix_timer_create(posix_clockid_t clockid,
     struct posix_sigevent *restrict evp,
@@ -159,13 +152,17 @@
 extern posix_clock_t posix_clock(void);
 
-
 #ifndef LIBPOSIX_INTERNAL
 	#define tm posix_tm
-
 	#define timespec posix_timespec
 	#define itimerspec posix_itimerspec
 	#define timer_t posix_timer_t
 
+	#define daylight posix_daylight
+	#define timezone posix_timezone
+	#define tzname posix_tzname
+	#define tzset posix_tzset
+
 	#define difftime posix_difftime
+
 	#define mktime posix_mktime
 	#define gmtime posix_gmtime
@@ -174,9 +171,4 @@
 	#define localtime_r posix_localtime_r
 
-	#define daylight posix_daylight
-	#define timezone posix_timezone
-	#define tzname posix_tzname
-	#define tzset posix_tzset
-
 	#define asctime posix_asctime
 	#define asctime_r posix_asctime_r
@@ -184,4 +176,5 @@
 	#define ctime_r posix_ctime_r
 	#define strftime posix_strftime
+	#define strftime_l posix_strftime_l
 
 	#define clock_getres posix_clock_getres
Index: uspace/lib/posix/unistd.c
===================================================================
--- uspace/lib/posix/unistd.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/unistd.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Miscellaneous standard definitions.
  */
 
@@ -90,5 +90,5 @@
 	/* Always returns false, because there is no easy way to find
 	 * out under HelenOS. */
-	return false;
+	return 0;
 }
 
@@ -207,9 +207,5 @@
 		/* Check file existence by attempt to open it. */
 		int fd = open(path, O_RDONLY);
-		if (fd < 0) {
-			/* FIXME: open() returns error code as negative retval. */
-			errno = -fd;
-			fd = -1;
-		} else {
+		if (fd != -1) {
 			close(fd);
 		}
@@ -239,6 +235,8 @@
 		clk_tck = ((long) cpu_stats[0].frequency_mhz) * 1000000L;
 	}
-	free(cpu_stats);
-	cpu_stats = 0;
+	if (cpu_stats) {
+		free(cpu_stats);
+		cpu_stats = 0;
+	}
 
 	long phys_pages = 0;
@@ -248,7 +246,7 @@
 		phys_pages = (long) (mem_stats->total / getpagesize());
 		avphys_pages = (long) (mem_stats->free / getpagesize());
-	}
-	free(mem_stats);
-	mem_stats = 0;
+		free(mem_stats);
+		mem_stats = 0;
+	}
 
 	switch (name) {
Index: uspace/lib/posix/unistd.h
===================================================================
--- uspace/lib/posix/unistd.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/posix/unistd.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -31,5 +31,5 @@
  * @{
  */
-/** @file
+/** @file Miscellaneous standard definitions.
  */
 
Index: uspace/lib/usb/include/usb/classes/hub.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hub.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/usb/include/usb/classes/hub.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -119,4 +119,6 @@
      */
     uint16_t hub_characteristics;
+#define HUB_CHAR_POWER_PER_PORT_FLAG  (1 << 0)
+#define HUB_CHAR_NO_POWER_SWITCH_FLAG (1 << 1)
 
     /**
Index: uspace/lib/usbhost/include/usb/host/endpoint.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/endpoint.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/usbhost/include/usb/host/endpoint.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -61,7 +61,7 @@
 } endpoint_t;
 
-int endpoint_init(endpoint_t *instance, usb_address_t address,
-    usb_endpoint_t endpoint, usb_direction_t direction,
-    usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size);
+endpoint_t * endpoint_get(usb_address_t address, usb_endpoint_t endpoint,
+    usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed,
+    size_t max_packet_size);
 
 void endpoint_destroy(endpoint_t *instance);
Index: uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -82,21 +82,15 @@
     size_t data_size)
 {
-	endpoint_t *ep = malloc(sizeof(endpoint_t));
-	if (ep == NULL)
+	endpoint_t *ep = endpoint_get(
+	    address, endpoint, direction, type, speed, max_packet_size);
+	if (!ep)
 		return ENOMEM;
 
-	int ret = endpoint_init(ep, address, endpoint, direction, type, speed,
-	    max_packet_size);
-	if (ret != EOK) {
-		free(ep);
-		return ret;
-	}
-
-	ret = usb_endpoint_manager_register_ep(instance, ep, data_size);
+	const int ret =
+	    usb_endpoint_manager_register_ep(instance, ep, data_size);
 	if (ret != EOK) {
 		endpoint_destroy(ep);
-		return ret;
 	}
-	return EOK;
+	return ret;
 }
 #endif
Index: uspace/lib/usbhost/src/batch.c
===================================================================
--- uspace/lib/usbhost/src/batch.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/usbhost/src/batch.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -109,4 +109,5 @@
 	assert(instance);
 	assert(instance->ep);
+	assert(instance->next_step);
 	endpoint_release(instance->ep);
 	instance->next_step(instance);
Index: uspace/lib/usbhost/src/endpoint.c
===================================================================
--- uspace/lib/usbhost/src/endpoint.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/lib/usbhost/src/endpoint.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -39,21 +39,23 @@
 #include <usb/host/endpoint.h>
 
-int endpoint_init(endpoint_t *instance, usb_address_t address,
-    usb_endpoint_t endpoint, usb_direction_t direction,
-    usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size)
+endpoint_t * endpoint_get(usb_address_t address, usb_endpoint_t endpoint,
+    usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed,
+    size_t max_packet_size)
 {
-	assert(instance);
-	instance->address = address;
-	instance->endpoint = endpoint;
-	instance->direction = direction;
-	instance->transfer_type = type;
-	instance->speed = speed;
-	instance->max_packet_size = max_packet_size;
-	instance->toggle = 0;
-	instance->active = false;
-	fibril_mutex_initialize(&instance->guard);
-	fibril_condvar_initialize(&instance->avail);
-	endpoint_clear_hc_data(instance);
-	return EOK;
+	endpoint_t *instance = malloc(sizeof(endpoint_t));
+	if (instance) {
+		instance->address = address;
+		instance->endpoint = endpoint;
+		instance->direction = direction;
+		instance->transfer_type = type;
+		instance->speed = speed;
+		instance->max_packet_size = max_packet_size;
+		instance->toggle = 0;
+		instance->active = false;
+		fibril_mutex_initialize(&instance->guard);
+		fibril_condvar_initialize(&instance->avail);
+		endpoint_clear_hc_data(instance);
+	}
+	return instance;
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/srv/hid/input/ctl/stty.c
===================================================================
--- uspace/srv/hid/input/ctl/stty.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/srv/hid/input/ctl/stty.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -34,4 +34,6 @@
  * @file
  * @brief Serial TTY-like keyboard controller driver.
+ *
+ * Keyboard emulation on a serial terminal.
  */
 
@@ -63,4 +65,9 @@
 #include <stdio.h>
 
+/**
+ * Sequnece definitions are primarily for Xterm. Additionally we define
+ * sequences that are unique to Gnome terminal -- most are the same but
+ * some differ.
+ */
 static int seq_defs[] = {
 	/* Not shifted */
@@ -81,4 +88,5 @@
 	0,	KC_MINUS,	0x2d, GSP_END,
 	0,	KC_EQUALS,	0x3d, GSP_END,
+
 	0,	KC_BACKSPACE,	0x08, GSP_END,
 
@@ -216,4 +224,11 @@
 	0,	KC_RIGHT,	0x1b, 0x5b, 0x43, GSP_END,
 
+	/*
+	 * Sequences specific to Gnome terminal
+	 */
+	0,	KC_BACKSPACE,	0x7f, GSP_END, /* ASCII DEL */
+	0,	KC_HOME,	0x1b, 0x4f, 0x48, GSP_END,
+	0,	KC_END,		0x1b, 0x4f, 0x46, GSP_END,
+
 	0,	0
 };
Index: uspace/srv/hid/input/generic/gsp.c
===================================================================
--- uspace/srv/hid/input/generic/gsp.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/srv/hid/input/generic/gsp.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -104,5 +104,5 @@
 		if (key == 0) break;
 
-		/* Insert one sequence. */		
+		/* Insert one sequence. */
 		rc = gsp_insert_seq(p, dp, mods, key);
 		if (rc != 0)
@@ -197,5 +197,6 @@
 
 	if (t == NULL) {
-		printf("gsp_step: not found\n");
+		printf("gsp_step: not found, state=%d, input=0x%x\n",
+		    state, input);
 		*mods = 0;
 		*key = 0;
@@ -205,4 +206,5 @@
 	*mods = t->out_mods;
 	*key = t->out_key;
+
 	return t->new_state;
 }
Index: uspace/srv/hid/input/generic/input.c
===================================================================
--- uspace/srv/hid/input/generic/input.c	(revision 5889fc748064079a47e18694d50ee1eefd0848ef)
+++ uspace/srv/hid/input/generic/input.c	(revision 6c69d19e1d534bd8ed18b32d34a896128d469e16)
@@ -410,5 +410,5 @@
 #endif
 #if defined(MACHINE_msim)
-	kbd_add_dev(&msim_port, &pc_ctl);
+	kbd_add_dev(&msim_port, &stty_ctl);
 #endif
 #if (defined(MACHINE_lgxemul) || defined(MACHINE_bgxemul)) && defined(CONFIG_FB)
