Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 5b082ba97e7288e1064574751f5fd623c8d8221f)
+++ uspace/lib/c/Makefile	(revision acc0efb56194119857ce5de37f04e87ced0e40ce)
@@ -140,5 +140,6 @@
 	generic/sort.c \
 	generic/stats.c \
-	generic/assert.c
+	generic/assert.c \
+	generic/pio_trace.c
 
 ifeq ($(CONFIG_RTLD),y)
Index: uspace/lib/c/generic/ddi.c
===================================================================
--- uspace/lib/c/generic/ddi.c	(revision 5b082ba97e7288e1064574751f5fd623c8d8221f)
+++ uspace/lib/c/generic/ddi.c	(revision acc0efb56194119857ce5de37f04e87ced0e40ce)
@@ -34,5 +34,7 @@
 
 #include <assert.h>
+#include <atomic.h>
 #include <unistd.h>
+#include <stdio.h>
 #include <errno.h>
 #include <sys/types.h>
@@ -46,4 +48,5 @@
 #include <libarch/config.h>
 #include "private/libc.h"
+
 
 /** Return unique device number.
@@ -171,4 +174,5 @@
 void pio_write_8(ioport8_t *reg, uint8_t val)
 {
+	pio_trace_log(reg, val, true);
 	arch_pio_write_8(reg, val);
 }
@@ -176,4 +180,5 @@
 void pio_write_16(ioport16_t *reg, uint16_t val)
 {
+	pio_trace_log(reg, val, true);
 	arch_pio_write_16(reg, val);
 }
@@ -181,4 +186,5 @@
 void pio_write_32(ioport32_t *reg, uint32_t val)
 {
+	pio_trace_log(reg, val, true);
 	arch_pio_write_32(reg, val);
 }
@@ -186,15 +192,21 @@
 uint8_t pio_read_8(ioport8_t *reg)
 {
-	return arch_pio_read_8(reg);
+	const uint8_t val = arch_pio_read_8(reg);
+	pio_trace_log(reg, val, false);
+	return val;
 }
 
 uint16_t pio_read_16(ioport16_t *reg)
 {
-	return arch_pio_read_16(reg);
+	const uint16_t val = arch_pio_read_16(reg);
+	pio_trace_log(reg, val, false);
+	return val;
 }
 
 uint32_t pio_read_32(ioport32_t *reg)
 {
-	return arch_pio_read_32(reg);
+	const uint32_t val = arch_pio_read_32(reg);
+	pio_trace_log(reg, val, false);
+	return val;
 }
 
Index: uspace/lib/c/generic/pio_trace.c
===================================================================
--- uspace/lib/c/generic/pio_trace.c	(revision acc0efb56194119857ce5de37f04e87ced0e40ce)
+++ uspace/lib/c/generic/pio_trace.c	(revision acc0efb56194119857ce5de37f04e87ced0e40ce)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <malloc.h>
+#include <adt/list.h>
+#include <fibril_synch.h>
+#include <ddi.h>
+#include <str.h>
+
+
+typedef struct {
+	link_t link;
+	volatile void *base;
+	size_t size;
+	void *data;
+	trace_fnc log;
+} region_t;
+
+static inline region_t * region_instance(link_t *l)
+{
+	return list_get_instance(l, region_t, link);
+}
+
+static inline region_t * region_create(volatile void* base, size_t size,
+    trace_fnc log, void* data)
+{
+	region_t *new_reg = malloc(sizeof(region_t));
+	if (new_reg) {
+		link_initialize(&new_reg->link);
+		new_reg->base = base;
+		new_reg->data = data;
+		new_reg->size = size;
+		new_reg->log = log;
+	}
+	return new_reg;
+}
+
+static inline void region_destroy(region_t *r)
+{
+	free(r);
+}
+
+typedef struct {
+	list_t list;
+	fibril_rwlock_t guard;
+} pio_regions_t;
+
+static pio_regions_t * get_regions(void)
+{
+	static pio_regions_t regions = {
+		.list = {
+			.head = { &regions.list.head, &regions.list.head },
+		},
+		.guard = FIBRIL_RWLOCK_INITIALIZER(regions.guard),
+	};
+	return &regions;
+}
+
+
+void pio_trace_log(volatile void *r, uint32_t val, bool write)
+{
+	pio_regions_t *regions = get_regions();
+	fibril_rwlock_read_lock(&regions->guard);
+	list_foreach(regions->list, it) {
+		assert(it);
+		region_t *reg = region_instance(it);
+		assert(reg);
+		if ((r >= reg->base) && (r < reg->base + reg->size)) {
+			if (reg->log)
+				reg->log(r, val, reg->base,
+				    reg->size, reg->data, write);
+			break;
+		}
+	}
+	fibril_rwlock_read_unlock(&regions->guard);
+}
+
+int pio_trace_enable(void *base, size_t size, trace_fnc log, void *data)
+{
+	pio_regions_t *regions = get_regions();
+	assert(regions);
+
+	region_t *region = region_create(base, size, log, data);
+	if (!region)
+		return ENOMEM;
+
+	fibril_rwlock_write_lock(&regions->guard);
+	list_append(&region->link, &regions->list);
+	fibril_rwlock_write_unlock(&regions->guard);
+	return EOK;
+}
+
+void pio_trace_disable(void *r)
+{
+	pio_regions_t *regions = get_regions();
+	assert(regions);
+
+	fibril_rwlock_write_lock(&regions->guard);
+	list_foreach_safe(regions->list, it, next) {
+		assert(it);
+		region_t *reg = region_instance(it);
+		assert(reg);
+		if (r >= reg->base && (r < reg->base + reg->size)) {
+				list_remove(&reg->link);
+				region_destroy(reg);
+		}
+	}
+	fibril_rwlock_write_unlock(&regions->guard);
+}
+
+/** @}
+ */
Index: uspace/lib/c/include/ddi.h
===================================================================
--- uspace/lib/c/include/ddi.h	(revision 5b082ba97e7288e1064574751f5fd623c8d8221f)
+++ uspace/lib/c/include/ddi.h	(revision acc0efb56194119857ce5de37f04e87ced0e40ce)
@@ -36,4 +36,5 @@
 #define LIBC_DDI_H_
 
+#include <bool.h>
 #include <sys/types.h>
 #include <sys/time.h>
@@ -52,4 +53,11 @@
 
 extern int pio_enable(void *, size_t, void **);
+
+typedef void (*trace_fnc)(volatile void *place, uint32_t val,
+    volatile void* base, size_t size, void *data, bool write);
+
+extern int pio_trace_enable(void *, size_t, trace_fnc, void *);
+extern void pio_trace_log(volatile void *, uint32_t val, bool write);
+extern void pio_trace_disable(void *);
 
 extern void pio_write_8(ioport8_t *, uint8_t);
