Index: .bzrignore
===================================================================
--- .bzrignore	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ .bzrignore	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -269,2 +269,8 @@
 uspace/dist/srv/dhcp
 uspace/srv/net/dhcp/dhcp
+uspace/app/netspeed/netspeed
+uspace/dist/app/netspeed
+uspace/app/df/df
+uspace/dist/app/df
+uspace/app/download/download
+uspace/dist/app/download
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ boot/Makefile.common	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -174,4 +174,5 @@
 	$(USPACE_PATH)/app/dnscfg/dnscfg \
 	$(USPACE_PATH)/app/dnsres/dnsres \
+	$(USPACE_PATH)/app/download/download \
 	$(USPACE_PATH)/app/edit/edit \
 	$(USPACE_PATH)/app/inet/inet \
@@ -197,4 +198,5 @@
 	$(USPACE_PATH)/app/nettest3/nettest3 \
 	$(USPACE_PATH)/app/netecho/netecho \
+	$(USPACE_PATH)/app/netspeed/netspeed \
 	$(USPACE_PATH)/app/nterm/nterm \
 	$(USPACE_PATH)/app/ping/ping \
Index: kernel/arch/mips32/include/arch/asm.h
===================================================================
--- kernel/arch/mips32/include/arch/asm.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ kernel/arch/mips32/include/arch/asm.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -42,12 +42,5 @@
 NO_TRACE static inline void cpu_sleep(void)
 {
-	/*
-	 * Unfortunatelly most of the simulators do not support
-	 *
-	 * asm volatile (
-	 *     "wait"
-	 * );
-	 *
-	 */
+	asm volatile ("wait");
 }
 
Index: kernel/generic/src/debug/panic.c
===================================================================
--- kernel/generic/src/debug/panic.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ kernel/generic/src/debug/panic.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -96,7 +96,13 @@
 	printf("THE=%p: ", THE);
 	if (THE != NULL) {
-		printf("pe=%" PRIun " thr=%p task=%p cpu=%p as=%p"
+		printf("pd=%" PRIun " thread=%p task=%p cpu=%p as=%p"
 		    " magic=%#" PRIx32 "\n", THE->preemption_disabled,
 		    THE->thread, THE->task, THE->cpu, THE->as, THE->magic);
+		
+		if (THE->thread != NULL)
+			printf("thread=\"%s\"\n", THE->thread->name);
+		
+		if (THE->task != NULL)
+			printf("task=\"%s\"\n", THE->task->name);
 	} else
 		printf("invalid\n");
Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ kernel/generic/src/mm/frame.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -443,6 +443,5 @@
 NO_TRACE static void zone_mark_unavailable(zone_t *zone, size_t index)
 {
-	if (!(zone->flags & ZONE_AVAILABLE))
-		return;
+	ASSERT(zone->flags & ZONE_AVAILABLE);
 	
 	frame_t *frame = zone_get_frame(zone, index);
Index: tools/config.py
===================================================================
--- tools/config.py	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ tools/config.py	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -363,6 +363,7 @@
 def create_output(mkname, mcname, config, rules):
 	"Create output configuration"
-	
-	timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
+
+	timestamp_unix = int(time.time())
+	timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp_unix))
 	
 	sys.stderr.write("Fetching current revision identifier ... ")
@@ -423,4 +424,8 @@
 		outmc.write('#define REVISION %s\n' % revision)
 		defs += ' "-DREVISION=%s"' % revision
+	
+	outmk.write('TIMESTAMP_UNIX = %d\n' % timestamp_unix)
+	outmc.write('#define TIMESTAMP_UNIX %d\n' % timestamp_unix)
+	defs += ' "-DTIMESTAMP_UNIX=%d"\n' % timestamp_unix
 	
 	outmk.write('TIMESTAMP = %s\n' % timestamp)
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/Makefile	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -42,4 +42,5 @@
 	app/dnscfg \
 	app/dnsres \
+	app/download \
 	app/edit \
 	app/getterm \
@@ -70,4 +71,5 @@
 	app/vuhid \
 	app/netecho \
+	app/netspeed \
 	app/nettest1 \
 	app/nettest2 \
@@ -233,4 +235,5 @@
 	lib/gui \
 	lib/hound \
+	lib/http \
 	lib/softrend \
 	lib/draw \
@@ -238,4 +241,5 @@
 	lib/nic \
 	lib/ext4 \
+	lib/uri \
 	lib/usb \
 	lib/usbhost \
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/Makefile.common	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -141,4 +141,7 @@
 LIBBITHENGE_PREFIX = $(LIB_PREFIX)/bithenge
 
+LIBHTTP_PREFIX = $(LIB_PREFIX)/http
+LIBURI_PREFIX = $(LIB_PREFIX)/uri
+
 ifeq ($(STATIC_NEEDED),y)
 	STATIC_BUILD = y
Index: uspace/app/df/df.c
===================================================================
--- uspace/app/df/df.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/app/df/df.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -50,5 +50,5 @@
 #define HEADER_TABLE_HR "Filesystem           Size           Used      Available Used%% Mounted on"
 
-#define PERCENTAGE(x, tot) ((unsigned long long) (100L * (x) / (tot)))
+#define PERCENTAGE(x, tot) (tot ? (100ULL * (x) / (tot)) : 0)
 #define FSBK_TO_BK(x, fsbk, bk) \
 	(((fsbk) != 0 && (fsbk) < (bk)) ? \
@@ -59,5 +59,5 @@
 static unsigned int human_readable;
 
-static int size_to_human_readable(char buf[], uint64_t bytes);
+static void size_to_human_readable(char *buf, uint64_t bytes);
 static void print_header(void);
 static void print_statfs(struct statfs *, char *, char *);
@@ -90,5 +90,6 @@
  
 		case ':':
-			fprintf(stderr, "Option -%c requires an operand\n", optopt);
+			fprintf(stderr, "Option -%c requires an operand\n",
+			    optopt);
 			errflg++;
 			break;
@@ -100,5 +101,6 @@
 
 		default:
-			fprintf(stderr, "Unknown error while parsing command line options.");
+			fprintf(stderr,
+			    "Unknown error while parsing command line options");
 			errflg++;
 			break;
@@ -107,5 +109,5 @@
 
 	if (optind > argc) {
-		fprintf(stderr, "Too many input parameter\n");
+		fprintf(stderr, "Too many input parameters\n");
 		errflg++;
 	}
@@ -118,4 +120,5 @@
 	LIST_INITIALIZE(mtab_list);
 	get_mtab_list(&mtab_list);
+
 	print_header();
 	list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {
@@ -123,24 +126,20 @@
 		print_statfs(&st, mtab_ent->fs_name, mtab_ent->mp);
 	}
+
 	putchar('\n');
 	return 0;
 }
 
-static int size_to_human_readable(char buf[], uint64_t bytes)
+static void size_to_human_readable(char *buf, uint64_t bytes)
 {
 	const char *units = "BkMGTPEZY";
 	int i = 0;
-	int limit;
-
-	limit = str_length(units);
+
 	while (bytes >= 1024) {
-		if (i >= limit) 
-			return -1;
 		bytes /= 1024;
 		i++;
 	}
-	snprintf(buf, 6, "%4llu%c", (unsigned long long)bytes, units[i]);
-
-	return 0;
+
+	snprintf(buf, 6, "%4llu%c", (unsigned long long) bytes, units[i]);
 }
 
@@ -151,4 +150,5 @@
 	else
 		printf(HEADER_TABLE, unit_size);
+
 	putchar('\n');
 }
@@ -156,27 +156,38 @@
 static void print_statfs(struct statfs *st, char *name, char *mountpoint)
 {
+	uint64_t const used_blocks = st->f_blocks - st->f_bfree;
+	unsigned const perc_used = PERCENTAGE(used_blocks, st->f_blocks);
+
 	printf("%10s", name);
 
 	if (human_readable) {
 		char tmp[1024];
+
+		/* Print size */
 		size_to_human_readable(tmp, st->f_blocks *  st->f_bsize);
-		printf(" %14s", tmp);                                                                  /* Size       */
-		size_to_human_readable(tmp, (st->f_blocks - st->f_bfree)  *  st->f_bsize);
-		printf(" %14s", tmp);                                                                  /* Used       */
+		printf(" %14s", tmp);
+
+		/* Number of used blocks */
+		size_to_human_readable(tmp, used_blocks  *  st->f_bsize);
+		printf(" %14s", tmp);
+
+		/* Number of available blocks */
 		size_to_human_readable(tmp, st->f_bfree *  st->f_bsize);
-		printf(" %14s", tmp);                                                                  /* Available  */
-		printf(" %4llu%% %s\n", 
-			(st->f_blocks)?PERCENTAGE(st->f_blocks - st->f_bfree, st->f_blocks):0L,        /* Used%      */
-			mountpoint                                                                     /* Mounted on */
-		);
-	}
-	else
-		printf(" %15llu %14llu %14llu %4llu%% %s\n", 
-			FSBK_TO_BK(st->f_blocks, st->f_bsize, unit_size),                              /* Blocks     */
-			FSBK_TO_BK(st->f_blocks - st->f_bfree, st->f_bsize, unit_size),                /* Used       */
-			FSBK_TO_BK(st->f_bfree, st->f_bsize, unit_size),                               /* Available  */
-			(st->f_blocks)?PERCENTAGE(st->f_blocks - st->f_bfree, st->f_blocks):0L,        /* Used%      */
-			mountpoint                                                                     /* Mounted on */
-		);
+		printf(" %14s", tmp);
+
+		/* Percentage of used blocks */
+		printf(" %4u%%", perc_used);
+
+		/* Mount point */
+		printf(" %s\n", mountpoint);
+	} else {
+		/* Blocks / Used blocks / Available blocks / Used% / Mounted on */
+		printf(" %15llu %14llu %14llu %4u%% %s\n", 
+		    FSBK_TO_BK(st->f_blocks, st->f_bsize, unit_size),
+		    FSBK_TO_BK(used_blocks, st->f_bsize, unit_size),
+		    FSBK_TO_BK(st->f_bfree, st->f_bsize, unit_size),
+		    perc_used,
+		    mountpoint);
+	}
 
 }
Index: uspace/app/download/Makefile
===================================================================
--- uspace/app/download/Makefile	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
+++ uspace/app/download/Makefile	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2013 Martin Sucha
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBHTTP_PREFIX)/libhttp.a $(LIBURI_PREFIX)/liburi.a
+EXTRA_CFLAGS = -I$(LIBHTTP_PREFIX) -I$(LIBURI_PREFIX)
+DEFS = -DRELEASE=$(RELEASE)
+BINARY = download
+
+SOURCES = \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/download/main.c
===================================================================
--- uspace/app/download/main.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
+++ uspace/app/download/main.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup download
+ * @{
+ */
+
+/** @file
+ * Download a file from a HTTP server
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <str_error.h>
+#include <task.h>
+#include <macros.h>
+
+#include <net/in.h>
+#include <net/inet.h>
+#include <net/socket.h>
+
+#include <http.h>
+#include <uri.h>
+
+#define NAME "download"
+#ifdef TIMESTAMP_UNIX
+#define VERSION STRING(RELEASE) "-" STRING(TIMESTAMP_UNIX)
+#else
+#define VERSION STRING(RELEASE)
+#endif
+#define USER_AGENT "HelenOS-" NAME "/" VERSION
+
+static void syntax_print(void)
+{
+	fprintf(stderr, "Usage: download <url>\n");
+	fprintf(stderr, "  This will write the data to stdout, so you may want\n");
+	fprintf(stderr, "  to redirect the output, e.g.\n");
+	fprintf(stderr, "\n");
+	fprintf(stderr, "    download http://helenos.org/ | to helenos.html\n\n");
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc != 2) {
+		syntax_print();
+		return 2;
+	}
+	
+	uri_t *uri = uri_parse(argv[1]);
+	if (uri == NULL) {
+		fprintf(stderr, "Failed parsing URI\n");
+		return 2;
+	}
+	
+	if (!uri_validate(uri)) {
+		fprintf(stderr, "The URI is invalid\n");
+		return 2;
+	}
+	
+	/* TODO uri_normalize(uri) */
+	
+	if (str_cmp(uri->scheme, "http") != 0) {
+		fprintf(stderr, "Only http scheme is supported at the moment\n");
+		return 2;
+	}
+	
+	if (uri->host == NULL) {
+		fprintf(stderr, "host not set\n");
+		return 2;
+	}
+	
+	uint16_t port = 80;
+	if (uri->port != NULL) {
+		int rc = str_uint16_t(uri->port, NULL, 10, true, &port);
+		if (rc != EOK) {
+			fprintf(stderr, "Invalid port number: %s\n", uri->port);
+			return 2;
+		}
+	}
+	
+	const char *path = uri->path;
+	if (path == NULL || *path == 0)
+		path = "/";
+	char *server_path = NULL;
+	if (uri->query == NULL) {
+		server_path = str_dup(path);
+		if (server_path == NULL) {
+			fprintf(stderr, "Failed allocating path\n");
+			uri_destroy(uri);
+			return 3;
+		}
+	}
+	else {
+		int rc = asprintf(&server_path, "%s?%s", path, uri->query);
+		if (rc < 0) {
+			fprintf(stderr, "Failed allocating path\n");
+			uri_destroy(uri);
+			return 3;
+		}
+	}
+	
+	http_request_t *req = http_request_create("GET", server_path);
+	free(server_path);
+	if (req == NULL) {
+		fprintf(stderr, "Failed creating request\n");
+		uri_destroy(uri);
+		free(server_path);
+		return 3;
+	}
+	
+	http_header_t *header_host = http_header_create("Host", uri->host);
+	if (header_host == NULL) {
+		fprintf(stderr, "Failed creating Host header\n");
+		uri_destroy(uri);
+		free(server_path);
+		return 3;
+	}
+	list_append(&header_host->link, &req->headers);
+	
+	http_header_t *header_ua = http_header_create("User-Agent", USER_AGENT);
+	if (header_ua == NULL) {
+		fprintf(stderr, "Failed creating User-Agent header\n");
+		uri_destroy(uri);
+		free(server_path);
+		return 3;
+	}
+	list_append(&header_ua->link, &req->headers);
+	
+	http_t *http = http_create(uri->host, port);
+	if (http == NULL) {
+		uri_destroy(uri);
+		free(server_path);
+		fprintf(stderr, "Failed creating HTTP object\n");
+		return 3;
+	}
+	
+	int rc = http_connect(http);
+	if (rc != EOK) {
+		fprintf(stderr, "Failed connecting: %s\n", str_error(rc));
+		uri_destroy(uri);
+		free(server_path);
+		return rc;
+	}
+	
+	rc = http_send_request(http, req);
+	if (rc != EOK) {
+		fprintf(stderr, "Failed sending request: %s\n", str_error(rc));
+		uri_destroy(uri);
+		free(server_path);
+		return rc;
+	}
+	
+	http_response_t *response = NULL;
+	rc = http_receive_response(http, &response);
+	if (rc != EOK) {
+		fprintf(stderr, "Failed receiving response: %s\n", str_error(rc));
+		uri_destroy(uri);
+		free(server_path);
+		return rc;
+	}
+	
+	if (response->status != 200) {
+		fprintf(stderr, "Server returned status %d %s\n", response->status,
+		    response->message);
+	}
+	else {
+		size_t buf_size = 4096;
+		void *buf = malloc(buf_size);
+		if (buf == NULL) {
+			fprintf(stderr, "Failed allocating buffer\n)");
+			uri_destroy(uri);
+			free(server_path);
+			return ENOMEM;
+		}
+		
+		int body_size;
+		while ((body_size = http_receive_body(http, buf, buf_size)) > 0) {
+			fwrite(buf, 1, body_size, stdout);
+		}
+		
+		if (body_size != 0) {
+			fprintf(stderr, "Failed receiving body: %s", str_error(body_size));
+		}
+	}
+	
+	uri_destroy(uri);
+	free(server_path);
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/app/netspeed/Makefile
===================================================================
--- uspace/app/netspeed/Makefile	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
+++ uspace/app/netspeed/Makefile	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2013 Martin Sucha
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = 
+EXTRA_CFLAGS = 
+BINARY = netspeed
+
+SOURCES = \
+	netspeed.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/netspeed/netspeed.c
===================================================================
--- uspace/app/netspeed/netspeed.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
+++ uspace/app/netspeed/netspeed.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup netspeed
+ * @{
+ */
+
+/** @file
+ * Network speed measurement (iperf counterpart)
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <str_error.h>
+#include <task.h>
+
+#include <net/in.h>
+#include <net/inet.h>
+#include <net/socket.h>
+
+#define NAME "netspeed"
+
+static int server(sock_type_t sock_type, unsigned port, void *buf, size_t bufsize)
+{
+	struct sockaddr_in addr;
+	
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	
+	int rc = inet_pton(AF_INET, "127.0.0.1", (void *)
+	    &addr.sin_addr.s_addr);
+	if (rc != EOK) {
+		fprintf(stderr, "inet_pton failed: %s\n", str_error(rc));
+		return rc;
+	}
+
+	int listen_sd = socket(PF_INET, sock_type, 0);
+	if (listen_sd < 0) {
+		fprintf(stderr, "socket failed: %s\n", str_error(rc));
+		return rc;
+	}
+	
+	rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
+	if (rc != EOK) {
+		fprintf(stderr, "bind failed: %s\n", str_error(rc));
+		closesocket(listen_sd);
+		return rc;
+	}
+	
+	rc = listen(listen_sd, 2);
+	if (rc != EOK) {
+		fprintf(stderr, "listen failed: %s\n", str_error(rc));
+		closesocket(listen_sd);
+		return rc;
+	}
+	
+	int conn_sd;
+	struct sockaddr_in raddr;
+	socklen_t raddr_len = sizeof(raddr);
+	if (sock_type == SOCK_STREAM) {
+		conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
+		    &raddr_len);
+		if (conn_sd < 0) {
+			fprintf(stderr, "accept failed: %s\n", str_error(conn_sd));
+			closesocket(listen_sd);
+			return conn_sd;
+		}
+	} else {
+		conn_sd = listen_sd;
+	}
+	
+	while (true) {
+		rc = recvfrom(conn_sd, buf, bufsize, 0, (struct sockaddr *) &raddr,
+		    &raddr_len);
+		if (rc <= 0) {
+			if (rc < 0)
+				fprintf(stderr, "recvfrom failed: %s\n", str_error(rc));
+			break;
+		}
+	}
+	
+	if (sock_type == SOCK_STREAM)
+		closesocket(conn_sd);
+	closesocket(listen_sd);
+	
+	return rc;
+}
+
+static int client(sock_type_t sock_type, const char *address, unsigned port,
+    unsigned long count, char *buf, size_t bufsize)
+{
+	struct sockaddr_in addr;
+	
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	
+	int rc = inet_pton(AF_INET, address, (void *) &addr.sin_addr.s_addr);
+	if (rc != EOK) {
+		fprintf(stderr, "inet_pton failed: %s\n", str_error(rc));
+		return rc;
+	}
+	
+	int conn_sd = socket(PF_INET, sock_type, 0);
+	if (conn_sd < 0) {
+		fprintf(stderr, "socket failed: %s\n", str_error(rc));
+		return rc;
+	}
+	
+	if (sock_type == SOCK_STREAM) {
+		rc = connect(conn_sd, (struct sockaddr *) &addr, sizeof(addr));
+		if (rc != EOK) {
+			fprintf(stderr, "connect failed: %s\n", str_error(rc));
+			closesocket(conn_sd);
+			return rc;
+		}
+	}
+	
+	for (size_t pos = 0; pos < bufsize; pos++) {
+		buf[pos] = '0' + (pos % 10);
+	}
+	
+	for (unsigned long i = 0; i < count; i++) {
+		if (sock_type == SOCK_STREAM) {
+			rc = send(conn_sd, buf, bufsize, 0);
+		} else {
+			rc = sendto(conn_sd, buf, bufsize, 0,
+			    (struct sockaddr *) &addr, sizeof(addr));
+		}
+		if (rc != EOK) {
+			fprintf(stderr, "send failed: %s\n", str_error(rc));
+			break;
+		}
+	}
+	
+	closesocket(conn_sd);
+	return rc;
+}
+
+static void syntax_print(void)
+{
+	fprintf(stderr, "Usage: netspeed <tcp|udp> server [port] <buffer size>\n");
+	fprintf(stderr, "       netspeed <tcp|udp> client <ip> <port> <count> <buffer size>\n");
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc < 3) {
+		syntax_print();
+		return 2;
+	}
+	
+	sock_type_t sock_type;
+	if (str_cmp(argv[1], "tcp") == 0) {
+		sock_type = SOCK_STREAM;
+	} else if (str_cmp(argv[1], "udp") == 0) {
+		sock_type = SOCK_DGRAM;
+	} else {
+		fprintf(stderr, "Invalid socket type\n");
+		syntax_print();
+		return 1;
+	}
+	
+	char *endptr;
+	int arg = 3;
+	unsigned long port = 5001;
+	const char *address;
+	bool is_server;
+	unsigned long count = 0;
+	
+	if (str_cmp(argv[2], "server") == 0) {
+		is_server = true;
+		if (argc < 4) {
+			syntax_print();
+			return 2;
+		}
+		if (argc > 4) {
+			port = strtoul(argv[3], &endptr, 0);
+			if (*endptr != 0) {
+				fprintf(stderr, "Invalid port number\n");
+				syntax_print();
+				return 1;
+			}
+			arg = 4;
+		}
+	}
+	else if (str_cmp(argv[2], "client") == 0) {
+		is_server = false;
+		if (argc < 6) {
+			syntax_print();
+			return 2;
+		}
+		address = argv[3];
+		port = strtoul(argv[4], &endptr, 0);
+		if (*endptr != 0) {
+			fprintf(stderr, "Invalid port number\n");
+			syntax_print();
+			return 1;
+		}
+		
+		count = strtoul(argv[5], &endptr, 0);
+		if (*endptr != 0) {
+			fprintf(stderr, "Invalid count\n");
+			syntax_print();
+			return 1;
+		}
+		
+		arg = 6;
+	}
+	else {
+		fprintf(stderr, "Invalid client/server mode\n");
+		syntax_print();
+		return 2;
+	}
+	
+	if (argc < arg + 1) {
+		syntax_print();
+		return 2;
+	}
+	
+	unsigned long bufsize = strtoul(argv[arg], &endptr, 0);
+	if (*endptr != 0 || bufsize == 0) {
+		fprintf(stderr, "Invalid buffer size\n");
+		syntax_print();
+		return 1;
+	}
+	
+	void *buf = malloc(bufsize);
+	if (buf == NULL) {
+		fprintf(stderr, "Cannot allocate buffer\n");
+		return ENOMEM;
+	}
+	
+	int rc = EOK;
+	if (is_server) {
+		rc = server(sock_type, port, buf, bufsize);
+		if (rc != EOK)
+			fprintf(stderr, "Server failed: %s\n", str_error(rc));
+	} else {
+		rc = client(sock_type, address, port, count, buf, bufsize);
+		if (rc != EOK)
+			fprintf(stderr, "Client failed: %s\n", str_error(rc));
+	}
+	
+	free(buf);
+
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/app/wavplay/dplay.c
===================================================================
--- uspace/app/wavplay/dplay.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/app/wavplay/dplay.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -151,5 +151,6 @@
 	    device_event_callback, pb);
 	if (ret != EOK) {
-		printf("Failed to register event callback.\n");
+		printf("Failed to register event callback: %s.\n",
+		    str_error(ret));
 		return;
 	}
@@ -285,5 +286,6 @@
 			    pb->f.sample_format);
 			if (ret != EOK) {
-				printf("Failed to start playback\n");
+				printf("Failed to start playback: %s\n",
+				    str_error(ret));
 				return;
 			}
@@ -291,5 +293,6 @@
 			ret = audio_pcm_get_buffer_pos(pb->device, &pos);
 			if (ret != EOK) {
-				printf("Failed to update position indicator\n");
+				printf("Failed to update position indicator "
+				   "%s\n", str_error(ret));
 			}
 		}
@@ -308,5 +311,6 @@
 		const int ret = audio_pcm_get_buffer_pos(pb->device, &pos);
 		if (ret != EOK) {
-			printf("Failed to update position indicator\n");
+			printf("Failed to update position indicator %s\n",
+			    str_error(ret));
 		}
 		getuptime(&time);
@@ -350,5 +354,5 @@
 	ret = audio_pcm_get_info_str(session, &info);
 	if (ret != EOK) {
-		printf("Failed to get PCM info.\n");
+		printf("Failed to get PCM info: %s.\n", str_error(ret));
 		goto close_session;
 	}
Index: uspace/app/wavplay/drec.c
===================================================================
--- uspace/app/wavplay/drec.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/app/wavplay/drec.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -213,7 +213,6 @@
 	wave_header_t header;
 	fseek(rec.file, sizeof(header), SEEK_SET);
-	const char *error;
-	if (ret != EOK) {
-		printf("Error parsing wav header: %s.\n", error);
+	if (ret != EOK) {
+		printf("Error parsing wav header\n");
 		goto cleanup;
 	}
Index: uspace/app/wavplay/main.c
===================================================================
--- uspace/app/wavplay/main.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/app/wavplay/main.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -79,8 +79,12 @@
 	    &format.sampling_rate, &format.sample_format, &error);
 	if (ret != EOK) {
-		printf("Error parsing wav header: %s.\n", error);
+		printf("Error parsing `%s' wav header: %s.\n", filename, error);
 		fclose(source);
 		return EINVAL;
 	}
+
+	printf("File `%s' format: %u channel(s), %uHz, %s.\n", filename,
+	    format.channels, format.sampling_rate,
+	    pcm_sample_format_str(format.sample_format));
 
 	/* Allocate buffer and create new context */
@@ -136,8 +140,11 @@
 	    &format.sampling_rate, &format.sample_format, &error);
 	if (ret != EOK) {
-		printf("Error parsing wav header: %s.\n", error);
+		printf("Error parsing `%s' wav header: %s.\n", filename, error);
 		fclose(source);
 		return EINVAL;
 	}
+	printf("File `%s' format: %u channel(s), %uHz, %s.\n", filename,
+	    format.channels, format.sampling_rate,
+	    pcm_sample_format_str(format.sample_format));
 
 	/* Connect new playback context */
Index: uspace/app/wavplay/wave.c
===================================================================
--- uspace/app/wavplay/wave.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/app/wavplay/wave.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -81,8 +81,10 @@
 	}
 
-	if (uint16_t_le2host(header->subchunk1_size) != PCM_SUBCHUNK1_SIZE) {
+	if (uint32_t_le2host(header->subchunk1_size) != PCM_SUBCHUNK1_SIZE) {
+		//TODO subchunk 1 sizes other than 16 are allowed ( 18, 40)
+		//http://www-mmsp.ece.mcgill.ca/documents/AudioFormats/WAVE/WAVE.html
 		if (error)
 			*error = "invalid subchunk1 size";
-		return EINVAL;
+//		return EINVAL;
 	}
 
@@ -94,10 +96,14 @@
 
 	if (str_lcmp(header->subchunk2_id, SUBCHUNK2_ID, 4) != 0) {
+		//TODO basedd on subchunk1 size, we might be reading wrong
+		//offset
 		if (error)
 			*error = "invalid subchunk2 id";
-		return EINVAL;
+//		return EINVAL;
 	}
 
 
+	//TODO data and data_size are incorrect in extended wav formats
+	//pcm params are OK
 	if (data)
 		*data = header->data;
Index: uspace/drv/audio/sb16/main.c
===================================================================
--- uspace/drv/audio/sb16/main.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/audio/sb16/main.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -49,7 +49,6 @@
 
 static int sb_add_device(ddf_dev_t *device);
-static int sb_get_res(ddf_dev_t *device, uintptr_t *sb_regs,
-    size_t *sb_regs_size, uintptr_t *mpu_regs, size_t *mpu_regs_size,
-    int *irq, int *dma8, int *dma16);
+static int sb_get_res(ddf_dev_t *device, addr_range_t **pp_sb_regs,
+    addr_range_t **pp_mpu_regs, int *irq, int *dma8, int *dma16);
 static int sb_enable_interrupts(ddf_dev_t *device);
 
@@ -103,10 +102,11 @@
 	}
 
-	uintptr_t sb_regs = 0, mpu_regs = 0;
-	size_t sb_regs_size = 0, mpu_regs_size = 0;
+	addr_range_t sb_regs;
+	addr_range_t *p_sb_regs = &sb_regs;
+	addr_range_t mpu_regs;
+	addr_range_t *p_mpu_regs = &mpu_regs;
 	int irq = 0, dma8 = 0, dma16 = 0;
 
-	rc = sb_get_res(device, &sb_regs, &sb_regs_size, &mpu_regs,
-	    &mpu_regs_size, &irq, &dma8, &dma16);
+	rc = sb_get_res(device, &p_sb_regs, &p_mpu_regs, &irq, &dma8, &dma16);
 	if (rc != EOK) {
 		ddf_log_error("Failed to get resources: %s.", str_error(rc));
@@ -114,5 +114,5 @@
 	}
 
-	sb16_irq_code((void*)sb_regs, dma8, dma16, irq_cmds, irq_ranges);
+	sb16_irq_code(p_sb_regs, dma8, dma16, irq_cmds, irq_ranges);
 
 	irq_code_t irq_code = {
@@ -139,6 +139,5 @@
 	}
 
-	rc = sb16_init_sb16(soft_state, (void*)sb_regs, sb_regs_size, device,
-	    dma8, dma16);
+	rc = sb16_init_sb16(soft_state, p_sb_regs, device, dma8, dma16);
 	if (rc != EOK) {
 		ddf_log_error("Failed to init sb16 driver: %s.",
@@ -147,5 +146,5 @@
 	}
 
-	rc = sb16_init_mpu(soft_state, (void*)mpu_regs, mpu_regs_size);
+	rc = sb16_init_mpu(soft_state, p_mpu_regs);
 	if (rc == EOK) {
 		ddf_fun_t *mpu_fun =
@@ -173,7 +172,6 @@
 }
 
-static int sb_get_res(ddf_dev_t *device, uintptr_t *sb_regs,
-    size_t *sb_regs_size, uintptr_t *mpu_regs, size_t *mpu_regs_size,
-    int *irq, int *dma8, int *dma16)
+static int sb_get_res(ddf_dev_t *device, addr_range_t **pp_sb_regs,
+    addr_range_t **pp_mpu_regs, int *irq, int *dma8, int *dma16)
 {
 	assert(device);
@@ -225,23 +223,18 @@
 	}
 
-
 	if (hw_res.io_ranges.count == 1) {
-		if (sb_regs)
-			*sb_regs = hw_res.io_ranges.ranges[0].address;
-		if (sb_regs_size)
-			*sb_regs_size = hw_res.io_ranges.ranges[0].size;
+		if (pp_sb_regs && *pp_sb_regs)
+			**pp_sb_regs = hw_res.io_ranges.ranges[0];
+		if (pp_mpu_regs)
+			*pp_mpu_regs = NULL;
 	} else {
 		const int sb =
 		    (hw_res.io_ranges.ranges[0].size >= sizeof(sb16_regs_t))
-		        ? 1 : 0;
+		        ? 0 : 1;
 		const int mpu = 1 - sb;
-		if (sb_regs)
-			*sb_regs = hw_res.io_ranges.ranges[sb].address;
-		if (sb_regs_size)
-			*sb_regs_size = hw_res.io_ranges.ranges[sb].size;
-		if (mpu_regs)
-			*sb_regs = hw_res.io_ranges.ranges[mpu].address;
-		if (mpu_regs_size)
-			*sb_regs_size = hw_res.io_ranges.ranges[mpu].size;
+		if (pp_sb_regs && *pp_sb_regs)
+			**pp_sb_regs = hw_res.io_ranges.ranges[sb];
+		if (pp_mpu_regs && *pp_mpu_regs)
+			**pp_mpu_regs = hw_res.io_ranges.ranges[mpu];
 	}
 
@@ -261,4 +254,5 @@
 	return enabled ? EOK : EIO;
 }
+
 /**
  * @}
Index: uspace/drv/audio/sb16/sb16.c
===================================================================
--- uspace/drv/audio/sb16/sb16.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/audio/sb16/sb16.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -77,16 +77,18 @@
 }
 
-void sb16_irq_code(void *regs, int dma8, int dma16, irq_cmd_t cmds[], irq_pio_range_t ranges[])
+void sb16_irq_code(addr_range_t *regs, int dma8, int dma16, irq_cmd_t cmds[],
+    irq_pio_range_t ranges[])
 {
 	assert(regs);
 	assert(dma8 > 0 && dma8 < 4);
-	sb16_regs_t *registers = regs;
+
+	sb16_regs_t *registers = RNGABSPTR(*regs);
 	memcpy(cmds, irq_cmds, sizeof(irq_cmds));
-	cmds[0].addr = (void*)&registers->dsp_read_status;
-	ranges[0].base = (uintptr_t)registers;
+	cmds[0].addr = (void *) &registers->dsp_read_status;
+	ranges[0].base = (uintptr_t) registers;
 	ranges[0].size = sizeof(*registers);
 	if (dma16 > 4 && dma16 < 8) {
 		/* Valid dma16 */
-		cmds[1].addr = (void*)&registers->dma16_ack;
+		cmds[1].addr = (void *) &registers->dma16_ack;
 	} else {
 		cmds[1].cmd = CMD_ACCEPT;
@@ -94,13 +96,14 @@
 }
 
-int sb16_init_sb16(sb16_t *sb, void *regs, size_t size,
-    ddf_dev_t *dev, int dma8, int dma16)
+int sb16_init_sb16(sb16_t *sb, addr_range_t *regs, ddf_dev_t *dev, int dma8,
+    int dma16)
 {
 	assert(sb);
+
 	/* Setup registers */
-	int ret = pio_enable(regs, size, (void**)&sb->regs);
+	int ret = pio_enable_range(regs, (void **) &sb->regs);
 	if (ret != EOK)
 		return ret;
-	ddf_log_debug("PIO registers at %p accessible.", sb->regs);
+	ddf_log_note("PIO registers at %p accessible.", sb->regs);
 
 	/* Initialize DSP */
@@ -187,5 +190,5 @@
 }
 
-int sb16_init_mpu(sb16_t *sb, void *regs, size_t size)
+int sb16_init_mpu(sb16_t *sb, addr_range_t *regs)
 {
 	sb->mpu_regs = NULL;
Index: uspace/drv/audio/sb16/sb16.h
===================================================================
--- uspace/drv/audio/sb16/sb16.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/audio/sb16/sb16.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -38,4 +38,5 @@
 #include <ddf/driver.h>
 #include <ddi.h>
+#include <device/hw_res_parsed.h>
 
 #include "dsp.h"
@@ -51,8 +52,7 @@
 
 size_t sb16_irq_code_size(void);
-void sb16_irq_code(void *regs, int dma8, int dma16, irq_cmd_t cmds[], irq_pio_range_t ranges[]);
-int sb16_init_sb16(sb16_t *sb, void *regs, size_t size,
-    ddf_dev_t *dev, int dma8, int dma16);
-int sb16_init_mpu(sb16_t *sb, void *regs, size_t size);
+void sb16_irq_code(addr_range_t *regs, int dma8, int dma16, irq_cmd_t cmds[], irq_pio_range_t ranges[]);
+int sb16_init_sb16(sb16_t *sb, addr_range_t *regs, ddf_dev_t *dev, int dma8, int dma16);
+int sb16_init_mpu(sb16_t *sb, addr_range_t *regs);
 void sb16_interrupt(sb16_t *sb);
 
Index: uspace/drv/block/ahci/ahci.c
===================================================================
--- uspace/drv/block/ahci/ahci.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/block/ahci/ahci.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -1157,5 +1157,5 @@
 	ahci->memregs = NULL;
 	
-	physmem_map((uintptr_t) (hw_res_parsed.mem_ranges.ranges[0].address),
+	physmem_map(RNGABS(hw_res_parsed.mem_ranges.ranges[0]),
 	    AHCI_MEMREGS_PAGES_COUNT, AS_AREA_READ | AS_AREA_WRITE,
 	    (void **) &ahci->memregs);
@@ -1164,5 +1164,5 @@
 	
 	/* Register interrupt handler */
-	ahci_ranges[0].base = (size_t) hw_res_parsed.mem_ranges.ranges[0].address;
+	ahci_ranges[0].base = RNGABS(hw_res_parsed.mem_ranges.ranges[0]);
 	ahci_ranges[0].size = sizeof(ahci_memregs_t);
 	
@@ -1171,5 +1171,5 @@
 		
 		ahci_cmds[base].addr =
-		    ((uint32_t *) (size_t) hw_res_parsed.mem_ranges.ranges[0].address) +
+		    ((uint32_t *) RNGABSPTR(hw_res_parsed.mem_ranges.ranges[0])) +
 		    AHCI_PORTS_REGISTERS_OFFSET + port * AHCI_PORT_REGISTERS_SIZE +
 		    AHCI_PORT_IS_REGISTER_OFFSET;
@@ -1177,5 +1177,5 @@
 		
 		ahci_cmds[base + 3].addr =
-		    ((uint32_t *) (size_t) hw_res_parsed.mem_ranges.ranges[0].address) +
+		    ((uint32_t *) RNGABSPTR(hw_res_parsed.mem_ranges.ranges[0])) +
 		    AHCI_GHC_IS_REGISTER_OFFSET;
 		ahci_cmds[base + 4].addr = ahci_cmds[base + 3].addr;
Index: uspace/drv/block/ata_bd/main.c
===================================================================
--- uspace/drv/block/ata_bd/main.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/block/ata_bd/main.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -84,13 +84,15 @@
 	}
 
-	ata_res->cmd = hw_res.io_ranges.ranges[0].address;
-	ata_res->ctl = hw_res.io_ranges.ranges[1].address;
-
-	if (hw_res.io_ranges.ranges[0].size < sizeof(ata_ctl_t)) {
+	addr_range_t *cmd_rng = &hw_res.io_ranges.ranges[0];
+	addr_range_t *ctl_rng = &hw_res.io_ranges.ranges[1];
+	ata_res->cmd = RNGABS(*cmd_rng);
+	ata_res->ctl = RNGABS(*ctl_rng);
+
+	if (RNGSZ(*ctl_rng) < sizeof(ata_ctl_t)) {
 		rc = EINVAL;
 		goto error;
 	}
 
-	if (hw_res.io_ranges.ranges[1].size < sizeof(ata_cmd_t)) {
+	if (RNGSZ(*cmd_rng) < sizeof(ata_cmd_t)) {
 		rc = EINVAL;
 		goto error;
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/isa/isa.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -65,4 +65,5 @@
 #include <ddf/log.h>
 #include <ops/hw_res.h>
+#include <ops/pio_window.h>
 
 #include <device/hw_res.h>
@@ -104,10 +105,10 @@
 }
 
-static hw_resource_list_t *isa_get_fun_resources(ddf_fun_t *fnode)
-{
-	isa_fun_t *isa = isa_fun(fnode);
-	assert(isa);
-
-	return &isa->hw_resources;
+static hw_resource_list_t *isa_fun_get_resources(ddf_fun_t *fnode)
+{
+	isa_fun_t *fun = isa_fun(fnode);
+	assert(fun);
+
+	return &fun->hw_resources;
 }
 
@@ -116,6 +117,6 @@
 	/* This is an old ugly way, copied from pci driver */
 	assert(fnode);
-	isa_fun_t *isa = isa_fun(fnode);
-	assert(isa);
+	isa_fun_t *fun = isa_fun(fnode);
+	assert(fun);
 
 	sysarg_t apic;
@@ -133,5 +134,5 @@
 		return false;
 
-	const hw_resource_list_t *res = &isa->hw_resources;
+	const hw_resource_list_t *res = &fun->hw_resources;
 	assert(res);
 	for (size_t i = 0; i < res->count; ++i) {
@@ -159,7 +160,7 @@
 {
 	assert(fnode);
-	isa_fun_t *isa = isa_fun(fnode);
-	assert(isa);
-	const hw_resource_list_t *res = &isa->hw_resources;
+	isa_fun_t *fun = isa_fun(fnode);
+	assert(fun);
+	const hw_resource_list_t *res = &fun->hw_resources;
 	assert(res);
 
@@ -182,7 +183,7 @@
 	assert(size);
 	assert(fnode);
-	isa_fun_t *isa = isa_fun(fnode);
-	assert(isa);
-	const hw_resource_list_t *res = &isa->hw_resources;
+	isa_fun_t *fun = isa_fun(fnode);
+	assert(fun);
+	const hw_resource_list_t *res = &fun->hw_resources;
 	assert(res);
 
@@ -201,5 +202,5 @@
 
 static hw_res_ops_t isa_fun_hw_res_ops = {
-	.get_resource_list = isa_get_fun_resources,
+	.get_resource_list = isa_fun_get_resources,
 	.enable_interrupt = isa_fun_enable_interrupt,
 	.dma_channel_setup = isa_fun_setup_dma,
@@ -207,6 +208,20 @@
 };
 
+static pio_window_t *isa_fun_get_pio_window(ddf_fun_t *fnode)
+{
+	ddf_dev_t *dev = ddf_fun_get_dev(fnode);
+	isa_bus_t *isa = isa_bus(dev);
+	assert(isa);
+
+	return &isa->pio_win;
+}
+
+static pio_window_ops_t isa_fun_pio_window_ops = {
+	.get_pio_window = isa_fun_get_pio_window
+};
+
 static ddf_dev_ops_t isa_fun_ops= {
 	.interfaces[HW_RES_DEV_IFACE] = &isa_fun_hw_res_ops,
+	.interfaces[PIO_WINDOW_DEV_IFACE] = &isa_fun_pio_window_ops,
 };
 
@@ -414,4 +429,5 @@
 		resources[count].res.io_range.address += isa->pio_win.io.base;
 		resources[count].res.io_range.size = len;
+		resources[count].res.io_range.relative = false;
 		resources[count].res.io_range.endianness = LITTLE_ENDIAN;
 
Index: uspace/drv/bus/pci/pciintel/pci.c
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -256,5 +256,5 @@
 	fibril_mutex_lock(&bus->conf_mutex);
 
-	pio_write_32(bus->conf_addr_port, host2uint32_t_le(conf_addr));
+	pio_write_32(bus->conf_addr_reg, host2uint32_t_le(conf_addr));
 
 	/*
@@ -263,5 +263,5 @@
 	 * support shorter PIO reads offset from this register.
  	 */
-	val = uint32_t_le2host(pio_read_32(bus->conf_data_port));
+	val = uint32_t_le2host(pio_read_32(bus->conf_data_reg));
 
 	switch (len) {
@@ -299,6 +299,6 @@
  		 * missing bits first.
  		 */
-		pio_write_32(bus->conf_addr_port, host2uint32_t_le(conf_addr));
-		val = uint32_t_le2host(pio_read_32(bus->conf_data_port));
+		pio_write_32(bus->conf_addr_reg, host2uint32_t_le(conf_addr));
+		val = uint32_t_le2host(pio_read_32(bus->conf_data_reg));
 	}
 	
@@ -317,6 +317,6 @@
 	}
 
-	pio_write_32(bus->conf_addr_port, host2uint32_t_le(conf_addr));
-	pio_write_32(bus->conf_data_port, host2uint32_t_le(val));
+	pio_write_32(bus->conf_addr_reg, host2uint32_t_le(conf_addr));
+	pio_write_32(bus->conf_data_reg, host2uint32_t_le(val));
 	
 	fibril_mutex_unlock(&bus->conf_mutex);
@@ -449,4 +449,5 @@
 		hw_resources[count].res.io_range.address = range_addr;
 		hw_resources[count].res.io_range.size = range_size;
+		hw_resources[count].res.io_range.relative = true;
 		hw_resources[count].res.io_range.endianness = LITTLE_ENDIAN;
 	} else {
@@ -454,4 +455,5 @@
 		hw_resources[count].res.mem_range.address = range_addr;
 		hw_resources[count].res.mem_range.size = range_size;
+		hw_resources[count].res.mem_range.relative = false;
 		hw_resources[count].res.mem_range.endianness = LITTLE_ENDIAN;
 	}
@@ -722,17 +724,12 @@
 	    hw_resources.resources[1].res.io_range.address);
 	
-	bus->conf_io_addr =
-	    (uint32_t) hw_resources.resources[0].res.io_range.address;
-	bus->conf_io_data =
-	    (uint32_t) hw_resources.resources[1].res.io_range.address;
-	
-	if (pio_enable((void *)(uintptr_t)bus->conf_io_addr, 4,
-	    &bus->conf_addr_port)) {
+	if (pio_enable_resource(&bus->pio_win, &hw_resources.resources[0],
+	    (void **) &bus->conf_addr_reg)) {
 		ddf_msg(LVL_ERROR, "Failed to enable configuration ports.");
 		rc = EADDRNOTAVAIL;
 		goto fail;
 	}
-	if (pio_enable((void *)(uintptr_t)bus->conf_io_data, 4,
-	    &bus->conf_data_port)) {
+	if (pio_enable_resource(&bus->pio_win, &hw_resources.resources[1],
+	    (void **) &bus->conf_data_reg)) {
 		ddf_msg(LVL_ERROR, "Failed to enable configuration ports.");
 		rc = EADDRNOTAVAIL;
Index: uspace/drv/bus/pci/pciintel/pci.h
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/pci/pciintel/pci.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -45,8 +45,6 @@
 	/** DDF device node */
 	ddf_dev_t *dnode;
-	uint32_t conf_io_addr;
-	uint32_t conf_io_data;
-	void *conf_data_port;
-	void *conf_addr_port;
+	ioport32_t *conf_addr_reg;
+	ioport32_t *conf_data_reg;
 	pio_window_t pio_win;
 	fibril_mutex_t conf_mutex;
Index: uspace/drv/bus/usb/ehci/main.c
===================================================================
--- uspace/drv/bus/usb/ehci/main.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/ehci/main.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -77,9 +77,8 @@
 	assert(device);
 
-	uintptr_t reg_base = 0;
-	size_t reg_size = 0;
+	addr_range_t reg_range;
 	int irq = 0;
 
-	int rc = get_my_registers(device, &reg_base, &reg_size, &irq);
+	int rc = get_my_registers(device, &reg_range, &irq);
 	if (rc != EOK) {
 		usb_log_error("Failed to get memory addresses for %" PRIun
@@ -88,8 +87,8 @@
 	}
 
-	usb_log_info("Memory mapped regs at 0x%" PRIxn " (size %zu), IRQ %d.\n",
-	    reg_base, reg_size, irq);
+	usb_log_info("Memory mapped regs at %p (size %zu), IRQ %d.\n",
+	    RNGABSPTR(reg_range), RNGSZ(reg_range), irq);
 
-	rc = disable_legacy(device, reg_base, reg_size);
+	rc = disable_legacy(device, &reg_range);
 	if (rc != EOK) {
 		usb_log_error("Failed to disable legacy USB: %s.\n",
Index: uspace/drv/bus/usb/ehci/res.c
===================================================================
--- uspace/drv/bus/usb/ehci/res.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/ehci/res.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -71,11 +71,10 @@
  *
  * @param[in] dev Device asking for the addresses.
- * @param[out] mem_reg_address Base address of the memory range.
- * @param[out] mem_reg_size Size of the memory range.
+ * @param[out] mem_regs_p Pointer to the register range.
  * @param[out] irq_no IRQ assigned to the device.
  * @return Error code.
  */
 int get_my_registers(ddf_dev_t *dev,
-    uintptr_t *mem_reg_address, size_t *mem_reg_size, int *irq_no)
+    addr_range_t *mem_regs_p, int *irq_no)
 {
 	assert(dev);
@@ -99,8 +98,6 @@
 	}
 
-	if (mem_reg_address)
-		*mem_reg_address = hw_res.mem_ranges.ranges[0].address;
-	if (mem_reg_size)
-		*mem_reg_size = hw_res.mem_ranges.ranges[0].size;
+	if (mem_regs_p)
+		*mem_regs_p = hw_res.mem_ranges.ranges[0];
 	if (irq_no)
 		*irq_no = hw_res.irqs.irqs[0];
@@ -267,5 +264,5 @@
 }
 
-int disable_legacy(ddf_dev_t *device, uintptr_t reg_base, size_t reg_size)
+int disable_legacy(ddf_dev_t *device, addr_range_t *reg_range)
 {
 	assert(device);
@@ -274,8 +271,8 @@
 	/* Map EHCI registers */
 	void *regs = NULL;
-	int rc = pio_enable((void*)reg_base, reg_size, &regs);
+	int rc = pio_enable_range(reg_range, &regs);
 	if (rc != EOK) {
 		usb_log_error("Failed to map registers %p: %s.\n",
-		    (void *) reg_base, str_error(rc));
+		    RNGABSPTR(*reg_range), str_error(rc));
 		return rc;
 	}
Index: uspace/drv/bus/usb/ehci/res.h
===================================================================
--- uspace/drv/bus/usb/ehci/res.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/ehci/res.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -37,8 +37,9 @@
 
 #include <ddf/driver.h>
+#include <device/hw_res_parsed.h>
 
-int get_my_registers(ddf_dev_t *, uintptr_t *, size_t *, int *);
+int get_my_registers(ddf_dev_t *, addr_range_t *, int *);
 int enable_interrupts(ddf_dev_t *);
-int disable_legacy(ddf_dev_t *, uintptr_t, size_t);
+int disable_legacy(ddf_dev_t *, addr_range_t *);
 
 #endif
Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -106,6 +106,5 @@
  * @param[out] cmds Commands buffer.
  * @param[in] cmds_size Size of the commands buffer (bytes).
- * @param[in] regs Physical address of device's registers.
- * @param[in] reg_size Size of the register area (bytes).
+ * @param[in] regs Device's register range.
  *
  * @return Error code.
@@ -113,16 +112,16 @@
 int
 hc_get_irq_code(irq_pio_range_t ranges[], size_t ranges_size, irq_cmd_t cmds[],
-    size_t cmds_size, uintptr_t regs, size_t reg_size)
+    size_t cmds_size, addr_range_t *regs)
 {
 	if ((ranges_size < sizeof(ohci_pio_ranges)) ||
 	    (cmds_size < sizeof(ohci_irq_commands)) ||
-	    (reg_size < sizeof(ohci_regs_t)))
+	    (RNGSZ(*regs) < sizeof(ohci_regs_t)))
 		return EOVERFLOW;
 
 	memcpy(ranges, ohci_pio_ranges, sizeof(ohci_pio_ranges));
-	ranges[0].base = regs;
+	ranges[0].base = RNGABS(*regs);
 
 	memcpy(cmds, ohci_irq_commands, sizeof(ohci_irq_commands));
-	ohci_regs_t *registers = (ohci_regs_t *) regs;
+	ohci_regs_t *registers = (ohci_regs_t *) RNGABSPTR(*regs);
 	cmds[0].addr = (void *) &registers->interrupt_status;
 	cmds[3].addr = (void *) &registers->interrupt_status;
@@ -135,6 +134,5 @@
  *
  * @param[in] device Host controller DDF device
- * @param[in] reg_base Register range base
- * @param[in] reg_size Register range size
+ * @param[in] regs Register range
  * @param[in] irq Interrupt number
  * @paran[in] handler Interrupt handler
@@ -142,6 +140,6 @@
  * @return EOK on success or negative error code
  */
-int hc_register_irq_handler(ddf_dev_t *device, uintptr_t reg_base, size_t reg_size,
-    int irq, interrupt_handler_t handler)
+int hc_register_irq_handler(ddf_dev_t *device, addr_range_t *regs, int irq,
+    interrupt_handler_t handler)
 {
 	int rc;
@@ -158,5 +156,5 @@
 
 	rc = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds,
-	    sizeof(irq_cmds), reg_base, reg_size);
+	    sizeof(irq_cmds), regs);
 	if (rc != EOK) {
 		usb_log_error("Failed to generate IRQ code: %s.\n",
@@ -259,15 +257,13 @@
  *
  * @param[in] instance Memory place for the structure.
- * @param[in] regs Address of the memory mapped I/O registers.
- * @param[in] reg_size Size of the memory mapped area.
+ * @param[in] regs Device's I/O registers range.
  * @param[in] interrupts True if w interrupts should be used
  * @return Error code
  */
-int hc_init(hc_t *instance, uintptr_t regs, size_t reg_size, bool interrupts)
-{
-	assert(instance);
-
-	int rc =
-	    pio_enable((void*)regs, reg_size, (void**)&instance->registers);
+int hc_init(hc_t *instance, addr_range_t *regs, bool interrupts)
+{
+	assert(instance);
+
+	int rc = pio_enable_range(regs, (void **) &instance->registers);
 	if (rc != EOK) {
 		usb_log_error("Failed to gain access to device registers: %s.\n",
Index: uspace/drv/bus/usb/ohci/hc.h
===================================================================
--- uspace/drv/bus/usb/ohci/hc.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/ohci/hc.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -75,9 +75,10 @@
 } hc_t;
 
-int hc_get_irq_code(irq_pio_range_t [], size_t, irq_cmd_t [], size_t, uintptr_t,
-    size_t);
-int hc_register_irq_handler(ddf_dev_t *, uintptr_t, size_t, int, interrupt_handler_t);
+int hc_get_irq_code(irq_pio_range_t [], size_t, irq_cmd_t [], size_t,
+    addr_range_t *);
+int hc_register_irq_handler(ddf_dev_t *, addr_range_t *, int,
+    interrupt_handler_t);
 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);
+int hc_init(hc_t *instance, addr_range_t *regs, bool interrupts);
 
 /** Safely dispose host controller internal structures
Index: uspace/drv/bus/usb/ohci/ohci.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/ohci/ohci.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -177,9 +177,8 @@
 	ddf_fun_set_ops(instance->rh_fun, &rh_ops);
 
-	uintptr_t reg_base = 0;
-	size_t reg_size = 0;
+	addr_range_t regs;
 	int irq = 0;
 
-	rc = get_my_registers(device, &reg_base, &reg_size, &irq);
+	rc = get_my_registers(device, &regs, &irq);
 	if (rc != EOK) {
 		usb_log_error("Failed to get register memory addresses "
@@ -190,7 +189,7 @@
 
 	usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
-	    (void *) reg_base, reg_size, irq);
-
-	rc = hc_register_irq_handler(device, reg_base, reg_size, irq, irq_handler);
+	    RNGABSPTR(regs), RNGSZ(regs), irq);
+
+	rc = hc_register_irq_handler(device, &regs, irq, irq_handler);
 	if (rc != EOK) {
 		usb_log_error("Failed to register interrupt handler: %s.\n",
@@ -215,5 +214,5 @@
 	}
 
-	rc = hc_init(&instance->hc, reg_base, reg_size, interrupts);
+	rc = hc_init(&instance->hc, &regs, interrupts);
 	if (rc != EOK) {
 		usb_log_error("Failed to init ohci_hcd: %s.\n", str_error(rc));
Index: uspace/drv/bus/usb/ohci/res.c
===================================================================
--- uspace/drv/bus/usb/ohci/res.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/ohci/res.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -48,11 +48,9 @@
  *
  * @param[in] dev Device asking for the addresses.
- * @param[out] mem_reg_address Base address of the memory range.
- * @param[out] mem_reg_size Size of the memory range.
+ * @param[out] p_regs Pointer to register range.
  * @param[out] irq_no IRQ assigned to the device.
  * @return Error code.
  */
-int get_my_registers(ddf_dev_t *dev,
-    uintptr_t *mem_reg_address, size_t *mem_reg_size, int *irq_no)
+int get_my_registers(ddf_dev_t *dev, addr_range_t *p_regs, int *irq_no)
 {
 	assert(dev);
@@ -66,5 +64,5 @@
 	hw_res_list_parsed_t hw_res;
 	hw_res_list_parsed_init(&hw_res);
-	const int ret =  hw_res_get_list_parsed(parent_sess, &hw_res, 0);
+	const int ret = hw_res_get_list_parsed(parent_sess, &hw_res, 0);
 	async_hangup(parent_sess);
 	if (ret != EOK) {
@@ -78,8 +76,6 @@
 	}
 
-	if (mem_reg_address)
-		*mem_reg_address = hw_res.mem_ranges.ranges[0].address;
-	if (mem_reg_size)
-		*mem_reg_size = hw_res.mem_ranges.ranges[0].size;
+	if (p_regs)
+		*p_regs = hw_res.mem_ranges.ranges[0];
 	if (irq_no)
 		*irq_no = hw_res.irqs.irqs[0];
Index: uspace/drv/bus/usb/ohci/res.h
===================================================================
--- uspace/drv/bus/usb/ohci/res.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/ohci/res.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -36,6 +36,7 @@
 
 #include <ddf/driver.h>
+#include <device/hw_res_parsed.h>
 
-int get_my_registers(ddf_dev_t *, uintptr_t *, size_t *, int *);
+int get_my_registers(ddf_dev_t *, addr_range_t *, int *);
 int enable_interrupts(ddf_dev_t *);
 
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -105,6 +105,5 @@
  * @param[out] cmds Commands buffer.
  * @param[in] cmds_size Size of the commands buffer (bytes).
- * @param[in] regs Physical address of device's registers.
- * @param[in] reg_size Size of the register area (bytes).
+ * @param[in] regs Device's register range.
  *
  * @return Error code.
@@ -112,16 +111,16 @@
 int
 hc_get_irq_code(irq_pio_range_t ranges[], size_t ranges_size, irq_cmd_t cmds[],
-    size_t cmds_size, uintptr_t regs, size_t reg_size)
+    size_t cmds_size, addr_range_t *regs)
 {
 	if ((ranges_size < sizeof(uhci_irq_pio_ranges)) ||
 	    (cmds_size < sizeof(uhci_irq_commands)) ||
-	    (reg_size < sizeof(uhci_regs_t)))
+	    (RNGSZ(*regs) < sizeof(uhci_regs_t)))
 		return EOVERFLOW;
 
 	memcpy(ranges, uhci_irq_pio_ranges, sizeof(uhci_irq_pio_ranges));
-	ranges[0].base = regs;
+	ranges[0].base = RNGABS(*regs);
 
 	memcpy(cmds, uhci_irq_commands, sizeof(uhci_irq_commands));
-	uhci_regs_t *registers = (uhci_regs_t *) regs;
+	uhci_regs_t *registers = (uhci_regs_t *) RNGABSPTR(*regs);
 	cmds[0].addr = &registers->usbsts;
 	cmds[3].addr = &registers->usbsts;
@@ -133,6 +132,5 @@
  *
  * @param[in] device Host controller DDF device
- * @param[in] reg_base Register range base
- * @param[in] reg_size Register range size
+ * @param[in] regs Register range
  * @param[in] irq Interrupt number
  * @paran[in] handler Interrupt handler
@@ -140,6 +138,6 @@
  * @return EOK on success or negative error code
  */
-int hc_register_irq_handler(ddf_dev_t *device, uintptr_t reg_base, size_t reg_size,
-    int irq, interrupt_handler_t handler)
+int hc_register_irq_handler(ddf_dev_t *device, addr_range_t *regs, int irq,
+    interrupt_handler_t handler)
 {
 	int rc;
@@ -147,5 +145,5 @@
 	irq_cmd_t irq_cmds[hc_irq_cmd_count];
 	rc = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds,
-	    sizeof(irq_cmds), reg_base, reg_size);
+	    sizeof(irq_cmds), regs);
 	if (rc != EOK) {
 		usb_log_error("Failed to generate IRQ commands: %s.\n",
@@ -232,6 +230,5 @@
  *
  * @param[in] instance Memory place to initialize.
- * @param[in] regs Address of I/O control registers.
- * @param[in] reg_size Size of I/O control registers.
+ * @param[in] regs Range of device's I/O control registers.
  * @param[in] interrupts True if hw interrupts should be used.
  * @return Error code.
@@ -241,7 +238,7 @@
  * interrupt fibrils.
  */
-int hc_init(hc_t *instance, void *regs, size_t reg_size, bool interrupts)
-{
-	assert(reg_size >= sizeof(uhci_regs_t));
+int hc_init(hc_t *instance, addr_range_t *regs, bool interrupts)
+{
+	assert(regs->size >= sizeof(uhci_regs_t));
 	int rc;
 
@@ -251,5 +248,5 @@
 	/* allow access to hc control registers */
 	uhci_regs_t *io;
-	rc = pio_enable(regs, reg_size, (void **)&io);
+	rc = pio_enable_range(regs, (void **) &io);
 	if (rc != EOK) {
 		usb_log_error("Failed to gain access to registers at %p: %s.\n",
@@ -260,5 +257,5 @@
 	instance->registers = io;
 	usb_log_debug(
-	    "Device registers at %p (%zuB) accessible.\n", io, reg_size);
+	    "Device registers at %p (%zuB) accessible.\n", io, regs->size);
 
 	rc = hc_init_mem_structures(instance);
Index: uspace/drv/bus/usb/uhci/hc.h
===================================================================
--- uspace/drv/bus/usb/uhci/hc.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/uhci/hc.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -37,4 +37,5 @@
 
 #include <ddf/interrupt.h>
+#include <device/hw_res_parsed.h>
 #include <fibril.h>
 #include <usb/host/hcd.h>
@@ -120,9 +121,10 @@
 } hc_t;
 
-int hc_register_irq_handler(ddf_dev_t *, uintptr_t, size_t, int, interrupt_handler_t);
-int hc_get_irq_code(irq_pio_range_t [], size_t, irq_cmd_t [], size_t, uintptr_t,
-    size_t);
+int hc_register_irq_handler(ddf_dev_t *, addr_range_t *, int,
+    interrupt_handler_t);
+int hc_get_irq_code(irq_pio_range_t [], size_t, irq_cmd_t [], size_t,
+    addr_range_t *);
 void hc_interrupt(hc_t *instance, uint16_t status);
-int hc_init(hc_t *instance, void *regs, size_t reg_size, bool interupts);
+int hc_init(hc_t *instance, addr_range_t *regs, bool interupts);
 
 /** Safely dispose host controller internal structures
@@ -132,4 +134,5 @@
 static inline void hc_fini(hc_t *instance) {} /* TODO: implement*/
 #endif
+
 /**
  * @}
Index: uspace/drv/bus/usb/uhci/res.c
===================================================================
--- uspace/drv/bus/usb/uhci/res.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/uhci/res.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -46,11 +46,9 @@
  *
  * @param[in] dev Device asking for the addresses.
- * @param[out] io_reg_address Base address of the I/O range.
- * @param[out] io_reg_size Size of the I/O range.
+ * @param[out] io_regs_p Pointer to register I/O range.
  * @param[out] irq_no IRQ assigned to the device.
  * @return Error code.
  */
-int get_my_registers(ddf_dev_t *dev,
-    uintptr_t *io_reg_address, size_t *io_reg_size, int *irq_no)
+int get_my_registers(ddf_dev_t *dev, addr_range_t *io_regs_p, int *irq_no)
 {
 	assert(dev);
@@ -76,8 +74,6 @@
 	}
 
-	if (io_reg_address)
-		*io_reg_address = hw_res.io_ranges.ranges[0].address;
-	if (io_reg_size)
-		*io_reg_size = hw_res.io_ranges.ranges[0].size;
+	if (io_regs_p)
+		*io_regs_p = hw_res.io_ranges.ranges[0];
 	if (irq_no)
 		*irq_no = hw_res.irqs.irqs[0];
Index: uspace/drv/bus/usb/uhci/res.h
===================================================================
--- uspace/drv/bus/usb/uhci/res.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/uhci/res.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -37,6 +37,7 @@
 
 #include <ddf/driver.h>
+#include <device/hw_res_parsed.h>
 
-int get_my_registers(ddf_dev_t *, uintptr_t *, size_t *, int *);
+int get_my_registers(ddf_dev_t *, addr_range_t *, int *);
 int enable_interrupts(ddf_dev_t *);
 int disable_legacy(ddf_dev_t *);
Index: uspace/drv/bus/usb/uhci/uhci.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/uhci/uhci.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -184,9 +184,8 @@
 	ddf_fun_data_implant(instance->rh_fun, &instance->rh);
 
-	uintptr_t reg_base = 0;
-	size_t reg_size = 0;
+	addr_range_t regs;
 	int irq = 0;
 
-	rc = get_my_registers(device, &reg_base, &reg_size, &irq);
+	rc = get_my_registers(device, &regs, &irq);
 	if (rc != EOK) {
 		usb_log_error("Failed to get I/O addresses for %" PRIun ": %s.\n",
@@ -194,6 +193,6 @@
 		goto error;
 	}
-	usb_log_debug("I/O regs at 0x%p (size %zu), IRQ %d.\n",
-	    (void *) reg_base, reg_size, irq);
+	usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n",
+	    RNGABSPTR(regs), RNGSZ(regs), irq);
 
 	rc = disable_legacy(device);
@@ -204,5 +203,5 @@
 	}
 
-	rc = hc_register_irq_handler(device, reg_base, reg_size, irq, irq_handler);
+	rc = hc_register_irq_handler(device, &regs, irq, irq_handler);
 	if (rc != EOK) {
 		usb_log_error("Failed to register interrupt handler: %s.\n",
@@ -223,5 +222,5 @@
 	}
 
-	rc = hc_init(&instance->hc, (void*)reg_base, reg_size, interrupts);
+	rc = hc_init(&instance->hc, &regs, interrupts);
 	if (rc != EOK) {
 		usb_log_error("Failed to init uhci_hcd: %s.\n", str_error(rc));
Index: uspace/drv/bus/usb/uhcirh/main.c
===================================================================
--- uspace/drv/bus/usb/uhcirh/main.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/uhcirh/main.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -48,6 +48,5 @@
 #define NAME "uhcirh"
 
-static int hc_get_my_registers(ddf_dev_t *dev,
-    uintptr_t *io_reg_address, size_t *io_reg_size);
+static int hc_get_my_registers(ddf_dev_t *dev, addr_range_t *io_regs);
 
 static int uhci_rh_dev_add(ddf_dev_t *device);
@@ -90,10 +89,9 @@
 	    ddf_dev_get_handle(device));
 
-	uintptr_t io_regs = 0;
-	size_t io_size = 0;
+	addr_range_t regs;
 	uhci_root_hub_t *rh = NULL;
 	int rc;
 
-	rc = hc_get_my_registers(device, &io_regs, &io_size);
+	rc = hc_get_my_registers(device, &regs);
 	if (rc != EOK) {
 		usb_log_error( "Failed to get registers from HC: %s.\n",
@@ -103,5 +101,5 @@
 
 	usb_log_debug("I/O regs at %p (size %zuB).\n",
-	    (void *) io_regs, io_size);
+	    RNGABSPTR(regs), RNGSZ(regs));
 
 	rh = ddf_dev_data_alloc(device, sizeof(uhci_root_hub_t));
@@ -111,5 +109,5 @@
 	}
 
-	rc = uhci_root_hub_init(rh, (void*)io_regs, io_size, device);
+	rc = uhci_root_hub_init(rh, &regs, device);
 	if (rc != EOK) {
 		usb_log_error("Failed(%d) to initialize rh driver instance: "
@@ -127,10 +125,8 @@
  *
  * @param[in] dev Device asking for the addresses.
- * @param[out] io_reg_address Base address of the memory range.
- * @param[out] io_reg_size Size of the memory range.
+ * @param[out] io_regs_p Pointer to the device's register range.
  * @return Error code.
  */
-int hc_get_my_registers(
-    ddf_dev_t *dev, uintptr_t *io_reg_address, size_t *io_reg_size)
+int hc_get_my_registers(ddf_dev_t *dev, addr_range_t *io_regs_p)
 {
 	async_sess_t *parent_sess =
@@ -153,9 +149,6 @@
 	}
 
-	if (io_reg_address != NULL)
-		*io_reg_address = hw_res.io_ranges.ranges[0].address;
-
-	if (io_reg_size != NULL)
-		*io_reg_size = hw_res.io_ranges.ranges[0].size;
+	if (io_regs_p != NULL)
+		*io_regs_p = hw_res.io_ranges.ranges[0];
 
 	hw_res_list_parsed_clean(&hw_res);
Index: uspace/drv/bus/usb/uhcirh/root_hub.c
===================================================================
--- uspace/drv/bus/usb/uhcirh/root_hub.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/uhcirh/root_hub.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -36,4 +36,5 @@
 #include <ddi.h>
 #include <usb/debug.h>
+#include <device/hw_res_parsed.h>
 
 #include "root_hub.h"
@@ -42,23 +43,24 @@
  *
  * @param[in] instance Driver memory structure to use.
- * @param[in] addr Address of I/O registers.
- * @param[in] size Size of available I/O space.
+ * @param[in] io_regs Range of I/O registers.
  * @param[in] rh Pointer to DDF instance of the root hub driver.
  * @return Error code.
  */
-int uhci_root_hub_init(
-  uhci_root_hub_t *instance, void *addr, size_t size, ddf_dev_t *rh)
+int uhci_root_hub_init(uhci_root_hub_t *instance, addr_range_t *io_regs,
+    ddf_dev_t *rh)
 {
+	port_status_t *regs;
+
 	assert(instance);
 	assert(rh);
 
 	/* Allow access to root hub port registers */
-	assert(sizeof(port_status_t) * UHCI_ROOT_HUB_PORT_COUNT <= size);
-	port_status_t *regs;
-	int ret = pio_enable(addr, size, (void**)&regs);
+	assert(sizeof(*regs) * UHCI_ROOT_HUB_PORT_COUNT <= io_regs->size);
+
+	int ret = pio_enable_range(io_regs, (void **) &regs);
 	if (ret < 0) {
 		usb_log_error(
 		    "Failed(%d) to gain access to port registers at %p: %s.\n",
-		    ret, regs, str_error(ret));
+		    ret, RNGABSPTR(*io_regs), str_error(ret));
 		return ret;
 	}
Index: uspace/drv/bus/usb/uhcirh/root_hub.h
===================================================================
--- uspace/drv/bus/usb/uhcirh/root_hub.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/bus/usb/uhcirh/root_hub.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -36,4 +36,5 @@
 
 #include <ddf/driver.h>
+#include <device/hw_res_parsed.h>
 
 #include "port.h"
@@ -48,6 +49,6 @@
 } uhci_root_hub_t;
 
-int uhci_root_hub_init(
-    uhci_root_hub_t *instance, void *addr, size_t size, ddf_dev_t *rh);
+int uhci_root_hub_init(uhci_root_hub_t *instance, addr_range_t *regs,
+    ddf_dev_t *rh);
 
 void uhci_root_hub_fini(uhci_root_hub_t *instance);
Index: uspace/drv/char/i8042/i8042.c
===================================================================
--- uspace/drv/char/i8042/i8042.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/char/i8042/i8042.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -145,6 +145,5 @@
  *
  * @param dev       Driver structure to initialize.
- * @param regs      I/O address of registers.
- * @param reg_size  size of the reserved I/O address space.
+ * @param regs      I/O range  of registers.
  * @param irq_kbd   IRQ for primary port.
  * @param irq_mouse IRQ for aux port.
@@ -154,5 +153,5 @@
  *
  */
-int i8042_init(i8042_t *dev, void *regs, size_t reg_size, int irq_kbd,
+int i8042_init(i8042_t *dev, addr_range_t *regs, int irq_kbd,
     int irq_mouse, ddf_dev_t *ddf_dev)
 {
@@ -162,4 +161,5 @@
 	const size_t cmd_count = sizeof(i8042_cmds) / sizeof(irq_cmd_t);
 	irq_cmd_t cmds[cmd_count];
+	i8042_regs_t *ar;
 
 	int rc;
@@ -170,10 +170,10 @@
 	dev->aux_fun = NULL;
 	
-	if (reg_size < sizeof(i8042_regs_t)) {
+	if (regs->size < sizeof(i8042_regs_t)) {
 		rc = EINVAL;
 		goto error;
 	}
 	
-	if (pio_enable(regs, sizeof(i8042_regs_t), (void **) &dev->regs) != 0) {
+	if (pio_enable_range(regs, (void **) &dev->regs) != 0) {
 		rc = EIO;
 		goto error;
@@ -234,9 +234,11 @@
 
 	memcpy(ranges, i8042_ranges, sizeof(i8042_ranges));
-	ranges[0].base = (uintptr_t) regs;
-
+	ranges[0].base = RNGABS(*regs);
+
+
+	ar = RNGABSPTR(*regs);
 	memcpy(cmds, i8042_cmds, sizeof(i8042_cmds));
-	cmds[0].addr = (void *) &(((i8042_regs_t *) regs)->status);
-	cmds[3].addr = (void *) &(((i8042_regs_t *) regs)->data);
+	cmds[0].addr = (void *) &ar->status;
+	cmds[3].addr = (void *) &ar->data;
 
 	irq_code_t irq_code = {
Index: uspace/drv/char/i8042/i8042.h
===================================================================
--- uspace/drv/char/i8042/i8042.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/char/i8042/i8042.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -68,5 +68,5 @@
 } i8042_t;
 
-int i8042_init(i8042_t *, void *, size_t, int, int, ddf_dev_t *);
+int i8042_init(i8042_t *, addr_range_t *, int, int, ddf_dev_t *);
 
 #endif
Index: uspace/drv/char/i8042/main.c
===================================================================
--- uspace/drv/char/i8042/main.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/char/i8042/main.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -49,6 +49,5 @@
  *
  * @param[in]  dev            Device asking for the addresses.
- * @param[out] io_reg_address Base address of the memory range.
- * @param[out] io_reg_size    Size of the memory range.
+ * @param[out] p_io_reg       Pointer to register range.
  * @param[out] kbd_irq        Primary port IRQ.
  * @param[out] mouse_irq      Auxiliary port IRQ.
@@ -57,6 +56,6 @@
  *
  */
-static int get_my_registers(ddf_dev_t *dev, uintptr_t *io_reg_address,
-    size_t *io_reg_size, int *kbd_irq, int *mouse_irq)
+static int get_my_registers(ddf_dev_t *dev, addr_range_t *p_io_reg,
+    int *kbd_irq, int *mouse_irq)
 {
 	assert(dev);
@@ -79,9 +78,6 @@
 	}
 	
-	if (io_reg_address)
-		*io_reg_address = hw_resources.io_ranges.ranges[0].address;
-	
-	if (io_reg_size)
-		*io_reg_size = hw_resources.io_ranges.ranges[0].size;
+	if (p_io_reg)
+		*p_io_reg = hw_resources.io_ranges.ranges[0];
 	
 	if (kbd_irq)
@@ -104,6 +100,5 @@
 static int i8042_dev_add(ddf_dev_t *device)
 {
-	uintptr_t io_regs = 0;
-	size_t io_size = 0;
+	addr_range_t io_regs;
 	int kbd = 0;
 	int mouse = 0;
@@ -113,5 +108,5 @@
 		return EINVAL;
 	
-	rc = get_my_registers(device, &io_regs, &io_size, &kbd, &mouse);
+	rc = get_my_registers(device, &io_regs, &kbd, &mouse);
 	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed to get registers: %s.",
@@ -120,6 +115,7 @@
 	}
 	
-	ddf_msg(LVL_DEBUG, "I/O regs at %p (size %zuB), IRQ kbd %d, IRQ mouse %d.",
-	    (void *) io_regs, io_size, kbd, mouse);
+	ddf_msg(LVL_DEBUG,
+	    "I/O regs at %p (size %zuB), IRQ kbd %d, IRQ mouse %d.",
+	    RNGABSPTR(io_regs), RNGSZ(io_regs), kbd, mouse);
 	
 	i8042_t *i8042 = ddf_dev_data_alloc(device, sizeof(i8042_t));
@@ -129,5 +125,5 @@
 	}
 	
-	rc = i8042_init(i8042, (void *) io_regs, io_size, kbd, mouse, device);
+	rc = i8042_init(i8042, &io_regs, kbd, mouse, device);
 	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed to initialize i8042 driver: %s.",
Index: uspace/drv/infrastructure/rootmac/rootmac.c
===================================================================
--- uspace/drv/infrastructure/rootmac/rootmac.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/infrastructure/rootmac/rootmac.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -54,4 +54,5 @@
 			.address = 0xfec00000,
 			.size = 4,
+			.relative = false,
 			.endianness = LITTLE_ENDIAN
 		}
@@ -62,4 +63,5 @@
 			.address = 0xfee00000,
 			.size = 4,
+			.relative = false,
 			.endianness = LITTLE_ENDIAN
 		}
Index: uspace/drv/infrastructure/rootmalta/rootmalta.c
===================================================================
--- uspace/drv/infrastructure/rootmalta/rootmalta.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/infrastructure/rootmalta/rootmalta.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -99,4 +99,5 @@
 			.address = GT_BASE + GT_PCI_CONFADDR,
 			.size = 4,
+			.relative = false,
 			.endianness = LITTLE_ENDIAN
 		}
@@ -107,4 +108,5 @@
 			.address = GT_BASE + GT_PCI_CONFDATA,
 			.size = 4,
+			.relative = false,
 			.endianness = LITTLE_ENDIAN
 		}
Index: uspace/drv/infrastructure/rootpc/rootpc.c
===================================================================
--- uspace/drv/infrastructure/rootpc/rootpc.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/infrastructure/rootpc/rootpc.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -81,4 +81,5 @@
 			.address = 0xCF8,
 			.size = 4,
+			.relative = false,
 			.endianness = LITTLE_ENDIAN
 		}
@@ -89,4 +90,5 @@
 			.address = 0xCFC,
 			.size = 4,
+			.relative = false,
 			.endianness = LITTLE_ENDIAN
 		}
Index: uspace/drv/nic/e1k/e1k.c
===================================================================
--- uspace/drv/nic/e1k/e1k.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/nic/e1k/e1k.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -1941,5 +1941,5 @@
 	e1000->irq = hw_resources->irqs.irqs[0];
 	e1000->reg_base_phys =
-	    MEMADDR_TO_PTR(hw_resources->mem_ranges.ranges[0].address);
+	    MEMADDR_TO_PTR(RNGABS(hw_resources->mem_ranges.ranges[0]));
 	
 	return EOK;
Index: uspace/drv/nic/ne2k/ne2k.c
===================================================================
--- uspace/drv/nic/ne2k/ne2k.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/nic/ne2k/ne2k.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -211,13 +211,12 @@
 	ne2k->irq = hw_res_parsed.irqs.irqs[0];
 	
-	ne2k->base_port = (void *) (uintptr_t)
-	    hw_res_parsed.io_ranges.ranges[0].address;
+	addr_range_t regs = hw_res_parsed.io_ranges.ranges[0];
+	ne2k->base_port = RNGABSPTR(regs);
 	
 	hw_res_list_parsed_clean(&hw_res_parsed);
 	
-	/* Enable port I/O */
-	if (pio_enable(ne2k->base_port, NE2K_IO_SIZE, &ne2k->port) != EOK)
+	/* Enable programmed I/O */
+	if (pio_enable_range(&regs, &ne2k->port) != EOK)
 		return EADDRNOTAVAIL;
-	
 	
 	ne2k->data_port = ne2k->port + NE2K_DATA;
Index: uspace/drv/nic/rtl8139/driver.c
===================================================================
--- uspace/drv/nic/rtl8139/driver.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/drv/nic/rtl8139/driver.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -1087,5 +1087,5 @@
 	ddf_msg(LVL_DEBUG, "%s device: irq 0x%x assigned", ddf_dev_get_name(dev), rtl8139->irq);
 
-	rtl8139->io_addr = IOADDR_TO_PTR(hw_resources->io_ranges.ranges[0].address);
+	rtl8139->io_addr = IOADDR_TO_PTR(RNGABS(hw_resources->io_ranges.ranges[0]));
 	if (hw_resources->io_ranges.ranges[0].size < RTL8139_IO_SIZE) {
 		ddf_msg(LVL_ERROR, "i/o range assigned to the device "
Index: uspace/lib/block/block.c
===================================================================
--- uspace/lib/block/block.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/block/block.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -37,5 +37,4 @@
  */
 
-#include "../../srv/vfs/vfs.h"
 #include <ipc/loc.h>
 #include <ipc/services.h>
Index: uspace/lib/block/block.h
===================================================================
--- uspace/lib/block/block.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/block/block.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -29,7 +29,7 @@
  */
 
-/** @addtogroup libblock 
+/** @addtogroup libblock
  * @{
- */ 
+ */
 /**
  * @file
@@ -41,8 +41,8 @@
 #include <stdint.h>
 #include <async.h>
-#include "../../srv/vfs/vfs.h"
 #include <fibril_synch.h>
 #include <adt/hash_table.h>
 #include <adt/list.h>
+#include <loc.h>
 
 /*
@@ -50,5 +50,5 @@
  */
 
-/** 
+/**
  * This macro is a symbolic value for situations where no special flags are
  * needed.
Index: uspace/lib/c/generic/ddi.c
===================================================================
--- uspace/lib/c/generic/ddi.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/c/generic/ddi.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -42,4 +42,7 @@
 #include <ddi.h>
 #include <libarch/ddi.h>
+#include <device/hw_res.h>
+#include <device/hw_res_parsed.h>
+#include <device/pio_window.h>
 #include <libc.h>
 #include <task.h>
@@ -134,4 +137,56 @@
 	
 	return __SYSCALL1(SYS_IOSPACE_ENABLE, (sysarg_t) &arg);
+}
+
+/** Enable PIO for specified address range.
+ *
+ * @param range I/O range to be enable.
+ * @param virt  Virtual address for application's PIO operations. 
+ */
+int pio_enable_range(addr_range_t *range, void **virt)
+{
+	return pio_enable(RNGABSPTR(*range), RNGSZ(*range), virt);
+}
+
+/** Enable PIO for specified HW resource wrt. to the PIO window.
+ *
+ * @param win      PIO window. May be NULL if the resources are known to be
+ *                 absolute.
+ * @param res      Resources specifying the I/O range wrt. to the PIO window.
+ * @param virt     Virtual address for application's PIO operations.
+ *
+ * @return EOK on success.
+ * @return Negative error code on failure.
+ *
+ */
+int pio_enable_resource(pio_window_t *win, hw_resource_t *res, void **virt)
+{
+	uintptr_t addr;
+	size_t size;
+
+	switch (res->type) {
+	case IO_RANGE:
+		addr = res->res.io_range.address;
+		if (res->res.io_range.relative) {
+			if (!win)
+				return EINVAL;
+			addr += win->io.base;
+		}
+		size = res->res.io_range.size;
+		break;
+	case MEM_RANGE:
+		addr = res->res.mem_range.address;
+		if (res->res.mem_range.relative) {
+			if (!win)
+				return EINVAL;
+			addr += win->mem.base;
+		}
+		size = res->res.mem_range.size;
+		break;
+	default:
+		return EINVAL;
+	}
+
+	return pio_enable((void *) addr, size, virt);	
 }
 
Index: uspace/lib/c/generic/device/hw_res_parsed.c
===================================================================
--- uspace/lib/c/generic/device/hw_res_parsed.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/c/generic/device/hw_res_parsed.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -80,12 +80,36 @@
 }
 
+static uint64_t absolutize(uint64_t addr, bool relative, uint64_t base)
+{
+	if (!relative)
+		return addr;
+	else
+		return addr + base;
+}
+
+static uint64_t relativize(uint64_t addr, bool relative, uint64_t base)
+{
+	if (relative)
+		return addr;
+	else
+		return addr - base;
+}
+
 static void hw_res_parse_add_io_range(hw_res_list_parsed_t *out,
-    const hw_resource_t *res, int flags)
-{
+    const pio_window_t *win, const hw_resource_t *res, int flags)
+{
+	endianness_t endianness;
+	uint64_t absolute;
+	uint64_t relative;
+	size_t size;
+
 	assert(res && (res->type == IO_RANGE));
 	
-	uint64_t address = res->res.io_range.address;
-	endianness_t endianness = res->res.io_range.endianness;
-	size_t size = res->res.io_range.size;
+	absolute = absolutize(res->res.io_range.address,
+	    res->res.io_range.relative, win->io.base);
+	relative = relativize(res->res.io_range.address,
+	    res->res.io_range.relative, win->io.base);
+	size = res->res.io_range.size;
+	endianness = res->res.io_range.endianness;
 	
 	if ((size == 0) && (!(flags & HW_RES_KEEP_ZERO_AREA)))
@@ -97,26 +121,38 @@
 	if (!keep_duplicit) {
 		for (size_t i = 0; i < count; i++) {
-			uint64_t s_address = out->io_ranges.ranges[i].address;
-			size_t s_size = out->io_ranges.ranges[i].size;
+			uint64_t s_address;
+			size_t s_size;
+
+			s_address = RNGABS(out->io_ranges.ranges[i]);
+			s_size = RNGSZ(out->io_ranges.ranges[i]);
 			
-			if ((address == s_address) && (size == s_size))
-				return;
-		}
-	}
-	
-	out->io_ranges.ranges[count].address = address;
+			if ((absolute == s_address) && (size == s_size))
+				return;
+		}
+	}
+	
+	RNGABS(out->io_ranges.ranges[count]) = absolute;
+	RNGREL(out->io_ranges.ranges[count]) = relative;
+	RNGSZ(out->io_ranges.ranges[count]) = size;
 	out->io_ranges.ranges[count].endianness = endianness;
-	out->io_ranges.ranges[count].size = size;
 	out->io_ranges.count++;
 }
 
 static void hw_res_parse_add_mem_range(hw_res_list_parsed_t *out,
-    const hw_resource_t *res, int flags)
-{
+    const pio_window_t *win, const hw_resource_t *res, int flags)
+{
+	endianness_t endianness;
+	uint64_t absolute;
+	uint64_t relative;
+	size_t size;
+	
 	assert(res && (res->type == MEM_RANGE));
 	
-	uint64_t address = res->res.mem_range.address;
-	endianness_t endianness = res->res.mem_range.endianness;
-	size_t size = res->res.mem_range.size;
+	absolute = absolutize(res->res.mem_range.address,
+	    res->res.mem_range.relative, win->mem.base);
+	relative = relativize(res->res.mem_range.address,
+	    res->res.mem_range.relative, win->mem.base);
+	size = res->res.mem_range.size;
+	endianness = res->res.mem_range.endianness;
 	
 	if ((size == 0) && (!(flags & HW_RES_KEEP_ZERO_AREA)))
@@ -128,15 +164,19 @@
 	if (!keep_duplicit) {
 		for (size_t i = 0; i < count; ++i) {
-			uint64_t s_address = out->mem_ranges.ranges[i].address;
-			size_t s_size = out->mem_ranges.ranges[i].size;
+			uint64_t s_address;
+			size_t s_size;
+
+			s_address = RNGABS(out->mem_ranges.ranges[i]);;
+			s_size = RNGSZ(out->mem_ranges.ranges[i]);
 			
-			if ((address == s_address) && (size == s_size))
-				return;
-		}
-	}
-	
-	out->mem_ranges.ranges[count].address = address;
+			if ((absolute == s_address) && (size == s_size))
+				return;
+		}
+	}
+	
+	RNGABS(out->mem_ranges.ranges[count]) = absolute;
+	RNGREL(out->mem_ranges.ranges[count]) = relative;
+	RNGSZ(out->mem_ranges.ranges[count]) = size;
 	out->mem_ranges.ranges[count].endianness = endianness;
-	out->mem_ranges.ranges[count].size = size;
 	out->mem_ranges.count++;
 }
@@ -144,21 +184,21 @@
 /** Parse list of hardware resources
  *
- * @param      hw_resources Original structure resource
- * @param[out] out          Output parsed resources
- * @param      flags        Flags of the parsing.
- *                          HW_RES_KEEP_ZERO_AREA for keeping
- *                          zero-size areas, HW_RES_KEEP_DUPLICITIES
- *                          for keep duplicit areas
+ * @param      win          PIO window.
+ * @param      res          Original structure resource.
+ * @param[out] out          Output parsed resources.
+ * @param      flags        Flags of the parsing:
+ *                          HW_RES_KEEP_ZERO_AREA for keeping zero-size areas,
+ *                          HW_RES_KEEP_DUPLICITIES to keep duplicit areas.
  *
  * @return EOK if succeed, error code otherwise.
  *
  */
-int hw_res_list_parse(const hw_resource_list_t *hw_resources,
-    hw_res_list_parsed_t *out, int flags)
-{
-	if ((!hw_resources) || (!out))
+int hw_res_list_parse(const pio_window_t *win,
+    const hw_resource_list_t *res, hw_res_list_parsed_t *out, int flags)
+{
+	if (!res || !out)
 		return EINVAL;
 	
-	size_t res_count = hw_resources->count;
+	size_t res_count = res->count;
 	hw_res_list_parsed_clean(out);
 	
@@ -174,5 +214,5 @@
 	
 	for (size_t i = 0; i < res_count; ++i) {
-		const hw_resource_t *resource = &(hw_resources->resources[i]);
+		const hw_resource_t *resource = &res->resources[i];
 		
 		switch (resource->type) {
@@ -181,8 +221,8 @@
 			break;
 		case IO_RANGE:
-			hw_res_parse_add_io_range(out, resource, flags);
+			hw_res_parse_add_io_range(out, win, resource, flags);
 			break;
 		case MEM_RANGE:
-			hw_res_parse_add_mem_range(out, resource, flags);
+			hw_res_parse_add_mem_range(out, win, resource, flags);
 			break;
 		case DMA_CHANNEL_8:
@@ -216,4 +256,7 @@
     hw_res_list_parsed_t *hw_res_parsed, int flags)
 {
+	pio_window_t pio_window;
+	int rc;
+
 	if (!hw_res_parsed)
 		return EBADMEM;
@@ -222,10 +265,15 @@
 	hw_res_list_parsed_clean(hw_res_parsed);
 	memset(&hw_resources, 0, sizeof(hw_resource_list_t));
-	
-	int rc = hw_res_get_resource_list(sess, &hw_resources);
+
+	rc = pio_window_get(sess, &pio_window);
+	if (rc != EOK)
+		return rc; 
+	
+	rc = hw_res_get_resource_list(sess, &hw_resources);
 	if (rc != EOK)
 		return rc;
-	
-	rc = hw_res_list_parse(&hw_resources, hw_res_parsed, flags);
+
+	rc = hw_res_list_parse(&pio_window, &hw_resources, hw_res_parsed,
+	    flags);
 	hw_res_clean_resource_list(&hw_resources);
 	
Index: uspace/lib/c/generic/io/asprintf.c
===================================================================
--- uspace/lib/c/generic/io/asprintf.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/c/generic/io/asprintf.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -50,4 +50,25 @@
 }
 
+int vprintf_size(const char *fmt, va_list args)
+{
+	printf_spec_t ps = {
+		asprintf_str_write,
+		asprintf_wstr_write,
+		NULL
+	};
+	
+	return printf_core(fmt, &ps, args);
+}
+
+int printf_size(const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	int ret = vprintf_size(fmt, args);
+	va_end(args);
+	
+	return ret;
+}
+
 /** Allocate and print to string.
  *
@@ -61,14 +82,7 @@
 int asprintf(char **strp, const char *fmt, ...)
 {
-	printf_spec_t ps = {
-		asprintf_str_write,
-		asprintf_wstr_write,
-		NULL
-	};
-	
 	va_list args;
 	va_start(args, fmt);
-	
-	int ret = printf_core(fmt, &ps, args);
+	int ret = vprintf_size(fmt, args);
 	va_end(args);
 	
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -893,41 +893,28 @@
 }
 
-int statfs(const char *path, struct statfs *statfs)
-{
-	sysarg_t rc;
-	sysarg_t rc_orig;
+int statfs(const char *path, struct statfs *st)
+{
+	sysarg_t rc, rc_orig;
 	aid_t req;
 	size_t pa_size;
-	
+
 	char *pa = absolutize(path, &pa_size);
 	if (!pa)
 		return ENOMEM;
-	async_exch_t *exch = vfs_exchange_begin();
-	
+
+	async_exch_t *exch = vfs_exchange_begin();
+
 	req = async_send_0(exch, VFS_IN_STATFS, NULL);
 	rc = async_data_write_start(exch, pa, pa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(pa);
-		async_wait_for(req, &rc_orig);
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	rc = async_data_read_start(exch, (void *) statfs, sizeof(struct statfs));
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(pa);
-		async_wait_for(req, &rc_orig);
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
+	if (rc != EOK)
+		goto exit;
+
+	rc = async_data_read_start(exch, (void *) st, sizeof(*st));
+
+exit:
 	vfs_exchange_end(exch);
 	free(pa);
-	async_wait_for(req, &rc);
-	return rc;
+	async_wait_for(req, &rc_orig);
+	return (int) (rc_orig != EOK ? rc_orig : rc);
 }
 
Index: uspace/lib/c/include/ddi.h
===================================================================
--- uspace/lib/c/include/ddi.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/c/include/ddi.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -40,4 +40,7 @@
 #include <sys/time.h>
 #include <abi/ddi/irq.h>
+#include <device/hw_res.h>
+#include <device/hw_res_parsed.h>
+#include <device/pio_window.h>
 #include <task.h>
 
@@ -55,4 +58,6 @@
 extern int dmamem_unmap_anonymous(void *);
 
+extern int pio_enable_range(addr_range_t *, void **);
+extern int pio_enable_resource(pio_window_t *, hw_resource_t *, void **);
 extern int pio_enable(void *, size_t, void **);
 
Index: uspace/lib/c/include/device/hw_res.h
===================================================================
--- uspace/lib/c/include/device/hw_res.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/c/include/device/hw_res.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -76,12 +76,14 @@
 		struct {
 			uint64_t address;
+			size_t size;
+			bool relative;
 			endianness_t endianness;
-			size_t size;
 		} mem_range;
 		
 		struct {
 			uint64_t address;
+			size_t size;
+			bool relative;
 			endianness_t endianness;
-			size_t size;
 		} io_range;
 		
Index: uspace/lib/c/include/device/hw_res_parsed.h
===================================================================
--- uspace/lib/c/include/device/hw_res_parsed.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/c/include/device/hw_res_parsed.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -37,4 +37,5 @@
 
 #include <device/hw_res.h>
+#include <device/pio_window.h>
 #include <str.h>
 
@@ -45,14 +46,28 @@
 #define HW_RES_KEEP_DUPLICIT   0x2
 
+
+#define RNGABS(rng)	(rng).address.absolute
+#define RNGREL(rng)	(rng).address.relative
+#define RNGSZ(rng)	(rng).size
+
+#define RNGABSPTR(rng)	((void *) ((uintptr_t) RNGABS((rng))))
+
+typedef struct address64 {
+	/** Aboslute address. */ 
+	uint64_t absolute;
+	/** PIO window base relative address. */
+	uint64_t relative; 
+} address64_t;
+
 /** Address range structure */
 typedef struct addr_range {
 	/** Start address */
-	uint64_t address;
-	
-	/** Endianness */
-	endianness_t endianness;
+	address64_t address;
 	
 	/** Area size */
 	size_t size;
+
+	/** Endianness */
+	endianness_t endianness;
 } addr_range_t;
 
@@ -139,5 +154,5 @@
 }
 
-extern int hw_res_list_parse(const hw_resource_list_t *,
+extern int hw_res_list_parse(const pio_window_t *, const hw_resource_list_t *,
     hw_res_list_parsed_t *, int);
 extern int hw_res_get_list_parsed(async_sess_t *, hw_res_list_parsed_t *, int);
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/c/include/stdio.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -124,4 +124,8 @@
 extern int vsnprintf(char *, size_t, const char *, va_list);
 
+extern int printf_size(const char *, ...)
+    PRINTF_ATTRIBUTE(1, 2);
+extern int vprintf_size(const char *, va_list);
+
 /* File stream functions */
 extern FILE *fopen(const char *, const char *);
Index: uspace/lib/ext4/libext4_filesystem.c
===================================================================
--- uspace/lib/ext4/libext4_filesystem.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/ext4/libext4_filesystem.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -39,4 +39,5 @@
 #include <errno.h>
 #include <malloc.h>
+#include <ipc/vfs.h>
 #include "libext4.h"
 
Index: uspace/lib/fs/libfs.c
===================================================================
--- uspace/lib/fs/libfs.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/fs/libfs.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -806,9 +806,9 @@
 	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	
+
 	fs_node_t *fn;
 	int rc = ops->node_get(&fn, service_id, index);
 	on_error(rc, answer_and_return(rid, rc));
-	
+
 	ipc_callid_t callid;
 	size_t size;
@@ -820,8 +820,8 @@
 		return;
 	}
-	
+
 	struct stat stat;
 	memset(&stat, 0, sizeof(struct stat));
-	
+
 	stat.fs_handle = fs_handle;
 	stat.service_id = service_id;
@@ -832,5 +832,5 @@
 	stat.size = ops->size_get(fn);
 	stat.service = ops->service_get(fn);
-	
+
 	ops->node_put(fn);
 
@@ -845,39 +845,39 @@
 	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	
+
 	fs_node_t *fn;
 	int rc = ops->node_get(&fn, service_id, index);
 	on_error(rc, answer_and_return(rid, rc));
-	
+
 	ipc_callid_t callid;
 	size_t size;
 	if ((!async_data_read_receive(&callid, &size)) ||
 	    (size != sizeof(struct statfs))) {
-		ops->node_put(fn);
-		async_answer_0(callid, EINVAL);
-		async_answer_0(rid, EINVAL);
-		return;
-	}
-	
-	struct statfs statfs;
-	memset(&statfs, 0, sizeof(struct statfs));
-
-	if (NULL != ops->size_block) {	
-		rc = ops->size_block(service_id, &statfs.f_bsize);
-		if (rc != EOK) goto error;
-	}
-
-	if (NULL != ops->total_block_count) {
-		rc = ops->total_block_count(service_id, &statfs.f_blocks);
-		if (rc != EOK) goto error;
-	}
-
-	if (NULL != ops->free_block_count) {
-		rc = ops->free_block_count(service_id, &statfs.f_bfree);
-		if (rc != EOK) goto error;
+		goto error;
+	}
+
+	struct statfs st;
+	memset(&st, 0, sizeof(struct statfs));
+
+	if (ops->size_block != NULL) {
+		rc = ops->size_block(service_id, &st.f_bsize);
+		if (rc != EOK)
+			goto error;
+	}
+
+	if (ops->total_block_count != NULL) {
+		rc = ops->total_block_count(service_id, &st.f_blocks);
+		if (rc != EOK)
+			goto error;
+	}
+
+	if (ops->free_block_count != NULL) {
+		rc = ops->free_block_count(service_id, &st.f_bfree);
+		if (rc != EOK)
+			goto error;
 	}
 
 	ops->node_put(fn);
-	async_data_read_finalize(callid, &statfs, sizeof(struct statfs));
+	async_data_read_finalize(callid, &st, sizeof(struct statfs));
 	async_answer_0(rid, EOK);
 	return;
Index: uspace/lib/gui/window.c
===================================================================
--- uspace/lib/gui/window.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/lib/gui/window.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -66,7 +66,7 @@
 
 static pixel_t border_color = PIXEL(255, 0, 0, 0);
-static pixel_t header_bg_focus_color = PIXEL(255, 25, 25, 112);
+static pixel_t header_bg_focus_color = PIXEL(255, 88, 106, 196);
 static pixel_t header_fg_focus_color = PIXEL(255, 255, 255, 255);
-static pixel_t header_bg_unfocus_color = PIXEL(255, 70, 130, 180);
+static pixel_t header_bg_unfocus_color = PIXEL(255, 12, 57, 92);
 static pixel_t header_fg_unfocus_color = PIXEL(255, 255, 255, 255);
 
Index: uspace/lib/http/Makefile
===================================================================
--- uspace/lib/http/Makefile	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
+++ uspace/lib/http/Makefile	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2013 Martin Sucha
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libhttp
+SLIBRARY = libhttp.so.0.0
+LSONAME = libhttp.so0
+#EXTRA_CFLAGS += 
+
+SOURCES = \
+	http.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/http/http.c
===================================================================
--- uspace/lib/http/http.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
+++ uspace/lib/http/http.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <macros.h>
+
+#include <net/socket.h>
+#include <inet/dnsr.h>
+
+#include "http.h"
+
+#define HTTP_METHOD_LINE "%s %s HTTP/1.1\r\n"
+#define HTTP_HEADER_LINE "%s: %s\r\n"
+#define HTTP_REQUEST_LINE "\r\n"
+
+static char *cut_str(const char *start, const char *end)
+{
+	size_t size = end - start;
+	return str_ndup(start, size);
+}
+
+static void recv_reset(http_t *http)
+{
+	http->recv_buffer_in = 0;
+	http->recv_buffer_out = 0;
+}
+
+/** Receive one character (with buffering) */
+static int recv_char(http_t *http, char *c, bool consume)
+{
+	if (http->recv_buffer_out == http->recv_buffer_in) {
+		recv_reset(http);
+		
+		ssize_t rc = recv(http->conn_sd, http->recv_buffer, http->buffer_size, 0);
+		if (rc <= 0)
+			return rc;
+		
+		http->recv_buffer_in = rc;
+	}
+	
+	*c = http->recv_buffer[http->recv_buffer_out];
+	if (consume)
+		http->recv_buffer_out++;
+	return EOK;
+}
+
+static ssize_t recv_buffer(http_t *http, char *buf, size_t buf_size)
+{
+	/* Flush any buffered data*/
+	if (http->recv_buffer_out != http->recv_buffer_in) {
+		size_t size = min(http->recv_buffer_in - http->recv_buffer_out, buf_size);
+		memcpy(buf, http->recv_buffer + http->recv_buffer_out, size);
+		http->recv_buffer_out += size;
+		return size;
+	}
+	
+	return recv(http->conn_sd, buf, buf_size, 0);
+}
+
+/** Receive a character and if it is c, discard it from input buffer */
+static int recv_discard(http_t *http, char discard)
+{
+	char c = 0;
+	int rc = recv_char(http, &c, false);
+	if (rc != EOK)
+		return rc;
+	if (c != discard)
+		return EOK;
+	return recv_char(http, &c, true);
+}
+
+/* Receive a single line */
+static ssize_t recv_line(http_t *http, char *line, size_t size)
+{
+	size_t written = 0;
+	
+	while (written < size) {
+		char c = 0;
+		int rc = recv_char(http, &c, true);
+		if (rc != EOK)
+			return rc;
+		if (c == '\n') {
+			recv_discard(http, '\r');
+			line[written++] = 0;
+			return written;
+		}
+		else if (c == '\r') {
+			recv_discard(http, '\n');
+			line[written++] = 0;
+			return written;
+		}
+		line[written++] = c;
+	}
+	
+	return ELIMIT;
+}
+
+http_t *http_create(const char *host, uint16_t port)
+{
+	http_t *http = malloc(sizeof(http_t));
+	if (http == NULL)
+		return NULL;
+	
+	http->host = str_dup(host);
+	if (http->host == NULL) {
+		free(http);
+		return NULL;
+	}
+	http->port = port;
+	
+	http->buffer_size = 4096;
+	http->recv_buffer = malloc(http->buffer_size);
+	if (http->recv_buffer == NULL) {
+		free(http->host);
+		free(http);
+		return NULL;
+	}
+	
+	return http;
+}
+
+int http_connect(http_t *http)
+{
+	if (http->connected)
+		return EBUSY;
+	
+	/* Interpret as address */
+	int rc = inet_addr_parse(http->host, &http->addr);
+	
+	if (rc != EOK) {
+		/* Interpret as a host name */
+		dnsr_hostinfo_t *hinfo = NULL;
+		rc = dnsr_name2host(http->host, &hinfo, AF_NONE);
+		
+		if (rc != EOK)
+			return rc;
+		
+		http->addr = hinfo->addr;
+		dnsr_hostinfo_destroy(hinfo);
+	}
+	
+	struct sockaddr_in addr;
+	struct sockaddr_in6 addr6;
+	uint16_t af = inet_addr_sockaddr_in(&http->addr, &addr, &addr6);
+	
+	http->conn_sd = socket(PF_INET, SOCK_STREAM, 0);
+	if (http->conn_sd < 0)
+		return http->conn_sd;
+	
+	switch (af) {
+	case AF_INET:
+		addr.sin_port = htons(http->port);
+		rc = connect(http->conn_sd, (struct sockaddr *) &addr, sizeof(addr));
+		break;
+	case AF_INET6:
+		addr6.sin6_port = htons(http->port);
+		rc = connect(http->conn_sd, (struct sockaddr *) &addr6, sizeof(addr6));
+		break;
+	default:
+		return ENOTSUP;
+	}
+	
+	return rc;
+}
+
+http_header_t *http_header_create(const char *name, const char *value)
+{
+	char *dname = str_dup(name);
+	if (dname == NULL)
+		return NULL;
+	
+	char *dvalue = str_dup(value);
+	if (dvalue == NULL) {
+		free(dname);
+		return NULL;
+	}
+
+	return http_header_create_no_copy(dname, dvalue);
+}
+
+http_header_t *http_header_create_no_copy(char *name, char *value)
+{
+	http_header_t *header = malloc(sizeof(http_header_t));
+	if (header == NULL)
+		return NULL;
+	
+	link_initialize(&header->link);
+	header->name = name;
+	header->value = value;
+	
+	return header;
+}
+
+void http_header_destroy(http_header_t *header)
+{
+	free(header->name);
+	free(header->value);
+	free(header);
+}
+
+http_request_t *http_request_create(const char *method, const char *path)
+{
+	http_request_t *req = malloc(sizeof(http_request_t));
+	if (req == NULL)
+		return NULL;
+	
+	req->method = str_dup(method);
+	if (req->method == NULL) {
+		free(req);
+		return NULL;
+	}
+	
+	req->path = str_dup(path);
+	if (req->path == NULL) {
+		free(req->method);
+		free(req);
+		return NULL;
+	}
+	
+	list_initialize(&req->headers);
+	
+	return req;
+}
+
+void http_request_destroy(http_request_t *req)
+{
+	free(req->method);
+	free(req->path);
+	link_t *link = req->headers.head.next;
+	while (link != &req->headers.head) {
+		link_t *next = link->next;
+		http_header_t *header = list_get_instance(link, http_header_t, link);
+		http_header_destroy(header);
+		link = next;
+	}
+	free(req);
+}
+
+static ssize_t http_encode_method(char *buf, size_t buf_size,
+    const char *method, const char *path)
+{
+	if (buf == NULL) {
+		return printf_size(HTTP_METHOD_LINE, method, path);
+	}
+	else {
+		return snprintf(buf, buf_size, HTTP_METHOD_LINE, method, path);
+	}
+}
+
+static ssize_t http_encode_header(char *buf, size_t buf_size,
+    http_header_t *header)
+{
+	/* TODO properly split long header values */
+	if (buf == NULL) {
+		return printf_size(HTTP_HEADER_LINE, header->name, header->value);
+	}
+	else {
+		return snprintf(buf, buf_size,
+		    HTTP_HEADER_LINE, header->name, header->value);
+	}
+}
+
+int http_request_format(http_request_t *req, char **out_buf,
+    size_t *out_buf_size)
+{
+	/* Compute the size of the request */
+	ssize_t meth_size = http_encode_method(NULL, 0, req->method, req->path);
+	if (meth_size < 0)
+		return meth_size;
+	size_t size = meth_size;
+	
+	list_foreach(req->headers, link, http_header_t, header) {
+		ssize_t header_size = http_encode_header(NULL, 0, header);
+		if (header_size < 0)
+			return header_size;
+		size += header_size;
+	}
+	size += str_length(HTTP_REQUEST_LINE);
+	
+	char *buf = malloc(size);
+	if (buf == NULL)
+		return ENOMEM;
+	
+	char *pos = buf;
+	size_t pos_size = size;
+	ssize_t written = http_encode_method(pos, pos_size, req->method, req->path);
+	if (written < 0) {
+		free(buf);
+		return written;
+	}
+	pos += written;
+	pos_size -= written;
+	
+	list_foreach(req->headers, link, http_header_t, header) {
+		written = http_encode_header(pos, pos_size, header);
+		if (written < 0) {
+			free(buf);
+			return written;
+		}
+		pos += written;
+		pos_size -= written;
+	}
+	
+	size_t rlsize = str_size(HTTP_REQUEST_LINE);
+	memcpy(pos, HTTP_REQUEST_LINE, rlsize);
+	pos_size -= rlsize;
+	assert(pos_size == 0);
+	
+	*out_buf = buf;
+	*out_buf_size = size;
+	return EOK;
+}
+
+int http_send_request(http_t *http, http_request_t *req)
+{
+	char *buf;
+	size_t buf_size;
+	
+	int rc = http_request_format(req, &buf, &buf_size);
+	if (rc != EOK)
+		return rc;
+	
+	rc = send(http->conn_sd, buf, buf_size, 0);
+	free(buf);
+	
+	return rc;
+}
+
+int http_parse_status(const char *line, http_version_t *out_version,
+    uint16_t *out_status, char **out_message)
+{
+	http_version_t version;
+	uint16_t status;
+	char *message = NULL;
+	
+	if (!str_test_prefix(line, "HTTP/"))
+		return EINVAL;
+	
+	const char *pos_version = line + 5;
+	const char *pos = pos_version;
+	
+	int rc = str_uint8_t(pos_version, &pos, 10, false, &version.major);
+	if (rc != EOK)
+		return rc;
+	if (*pos != '.')
+		return EINVAL;
+	pos++;
+	
+	pos_version = pos;
+	rc = str_uint8_t(pos_version, &pos, 10, false, &version.minor);
+	if (rc != EOK)
+		return rc;
+	if (*pos != ' ')
+		return EINVAL;
+	pos++;
+	
+	const char *pos_status = pos;
+	rc = str_uint16_t(pos_status, &pos, 10, false, &status);
+	if (rc != EOK)
+		return rc;
+	if (*pos != ' ')
+		return EINVAL;
+	pos++;
+	
+	if (out_message) {
+		message = str_dup(pos);
+		if (message == NULL)
+			return ENOMEM;
+	}
+	
+	if (out_version)
+		*out_version = version;
+	if (out_status)
+		*out_status = status;
+	if (out_message)
+		*out_message = message;
+	return EOK;
+}
+
+int http_parse_header(const char *line, char **out_name, char **out_value)
+{
+	const char *pos = line;
+	while (*pos != 0 && *pos != ':') pos++;
+	if (*pos != ':')
+		return EINVAL;
+	
+	char *name = cut_str(line, pos);
+	if (name == NULL)
+		return ENOMEM;
+	
+	pos++;
+	
+	while (*pos == ' ') pos++;
+	
+	char *value = str_dup(pos);
+	if (value == NULL) {
+		free(name);
+		return ENOMEM;
+	}
+	
+	*out_name = name;
+	*out_value = value;
+	
+	return EOK;
+}
+
+int http_receive_response(http_t *http, http_response_t **out_response)
+{
+	http_response_t *resp = malloc(sizeof(http_response_t));
+	if (resp == NULL)
+		return ENOMEM;
+	memset(resp, 0, sizeof(http_response_t));
+	list_initialize(&resp->headers);
+	
+	char *line = malloc(http->buffer_size);
+	if (line == NULL) {
+		free(resp);
+		return ENOMEM;
+	}
+	
+	int rc = recv_line(http, line, http->buffer_size);
+	if (rc < 0)
+		goto error;
+	
+	rc = http_parse_status(line, &resp->version, &resp->status,
+	    &resp->message);
+	if (rc != EOK)
+		goto error;
+	
+	while (true) {
+		rc = recv_line(http, line, http->buffer_size);
+		if (rc < 0)
+			goto error;
+		if (*line == 0)
+			break;
+		
+		char *name = NULL;
+		char *value = NULL;
+		rc = http_parse_header(line, &name, &value);
+		if (rc != EOK)
+			goto error;
+		
+		http_header_t *header = http_header_create_no_copy(name, value);
+		if (header == NULL) {
+			free(name);
+			free(value);
+			rc = ENOMEM;
+			goto error;
+		}
+		
+		list_append(&header->link, &resp->headers);
+	}
+	
+	*out_response = resp;
+	
+	return EOK;
+error:
+	free(line);
+	http_response_destroy(resp);
+	return rc;
+}
+
+int http_receive_body(http_t *http, void *buf, size_t buf_size)
+{
+	return recv_buffer(http, buf, buf_size);
+}
+
+void http_response_destroy(http_response_t *resp)
+{
+	free(resp->message);
+	link_t *link = resp->headers.head.next;
+	while (link != &resp->headers.head) {
+		link_t *next = link->next;
+		http_header_t *header = list_get_instance(link, http_header_t, link);
+		http_header_destroy(header);
+		link = next;
+	}
+	free(resp);
+}
+
+int http_close(http_t *http)
+{
+	if (!http->connected)
+		return EINVAL;
+	
+	return closesocket(http->conn_sd);
+}
+
+void http_destroy(http_t *http)
+{
+	free(http->recv_buffer);
+	free(http);
+}
+
+/** @}
+ */
Index: uspace/lib/http/http.h
===================================================================
--- uspace/lib/http/http.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
+++ uspace/lib/http/http.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup http
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef HTTP_HTTP_H_
+#define HTTP_HTTP_H_
+
+#include <net/socket.h>
+#include <adt/list.h>
+#include <inet/addr.h>
+
+typedef struct {
+	char *host;
+	uint16_t port;
+	inet_addr_t addr;
+
+	bool connected;
+	int conn_sd;
+	
+	size_t buffer_size;
+	char *recv_buffer;
+	size_t recv_buffer_in;
+	size_t recv_buffer_out;
+} http_t;
+
+typedef struct {
+	uint8_t minor;
+	uint8_t major;
+} http_version_t;
+
+typedef struct {
+	link_t link;
+	char *name;
+	char *value;
+} http_header_t;
+
+typedef struct {
+	char *method;
+	char *path;
+	list_t headers;
+} http_request_t;
+
+typedef struct {
+	http_version_t version;
+	uint16_t status;
+	char *message;
+	list_t headers;
+} http_response_t;
+
+extern http_t *http_create(const char *, uint16_t);
+extern int http_connect(http_t *);
+extern http_header_t *http_header_create(const char *, const char *);
+extern http_header_t *http_header_create_no_copy(char *, char *);
+extern void http_header_destroy(http_header_t *);
+extern http_request_t *http_request_create(const char *, const char *);
+extern void http_request_destroy(http_request_t *);
+extern int http_request_format(http_request_t *, char **, size_t *);
+extern int http_send_request(http_t *, http_request_t *);
+extern int http_parse_status(const char *, http_version_t *, uint16_t *,
+    char **);
+extern int http_parse_header(const char *, char **, char **);
+extern int http_receive_response(http_t *, http_response_t **);
+extern int http_receive_body(http_t *, void *, size_t);
+extern void http_response_destroy(http_response_t *);
+extern int http_close(http_t *);
+extern void http_destroy(http_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/uri/Makefile
===================================================================
--- uspace/lib/uri/Makefile	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
+++ uspace/lib/uri/Makefile	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2013 Martin Sucha
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = liburi
+SLIBRARY = liburi.so.0.0
+LSONAME = liburi.so0
+#EXTRA_CFLAGS += 
+
+SOURCES = \
+	uri.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/uri/ctype.h
===================================================================
--- uspace/lib/uri/ctype.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
+++ uspace/lib/uri/ctype.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup uri
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef URI_CTYPE_H_
+#define URI_CTYPE_H_
+
+static inline bool is_unreserved(char c)
+{
+	return isalpha(c) || isdigit(c) ||
+	    c == '-' || c == '.' || c == '_' || c == '~';
+}
+
+static inline bool is_hexdig(char c)
+{
+	return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
+	    (c >= 'A' && c <= 'F');
+}
+
+static inline bool is_subdelim(char c)
+{
+	switch (c) {
+	case '!':
+	case '$':
+	case '&':
+	case '\'':
+	case '(':
+	case ')':
+	case '*':
+	case '+':
+	case ',':
+	case ';':
+	case '=':
+		return true;
+	default:
+		return false;
+	}
+}
+
+static inline bool is_gendelim(char c)
+{
+	switch (c) {
+	case ':':
+	case '/':
+	case '?':
+	case '#':
+	case '[':
+	case ']':
+	case '@':
+		return true;
+	default:
+		return false;
+	}
+}
+
+static inline bool is_reserved(char c)
+{
+	return is_gendelim(c) || is_subdelim(c);
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/uri/uri.c
===================================================================
--- uspace/lib/uri/uri.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
+++ uspace/lib/uri/uri.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup uri
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <str.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "uri.h"
+#include "ctype.h"
+
+static char *cut_str(const char *start, const char *end)
+{
+	size_t size = end - start;
+	return str_ndup(start, size);
+}
+
+uri_t *uri_parse(const char *str)
+{
+	uri_t *uri = malloc(sizeof(uri_t));
+	if (uri == NULL)
+		return NULL;
+	memset(uri, 0, sizeof(uri_t));
+	
+	/* scheme ":" */
+	const char *scheme = str;
+	while (*str != 0 && *str != ':') str++;
+	if (*str == 0) {
+		uri_destroy(uri);
+		return NULL;
+	}
+	uri->scheme = cut_str(scheme, str);
+	
+	/* skip the colon */
+	str++;
+	
+	if (*str == '/' && str[1] == '/') {
+		/* "//" [user-info [":" user-credential] "@"] host [":" port] */
+		str++;
+		str++;
+		const char *authority_start = str;
+	
+		char *host_or_user_info = NULL;
+		char *port_or_user_credential = NULL;
+	
+		while (*str != 0 && *str != '?' && *str != '#' && *str != '@'
+			&& *str != ':' && *str != '/')
+			str++;
+	
+		host_or_user_info = cut_str(authority_start, str);
+		if (*str == ':') {
+			str++;
+			const char *second_part = str;
+			while (*str != 0 && *str != '?' && *str != '#' &&
+				*str != '@' && *str != '/') str++;
+			port_or_user_credential = cut_str(second_part, str);
+		}
+	
+		if (*str == '@') {
+			uri->user_info = host_or_user_info;
+			uri->user_credential = port_or_user_credential;
+		
+			str++;
+			const char *host_start = str;
+			while (*str != 0 && *str != '?' && *str != '#'
+				&& *str != ':' && *str != '/') str++;
+			uri->host = cut_str(host_start, str);
+		
+			if (*str == ':') {
+				str++;
+				const char *port_start = str;
+				while (*str != 0 && *str != '?' && *str != '#' && *str != '/')
+					str++;
+				uri->port = cut_str(port_start, str);
+			}
+		}
+		else {
+			uri->host = host_or_user_info;
+			uri->port = port_or_user_credential;
+		}
+	}
+	
+	const char *path_start = str;
+	while (*str != 0 && *str != '?' && *str != '#') str++;
+	uri->path = cut_str(path_start, str);
+	
+	if (*str == '?') {
+		str++;
+		const char *query_start = str;
+		while (*str != 0 && *str != '#') str++;
+		uri->query = cut_str(query_start, str);
+	}
+	
+	if (*str == '#') {
+		str++;
+		const char *fragment_start = str;
+		while (*str != 0) str++;
+		uri->fragment = cut_str(fragment_start, str);
+	}
+	
+	assert(*str == 0);
+	return uri;
+}
+
+/** Parse the URI scheme
+ *
+ * @param endptr The position of the first character after the scheme
+ *               is stored there.
+ * @return EOK on success
+ */
+int uri_scheme_parse(const char *str, const char **endptr)
+{
+	if (*str == 0) {
+		*endptr = str;
+		return ELIMIT;
+	}
+	
+	if (!isalpha(*str)) {
+		*endptr = str;
+		return EINVAL;
+	}
+	
+	while (isalpha(*str) || isdigit(*str) ||
+	    *str == '+' || *str == '-' || *str == '.') {
+		str++;
+	}
+	
+	*endptr = str;
+	return EOK;
+}
+
+/** Determine if the URI scheme is valid
+ *
+ */
+bool uri_scheme_validate(const char *str)
+{
+	const char *endptr = NULL;
+	if (uri_scheme_parse(str, &endptr) != EOK)
+		return false;
+	return *endptr == 0;
+}
+
+int uri_percent_parse(const char *str, const char **endptr,
+    uint8_t *decoded)
+{
+	*endptr = str;
+	if (str[0] == 0 || str[1] == 0 || str[2] == 0)
+		return ELIMIT;
+	
+	if (str[0] != '%' || !is_hexdig(str[1]) || !is_hexdig(str[2]))
+		return EINVAL;
+	
+	if (decoded != NULL) {
+		int rc = str_uint8_t(str + 1, NULL, 16, true, decoded);
+		if (rc != EOK)
+			return rc;
+	}
+	
+	*endptr = str + 3;
+	return EOK;
+}
+
+int uri_user_info_parse(const char *str, const char **endptr)
+{
+	while (*str != 0) {
+		while (is_unreserved(*str) || is_subdelim(*str) || *str == ':') str++;
+		if (*str == 0)
+			break;
+		int rc = uri_percent_parse(str, &str, NULL);
+		if (rc != EOK) {
+			*endptr = str;
+			return rc;
+		}
+	}
+	
+	*endptr = str;
+	return EOK;
+}
+
+bool uri_user_info_validate(const char *str)
+{
+	const char *endptr = NULL;
+	if (uri_user_info_parse(str, &endptr) != EOK)
+		return false;
+	return *endptr == 0;
+}
+
+int uri_port_parse(const char *str, const char **endptr)
+{
+	if (*str == 0)
+		return ELIMIT;
+	if (!isdigit(*str))
+		return EINVAL;
+	while (isdigit(*str)) str++;
+	*endptr = str;
+	return EOK;
+}
+
+bool uri_port_validate(const char *str)
+{
+	const char *endptr = NULL;
+	if (uri_port_parse(str, &endptr) != EOK)
+		return false;
+	return *endptr == 0;
+}
+
+bool uri_validate(uri_t *uri)
+{
+	if (uri->scheme && !uri_scheme_validate(uri->scheme))
+		return false;
+	
+	if (uri->user_info && !uri_user_info_validate(uri->user_info))
+		return false;
+	
+	if (uri->user_credential && !uri_user_info_validate(uri->user_credential))
+		return false;
+	
+	if (uri->port && !uri_port_validate(uri->port))
+		return false;
+	
+	return true;
+}
+
+void uri_destroy(uri_t *uri)
+{
+	free(uri->scheme);
+	free(uri->user_info);
+	free(uri->user_credential);
+	free(uri->host);
+	free(uri->port);
+	free(uri->path);
+	free(uri->query);
+	free(uri->fragment);
+	free(uri);
+}
+
+/** @}
+ */
Index: uspace/lib/uri/uri.h
===================================================================
--- uspace/lib/uri/uri.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
+++ uspace/lib/uri/uri.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup uri
+ * @{
+ */
+/**
+ * @file
+ */
+
+#ifndef URI_URI_H_
+#define URI_URI_H_
+
+typedef struct {
+	char *scheme;
+	char *user_info;
+	char *user_credential;
+	char *host;
+	char *port;
+	char *path;
+	char *query;
+	char *fragment;
+} uri_t;
+
+extern uri_t *uri_parse(const char *);
+extern int uri_scheme_parse(const char *, const char **);
+extern bool uri_scheme_validate(const char *);
+extern int uri_percent_parse(const char *, const char **, uint8_t *);
+extern int uri_user_info_parse(const char *, const char **);
+extern bool uri_user_info_validate(const char *);
+extern int uri_port_parse(const char *, const char **);
+extern bool uri_port_validate(const char *);
+extern bool uri_validate(uri_t *);
+extern void uri_destroy(uri_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/audio/hound/audio_device.c
===================================================================
--- uspace/srv/audio/hound/audio_device.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/srv/audio/hound/audio_device.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -162,5 +162,5 @@
 		}
 		audio_pcm_register_event_callback(dev->sess,
-		    device_event_callback, dev);\
+		    device_event_callback, dev);
 
 		/* Fill the buffer first. Fill the first two fragments,
Index: uspace/srv/fs/ext4fs/ext4fs_ops.c
===================================================================
--- uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/srv/fs/ext4fs/ext4fs_ops.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -876,6 +876,4 @@
 	if (rc != EOK)
 		return rc;
-	if (NULL == inst)
-		return ENOENT;
 
 	ext4_superblock_t *sb = inst->filesystem->superblock;
Index: uspace/srv/fs/mfs/mfs.h
===================================================================
--- uspace/srv/fs/mfs/mfs.h	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/srv/fs/mfs/mfs.h	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -44,4 +44,5 @@
 #include <errno.h>
 #include <assert.h>
+#include <stdbool.h>
 #include "../../vfs/vfs.h"
 
@@ -105,4 +106,14 @@
 	unsigned isearch;
 	unsigned zsearch;
+
+	/* Indicates wether if the cached number of free zones
+	 * is to be considered valid or not.
+	 */
+	bool nfree_zones_valid;
+	/* Cached number of free zones, used to avoid to scan
+	 * the whole bitmap every time the mfs_free_block_count()
+	 * is invoked.
+	 */
+	unsigned nfree_zones;
 };
 
Index: uspace/srv/fs/mfs/mfs_balloc.c
===================================================================
--- uspace/srv/fs/mfs/mfs_balloc.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/srv/fs/mfs/mfs_balloc.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -88,4 +88,11 @@
 {
 	int r = mfs_alloc_bit(inst, zone, BMAP_ZONE);
+	if (r != EOK)
+		return r;
+
+	/* Update the cached number of free zones */
+	struct mfs_sb_info *sbi = inst->sbi;
+	if (sbi->nfree_zones_valid)
+		sbi->nfree_zones--;
 
 	*zone += inst->sbi->firstdatazone - 1;
@@ -103,7 +110,18 @@
 mfs_free_zone(struct mfs_instance *inst, uint32_t zone)
 {
+	int r;
+
 	zone -= inst->sbi->firstdatazone - 1;
 
-	return mfs_free_bit(inst, zone, BMAP_ZONE);
+	r = mfs_free_bit(inst, zone, BMAP_ZONE);
+	if (r != EOK)
+		return r;
+
+	/* Update the cached number of free zones */
+	struct mfs_sb_info *sbi = inst->sbi;
+	if (sbi->nfree_zones_valid)
+		sbi->nfree_zones++;
+
+	return r;
 }
 
Index: uspace/srv/fs/mfs/mfs_ops.c
===================================================================
--- uspace/srv/fs/mfs/mfs_ops.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/srv/fs/mfs/mfs_ops.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -216,4 +216,6 @@
 	sbi->isearch = 0;
 	sbi->zsearch = 0;
+	sbi->nfree_zones_valid = false;
+	sbi->nfree_zones = 0;
 
 	if (version == MFS_VERSION_V3) {
@@ -1181,11 +1183,23 @@
 		return rc;
 
-	if (NULL == inst)
-		return ENOENT;
-
-	mfs_count_free_zones(inst, &block_free);
-	*count = block_free;
-
-	return EOK;
+	struct mfs_sb_info *sbi = inst->sbi;
+
+	if (!sbi->nfree_zones_valid) {
+		/* The cached number of free zones is not valid,
+		 * we need to scan the bitmap to retrieve the
+		 * current value.
+		 */
+
+		rc = mfs_count_free_zones(inst, &block_free);
+		if (rc != EOK)
+			return rc;
+
+		sbi->nfree_zones = block_free;
+		sbi->nfree_zones_valid = true;
+	}
+
+	*count = sbi->nfree_zones;
+
+	return rc;
 }
 
Index: uspace/srv/hid/compositor/compositor.c
===================================================================
--- uspace/srv/hid/compositor/compositor.c	(revision 947e2ef52b4d89628cb7e4dc1fec8ca166910b10)
+++ uspace/srv/hid/compositor/compositor.c	(revision b9f7848b5b183be4b67751ef810198d86022cc26)
@@ -2176,5 +2176,5 @@
 	
 	/* Color of the viewport background. Must be opaque. */
-	bg_color = PIXEL(255, 75, 70, 75);
+	bg_color = PIXEL(255, 69, 51, 103);
 	
 	/* Register compositor server. */
