Index: uspace/drv/audio/hdaudio/codec.c
===================================================================
--- uspace/drv/audio/hdaudio/codec.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/audio/hdaudio/codec.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -37,4 +37,5 @@
 #include <ddf/log.h>
 #include <errno.h>
+#include <str_error.h>
 #include <stdlib.h>
 
@@ -514,5 +515,5 @@
 		goto error;
 
-	ddf_msg(LVL_NOTE, "hda_get_subnc -> %d", rc);
+	ddf_msg(LVL_NOTE, "hda_get_subnc -> %s", str_error_name(rc));
 	ddf_msg(LVL_NOTE, "sfg=%d nfg=%d", sfg, nfg);
 
@@ -524,5 +525,5 @@
 			goto error;
 
-		ddf_msg(LVL_NOTE, "hda_get_fgrp_type -> %d", rc);
+		ddf_msg(LVL_NOTE, "hda_get_fgrp_type -> %s", str_error_name(rc));
 		ddf_msg(LVL_NOTE, "unsol: %d, grptype: %d", unsol, grptype);
 
@@ -546,5 +547,5 @@
 			goto error;
 
-		ddf_msg(LVL_NOTE, "hda_get_subnc -> %d", rc);
+		ddf_msg(LVL_NOTE, "hda_get_subnc -> %s", str_error_name(rc));
 		ddf_msg(LVL_NOTE, "saw=%d baw=%d", saw, naw);
 
Index: uspace/drv/audio/hdaudio/hdaudio.c
===================================================================
--- uspace/drv/audio/hdaudio/hdaudio.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/audio/hdaudio/hdaudio.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -58,5 +58,5 @@
 static int hda_fun_offline(ddf_fun_t *fun);
 
-static void hdaudio_interrupt(ipc_callid_t, ipc_call_t *, ddf_dev_t *);
+static void hdaudio_interrupt(ipc_call_t *, ddf_dev_t *);
 
 static driver_ops_t driver_ops = {
@@ -259,14 +259,14 @@
 	rc = hw_res_enable_interrupt(hda->parent_sess, res.irqs.irqs[0]);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed enabling interrupt. (%d)", rc);
-		goto error;
-	}
-
-	int irq_cap = register_interrupt_handler(dev, res.irqs.irqs[0],
-	    hdaudio_interrupt, &irq_code);
-	if (irq_cap < 0) {
-		rc = irq_cap;
-		ddf_msg(LVL_ERROR, "Failed registering interrupt handler. (%d)",
-		    rc);
+		ddf_msg(LVL_ERROR, "Failed enabling interrupt.: %s", str_error(rc));
+		goto error;
+	}
+
+	int irq_cap;
+	rc = register_interrupt_handler(dev, res.irqs.irqs[0],
+	    hdaudio_interrupt, &irq_code, &irq_cap);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed registering interrupt handler: %s",
+		    str_error_name(rc));
 		goto error;
 	}
@@ -314,5 +314,5 @@
 	hw_res_list_parsed_clean(&res);
 
-	ddf_msg(LVL_NOTE, "Failing hda_dev_add() -> %d", rc);
+	ddf_msg(LVL_NOTE, "Failing hda_dev_add() -> %s", str_error_name(rc));
 	return rc;
 }
@@ -368,6 +368,5 @@
 }
 
-static void hdaudio_interrupt(ipc_callid_t iid, ipc_call_t *icall,
-    ddf_dev_t *dev)
+static void hdaudio_interrupt(ipc_call_t *icall, ddf_dev_t *dev)
 {
 	hda_t *hda = (hda_t *)ddf_dev_data_get(dev);
Index: uspace/drv/audio/hdaudio/pcm_iface.c
===================================================================
--- uspace/drv/audio/hdaudio/pcm_iface.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/audio/hdaudio/pcm_iface.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -120,5 +120,5 @@
 		return 16384;
 	default:
-		return ENOTSUP;
+		return -1;
 	}
 }
Index: uspace/drv/audio/hdaudio/stream.c
===================================================================
--- uspace/drv/audio/hdaudio/stream.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/audio/hdaudio/stream.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -39,4 +39,5 @@
 #include <ddi.h>
 #include <errno.h>
+#include <str_error.h>
 #include <macros.h>
 #include <stdlib.h>
@@ -122,5 +123,5 @@
 	    0, &buffer_phys, &buffer);
 	if (rc != EOK) {
-		ddf_msg(LVL_NOTE, "dmamem_map_anon -> %d", rc);
+		ddf_msg(LVL_NOTE, "dmamem_map_anon -> %s", str_error_name(rc));
 		goto error;
 	}
Index: uspace/drv/audio/sb16/dsp.c
===================================================================
--- uspace/drv/audio/sb16/dsp.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/audio/sb16/dsp.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -290,5 +290,5 @@
 		return 16535;
 	default:
-		return ENOTSUP;
+		return -1;
 	}
 }
@@ -303,10 +303,10 @@
 
 	// TODO: Assumes DMA 16
-	const int remain = hw_res_dma_channel_remain(sess, dsp->dma16_channel);
-	if (remain >= 0) {
+	size_t remain;
+	int rc = hw_res_dma_channel_remain(sess, dsp->dma16_channel, &remain);
+	if (rc == EOK) {
 		*pos = dsp->buffer.size - remain;
-		return EOK;
-	}
-	return remain;
+	}
+	return rc;
 }
 
Index: uspace/drv/audio/sb16/main.c
===================================================================
--- uspace/drv/audio/sb16/main.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/audio/sb16/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -76,5 +76,5 @@
 }
 
-static void irq_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev)
+static void irq_handler(ipc_call_t *call, ddf_dev_t *dev)
 {
 	sb16_t *sb16_dev = ddf_dev_data_get(dev);
@@ -123,8 +123,7 @@
 	};
 
-	irq_cap = register_interrupt_handler(device, irq, irq_handler,
-	    &irq_code);
-	if (irq_cap < 0) {
-		rc = irq_cap;
+	rc = register_interrupt_handler(device, irq, irq_handler,
+	    &irq_code, &irq_cap);
+	if (rc != EOK) {
 		ddf_log_error("Failed to register irq handler: %s.",
 		    str_error(rc));
Index: uspace/drv/block/ahci/ahci.c
===================================================================
--- uspace/drv/block/ahci/ahci.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/block/ahci/ahci.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -890,10 +890,9 @@
 /** AHCI interrupt handler.
  *
- * @param iid   The IPC call id.
  * @param icall The IPC call structure.
  * @param dev   DDF device structure.
  *
  */
-static void ahci_interrupt(ipc_callid_t iid, ipc_call_t *icall, ddf_dev_t *dev)
+static void ahci_interrupt(ipc_call_t *icall, ddf_dev_t *dev)
 {
 	ahci_dev_t *ahci = dev_ahci_dev(dev);
@@ -1185,12 +1184,13 @@
 	ct.ranges = ahci_ranges;
 	
-	int irq_cap = register_interrupt_handler(dev,
-	    hw_res_parsed.irqs.irqs[0], ahci_interrupt, &ct);
-	if (irq_cap < 0) {
+	int irq_cap;
+	int rc = register_interrupt_handler(dev,
+	    hw_res_parsed.irqs.irqs[0], ahci_interrupt, &ct, &irq_cap);
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed registering interrupt handler.");
 		goto error_register_interrupt_handler;
 	}
 	
-	int rc = hw_res_enable_interrupt(ahci->parent_sess,
+	rc = hw_res_enable_interrupt(ahci->parent_sess,
 	    hw_res_parsed.irqs.irqs[0]);
 	if (rc != EOK) {
Index: uspace/drv/block/ata_bd/ata_bd.c
===================================================================
--- uspace/drv/block/ata_bd/ata_bd.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/block/ata_bd/ata_bd.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -62,9 +62,7 @@
 #include <stddef.h>
 #include <str.h>
-#include <loc.h>
 #include <inttypes.h>
 #include <errno.h>
 #include <byteorder.h>
-#include <task.h>
 #include <macros.h>
 
@@ -147,5 +145,6 @@
 int ata_ctrl_init(ata_ctrl_t *ctrl, ata_base_t *res)
 {
-	int i, rc;
+	int i;
+	int rc;
 	int n_disks;
 
@@ -212,5 +211,6 @@
 int ata_ctrl_remove(ata_ctrl_t *ctrl)
 {
-	int i, rc;
+	int i;
+	int rc;
 
 	ddf_msg(LVL_DEBUG, ": ata_ctrl_remove()");
@@ -236,5 +236,6 @@
 int ata_ctrl_gone(ata_ctrl_t *ctrl)
 {
-	int i, rc;
+	int i;
+	int rc;
 
 	ddf_msg(LVL_DEBUG, "ata_ctrl_gone()");
Index: uspace/drv/block/ata_bd/main.c
===================================================================
--- uspace/drv/block/ata_bd/main.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/block/ata_bd/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -106,5 +106,5 @@
  *
  * @param  dev New device
- * @return     EOK on success or negative error code.
+ * @return     EOK on success or an error code.
  */
 static int ata_dev_add(ddf_dev_t *dev)
Index: uspace/drv/block/ddisk/ddisk.c
===================================================================
--- uspace/drv/block/ddisk/ddisk.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/block/ddisk/ddisk.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -64,5 +64,5 @@
 static void ddisk_bd_connection(ipc_callid_t, ipc_call_t *, void *);
 
-static void ddisk_irq_handler(ipc_callid_t, ipc_call_t *, ddf_dev_t *);
+static void ddisk_irq_handler(ipc_call_t *, ddf_dev_t *);
 
 static driver_ops_t driver_ops = {
@@ -176,5 +176,5 @@
 };
 
-void ddisk_irq_handler(ipc_callid_t iid, ipc_call_t *icall, ddf_dev_t *dev)
+void ddisk_irq_handler(ipc_call_t *icall, ddf_dev_t *dev)
 {
 	ddf_msg(LVL_DEBUG, "ddisk_irq_handler(), status=%" PRIx32,
@@ -408,5 +408,5 @@
  *
  * @param  dev New device
- * @return     EOK on success or negative error code.
+ * @return     EOK on success or an error code.
  */
 static int ddisk_dev_add(ddf_dev_t *dev)
@@ -503,8 +503,7 @@
 	ddisk_irq_commands[0].addr = (void *) &res_phys->status;
 	ddisk_irq_commands[3].addr = (void *) &res_phys->command;
-	ddisk->irq_cap = register_interrupt_handler(dev, ddisk->ddisk_res.irq,
-	    ddisk_irq_handler, &ddisk_irq_code);
-	if (ddisk->irq_cap < 0) {
-		rc = ddisk->irq_cap;
+	rc = register_interrupt_handler(dev, ddisk->ddisk_res.irq,
+	    ddisk_irq_handler, &ddisk_irq_code, &ddisk->irq_cap);
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed to register interrupt handler.");
 		goto error;
Index: uspace/drv/block/usbmast/bo_trans.c
===================================================================
--- uspace/drv/block/usbmast/bo_trans.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/block/usbmast/bo_trans.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -228,5 +228,5 @@
  *
  * @param mfun		Mass storage function
- * @return		Error code of maximum LUN (index, not count)
+ * @return		Maximum LUN (index, not count), or -1
  */
 int usb_massstor_get_max_lun(usbmast_dev_t *mdev)
@@ -240,10 +240,10 @@
 	    &data_recv_len);
 	if (rc != EOK) {
-		return rc;
+		return -1;
 	}
 	if (data_recv_len != 1) {
-		return EEMPTY;
-	}
-	return (int) max_lun;
+		return -1;
+	}
+	return max_lun;
 }
 
Index: uspace/drv/block/usbmast/main.c
===================================================================
--- uspace/drv/block/usbmast/main.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/block/usbmast/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -215,5 +215,5 @@
  * @param mdev		Mass storage device
  * @param lun		LUN
- * @return		EOK on success or negative error code.
+ * @return		EOK on success or an error code.
  */
 static int usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun)
Index: uspace/drv/bus/adb/cuda_adb/cuda_adb.c
===================================================================
--- uspace/drv/bus/adb/cuda_adb/cuda_adb.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/adb/cuda_adb/cuda_adb.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -46,5 +46,4 @@
 #include <stdbool.h>
 #include <stddef.h>
-#include <sysinfo.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -58,5 +57,5 @@
 static void cuda_dev_connection(ipc_callid_t, ipc_call_t *, void *);
 static int cuda_init(cuda_t *);
-static void cuda_irq_handler(ipc_callid_t, ipc_call_t *, void *);
+static void cuda_irq_handler(ipc_call_t *, void *);
 
 static void cuda_irq_listen(cuda_t *);
@@ -109,5 +108,6 @@
 };
 
-static int cuda_dev_create(cuda_t *cuda, const char *name, adb_dev_t **rdev)
+static int cuda_dev_create(cuda_t *cuda, const char *name, const char *id,
+    adb_dev_t **rdev)
 {
 	adb_dev_t *dev = NULL;
@@ -115,7 +115,14 @@
 	int rc;
 
-	fun = ddf_fun_create(cuda->dev, fun_exposed, name);
+	fun = ddf_fun_create(cuda->dev, fun_inner, name);
 	if (fun == NULL) {
 		ddf_msg(LVL_ERROR, "Failed creating function '%s'.", name);
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = ddf_fun_add_match_id(fun, id, 10);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding match ID.");
 		rc = ENOMEM;
 		goto error;
@@ -156,9 +163,9 @@
 	cuda->phys_base = res->base;
 
-	rc = cuda_dev_create(cuda, "kbd", &kbd);
+	rc = cuda_dev_create(cuda, "kbd", "adb/keyboard", &kbd);
 	if (rc != EOK)
 		goto error;
 
-	rc = cuda_dev_create(cuda, "mouse", &mouse);
+	rc = cuda_dev_create(cuda, "mouse", "adb/mouse", &mouse);
 	if (rc != EOK)
 		goto error;
@@ -245,5 +252,5 @@
 	cuda_irq_code.cmds[0].addr = (void *) &((cuda_regs_t *)
 	    cuda->phys_base)->ifr;
-	async_irq_subscribe(10, cuda_irq_handler, cuda, &cuda_irq_code);
+	async_irq_subscribe(10, cuda_irq_handler, cuda, &cuda_irq_code, NULL);
 
 	/* Enable SR interrupt. */
@@ -257,5 +264,5 @@
 }
 
-static void cuda_irq_handler(ipc_callid_t iid, ipc_call_t *call, void *arg)
+static void cuda_irq_handler(ipc_call_t *call, void *arg)
 {
 	uint8_t rbuf[CUDA_RCV_BUF_SIZE];
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/isa/isa.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -49,5 +49,5 @@
 #include <ctype.h>
 #include <macros.h>
-#include <malloc.h>
+#include <stdlib.h>
 #include <dirent.h>
 #include <ipc/irc.h>
@@ -277,9 +277,10 @@
 	int fd;
 	size_t len;
-	ssize_t r;
+	int rc;
+	size_t nread;
 	struct stat st;
 
-	fd = vfs_lookup_open(conf_path, WALK_REGULAR, MODE_READ);
-	if (fd < 0) {
+	rc = vfs_lookup_open(conf_path, WALK_REGULAR, MODE_READ, &fd);
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Unable to open %s", conf_path);
 		goto cleanup;
@@ -306,11 +307,11 @@
 	}
 
-	r = vfs_read(fd, (aoff64_t []) {0}, buf, len);
-	if (r < 0) {
+	rc = vfs_read(fd, (aoff64_t []) {0}, buf, len, &nread);
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Unable to read file '%s'.", conf_path);
 		goto cleanup;
 	}
 
-	buf[len] = 0;
+	buf[nread] = 0;
 
 	suc = true;
Index: uspace/drv/bus/pci/pciintel/pci.c
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -99,5 +99,5 @@
 }
 
-static int pciintel_fun_owns_interrupt(pci_fun_t *fun, int irq)
+static bool pciintel_fun_owns_interrupt(pci_fun_t *fun, int irq)
 {
 	size_t i;
@@ -383,12 +383,12 @@
 {
 	int rc;
+	int ret;
 	char match_id_str[ID_MAX_STR_LEN];
 
 	/* Vendor ID & Device ID, length(incl \0) 22 */
-	rc = snprintf(match_id_str, ID_MAX_STR_LEN, "pci/ven=%04"
+	ret = snprintf(match_id_str, ID_MAX_STR_LEN, "pci/ven=%04"
 	    PRIx16 "&dev=%04" PRIx16, fun->vendor_id, fun->device_id);
-	if (rc < 0) {
-		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
-		    str_error(rc));
+	if (ret < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str");
 	}
 
@@ -399,10 +399,9 @@
 
 	/* Class, subclass, prog IF, revision, length(incl \0) 47 */
-	rc = snprintf(match_id_str, ID_MAX_STR_LEN,
+	ret = snprintf(match_id_str, ID_MAX_STR_LEN,
 	    "pci/class=%02x&subclass=%02x&progif=%02x&revision=%02x",
 	    fun->class_code, fun->subclass_code, fun->prog_if, fun->revision);
-	if (rc < 0) {
-		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
-		    str_error(rc));
+	if (ret < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str");
 	}
 
@@ -413,10 +412,9 @@
 
 	/* Class, subclass, prog IF, length(incl \0) 35 */
-	rc = snprintf(match_id_str, ID_MAX_STR_LEN,
+	ret = snprintf(match_id_str, ID_MAX_STR_LEN,
 	    "pci/class=%02x&subclass=%02x&progif=%02x",
 	    fun->class_code, fun->subclass_code, fun->prog_if);
-	if (rc < 0) {
-		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
-		    str_error(rc));
+	if (ret < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str");
 	}
 
@@ -427,10 +425,9 @@
 
 	/* Class, subclass, length(incl \0) 25 */
-	rc = snprintf(match_id_str, ID_MAX_STR_LEN,
+	ret = snprintf(match_id_str, ID_MAX_STR_LEN,
 	    "pci/class=%02x&subclass=%02x",
 	    fun->class_code, fun->subclass_code);
-	if (rc < 0) {
-		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
-		    str_error(rc));
+	if (ret < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str");
 	}
 
@@ -441,9 +438,8 @@
 
 	/* Class, length(incl \0) 13 */
-	rc = snprintf(match_id_str, ID_MAX_STR_LEN, "pci/class=%02x",
+	ret = snprintf(match_id_str, ID_MAX_STR_LEN, "pci/class=%02x",
 	    fun->class_code);
-	if (rc < 0) {
-		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
-		    str_error(rc));
+	if (ret < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str");
 	}
 
@@ -514,5 +510,5 @@
 #define MEM_MASK (~0xf)
 	
-	io = (bool) (val & 1);
+	io = (val & 1) != 0;
 	if (io) {
 		addrw64 = false;
Index: uspace/drv/bus/usb/ehci/ehci_batch.c
===================================================================
--- uspace/drv/bus/usb/ehci/ehci_batch.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/ehci/ehci_batch.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -205,8 +205,8 @@
 			    -= td_remain_size(&ehci_batch->tds[i]);
 		} else {
-			usb_log_debug("Batch %p found error TD(%zu):%08x (%d).",
+			usb_log_debug("Batch %p found error TD(%zu):%08x: %s.",
 			    ehci_batch, i,
 			    ehci_batch->tds[i].status,
-			    ehci_batch->base.error);
+			    str_error_name(ehci_batch->base.error));
 			/* Clear possible ED HALT */
 			qh_clear_halt(ehci_batch->qh);
Index: uspace/drv/bus/usb/ehci/hc.c
===================================================================
--- uspace/drv/bus/usb/ehci/hc.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/ehci/hc.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -95,7 +95,9 @@
  * @param[in] hw_res Device's resources.
  *
+ * @param[out] irq
+ *
  * @return Error code.
  */
-int hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
+int hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
 {
 	assert(code);
@@ -138,5 +140,6 @@
 	    RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
 
-	return hw_res->irqs.irqs[0];
+	*irq = hw_res->irqs.irqs[0];
+	return EOK;
 }
 
Index: uspace/drv/bus/usb/ehci/hc.h
===================================================================
--- uspace/drv/bus/usb/ehci/hc.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/ehci/hc.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -103,5 +103,5 @@
 extern int hc_start(hc_device_t *);
 extern int hc_setup_roothub(hc_device_t *);
-extern int hc_gen_irq_code(irq_code_t *, hc_device_t *, const hw_res_list_parsed_t *);
+extern int hc_gen_irq_code(irq_code_t *, hc_device_t *, const hw_res_list_parsed_t *, int *);
 extern int hc_gone(hc_device_t *);
 
Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -102,5 +102,5 @@
  * @return Error code.
  */
-int hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
+int hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
 {
 	assert(code);
@@ -140,5 +140,6 @@
 	    RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
 
-	return hw_res->irqs.irqs[0];
+	*irq = hw_res->irqs.irqs[0];
+	return EOK;
 }
 
Index: uspace/drv/bus/usb/ohci/hc.h
===================================================================
--- uspace/drv/bus/usb/ohci/hc.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/ohci/hc.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -90,5 +90,5 @@
 
 extern int hc_add(hc_device_t *, const hw_res_list_parsed_t *);
-extern int hc_gen_irq_code(irq_code_t *, hc_device_t *, const hw_res_list_parsed_t *);
+extern int hc_gen_irq_code(irq_code_t *, hc_device_t *, const hw_res_list_parsed_t *, int *);
 extern int hc_gain_control(hc_device_t *);
 extern int hc_start(hc_device_t *);
Index: uspace/drv/bus/usb/ohci/hw_struct/completion_codes.h
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/completion_codes.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/ohci/hw_struct/completion_codes.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -54,5 +54,5 @@
 };
 
-inline static unsigned int cc_to_rc(unsigned int cc)
+inline static int cc_to_rc(unsigned int cc)
 {
 	switch (cc) {
Index: uspace/drv/bus/usb/ohci/hw_struct/hcca.h
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/hcca.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/ohci/hw_struct/hcca.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -37,5 +37,5 @@
 #define DRV_OHCI_HW_STRUCT_HCCA_H
 
-#include <malloc.h>
+#include <stdlib.h>
 #include <stdint.h>
 #include <macros.h>
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -106,8 +106,9 @@
  * @param[out] code IRQ code structure.
  * @param[in] hw_res Device's resources.
+ * @param[out] irq
  *
  * @return Error code.
  */
-int hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
+int hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
 {
 	assert(code);
@@ -145,5 +146,6 @@
 	    RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
 
-	return hw_res->irqs.irqs[0];
+	*irq = hw_res->irqs.irqs[0];
+	return EOK;
 }
 
Index: uspace/drv/bus/usb/uhci/hc.h
===================================================================
--- uspace/drv/bus/usb/uhci/hc.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/uhci/hc.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -158,5 +158,5 @@
 
 extern int hc_add(hc_device_t *, const hw_res_list_parsed_t *);
-extern int hc_gen_irq_code(irq_code_t *, hc_device_t *, const hw_res_list_parsed_t *);
+extern int hc_gen_irq_code(irq_code_t *, hc_device_t *, const hw_res_list_parsed_t *, int *);
 extern int hc_start(hc_device_t *);
 extern int hc_setup_roothub(hc_device_t *);
Index: uspace/drv/bus/usb/usbmid/usbmid.c
===================================================================
--- uspace/drv/bus/usb/usbmid/usbmid.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/usbmid/usbmid.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -120,8 +120,8 @@
 	 * class name something humanly understandable.
 	 */
-	rc = asprintf(&child_name, "%s%hhu",
+	int ret = asprintf(&child_name, "%s%hhu",
 	    usb_str_class(interface_descriptor->interface_class),
 	    interface_descriptor->interface_number);
-	if (rc < 0) {
+	if (ret < 0) {
 		return ENOMEM;
 	}
Index: uspace/drv/bus/usb/vhc/conndev.c
===================================================================
--- uspace/drv/bus/usb/vhc/conndev.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/vhc/conndev.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -75,6 +75,6 @@
 	}
 	
-	sysarg_t data_request_rc;
-	sysarg_t opening_request_rc;
+	int data_request_rc;
+	int opening_request_rc;
 	async_wait_for(data_request, &data_request_rc);
 	async_wait_for(opening_request, &opening_request_rc);
Index: uspace/drv/bus/usb/xhci/hc.c
===================================================================
--- uspace/drv/bus/usb/xhci/hc.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/xhci/hc.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -369,5 +369,5 @@
  * (except 0) are disabled.
  */
-int hc_irq_code_gen(irq_code_t *code, xhci_hc_t *hc, const hw_res_list_parsed_t *hw_res)
+int hc_irq_code_gen(irq_code_t *code, xhci_hc_t *hc, const hw_res_list_parsed_t *hw_res, int *irq)
 {
 	assert(code);
@@ -412,5 +412,6 @@
 	code->cmds[6].addr = intr0_iman;
 
-	return hw_res->irqs.irqs[0];
+        *irq = hw_res->irqs.irqs[0];
+        return EOK;
 }
 
Index: uspace/drv/bus/usb/xhci/hc.h
===================================================================
--- uspace/drv/bus/usb/xhci/hc.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/xhci/hc.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -117,5 +117,5 @@
 extern int hc_init_memory(xhci_hc_t *, ddf_dev_t *);
 extern int hc_claim(xhci_hc_t *, ddf_dev_t *);
-extern int hc_irq_code_gen(irq_code_t *, xhci_hc_t *, const hw_res_list_parsed_t *);
+extern int hc_irq_code_gen(irq_code_t *, xhci_hc_t *, const hw_res_list_parsed_t *, int *);
 extern int hc_start(xhci_hc_t *, bool);
 extern void hc_fini(xhci_hc_t *);
Index: uspace/drv/bus/usb/xhci/main.c
===================================================================
--- uspace/drv/bus/usb/xhci/main.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/bus/usb/xhci/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -68,8 +68,8 @@
 }
 
-static int hcd_irq_code_gen(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
+static int hcd_irq_code_gen(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
 {
 	xhci_hc_t *hc = hcd_to_hc(hcd);
-	return hc_irq_code_gen(code, hc, hw_res);
+	return hc_irq_code_gen(code, hc, hw_res, irq);
 }
 
Index: uspace/drv/char/i8042/buffer.h
===================================================================
--- uspace/drv/char/i8042/buffer.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ 	(revision )
@@ -1,153 +1,0 @@
-/*
- * Copyright (c) 2011 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 kbd
- * @{
- */
-
-/** @file
- * @brief Cyclic buffer structure.
- */
-
-#ifndef BUFFER_H_
-#define BUFFER_H_
-
-#include <assert.h>
-#include <fibril_synch.h>
-
-/** Cyclic buffer that blocks on full/empty.
- *
- * read_head == write_head means that the buffer is empty.
- * write_head + 1 == read_head means that the buffer is full.
- * Attempt to insert byte into the full buffer will block until it can succeed.
- * Attempt to read from empty buffer will block until it can succeed.
- *
- */
-typedef struct {
-	uint8_t *buffer;          /**< Storage space. */
-	uint8_t *buffer_end;      /**< End of storage place. */
-	fibril_mutex_t guard;     /**< Protects buffer structures. */
-	fibril_condvar_t change;  /**< Indicates change (empty/full). */
-	uint8_t *read_head;       /**< Place of the next readable element. */
-	uint8_t *write_head;      /**< Pointer to the next writable place. */
-} buffer_t;
-
-/** Initialize cyclic buffer using provided memory space.
- *
- * @param buffer Cyclic buffer structure to initialize.
- * @param data   Memory space to use.
- * @param size   Size of the memory place.
- *
- */
-static inline void buffer_init(buffer_t *buffer, uint8_t *data, size_t size)
-{
-	assert(buffer);
-	
-	fibril_mutex_initialize(&buffer->guard);
-	fibril_condvar_initialize(&buffer->change);
-	buffer->buffer = data;
-	buffer->buffer_end = data + size;
-	buffer->read_head = buffer->buffer;
-	buffer->write_head = buffer->buffer;
-	memset(buffer->buffer, 0, size);
-}
-
-/** Write byte to cyclic buffer.
- *
- * @param buffer Cyclic buffer to write to.
- * @param data   Data to write.
- *
- */
-static inline void buffer_write(buffer_t *buffer, uint8_t data)
-{
-	fibril_mutex_lock(&buffer->guard);
-	
-	/* Next position. */
-	uint8_t *new_head = buffer->write_head + 1;
-	if (new_head == buffer->buffer_end)
-		new_head = buffer->buffer;
-	
-	/* Buffer full. */
-	while (new_head == buffer->read_head)
-		fibril_condvar_wait(&buffer->change, &buffer->guard);
-	
-	/* Write data. */
-	*buffer->write_head = data;
-	
-	/* Buffer was empty. */
-	if (buffer->write_head == buffer->read_head)
-		fibril_condvar_broadcast(&buffer->change);
-	
-	/* Move head */
-	buffer->write_head = new_head;
-	fibril_mutex_unlock(&buffer->guard);
-}
-
-/** Read byte from cyclic buffer.
- *
- * @param buffer Cyclic buffer to read from.
- *
- * @return Byte read.
- *
- */
-static inline uint8_t buffer_read(buffer_t *buffer)
-{
-	fibril_mutex_lock(&buffer->guard);
-	
-	/* Buffer is empty. */
-	while (buffer->write_head == buffer->read_head)
-		fibril_condvar_wait(&buffer->change, &buffer->guard);
-	
-	/* Next position. */
-	uint8_t *new_head = buffer->read_head + 1;
-	if (new_head == buffer->buffer_end)
-		new_head = buffer->buffer;
-	
-	/* Read data. */
-	const uint8_t data = *buffer->read_head;
-	
-	/* Buffer was full. */
-	uint8_t *new_write_head = buffer->write_head + 1;
-	if (new_write_head == buffer->buffer_end)
-		new_write_head = buffer->buffer;
-	if (new_write_head == buffer->read_head)
-		fibril_condvar_broadcast(&buffer->change);
-	
-	/* Move head */
-	buffer->read_head = new_head;
-	
-	fibril_mutex_unlock(&buffer->guard);
-	return data;
-}
-
-#endif
-
-/**
- * @}
- */
Index: uspace/drv/char/i8042/i8042.c
===================================================================
--- uspace/drv/char/i8042/i8042.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/i8042/i8042.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -2,5 +2,5 @@
  * Copyright (c) 2001-2004 Jakub Jermar
  * Copyright (c) 2006 Josef Cejka
- * Copyright (c) 2014 Jiri Svoboda
+ * Copyright (c) 2017 Jiri Svoboda
  * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
@@ -39,4 +39,5 @@
  */
 
+#include <adt/circ_buf.h>
 #include <ddf/log.h>
 #include <ddf/interrupt.h>
@@ -67,6 +68,6 @@
 
 static void i8042_char_conn(ipc_callid_t, ipc_call_t *, void *);
-static int i8042_read(chardev_srv_t *, void *, size_t);
-static int i8042_write(chardev_srv_t *, const void *, size_t);
+static int i8042_read(chardev_srv_t *, void *, size_t, size_t *);
+static int i8042_write(chardev_srv_t *, const void *, size_t, size_t *);
 
 static chardev_ops_t i8042_chardev_ops = {
@@ -121,21 +122,27 @@
  * Write new data to the corresponding buffer.
  *
- * @param iid  Call id.
  * @param call pointerr to call data.
  * @param dev  Device that caued the interrupt.
  *
  */
-static void i8042_irq_handler(ipc_callid_t iid, ipc_call_t *call,
-    ddf_dev_t *dev)
+static void i8042_irq_handler(ipc_call_t *call, ddf_dev_t *dev)
 {
 	i8042_t *controller = ddf_dev_data_get(dev);
+	int rc;
 	
 	const uint8_t status = IPC_GET_ARG1(*call);
 	const uint8_t data = IPC_GET_ARG2(*call);
 	
-	buffer_t *buffer = (status & i8042_AUX_DATA) ?
-	    &controller->aux_buffer : &controller->kbd_buffer;
-	
-	buffer_write(buffer, data);
+	i8042_port_t *port = (status & i8042_AUX_DATA) ?
+	    controller->aux : controller->kbd;
+	
+	fibril_mutex_lock(&port->buf_lock);
+	
+	rc = circ_buf_push(&port->cbuf, &data);
+	if (rc != EOK)
+		ddf_msg(LVL_ERROR, "Buffer overrun");
+
+	fibril_mutex_unlock(&port->buf_lock);
+	fibril_condvar_broadcast(&port->buf_cv);
 }
 
@@ -159,12 +166,11 @@
 	const size_t cmd_count = sizeof(i8042_cmds) / sizeof(irq_cmd_t);
 	irq_cmd_t cmds[cmd_count];
+	ddf_fun_t *kbd_fun;
+	ddf_fun_t *aux_fun;
 	i8042_regs_t *ar;
-
+	
 	int rc;
 	bool kbd_bound = false;
 	bool aux_bound = false;
-
-	dev->kbd_fun = NULL;
-	dev->aux_fun = NULL;
 	
 	if (regs->size < sizeof(i8042_regs_t)) {
@@ -178,11 +184,11 @@
 	}
 	
-	dev->kbd_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2a");
-	if (dev->kbd_fun == NULL) {
+	kbd_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2a");
+	if (kbd_fun == NULL) {
 		rc = ENOMEM;
 		goto error;
 	};
 	
-	dev->kbd = ddf_fun_data_alloc(dev->kbd_fun, sizeof(i8042_port_t));
+	dev->kbd = ddf_fun_data_alloc(kbd_fun, sizeof(i8042_port_t));
 	if (dev->kbd == NULL) {
 		rc = ENOMEM;
@@ -190,20 +196,23 @@
 	}
 	
+	dev->kbd->fun = kbd_fun;
 	dev->kbd->ctl = dev;
 	chardev_srvs_init(&dev->kbd->cds);
 	dev->kbd->cds.ops = &i8042_chardev_ops;
 	dev->kbd->cds.sarg = dev->kbd;
-	
-	rc = ddf_fun_add_match_id(dev->kbd_fun, "char/xtkbd", 90);
+	fibril_mutex_initialize(&dev->kbd->buf_lock);
+	fibril_condvar_initialize(&dev->kbd->buf_cv);
+	
+	rc = ddf_fun_add_match_id(dev->kbd->fun, "char/xtkbd", 90);
 	if (rc != EOK)
 		goto error;
 	
-	dev->aux_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2b");
-	if (dev->aux_fun == NULL) {
+	aux_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2b");
+	if (aux_fun == NULL) {
 		rc = ENOMEM;
 		goto error;
 	}
 	
-	dev->aux = ddf_fun_data_alloc(dev->aux_fun, sizeof(i8042_port_t));
+	dev->aux = ddf_fun_data_alloc(aux_fun, sizeof(i8042_port_t));
 	if (dev->aux == NULL) {
 		rc = ENOMEM;
@@ -211,32 +220,35 @@
 	}
 	
+	dev->aux->fun = aux_fun;
 	dev->aux->ctl = dev;
 	chardev_srvs_init(&dev->aux->cds);
 	dev->aux->cds.ops = &i8042_chardev_ops;
 	dev->aux->cds.sarg = dev->aux;
-	
-	rc = ddf_fun_add_match_id(dev->aux_fun, "char/ps2mouse", 90);
+	fibril_mutex_initialize(&dev->aux->buf_lock);
+	fibril_condvar_initialize(&dev->aux->buf_cv);
+	
+	rc = ddf_fun_add_match_id(dev->aux->fun, "char/ps2mouse", 90);
 	if (rc != EOK)
 		goto error;
 	
-	ddf_fun_set_conn_handler(dev->kbd_fun, i8042_char_conn);
-	ddf_fun_set_conn_handler(dev->aux_fun, i8042_char_conn);
-	
-	buffer_init(&dev->kbd_buffer, dev->kbd_data, BUFFER_SIZE);
-	buffer_init(&dev->aux_buffer, dev->aux_data, BUFFER_SIZE);
+	ddf_fun_set_conn_handler(dev->kbd->fun, i8042_char_conn);
+	ddf_fun_set_conn_handler(dev->aux->fun, i8042_char_conn);
+	
+	circ_buf_init(&dev->kbd->cbuf, dev->kbd->buf_data, BUFFER_SIZE, 1);
+	circ_buf_init(&dev->aux->cbuf, dev->aux->buf_data, BUFFER_SIZE, 1);
 	fibril_mutex_initialize(&dev->write_guard);
 	
-	rc = ddf_fun_bind(dev->kbd_fun);
+	rc = ddf_fun_bind(dev->kbd->fun);
 	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed to bind keyboard function: %s.",
-		    ddf_fun_get_name(dev->kbd_fun));
+		    ddf_fun_get_name(dev->kbd->fun));
 		goto error;
 	}
 	kbd_bound = true;
 	
-	rc = ddf_fun_bind(dev->aux_fun);
+	rc = ddf_fun_bind(dev->aux->fun);
 	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed to bind aux function: %s.",
-		    ddf_fun_get_name(dev->aux_fun));
+		    ddf_fun_get_name(dev->aux->fun));
 		goto error;
 	}
@@ -269,8 +281,8 @@
 	};
 	
-	const int irq_kbd_cap = register_interrupt_handler(ddf_dev, irq_kbd,
-	    i8042_irq_handler, &irq_code);
-	if (irq_kbd_cap < 0) {
-		rc = irq_kbd_cap;
+	int irq_kbd_cap;
+	rc = register_interrupt_handler(ddf_dev, irq_kbd,
+	    i8042_irq_handler, &irq_code, &irq_kbd_cap);
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed set handler for kbd: %s.",
 		    ddf_dev_get_name(ddf_dev));
@@ -278,8 +290,8 @@
 	}
 	
-	const int irq_mouse_cap = register_interrupt_handler(ddf_dev, irq_mouse,
-	    i8042_irq_handler, &irq_code);
-	if (irq_mouse_cap < 0) {
-		rc = irq_mouse_cap;
+	int irq_mouse_cap;
+	rc = register_interrupt_handler(ddf_dev, irq_mouse,
+	    i8042_irq_handler, &irq_code, &irq_mouse_cap);
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed set handler for mouse: %s.",
 		    ddf_dev_get_name(ddf_dev));
@@ -317,11 +329,11 @@
 error:
 	if (kbd_bound)
-		ddf_fun_unbind(dev->kbd_fun);
+		ddf_fun_unbind(dev->kbd->fun);
 	if (aux_bound)
-		ddf_fun_unbind(dev->aux_fun);
-	if (dev->kbd_fun != NULL)
-		ddf_fun_destroy(dev->kbd_fun);
-	if (dev->aux_fun != NULL)
-		ddf_fun_destroy(dev->aux_fun);
+		ddf_fun_unbind(dev->aux->fun);
+	if (dev->kbd->fun != NULL)
+		ddf_fun_destroy(dev->kbd->fun);
+	if (dev->aux->fun != NULL)
+		ddf_fun_destroy(dev->aux->fun);
 
 	return rc;
@@ -333,9 +345,11 @@
  * @param buffer Data source
  * @param size   Data size
- *
- * @return Bytes written.
- *
- */
-static int i8042_write(chardev_srv_t *srv, const void *data, size_t size)
+ * @param nwr    Place to store number of bytes successfully written
+ *
+ * @return EOK on success or non-zero error code
+ *
+ */
+static int i8042_write(chardev_srv_t *srv, const void *data, size_t size,
+    size_t *nwr)
 {
 	i8042_port_t *port = (i8042_port_t *)srv->srvs->sarg;
@@ -357,5 +371,6 @@
 	
 	fibril_mutex_unlock(&i8042->write_guard);
-	return size;
+	*nwr = size;
+	return EOK;
 }
 
@@ -365,21 +380,34 @@
  * @param buffer Data place
  * @param size   Data place size
- *
- * @return Bytes read.
- *
- */
-static int i8042_read(chardev_srv_t *srv, void *dest, size_t size)
+ * @param nread  Place to store number of bytes successfully read
+ *
+ * @return EOK on success or non-zero error code
+ *
+ */
+static int i8042_read(chardev_srv_t *srv, void *dest, size_t size,
+    size_t *nread)
 {
 	i8042_port_t *port = (i8042_port_t *)srv->srvs->sarg;
-	i8042_t *i8042 = port->ctl;
+	size_t p;
 	uint8_t *destp = (uint8_t *)dest;
-	
-	buffer_t *buffer = (port == i8042->aux) ?
-	    &i8042->aux_buffer : &i8042->kbd_buffer;
-	
-	for (size_t i = 0; i < size; ++i)
-		*destp++ = buffer_read(buffer);
-	
-	return size;
+	int rc;
+	
+	fibril_mutex_lock(&port->buf_lock);
+	
+	while (circ_buf_nused(&port->cbuf) == 0)
+		fibril_condvar_wait(&port->buf_cv, &port->buf_lock);
+
+	p = 0;
+	while (p < size) {
+		rc = circ_buf_pop(&port->cbuf, &destp[p]);
+		if (rc != EOK)
+			break;
+		++p;
+	}
+
+	fibril_mutex_unlock(&port->buf_lock);
+
+	*nread = p;
+	return EOK;
 }
 
Index: uspace/drv/char/i8042/i8042.h
===================================================================
--- uspace/drv/char/i8042/i8042.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/i8042/i8042.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -2,4 +2,5 @@
  * Copyright (c) 2006 Josef Cejka
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -40,9 +41,9 @@
 #define i8042_H_
 
+#include <adt/circ_buf.h>
 #include <io/chardev_srv.h>
 #include <ddi.h>
 #include <fibril_synch.h>
 #include <ddf/driver.h>
-#include "buffer.h"
 
 #define NAME  "i8042"
@@ -59,22 +60,31 @@
 /** i8042 Port. */
 typedef struct {
-	struct i8042 *ctl;		/**< Controller */
-	chardev_srvs_t cds;		/**< Character device server data */
+	/** Controller */
+	struct i8042 *ctl;
+	/** Device function */
+	ddf_fun_t *fun;
+	/** Character device server data */
+	chardev_srvs_t cds;
+	/** Circular buffer */
+	circ_buf_t cbuf;
+	/** Buffer data space */
+	uint8_t buf_data[BUFFER_SIZE];
+	/** Protect buffer */
+	fibril_mutex_t buf_lock;
+	/** Signal new data in buffer */
+	fibril_condvar_t buf_cv;
 } i8042_port_t;
 
 /** i8042 Controller. */
 typedef struct i8042 {
-	i8042_regs_t *regs;             /**< I/O registers. */
-	ddf_fun_t *kbd_fun;             /**< Pirmary port device function. */
-	ddf_fun_t *aux_fun;             /**< Auxiliary port device function. */
-	buffer_t kbd_buffer;            /**< Primary port buffer. */
-	buffer_t aux_buffer;            /**< Aux. port buffer. */
-	uint8_t aux_data[BUFFER_SIZE];  /**< Primary port buffer space. */
-	uint8_t kbd_data[BUFFER_SIZE];  /**< Aux. port buffer space. */
+	/**< I/O registers. */
+	i8042_regs_t *regs;
+	/** Keyboard port */
 	i8042_port_t *kbd;
+	/** AUX port */
 	i8042_port_t *aux;
-	fibril_mutex_t write_guard;     /**< Prevents simultanous port writes.*/
+	/** Prevents simultanous port writes.*/
+	fibril_mutex_t write_guard;
 } i8042_t;
-
 
 extern int i8042_init(i8042_t *, addr_range_t *, int, int, ddf_dev_t *);
Index: uspace/drv/char/msim-con/main.c
===================================================================
--- uspace/drv/char/msim-con/main.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/msim-con/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -35,4 +35,5 @@
 #include <ddf/driver.h>
 #include <ddf/log.h>
+#include <device/hw_res_parsed.h>
 #include <errno.h>
 #include <stdio.h>
@@ -61,9 +62,47 @@
 };
 
+static int msim_con_get_res(ddf_dev_t *dev, msim_con_res_t *res)
+{
+	async_sess_t *parent_sess;
+	hw_res_list_parsed_t hw_res;
+	int rc;
+
+	parent_sess = ddf_dev_parent_sess_get(dev);
+	if (parent_sess == NULL)
+		return ENOMEM;
+
+	hw_res_list_parsed_init(&hw_res);
+	rc = hw_res_get_list_parsed(parent_sess, &hw_res, 0);
+	if (rc != EOK)
+		return rc;
+
+	if (hw_res.mem_ranges.count != 1) {
+		rc = EINVAL;
+		goto error;
+	}
+
+	res->base = RNGABS(hw_res.mem_ranges.ranges[0]);
+
+	if (hw_res.irqs.count != 1) {
+		rc = EINVAL;
+		goto error;
+	}
+
+	res->irq = hw_res.irqs.irqs[0];
+
+	return EOK;
+error:
+	hw_res_list_parsed_clean(&hw_res);
+	return rc;
+}
+
 static int msim_con_dev_add(ddf_dev_t *dev)
 {
 	msim_con_t *msim_con;
+	msim_con_res_t res;
+	int rc;
 
         ddf_msg(LVL_DEBUG, "msim_con_dev_add(%p)", dev);
+
 	msim_con = ddf_dev_data_alloc(dev, sizeof(msim_con_t));
 	if (msim_con == NULL) {
@@ -74,5 +113,11 @@
 	msim_con->dev = dev;
 
-	return msim_con_add(msim_con);
+	rc = msim_con_get_res(dev, &res);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed getting hardware resource list.\n");
+		return EIO;
+	}
+
+	return msim_con_add(msim_con, &res);
 }
 
Index: uspace/drv/char/msim-con/msim-con.c
===================================================================
--- uspace/drv/char/msim-con/msim-con.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/msim-con/msim-con.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -37,6 +37,5 @@
 #include <ddi.h>
 #include <errno.h>
-#include <ipc/char.h>
-#include <sysinfo.h>
+#include <io/chardev_srv.h>
 
 #include "msim-con.h"
@@ -44,12 +43,13 @@
 static void msim_con_connection(ipc_callid_t, ipc_call_t *, void *);
 
-static irq_pio_range_t msim_ranges[] = {
-	{
-		.base = 0,
-		.size = 1
-	}
+static int msim_con_read(chardev_srv_t *, void *, size_t, size_t *);
+static int msim_con_write(chardev_srv_t *, const void *, size_t, size_t *);
+
+static chardev_ops_t msim_con_chardev_ops = {
+	.read = msim_con_read,
+	.write = msim_con_write
 };
 
-static irq_cmd_t msim_cmds[] = {
+static irq_cmd_t msim_cmds_proto[] = {
 	{
 		.cmd = CMD_PIO_READ_8,
@@ -62,31 +62,40 @@
 };
 
-static irq_code_t msim_kbd = {
-	sizeof(msim_ranges) / sizeof(irq_pio_range_t),
-	msim_ranges,
-	sizeof(msim_cmds) / sizeof(irq_cmd_t),
-	msim_cmds
-};
-
-static void msim_irq_handler(ipc_callid_t iid, ipc_call_t *call, void *arg)
+static void msim_irq_handler(ipc_call_t *call, void *arg)
 {
 	msim_con_t *con = (msim_con_t *) arg;
 	uint8_t c;
+	int rc;
+
+	fibril_mutex_lock(&con->buf_lock);
 
 	c = IPC_GET_ARG2(*call);
-
-	if (con->client_sess != NULL) {
-		async_exch_t *exch = async_exchange_begin(con->client_sess);
-		async_msg_1(exch, CHAR_NOTIF_BYTE, c);
-		async_exchange_end(exch);
-	}
+	rc = circ_buf_push(&con->cbuf, &c);
+	if (rc != EOK)
+		ddf_msg(LVL_ERROR, "Buffer overrun");
+
+	fibril_mutex_unlock(&con->buf_lock);
+	fibril_condvar_broadcast(&con->buf_cv);
 }
 
 /** Add msim console device. */
-int msim_con_add(msim_con_t *con)
+int msim_con_add(msim_con_t *con, msim_con_res_t *res)
 {
 	ddf_fun_t *fun = NULL;
 	bool subscribed = false;
+	irq_cmd_t *msim_cmds = NULL;
 	int rc;
+
+	circ_buf_init(&con->cbuf, con->buf, msim_con_buf_size, 1);
+	fibril_mutex_initialize(&con->buf_lock);
+	fibril_condvar_initialize(&con->buf_cv);
+
+	msim_cmds = malloc(sizeof(msim_cmds_proto));
+	if (msim_cmds == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	con->res = *res;
 
 	fun = ddf_fun_create(con->dev, fun_exposed, "a");
@@ -97,22 +106,29 @@
 	}
 
+	rc = pio_enable((void *)res->base, 1, (void **) &con->out_reg);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Error enabling I/O");
+		goto error;
+	}
+
 	ddf_fun_set_conn_handler(fun, msim_con_connection);
 
-	sysarg_t paddr;
-	if (sysinfo_get_value("kbd.address.physical", &paddr) != EOK) {
-		rc = ENOENT;
-		goto error;
-	}
-
-	sysarg_t inr;
-	if (sysinfo_get_value("kbd.inr", &inr) != EOK) {
-		rc = ENOENT;
-		goto error;
-	}
-
-	msim_ranges[0].base = paddr;
-	msim_cmds[0].addr = (void *) paddr;
-	async_irq_subscribe(inr, msim_irq_handler, con, &msim_kbd);
+	con->irq_range[0].base = res->base;
+	con->irq_range[0].size = 1;
+
+	memcpy(msim_cmds, msim_cmds_proto, sizeof(msim_cmds_proto));
+	msim_cmds[0].addr = (void *) res->base;
+
+	con->irq_code.rangecount = 1;
+	con->irq_code.ranges = con->irq_range;
+	con->irq_code.cmdcount = sizeof(msim_cmds_proto) / sizeof(irq_cmd_t);
+	con->irq_code.cmds = msim_cmds;
+
+	async_irq_subscribe(res->irq, msim_irq_handler, con, &con->irq_code, NULL);
 	subscribed = true;
+
+	chardev_srvs_init(&con->cds);
+	con->cds.ops = &msim_con_chardev_ops;
+	con->cds.sarg = con;
 
 	rc = ddf_fun_bind(fun);
@@ -122,10 +138,13 @@
 	}
 
+	ddf_fun_add_to_category(fun, "console");
+
 	return EOK;
 error:
 	if (subscribed)
-		async_irq_unsubscribe(inr);
+		async_irq_unsubscribe(res->irq);
 	if (fun != NULL)
 		ddf_fun_destroy(fun);
+	free(msim_cmds);
 
 	return rc;
@@ -146,4 +165,48 @@
 static void msim_con_putchar(msim_con_t *con, uint8_t ch)
 {
+	pio_write_8(con->out_reg, ch);
+}
+
+/** Read from msim console device */
+static int msim_con_read(chardev_srv_t *srv, void *buf, size_t size,
+    size_t *nread)
+{
+	msim_con_t *con = (msim_con_t *) srv->srvs->sarg;
+	size_t p;
+	uint8_t *bp = (uint8_t *) buf;
+	int rc;
+
+	fibril_mutex_lock(&con->buf_lock);
+
+	while (circ_buf_nused(&con->cbuf) == 0)
+		fibril_condvar_wait(&con->buf_cv, &con->buf_lock);
+
+	p = 0;
+	while (p < size) {
+		rc = circ_buf_pop(&con->cbuf, &bp[p]);
+		if (rc != EOK)
+			break;
+		++p;
+	}
+
+	fibril_mutex_unlock(&con->buf_lock);
+
+	*nread = p;
+	return EOK;
+}
+
+/** Write to msim console device */
+static int msim_con_write(chardev_srv_t *srv, const void *data, size_t size,
+    size_t *nwr)
+{
+	msim_con_t *con = (msim_con_t *) srv->srvs->sarg;
+	size_t i;
+	uint8_t *dp = (uint8_t *) data;
+
+	for (i = 0; i < size; i++)
+		msim_con_putchar(con, dp[i]); 
+
+	*nwr = size;
+	return EOK;
 }
 
@@ -152,43 +215,8 @@
     void *arg)
 {
-	msim_con_t *con;
-
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-
-	con = (msim_con_t *)ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *)arg));
-
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		sysarg_t method = IPC_GET_IMETHOD(call);
-
-		if (!method) {
-			/* The other side has hung up. */
-			async_answer_0(callid, EOK);
-			return;
-		}
-
-		async_sess_t *sess =
-		    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
-		if (sess != NULL) {
-			if (con->client_sess == NULL) {
-				con->client_sess = sess;
-				async_answer_0(callid, EOK);
-			} else
-				async_answer_0(callid, ELIMIT);
-		} else {
-			switch (method) {
-			case CHAR_WRITE_BYTE:
-				ddf_msg(LVL_DEBUG, "Write %" PRIun " to device\n",
-				    IPC_GET_ARG1(call));
-				msim_con_putchar(con, (uint8_t) IPC_GET_ARG1(call));
-				async_answer_0(callid, EOK);
-				break;
-			default:
-				async_answer_0(callid, EINVAL);
-			}
-		}
-	}
+	msim_con_t *con = (msim_con_t *) ddf_dev_data_get(
+	    ddf_fun_get_dev((ddf_fun_t *) arg));
+
+	chardev_conn(iid, icall, &con->cds);
 }
 
Index: uspace/drv/char/msim-con/msim-con.h
===================================================================
--- uspace/drv/char/msim-con/msim-con.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/msim-con/msim-con.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -36,8 +36,22 @@
 #define MSIM_CON_H
 
+#include <adt/circ_buf.h>
 #include <async.h>
 #include <ddf/driver.h>
+#include <ddi.h>
+#include <fibril_synch.h>
+#include <io/chardev_srv.h>
 #include <loc.h>
 #include <stdint.h>
+
+enum {
+	msim_con_buf_size = 64
+};
+
+/** MSIM console resources */
+typedef struct {
+	uintptr_t base;
+	int irq;
+} msim_con_res_t;
 
 /** MSIM console */
@@ -45,11 +59,16 @@
 	async_sess_t *client_sess;
 	ddf_dev_t *dev;
+	chardev_srvs_t cds;
+	msim_con_res_t res;
+	irq_pio_range_t irq_range[1];
+	irq_code_t irq_code;
+	circ_buf_t cbuf;
+	uint8_t buf[msim_con_buf_size];
+	fibril_mutex_t buf_lock;
+	fibril_condvar_t buf_cv;
+	ioport8_t *out_reg;
 } msim_con_t;
 
-extern int msim_con_init(msim_con_t *);
-extern void msim_con_write(uint8_t data);
-
-
-extern int msim_con_add(msim_con_t *);
+extern int msim_con_add(msim_con_t *, msim_con_res_t *);
 extern int msim_con_remove(msim_con_t *);
 extern int msim_con_gone(msim_con_t *);
Index: uspace/drv/char/ns8250/ns8250.c
===================================================================
--- uspace/drv/char/ns8250/ns8250.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/ns8250/ns8250.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -1,5 +1,5 @@
 /*
  * Copyright (c) 2010 Lenka Trochtova
- * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -40,4 +40,5 @@
 #include <stdio.h>
 #include <errno.h>
+#include <str_error.h>
 #include <stdbool.h>
 #include <fibril_synch.h>
@@ -46,5 +47,5 @@
 #include <ctype.h>
 #include <macros.h>
-#include <malloc.h>
+#include <stdlib.h>
 #include <dirent.h>
 #include <ddi.h>
@@ -53,5 +54,5 @@
 #include <ddf/interrupt.h>
 #include <ddf/log.h>
-#include <ops/char_dev.h>
+#include <io/chardev_srv.h>
 
 #include <device/hw_res.h>
@@ -153,4 +154,6 @@
 	/** DDF function node */
 	ddf_fun_t *fun;
+	/** Character device service */
+	chardev_srvs_t cds;
 	/** Parent session */
 	async_sess_t *parent_sess;
@@ -189,4 +192,11 @@
 }
 
+/** Obtain soft-state structure from chardev srv */
+static ns8250_t *srv_ns8250(chardev_srv_t *srv)
+{
+	return (ns8250_t *)srv->srvs->sarg;
+}
+
+
 /** Find out if there is some incoming data available on the serial port.
  *
@@ -234,28 +244,33 @@
 /** Read data from the serial port device.
  *
- * @param fun		The serial port function
+ * @param srv		Server-side connection data
  * @param buf		The output buffer for read data.
  * @param count		The number of bytes to be read.
- *
- * @return		The number of bytes actually read on success, negative
- *			error number otherwise.
- */
-static int ns8250_read(ddf_fun_t *fun, char *buf, size_t count)
-{
-	ns8250_t *ns = fun_ns8250(fun);
-	int ret = 0;
-	
-	if (count == 0) return 0;
+ * @param nread		Place to store number of bytes actually read
+ *
+ * @return		EOK on success or non-zero error code
+ */
+static int ns8250_read(chardev_srv_t *srv, void *buf, size_t count, size_t *nread)
+{
+	ns8250_t *ns = srv_ns8250(srv);
+	char *bp = (char *) buf;
+	size_t pos = 0;
+	
+	if (count == 0) {
+		*nread = 0;
+		return EOK;
+	}
 	
 	fibril_mutex_lock(&ns->mutex);
 	while (buf_is_empty(&ns->input_buffer))
 		fibril_condvar_wait(&ns->input_buffer_available, &ns->mutex);
-	while (!buf_is_empty(&ns->input_buffer) && (size_t)ret < count) {
-		buf[ret] = (char)buf_pop_front(&ns->input_buffer);
-		ret++;
+	while (!buf_is_empty(&ns->input_buffer) && pos < count) {
+		bp[pos] = (char)buf_pop_front(&ns->input_buffer);
+		pos++;
 	}
 	fibril_mutex_unlock(&ns->mutex);
 	
-	return ret;
+	*nread = pos;
+	return EOK;
 }
 
@@ -274,27 +289,38 @@
 /** Write data to the serial port.
  *
- * @param fun		The serial port function
+ * @param srv		Server-side connection data
  * @param buf		The data to be written
  * @param count		The number of bytes to be written
- * @return		Zero on success
- */
-static int ns8250_write(ddf_fun_t *fun, char *buf, size_t count)
-{
-	ns8250_t *ns = fun_ns8250(fun);
+ * @param nwritten	Place to store number of bytes successfully written
+ * @return		EOK on success or non-zero error code
+ */
+static int ns8250_write(chardev_srv_t *srv, const void *buf, size_t count,
+    size_t *nwritten)
+{
+	ns8250_t *ns = srv_ns8250(srv);
 	size_t idx;
+	uint8_t *bp = (uint8_t *) buf;
 	
 	for (idx = 0; idx < count; idx++)
-		ns8250_putchar(ns, (uint8_t) buf[idx]);
-	
-	return count;
-}
-
-static ddf_dev_ops_t ns8250_dev_ops;
+		ns8250_putchar(ns, bp[idx]);
+	
+	*nwritten = count;
+	return EOK;
+}
+
+static int ns8250_open(chardev_srvs_t *, chardev_srv_t *);
+static int ns8250_close(chardev_srv_t *);
+static void ns8250_default_handler(chardev_srv_t *, ipc_callid_t, ipc_call_t *);
 
 /** The character interface's callbacks. */
-static char_dev_ops_t ns8250_char_dev_ops = {
-	.read = &ns8250_read,
-	.write = &ns8250_write
+static chardev_ops_t ns8250_chardev_ops = {
+	.open = ns8250_open,
+	.close = ns8250_close,
+	.read = ns8250_read,
+	.write = ns8250_write,
+	.def_handler = ns8250_default_handler
 };
+
+static void ns8250_char_conn(ipc_callid_t, ipc_call_t *, void *);
 
 static int ns8250_dev_add(ddf_dev_t *dev);
@@ -379,5 +405,5 @@
  *
  * @param ns		Serial port device
- * @return		Zero on success, negative error number otherwise
+ * @return		Zero on success, error number otherwise
  */
 static int ns8250_dev_initialize(ns8250_t *ns)
@@ -473,5 +499,5 @@
  *
  * @param ns		Serial port device
- * @return		Zero on success, negative error number otherwise
+ * @return		Zero on success, error number otherwise
  */
 static int ns8250_interrupt_enable(ns8250_t *ns)
@@ -518,5 +544,5 @@
  * @param port		The base address of the serial port device's ports.
  * @param baud_rate	The baud rate to be used by the device.
- * @return		Zero on success, negative error number otherwise (EINVAL
+ * @return		Zero on success, error number otherwise (EINVAL
  *			if the specified baud_rate is not valid).
  */
@@ -758,6 +784,5 @@
  *
  */
-static inline void ns8250_interrupt_handler(ipc_callid_t iid, ipc_call_t *icall,
-    ddf_dev_t *dev)
+static inline void ns8250_interrupt_handler(ipc_call_t *icall, ddf_dev_t *dev)
 {
 	ns8250_t *ns = dev_ns8250(dev);
@@ -778,8 +803,9 @@
  * @param ns		Serial port device
  */
-static inline int ns8250_register_interrupt_handler(ns8250_t *ns)
+static inline int ns8250_register_interrupt_handler(ns8250_t *ns,
+    cap_handle_t *handle)
 {
 	return register_interrupt_handler(ns->dev, ns->irq,
-	    ns8250_interrupt_handler, NULL);
+	    ns8250_interrupt_handler, NULL, handle);
 }
 
@@ -850,6 +876,6 @@
 	
 	/* Register interrupt handler. */
-	ns->irq_cap = ns8250_register_interrupt_handler(ns);
-	if (ns->irq_cap < 0) {
+	rc = ns8250_register_interrupt_handler(ns, &ns->irq_cap);
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed to register interrupt handler.");
 		rc = EADDRNOTAVAIL;
@@ -862,5 +888,5 @@
 	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed to enable the interrupt. Error code = "
-		    "%d.", rc);
+		    "%s.", str_error_name(rc));
 		goto fail;
 	}
@@ -872,6 +898,10 @@
 	}
 	
-	/* Set device operations. */
-	ddf_fun_set_ops(fun, &ns8250_dev_ops);
+	ddf_fun_set_conn_handler(fun, ns8250_char_conn);
+	
+	chardev_srvs_init(&ns->cds);
+	ns->cds.ops = &ns8250_chardev_ops;
+	ns->cds.sarg = ns;
+	
 	rc = ddf_fun_bind(fun);
 	if (rc != EOK) {
@@ -930,9 +960,10 @@
  * device.
  *
- * @param dev		The device.
- */
-static int ns8250_open(ddf_fun_t *fun)
-{
-	ns8250_t *ns = fun_ns8250(fun);
+ * @param srvs		Service structure
+ * @param srv		Server-side connection structure
+ */
+static int ns8250_open(chardev_srvs_t *srvs, chardev_srv_t *srv)
+{
+	ns8250_t *ns = srv_ns8250(srv);
 	int res;
 	
@@ -954,9 +985,9 @@
  * the device.
  *
- * @param dev		The device.
- */
-static void ns8250_close(ddf_fun_t *fun)
-{
-	ns8250_t *data = fun_ns8250(fun);
+ * @param srv		Server-side connection structure
+ */
+static int ns8250_close(chardev_srv_t *srv)
+{
+	ns8250_t *data = srv_ns8250(srv);
 	
 	fibril_mutex_lock(&data->mutex);
@@ -968,4 +999,6 @@
 	
 	fibril_mutex_unlock(&data->mutex);
+	
+	return EOK;
 }
 
@@ -1034,7 +1067,8 @@
  * Configure the parameters of the serial communication.
  */
-static void ns8250_default_handler(ddf_fun_t *fun, ipc_callid_t callid,
+static void ns8250_default_handler(chardev_srv_t *srv, ipc_callid_t callid,
     ipc_call_t *call)
 {
+	ns8250_t *ns8250 = srv_ns8250(srv);
 	sysarg_t method = IPC_GET_IMETHOD(*call);
 	int ret;
@@ -1043,5 +1077,5 @@
 	switch (method) {
 	case SERIAL_GET_COM_PROPS:
-		ns8250_get_props(ddf_fun_get_dev(fun), &baud_rate, &parity, &word_length,
+		ns8250_get_props(ns8250->dev, &baud_rate, &parity, &word_length,
 		    &stop_bits);
 		async_answer_4(callid, EOK, baud_rate, parity, word_length,
@@ -1054,5 +1088,5 @@
 		word_length = IPC_GET_ARG3(*call);
 		stop_bits = IPC_GET_ARG4(*call);
-		ret = ns8250_set_props(ddf_fun_get_dev(fun), baud_rate, parity, word_length,
+		ret = ns8250_set_props(ns8250->dev, baud_rate, parity, word_length,
 		    stop_bits);
 		async_answer_0(callid, ret);
@@ -1064,4 +1098,11 @@
 }
 
+void ns8250_char_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	ns8250_t *ns8250 = fun_ns8250((ddf_fun_t *)arg);
+
+	chardev_conn(iid, icall, &ns8250->cds);
+}
+
 /** Initialize the serial port driver.
  *
@@ -1072,10 +1113,4 @@
 {
 	ddf_log_init(NAME);
-	
-	ns8250_dev_ops.open = &ns8250_open;
-	ns8250_dev_ops.close = &ns8250_close;
-	
-	ns8250_dev_ops.interfaces[CHAR_DEV_IFACE] = &ns8250_char_dev_ops;
-	ns8250_dev_ops.default_handler = &ns8250_default_handler;
 }
 
Index: uspace/drv/char/pl050/pl050.c
===================================================================
--- uspace/drv/char/pl050/pl050.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/pl050/pl050.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -35,4 +35,5 @@
 #include <stdio.h>
 #include <errno.h>
+#include <str_error.h>
 #include <ddf/driver.h>
 #include <ddf/interrupt.h>
@@ -54,6 +55,6 @@
 static int pl050_fun_offline(ddf_fun_t *);
 static void pl050_char_conn(ipc_callid_t, ipc_call_t *, void *);
-static int pl050_read(chardev_srv_t *, void *, size_t);
-static int pl050_write(chardev_srv_t *, const void *, size_t);
+static int pl050_read(chardev_srv_t *, void *, size_t, size_t *);
+static int pl050_write(chardev_srv_t *, const void *, size_t, size_t *);
 
 static driver_ops_t driver_ops = {
@@ -137,5 +138,5 @@
 }
 
-static void pl050_interrupt(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev)
+static void pl050_interrupt(ipc_call_t *call, ddf_dev_t *dev)
 {
 	pl050_t *pl050 = (pl050_t *)ddf_dev_data_get(dev);
@@ -212,10 +213,10 @@
 	pl050->regs = regs;
 
-	const int irq_cap = register_interrupt_handler(pl050->dev,
-	    res.irqs.irqs[0], pl050_interrupt, &pl050_irq_code);
-	if (irq_cap < 0) {
-		rc = irq_cap;
-		ddf_msg(LVL_ERROR, "Failed registering interrupt handler. (%d)",
-		    rc);
+	int irq_cap;
+	rc = register_interrupt_handler(pl050->dev,
+	    res.irqs.irqs[0], pl050_interrupt, &pl050_irq_code, &irq_cap);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed registering interrupt handler. (%s)",
+		    str_error_name(rc));
 		goto error;
 	}
@@ -223,5 +224,5 @@
 	rc = hw_res_enable_interrupt(pl050->parent_sess, res.irqs.irqs[0]);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed enabling interrupt. (%d)", rc);
+		ddf_msg(LVL_ERROR, "Failed enabling interrupt: %s", str_error(rc));
 		goto error;
 	}
@@ -236,5 +237,6 @@
 }
 
-static int pl050_read(chardev_srv_t *srv, void *buffer, size_t size)
+static int pl050_read(chardev_srv_t *srv, void *buffer, size_t size,
+    size_t *nread)
 {
 	pl050_t *pl050 = (pl050_t *)srv->srvs->sarg;
@@ -246,6 +248,8 @@
 	left = size;
 	while (left > 0) {
-		while (pl050->buf_rp == pl050->buf_wp)
+		while (left == size && pl050->buf_rp == pl050->buf_wp)
 			fibril_condvar_wait(&pl050->buf_cv, &pl050->buf_lock);
+		if (pl050->buf_rp == pl050->buf_wp)
+			break;
 		*bp++ = pl050->buffer[pl050->buf_rp];
 		--left;
@@ -255,8 +259,10 @@
 	fibril_mutex_unlock(&pl050->buf_lock);
 
-	return size;
-}
-
-static int pl050_write(chardev_srv_t *srv, const void *data, size_t size)
+	*nread = size - left;
+	return EOK;
+}
+
+static int pl050_write(chardev_srv_t *srv, const void *data, size_t size,
+    size_t *nwritten)
 {
 	pl050_t *pl050 = (pl050_t *)srv->srvs->sarg;
@@ -276,5 +282,6 @@
 	ddf_msg(LVL_NOTE, "%s/pl050_write() success", pl050->name);
 
-	return size;
+	*nwritten = size;
+	return EOK;
 }
 
@@ -343,5 +350,5 @@
 	rc = ddf_fun_bind(fun_a);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed binding function 'a'. (%d)", rc);
+		ddf_msg(LVL_ERROR, "Failed binding function 'a': %s", str_error(rc));
 		ddf_fun_destroy(fun_a);
 		goto error;
Index: uspace/drv/char/ski-con/ski-con.c
===================================================================
--- uspace/drv/char/ski-con/ski-con.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/ski-con/ski-con.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -1,5 +1,5 @@
 /*
  * Copyright (c) 2005 Jakub Jermar
- * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -31,11 +31,12 @@
  */
 
+#include <async.h>
 #include <ddf/driver.h>
 #include <ddf/log.h>
 #include <errno.h>
-#include <ipc/char.h>
+#include <fibril.h>
+#include <io/chardev.h>
 #include <stdint.h>
 #include <stdlib.h>
-#include <thread.h>
 #include <stdbool.h>
 
@@ -43,18 +44,33 @@
 
 #define SKI_GETCHAR		21
+#define SKI_PUTCHAR		31
 
 #define POLL_INTERVAL		10000
 
-static void ski_con_thread_impl(void *arg);
+static int ski_con_fibril(void *arg);
 static int32_t ski_con_getchar(void);
 static void ski_con_connection(ipc_callid_t, ipc_call_t *, void *);
 
+static int ski_con_read(chardev_srv_t *, void *, size_t, size_t *);
+static int ski_con_write(chardev_srv_t *, const void *, size_t, size_t *);
+
+static chardev_ops_t ski_con_chardev_ops = {
+	.read = ski_con_read,
+	.write = ski_con_write
+};
+
+static void ski_con_putchar(ski_con_t *con, char ch); /* XXX */
+
 /** Add ski console device. */
 int ski_con_add(ski_con_t *con)
 {
-	thread_id_t tid;
+	fid_t fid;
 	ddf_fun_t *fun = NULL;
 	bool bound = false;
 	int rc;
+
+	circ_buf_init(&con->cbuf, con->buf, ski_con_buf_size, 1);
+	fibril_mutex_initialize(&con->buf_lock);
+	fibril_condvar_initialize(&con->buf_cv);
 
 	fun = ddf_fun_create(con->dev, fun_exposed, "a");
@@ -67,4 +83,8 @@
 	ddf_fun_set_conn_handler(fun, ski_con_connection);
 
+	chardev_srvs_init(&con->cds);
+	con->cds.ops = &ski_con_chardev_ops;
+	con->cds.sarg = con;
+
 	rc = ddf_fun_bind(fun);
 	if (rc != EOK) {
@@ -73,11 +93,16 @@
 	}
 
+	ddf_fun_add_to_category(fun, "console");
+
 	bound = true;
 
-	rc = thread_create(ski_con_thread_impl, con, "kbd_poll", &tid);
-	if (rc != 0) {
-		return rc;
-	}
-
+	fid = fibril_create(ski_con_fibril, con);
+	if (fid == 0) {
+		ddf_msg(LVL_ERROR, "Error creating fibril.");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	fibril_add_ready(fid);
 	return EOK;
 error:
@@ -102,9 +127,10 @@
 }
 
-/** Thread to poll Ski for keypresses. */
-static void ski_con_thread_impl(void *arg)
+/** Poll Ski for keypresses. */
+static int ski_con_fibril(void *arg)
 {
 	int32_t c;
 	ski_con_t *con = (ski_con_t *) arg;
+	int rc;
 
 	while (1) {
@@ -114,13 +140,18 @@
 				break;
 
-			if (con->client_sess != NULL) {
-				async_exch_t *exch = async_exchange_begin(con->client_sess);
-				async_msg_1(exch, CHAR_NOTIF_BYTE, c);
-				async_exchange_end(exch);
-			}
+			fibril_mutex_lock(&con->buf_lock);
+
+			rc = circ_buf_push(&con->cbuf, &c);
+			if (rc != EOK)
+				ddf_msg(LVL_ERROR, "Buffer overrun");
+
+			fibril_mutex_unlock(&con->buf_lock);
+			fibril_condvar_broadcast(&con->buf_cv);
 		}
 
-		thread_usleep(POLL_INTERVAL);
-	}
+		async_usleep(POLL_INTERVAL);
+	}
+
+	return 0;
 }
 
@@ -152,7 +183,73 @@
 }
 
+
+/** Display character on ski debug console
+ *
+ * Use SSC (Simulator System Call) to
+ * display character on debug console.
+ *
+ * @param c Character to be printed.
+ *
+ */
 static void ski_con_putchar(ski_con_t *con, char ch)
 {
-	
+	if (ch == '\n')
+		ski_con_putchar(con, '\r');
+
+#ifdef UARCH_ia64
+	asm volatile (
+		"mov r15 = %0\n"
+		"mov r32 = %1\n"   /* r32 is in0 */
+		"break 0x80000\n"  /* modifies r8 */
+		:
+		: "i" (SKI_PUTCHAR), "r" (ch)
+		: "r15", "in0", "r8"
+	);
+#else
+	(void) ch;
+#endif
+}
+
+/** Read from Ski console device */
+static int ski_con_read(chardev_srv_t *srv, void *buf, size_t size,
+    size_t *nread)
+{
+	ski_con_t *con = (ski_con_t *) srv->srvs->sarg;
+	size_t p;
+	uint8_t *bp = (uint8_t *) buf;
+	int rc;
+
+	fibril_mutex_lock(&con->buf_lock);
+
+	while (circ_buf_nused(&con->cbuf) == 0)
+		fibril_condvar_wait(&con->buf_cv, &con->buf_lock);
+
+	p = 0;
+	while (p < size) {
+		rc = circ_buf_pop(&con->cbuf, &bp[p]);
+		if (rc != EOK)
+			break;
+		++p;
+	}
+
+	fibril_mutex_unlock(&con->buf_lock);
+
+	*nread = p;
+	return EOK;
+}
+
+/** Write to Ski console device */
+static int ski_con_write(chardev_srv_t *srv, const void *data, size_t size,
+    size_t *nwr)
+{
+	ski_con_t *con = (ski_con_t *) srv->srvs->sarg;
+	size_t i;
+	uint8_t *dp = (uint8_t *) data;
+
+	for (i = 0; i < size; i++)
+		ski_con_putchar(con, dp[i]); 
+
+	*nwr = size;
+	return EOK;
 }
 
@@ -161,43 +258,8 @@
     void *arg)
 {
-	ski_con_t *con;
-
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-
-	con = (ski_con_t *)ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *)arg));
-
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		sysarg_t method = IPC_GET_IMETHOD(call);
-
-		if (!method) {
-			/* The other side has hung up. */
-			async_answer_0(callid, EOK);
-			return;
-		}
-
-		async_sess_t *sess =
-		    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
-		if (sess != NULL) {
-			if (con->client_sess == NULL) {
-				con->client_sess = sess;
-				async_answer_0(callid, EOK);
-			} else
-				async_answer_0(callid, ELIMIT);
-		} else {
-			switch (method) {
-			case CHAR_WRITE_BYTE:
-				ddf_msg(LVL_DEBUG, "Write %" PRIun " to device\n",
-				    IPC_GET_ARG1(call));
-				ski_con_putchar(con, (uint8_t) IPC_GET_ARG1(call));
-				async_answer_0(callid, EOK);
-				break;
-			default:
-				async_answer_0(callid, EINVAL);
-			}
-		}
-	}
+	ski_con_t *con = (ski_con_t *) ddf_dev_data_get(
+	    ddf_fun_get_dev((ddf_fun_t *) arg));
+
+	chardev_conn(iid, icall, &con->cds);
 }
 
Index: uspace/drv/char/ski-con/ski-con.h
===================================================================
--- uspace/drv/char/ski-con/ski-con.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/ski-con/ski-con.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -36,8 +36,14 @@
 #define SKI_CON_H
 
+#include <adt/circ_buf.h>
 #include <async.h>
 #include <ddf/driver.h>
+#include <io/chardev_srv.h>
 #include <loc.h>
 #include <stdint.h>
+
+enum {
+	ski_con_buf_size = 64
+};
 
 /** Ski console */
@@ -45,4 +51,9 @@
 	async_sess_t *client_sess;
 	ddf_dev_t *dev;
+	chardev_srvs_t cds;
+	circ_buf_t cbuf;
+	uint8_t buf[ski_con_buf_size];
+	fibril_mutex_t buf_lock;
+	fibril_condvar_t buf_cv;
 } ski_con_t;
 
Index: uspace/drv/char/sun4v-con/main.c
===================================================================
--- uspace/drv/char/sun4v-con/main.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/sun4v-con/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -32,4 +32,5 @@
 #include <ddf/driver.h>
 #include <ddf/log.h>
+#include <device/hw_res_parsed.h>
 #include <errno.h>
 #include <stdio.h>
@@ -58,7 +59,38 @@
 };
 
+static int sun4v_con_get_res(ddf_dev_t *dev, sun4v_con_res_t *res)
+{
+	async_sess_t *parent_sess;
+	hw_res_list_parsed_t hw_res;
+	int rc;
+
+	parent_sess = ddf_dev_parent_sess_get(dev);
+	if (parent_sess == NULL)
+		return ENOMEM;
+
+	hw_res_list_parsed_init(&hw_res);
+	rc = hw_res_get_list_parsed(parent_sess, &hw_res, 0);
+	if (rc != EOK)
+		return rc;
+
+	if (hw_res.mem_ranges.count != 2) {
+		rc = EINVAL;
+		goto error;
+	}
+
+	res->in_base = RNGABS(hw_res.mem_ranges.ranges[0]);
+	res->out_base = RNGABS(hw_res.mem_ranges.ranges[1]);
+	return EOK;
+error:
+	hw_res_list_parsed_clean(&hw_res);
+	return rc;
+}
+
+
 static int sun4v_con_dev_add(ddf_dev_t *dev)
 {
 	sun4v_con_t *sun4v_con;
+	sun4v_con_res_t res;
+	int rc;
 
         ddf_msg(LVL_DEBUG, "sun4v_con_dev_add(%p)", dev);
@@ -71,5 +103,11 @@
 	sun4v_con->dev = dev;
 
-	return sun4v_con_add(sun4v_con);
+	rc = sun4v_con_get_res(dev, &res);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed getting hardware resource list.\n");
+		return EIO;
+	}
+
+	return sun4v_con_add(sun4v_con, &res);
 }
 
Index: uspace/drv/char/sun4v-con/niagara_buf.h
===================================================================
--- uspace/drv/char/sun4v-con/niagara_buf.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/char/sun4v-con/niagara_buf.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,1 @@
+../../../../kernel/arch/sparc64/include/arch/drivers/niagara_buf.h
Index: uspace/drv/char/sun4v-con/sun4v-con.c
===================================================================
--- uspace/drv/char/sun4v-con/sun4v-con.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/sun4v-con/sun4v-con.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -1,5 +1,5 @@
 /*
  * Copyright (c) 2008 Pavel Rimsky
- * Copyright (c) 2011 Jiri Svoboda
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -36,8 +36,7 @@
 #include <ddi.h>
 #include <errno.h>
-#include <ipc/char.h>
+#include <str_error.h>
+#include <io/chardev_srv.h>
 #include <stdbool.h>
-#include <sysinfo.h>
-#include <thread.h>
 
 #include "sun4v-con.h"
@@ -47,35 +46,34 @@
 #define POLL_INTERVAL  10000
 
-/*
- * Kernel counterpart of the driver pushes characters (it has read) here.
- * Keep in sync with the definition from
- * kernel/arch/sparc64/src/drivers/niagara.c.
- */
-#define INPUT_BUFFER_SIZE  ((PAGE_SIZE) - 2 * 8)
+static int sun4v_con_read(chardev_srv_t *, void *, size_t, size_t *);
+static int sun4v_con_write(chardev_srv_t *, const void *, size_t, size_t *);
 
-typedef volatile struct {
-	uint64_t write_ptr;
-	uint64_t read_ptr;
-	char data[INPUT_BUFFER_SIZE];
-} __attribute__((packed)) __attribute__((aligned(PAGE_SIZE))) *input_buffer_t;
-
-/* virtual address of the shared buffer */
-static input_buffer_t input_buffer;
-
-static void sun4v_thread_impl(void *arg);
+static chardev_ops_t sun4v_con_chardev_ops = {
+	.read = sun4v_con_read,
+	.write = sun4v_con_write
+};
 
 static void sun4v_con_putchar(sun4v_con_t *con, uint8_t data)
 {
-	(void) con;
-	(void) data;
+	if (data == '\n')
+		sun4v_con_putchar(con, '\r');
+
+	while (con->output_buffer->write_ptr ==
+	    (con->output_buffer->read_ptr + OUTPUT_BUFFER_SIZE - 1)
+	    % OUTPUT_BUFFER_SIZE);
+
+	con->output_buffer->data[con->output_buffer->write_ptr] = data;
+	con->output_buffer->write_ptr =
+	    ((con->output_buffer->write_ptr) + 1) % OUTPUT_BUFFER_SIZE;
 }
 
 /** Add sun4v console device. */
-int sun4v_con_add(sun4v_con_t *con)
+int sun4v_con_add(sun4v_con_t *con, sun4v_con_res_t *res)
 {
 	ddf_fun_t *fun = NULL;
 	int rc;
 
-	input_buffer = (input_buffer_t) AS_AREA_ANY;
+	con->res = *res;
+	con->input_buffer = (niagara_input_buffer_t *) AS_AREA_ANY;
 
 	fun = ddf_fun_create(con->dev, fun_exposed, "a");
@@ -86,24 +84,25 @@
 	}
 
+	chardev_srvs_init(&con->cds);
+	con->cds.ops = &sun4v_con_chardev_ops;
+	con->cds.sarg = con;
+
 	ddf_fun_set_conn_handler(fun, sun4v_con_connection);
 
-	sysarg_t paddr;
-	rc = sysinfo_get_value("niagara.inbuf.address", &paddr);
+	rc = physmem_map(res->in_base, 1, AS_AREA_READ | AS_AREA_WRITE,
+	    (void *) &con->input_buffer);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "niagara.inbuf.address not set (%d)", rc);
+		ddf_msg(LVL_ERROR, "Error mapping memory: %s", str_error_name(rc));
 		goto error;
 	}
 
-	rc = physmem_map(paddr, 1, AS_AREA_READ | AS_AREA_WRITE,
-	    (void *) &input_buffer);
+	con->output_buffer = (niagara_output_buffer_t *) AS_AREA_ANY;
+
+	rc = physmem_map(res->out_base, 1, AS_AREA_READ | AS_AREA_WRITE,
+	    (void *) &con->output_buffer);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Error mapping memory: %d", rc);
-		goto error;
+		ddf_msg(LVL_ERROR, "Error mapping memory: %s", str_error_name(rc));
+		return rc;
 	}
-
-	thread_id_t tid;
-	rc = thread_create(sun4v_thread_impl, con, "kbd_poll", &tid);
-	if (rc != EOK)
-		goto error;
 
 	rc = ddf_fun_bind(fun);
@@ -113,10 +112,13 @@
 	}
 
+	ddf_fun_add_to_category(fun, "console");
+
 	return EOK;
 error:
-	/* XXX Clean up thread */
+	if (con->input_buffer != (niagara_input_buffer_t *) AS_AREA_ANY)
+		physmem_unmap((void *) con->input_buffer);
 
-	if (input_buffer != (input_buffer_t) AS_AREA_ANY)
-		physmem_unmap((void *) input_buffer);
+	if (con->output_buffer != (niagara_output_buffer_t *) AS_AREA_ANY)
+		physmem_unmap((void *) con->output_buffer);
 
 	if (fun != NULL)
@@ -138,36 +140,41 @@
 }
 
-/**
- * Called regularly by the polling thread. Reads codes of all the
- * pressed keys from the buffer.
- */
-static void sun4v_key_pressed(sun4v_con_t *con)
+/** Read from Sun4v console device */
+static int sun4v_con_read(chardev_srv_t *srv, void *buf, size_t size,
+    size_t *nread)
 {
+	sun4v_con_t *con = (sun4v_con_t *) srv->srvs->sarg;
+	size_t p;
+	uint8_t *bp = (uint8_t *) buf;
 	char c;
 
-	while (input_buffer->read_ptr != input_buffer->write_ptr) {
-		c = input_buffer->data[input_buffer->read_ptr];
-		input_buffer->read_ptr =
-		    ((input_buffer->read_ptr) + 1) % INPUT_BUFFER_SIZE;
-		if (con->client_sess != NULL) {
-			async_exch_t *exch = async_exchange_begin(con->client_sess);
-			async_msg_1(exch, CHAR_NOTIF_BYTE, c);
-			async_exchange_end(exch);
-		}
-		(void) c;
+	while (con->input_buffer->read_ptr == con->input_buffer->write_ptr)
+		async_usleep(POLL_INTERVAL);
+
+	p = 0;
+	while (p < size && con->input_buffer->read_ptr != con->input_buffer->write_ptr) {
+		c = con->input_buffer->data[con->input_buffer->read_ptr];
+		con->input_buffer->read_ptr =
+		    ((con->input_buffer->read_ptr) + 1) % INPUT_BUFFER_SIZE;
+		bp[p++] = c;
 	}
+
+	*nread = p;
+	return EOK;
 }
 
-/**
- * Thread to poll Sun4v console for keypresses.
- */
-static void sun4v_thread_impl(void *arg)
+/** Write to Sun4v console device */
+static int sun4v_con_write(chardev_srv_t *srv, const void *data, size_t size,
+    size_t *nwr)
 {
-	sun4v_con_t *con = (sun4v_con_t *) arg;
+	sun4v_con_t *con = (sun4v_con_t *) srv->srvs->sarg;
+	size_t i;
+	uint8_t *dp = (uint8_t *) data;
 
-	while (true) {
-		sun4v_key_pressed(con);
-		thread_usleep(POLL_INTERVAL);
-	}
+	for (i = 0; i < size; i++)
+		sun4v_con_putchar(con, dp[i]); 
+
+	*nwr = size;
+	return EOK;
 }
 
@@ -176,43 +183,8 @@
     void *arg)
 {
-	sun4v_con_t *con;
+	sun4v_con_t *con = (sun4v_con_t *) ddf_dev_data_get(
+	    ddf_fun_get_dev((ddf_fun_t *) arg));
 
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-
-	con = (sun4v_con_t *)ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *)arg));
-
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		sysarg_t method = IPC_GET_IMETHOD(call);
-
-		if (!method) {
-			/* The other side has hung up. */
-			async_answer_0(callid, EOK);
-			return;
-		}
-
-		async_sess_t *sess =
-		    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
-		if (sess != NULL) {
-			if (con->client_sess == NULL) {
-				con->client_sess = sess;
-				async_answer_0(callid, EOK);
-			} else
-				async_answer_0(callid, ELIMIT);
-		} else {
-			switch (method) {
-			case CHAR_WRITE_BYTE:
-				ddf_msg(LVL_DEBUG, "Write %" PRIun " to device\n",
-				    IPC_GET_ARG1(call));
-				sun4v_con_putchar(con, (uint8_t) IPC_GET_ARG1(call));
-				async_answer_0(callid, EOK);
-				break;
-			default:
-				async_answer_0(callid, EINVAL);
-			}
-		}
-	}
+	chardev_conn(iid, icall, &con->cds);
 }
 
Index: uspace/drv/char/sun4v-con/sun4v-con.h
===================================================================
--- uspace/drv/char/sun4v-con/sun4v-con.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/char/sun4v-con/sun4v-con.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -38,6 +38,15 @@
 #include <async.h>
 #include <ddf/driver.h>
+#include <io/chardev_srv.h>
 #include <loc.h>
 #include <stdint.h>
+
+#include "niagara_buf.h"
+
+/** Sun4v console resources */
+typedef struct {
+	uintptr_t in_base;
+	uintptr_t out_base;
+} sun4v_con_res_t;
 
 /** Sun4v console */
@@ -45,11 +54,13 @@
 	async_sess_t *client_sess;
 	ddf_dev_t *dev;
+	chardev_srvs_t cds;
+	sun4v_con_res_t res;
+	/** Virtual address of the shared input buffer */
+	niagara_input_buffer_t *input_buffer;
+	/** Virtual address of the shared input buffer */
+	niagara_output_buffer_t *output_buffer;
 } sun4v_con_t;
 
-extern int sun4v_con_init(sun4v_con_t *);
-extern void sun4v_con_write(uint8_t data);
-
-
-extern int sun4v_con_add(sun4v_con_t *);
+extern int sun4v_con_add(sun4v_con_t *, sun4v_con_res_t *);
 extern int sun4v_con_remove(sun4v_con_t *);
 extern int sun4v_con_gone(sun4v_con_t *);
Index: uspace/drv/fb/kfb/kfb.c
===================================================================
--- uspace/drv/fb/kfb/kfb.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/fb/kfb/kfb.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -36,7 +36,4 @@
 #include <errno.h>
 #include <stdio.h>
-#include <loc.h>
-#include <async.h>
-#include <task.h>
 #include <graph.h>
 #include "port.h"
Index: uspace/drv/fb/kfb/port.c
===================================================================
--- uspace/drv/fb/kfb/port.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/fb/kfb/port.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -42,5 +42,5 @@
 #include <errno.h>
 
-#include <malloc.h>
+#include <stdlib.h>
 #include <mem.h>
 #include <as.h>
Index: uspace/drv/hid/adb-kbd/Makefile
===================================================================
--- uspace/drv/hid/adb-kbd/Makefile	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-kbd/Makefile	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2017 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = drv
+BINARY = adb-kbd
+
+SOURCES = \
+	main.c \
+	adb-kbd.c \
+	ctl.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/hid/adb-kbd/adb-kbd.c
===================================================================
--- uspace/drv/hid/adb-kbd/adb-kbd.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-kbd/adb-kbd.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * @brief ADB keyboard port driver.
+ */
+
+#include <async.h>
+#include <ddf/log.h>
+#include <errno.h>
+#include <io/console.h>
+#include <ipc/adb.h>
+#include <ipc/kbdev.h>
+#include <loc.h>
+#include <vfs/vfs.h>
+
+#include "adb-kbd.h"
+#include "ctl.h"
+
+static void adb_kbd_events(ipc_callid_t, ipc_call_t *, void *);
+static void adb_kbd_reg0_data(adb_kbd_t *, uint16_t);
+static void adb_kbd_conn(ipc_callid_t, ipc_call_t *, void *);
+
+/** Add ADB keyboard device */
+int adb_kbd_add(adb_kbd_t *kbd)
+{
+	int rc;
+	bool bound = false;
+
+	kbd->fun = ddf_fun_create(kbd->dev, fun_exposed, "a");
+	if (kbd->fun == NULL) {
+		ddf_msg(LVL_ERROR, "Error creating function");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	kbd->parent_sess = ddf_dev_parent_sess_get(kbd->dev);
+	if (kbd->parent_sess == NULL) {
+		ddf_msg(LVL_ERROR, "Error connecting parent driver");
+		rc = EIO;
+		goto error;
+	}
+
+	async_exch_t *exch = async_exchange_begin(kbd->parent_sess);
+	if (exch == NULL) {
+		ddf_msg(LVL_ERROR, "Error starting exchange with parent");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	port_id_t port;
+	rc = async_create_callback_port(exch, INTERFACE_ADB_CB, 0, 0,
+	    adb_kbd_events, kbd, &port);
+
+	async_exchange_end(exch);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Error creating callback from device");
+		goto error;
+	}
+
+	ddf_fun_set_conn_handler(kbd->fun, adb_kbd_conn);
+
+	rc = ddf_fun_bind(kbd->fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Error binding function");
+		goto error;
+	}
+
+	bound = true;
+
+	rc = ddf_fun_add_to_category(kbd->fun, "keyboard");
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Error adding function to category");
+		goto error;
+	}
+
+	return EOK;
+error:
+	if (bound)
+		ddf_fun_unbind(kbd->fun);
+
+	if (kbd->parent_sess != NULL) {
+		async_hangup(kbd->parent_sess);
+		kbd->parent_sess = NULL;
+	}
+
+	if (kbd->fun != NULL) {
+		ddf_fun_destroy(kbd->fun);
+		kbd->fun = NULL;
+	}
+
+	return rc;
+}
+
+/** Remove ADB keyboard device */
+int adb_kbd_remove(adb_kbd_t *con)
+{
+	return ENOTSUP;
+}
+
+/** ADB keyboard device gone */
+int adb_kbd_gone(adb_kbd_t *con)
+{
+	return ENOTSUP;
+}
+
+static void adb_kbd_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	adb_kbd_t *kbd = (adb_kbd_t *) arg;
+
+	/* Ignore parameters, the connection is already opened */
+	while (true) {
+
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+
+		int retval = EOK;
+
+		if (!IPC_GET_IMETHOD(call)) {
+			/* TODO: Handle hangup */
+			return;
+		}
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case ADB_REG_NOTIF:
+			adb_kbd_reg0_data(kbd, IPC_GET_ARG1(call));
+			break;
+		default:
+			retval = ENOENT;
+		}
+		async_answer_0(callid, retval);
+	}
+}
+
+static void adb_kbd_data(adb_kbd_t *kbd, uint8_t b)
+{
+	kbd_event_type_t etype;
+	unsigned int key;
+	int rc;
+
+	rc = adb_kbd_key_translate(b, &etype, &key);
+	if (rc != EOK)
+		return;
+
+	if (kbd->client_sess == NULL)
+		return;
+
+	async_exch_t *exch = async_exchange_begin(kbd->client_sess);
+	async_msg_4(exch, KBDEV_EVENT, etype, key, 0, 0);
+	async_exchange_end(exch);
+}
+
+static void adb_kbd_reg0_data(adb_kbd_t *kbd, uint16_t data)
+{
+	uint8_t b0 = (data >> 8) & 0xff;
+	uint8_t b1 = data & 0xff;
+
+	if (b0 != 0xff)
+		adb_kbd_data(kbd, b0);
+
+	if (b1 != 0xff)
+		adb_kbd_data(kbd, b1);
+	(void)b0; (void)b1;
+}
+
+/** Handle client connection */
+static void adb_kbd_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	ipc_callid_t callid;
+	ipc_call_t call;
+	sysarg_t method;
+	adb_kbd_t *kbd;
+
+	/*
+	 * Answer the first IPC_M_CONNECT_ME_TO call.
+	 */
+	async_answer_0(iid, EOK);
+
+	kbd = (adb_kbd_t *)ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *)arg));
+
+	while (true) {
+		callid = async_get_call(&call);
+		method = IPC_GET_IMETHOD(call);
+
+		if (!method) {
+			/* The other side has hung up. */
+			async_answer_0(callid, EOK);
+			return;
+		}
+
+		async_sess_t *sess =
+		    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
+		if (sess != NULL) {
+			kbd->client_sess = sess;
+			async_answer_0(callid, EOK);
+		} else {
+			async_answer_0(callid, EINVAL);
+		}
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/adb-kbd/adb-kbd.h
===================================================================
--- uspace/drv/hid/adb-kbd/adb-kbd.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-kbd/adb-kbd.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ */
+
+#ifndef ADB_KBD_H
+#define ADB_KBD_H
+
+#include <async.h>
+#include <ddf/driver.h>
+
+/** ADB keyboard */
+typedef struct {
+	ddf_dev_t *dev;
+	async_sess_t *parent_sess;
+	ddf_fun_t *fun;
+	async_sess_t *client_sess;
+} adb_kbd_t;
+
+extern int adb_kbd_add(adb_kbd_t *);
+extern int adb_kbd_remove(adb_kbd_t *);
+extern int adb_kbd_gone(adb_kbd_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/drv/hid/adb-kbd/adb-kbd.ma
===================================================================
--- uspace/drv/hid/adb-kbd/adb-kbd.ma	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-kbd/adb-kbd.ma	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,1 @@
+10 adb/keyboard
Index: uspace/drv/hid/adb-kbd/ctl.c
===================================================================
--- uspace/drv/hid/adb-kbd/ctl.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-kbd/ctl.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * @brief Apple ADB keyboard controller
+ */
+
+#include <errno.h>
+#include <io/console.h>
+#include <io/keycode.h>
+
+#include "ctl.h"
+
+#define KBD_KEY_RELEASE  0x80
+
+static unsigned int scanmap[] = {
+	[0x00] = KC_A,
+	[0x01] = KC_S,
+	[0x02] = KC_D,
+	[0x03] = KC_F,
+	[0x04] = KC_H,
+	[0x05] = KC_G,
+	[0x06] = KC_Z,
+	[0x07] = KC_X,
+	[0x08] = KC_C,
+	[0x09] = KC_V,
+	[0x0a] = KC_BACKSLASH,
+	[0x0b] = KC_B,
+	[0x0c] = KC_Q,
+	[0x0d] = KC_W,
+	[0x0e] = KC_E,
+	[0x0f] = KC_R,
+	[0x10] = KC_Y,
+	[0x11] = KC_T,
+	[0x12] = KC_1,
+	[0x13] = KC_2,
+	[0x14] = KC_3,
+	[0x15] = KC_4,
+	[0x16] = KC_6,
+	[0x17] = KC_5,
+	[0x18] = KC_EQUALS,
+	[0x19] = KC_9,
+	[0x1a] = KC_7,
+	[0x1b] = KC_MINUS,
+	[0x1c] = KC_8,
+	[0x1d] = KC_0,
+	[0x1e] = KC_RBRACKET,
+	[0x1f] = KC_O,
+	[0x20] = KC_U,
+	[0x21] = KC_LBRACKET,
+	[0x22] = KC_I,
+	[0x23] = KC_P,
+	[0x24] = KC_ENTER,
+	[0x25] = KC_L,
+	[0x26] = KC_J,
+	[0x27] = KC_QUOTE,
+	[0x28] = KC_K,
+	[0x29] = KC_SEMICOLON,
+	[0x2a] = KC_BACKSLASH,
+	[0x2b] = KC_COMMA,
+	[0x2c] = KC_SLASH,
+	[0x2d] = KC_N,
+	[0x2e] = KC_M,
+	[0x2f] = KC_PERIOD,
+	[0x30] = KC_TAB,
+	[0x31] = KC_SPACE,
+	[0x32] = KC_BACKTICK,
+	[0x33] = KC_BACKSPACE,
+	[0x34] = 0,
+	[0x35] = KC_ESCAPE,
+	[0x36] = KC_LCTRL,
+	[0x37] = 0,
+	[0x38] = KC_LSHIFT,
+	[0x39] = KC_CAPS_LOCK,
+	[0x3a] = KC_LALT,
+	[0x3b] = KC_LEFT,
+	[0x3c] = KC_RIGHT,
+	[0x3d] = KC_DOWN,
+	[0x3e] = KC_UP,
+	[0x3f] = 0,
+	[0x40] = 0,
+	[0x41] = KC_NPERIOD,
+	[0x42] = 0,
+	[0x43] = KC_NTIMES,
+	[0x44] = 0,
+	[0x45] = KC_NPLUS,
+	[0x46] = 0,
+	[0x47] = KC_NUM_LOCK,
+	[0x48] = 0,
+	[0x49] = 0,
+	[0x4a] = 0,
+	[0x4b] = KC_NSLASH,
+	[0x4c] = KC_NENTER,
+	[0x4d] = 0,
+	[0x4e] = KC_NMINUS,
+	[0x4f] = 0,
+	[0x50] = 0,
+	[0x51] = 0,
+	[0x52] = KC_N0,
+	[0x53] = KC_N1,
+	[0x54] = KC_N2,
+	[0x55] = KC_N3,
+	[0x56] = KC_N4,
+	[0x57] = KC_N5,
+	[0x58] = KC_N6,
+	[0x59] = KC_N7,
+	[0x5a] = 0,
+	[0x5b] = KC_N8,
+	[0x5c] = KC_N9,
+	[0x5d] = 0,
+	[0x5e] = 0,
+	[0x5f] = 0,
+	[0x60] = KC_F5,
+	[0x61] = KC_F6,
+	[0x62] = KC_F7,
+	[0x63] = KC_F3,
+	[0x64] = KC_F8,
+	[0x65] = KC_F9,
+	[0x66] = 0,
+	[0x67] = KC_F11,
+	[0x68] = 0,
+	[0x69] = KC_SYSREQ,
+	[0x6a] = 0,
+	[0x6b] = KC_SCROLL_LOCK,
+	[0x6c] = 0,
+	[0x6d] = KC_F10,
+	[0x6e] = 0,
+	[0x6f] = KC_F12,
+	[0x70] = 0,
+	[0x71] = KC_PAUSE,
+	[0x72] = KC_INSERT,
+	[0x73] = KC_HOME,
+	[0x74] = KC_PAGE_UP,
+	[0x75] = KC_DELETE,
+	[0x76] = KC_F4,
+	[0x77] = KC_END,
+	[0x78] = KC_F2,
+	[0x79] = KC_PAGE_DOWN,
+	[0x7a] = KC_F1,
+	[0x7b] = KC_RSHIFT,
+	[0x7c] = KC_RALT,
+	[0x7d] = KC_RCTRL,
+	[0x7e] = 0,
+	[0x7f] = 0
+};
+
+/** Translate ADB keyboard scancode into keyboard event.
+ *
+ * @param scancode Scancode
+ * @param rtype Place to store type of keyboard event (press or release)
+ * @param rkey Place to store key code
+ *
+ * @return EOK on success, ENOENT if no translation exists
+ */
+int adb_kbd_key_translate(sysarg_t scancode, kbd_event_type_t *rtype,
+    unsigned int *rkey)
+{
+	kbd_event_type_t etype;
+	unsigned int key;
+
+	if (scancode & KBD_KEY_RELEASE) {
+		scancode &= ~KBD_KEY_RELEASE;
+		etype = KEY_RELEASE;
+	} else {
+		etype = KEY_PRESS;
+	}
+
+	if (scancode >= sizeof(scanmap) / sizeof(unsigned int))
+		return ENOENT;
+
+	key = scanmap[scancode];
+	if (key == 0)
+		return ENOENT;
+
+	*rtype = etype;
+	*rkey = key;
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/drv/hid/adb-kbd/ctl.h
===================================================================
--- uspace/drv/hid/adb-kbd/ctl.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-kbd/ctl.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * @brief Apple ADB keyboard controller
+ */
+
+#ifndef CTL_H
+#define CTL_H
+
+extern int adb_kbd_key_translate(sysarg_t, kbd_event_type_t *, unsigned int *);
+
+#endif
+
+/** @}
+ */
Index: uspace/drv/hid/adb-kbd/main.c
===================================================================
--- uspace/drv/hid/adb-kbd/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-kbd/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genarch
+ * @{
+ */
+/** @file ADB keyboard driver
+ */
+
+#include <ddf/driver.h>
+#include <ddf/log.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "adb-kbd.h"
+
+#define NAME  "adb-kbd"
+
+static int adb_kbd_dev_add(ddf_dev_t *dev);
+static int adb_kbd_dev_remove(ddf_dev_t *dev);
+static int adb_kbd_dev_gone(ddf_dev_t *dev);
+static int adb_kbd_fun_online(ddf_fun_t *fun);
+static int adb_kbd_fun_offline(ddf_fun_t *fun);
+
+static driver_ops_t driver_ops = {
+	.dev_add = adb_kbd_dev_add,
+	.dev_remove = adb_kbd_dev_remove,
+	.dev_gone = adb_kbd_dev_gone,
+	.fun_online = adb_kbd_fun_online,
+	.fun_offline = adb_kbd_fun_offline
+};
+
+static driver_t adb_kbd_driver = {
+	.name = NAME,
+	.driver_ops = &driver_ops
+};
+
+static int adb_kbd_dev_add(ddf_dev_t *dev)
+{
+	adb_kbd_t *adb_kbd;
+
+        ddf_msg(LVL_DEBUG, "adb_kbd_dev_add(%p)", dev);
+	adb_kbd = ddf_dev_data_alloc(dev, sizeof(adb_kbd_t));
+	if (adb_kbd == NULL) {
+		ddf_msg(LVL_ERROR, "Failed allocating soft state.");
+		return ENOMEM;
+	}
+
+	adb_kbd->dev = dev;
+
+	return adb_kbd_add(adb_kbd);
+}
+
+static int adb_kbd_dev_remove(ddf_dev_t *dev)
+{
+        adb_kbd_t *adb_kbd = (adb_kbd_t *)ddf_dev_data_get(dev);
+
+        ddf_msg(LVL_DEBUG, "adb_kbd_dev_remove(%p)", dev);
+
+        return adb_kbd_remove(adb_kbd);
+}
+
+static int adb_kbd_dev_gone(ddf_dev_t *dev)
+{
+        adb_kbd_t *adb_kbd = (adb_kbd_t *)ddf_dev_data_get(dev);
+
+        ddf_msg(LVL_DEBUG, "adb_kbd_dev_gone(%p)", dev);
+
+        return adb_kbd_gone(adb_kbd);
+}
+
+static int adb_kbd_fun_online(ddf_fun_t *fun)
+{
+        ddf_msg(LVL_DEBUG, "adb_kbd_fun_online()");
+        return ddf_fun_online(fun);
+}
+
+static int adb_kbd_fun_offline(ddf_fun_t *fun)
+{
+        ddf_msg(LVL_DEBUG, "adb_kbd_fun_offline()");
+        return ddf_fun_offline(fun);
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": ADB keyboard driver\n");
+	ddf_log_init(NAME);
+	return ddf_driver_main(&adb_kbd_driver);
+}
+
+/** @}
+ */
Index: uspace/drv/hid/adb-mouse/Makefile
===================================================================
--- uspace/drv/hid/adb-mouse/Makefile	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-mouse/Makefile	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2017 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = drv
+BINARY = adb-mouse
+
+SOURCES = \
+	main.c \
+	adb-mouse.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/hid/adb-mouse/adb-mouse.c
===================================================================
--- uspace/drv/hid/adb-mouse/adb-mouse.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-mouse/adb-mouse.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * @brief ADB mouse driver
+ */
+
+#include <async.h>
+#include <ddf/log.h>
+#include <errno.h>
+#include <ipc/adb.h>
+#include <ipc/mouseev.h>
+#include <loc.h>
+#include <stdio.h>
+
+#include "adb-mouse.h"
+
+static void adb_mouse_conn(ipc_callid_t, ipc_call_t *, void *);
+
+static void adb_mouse_event_button(adb_mouse_t *mouse, int bnum, int bpress)
+{
+	async_exch_t *exch = async_exchange_begin(mouse->client_sess);
+	async_msg_2(exch, MOUSEEV_BUTTON_EVENT, bnum, bpress);
+	async_exchange_end(exch);
+}
+
+static void adb_mouse_event_move(adb_mouse_t *mouse, int dx, int dy, int dz)
+{
+	async_exch_t *exch = async_exchange_begin(mouse->client_sess);
+	async_msg_3(exch, MOUSEEV_MOVE_EVENT, dx, dy, dz);
+	async_exchange_end(exch);
+}
+
+/** Process mouse data */
+static void adb_mouse_data(adb_mouse_t *mouse, sysarg_t data)
+{
+	bool b1, b2;
+	uint16_t udx, udy;
+	int dx, dy;
+
+	/* Extract fields. */
+	b1 = ((data >> 15) & 1) == 0;
+	udy = (data >> 8) & 0x7f;
+	b2 = ((data >> 7) & 1) == 0;
+	udx = data & 0x7f;
+
+	/* Decode 7-bit two's complement signed values. */
+	dx = (udx & 0x40) ? (udx - 0x80) : udx;
+	dy = (udy & 0x40) ? (udy - 0x80) : udy;
+
+	if (b1 != mouse->b1_pressed) {
+		adb_mouse_event_button(mouse, 1, b1);
+		mouse->b1_pressed = b1;
+	}
+
+	if (b2 != mouse->b2_pressed) {
+		adb_mouse_event_button(mouse, 2, b2);
+		mouse->b2_pressed = b2;
+	}
+
+	if (dx != 0 || dy != 0)
+		adb_mouse_event_move(mouse, dx, dy, 0);
+}
+
+static void adb_mouse_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	adb_mouse_t *mouse = (adb_mouse_t *) arg;
+
+	/* Ignore parameters, the connection is already opened */
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+
+		int retval = EOK;
+
+		if (!IPC_GET_IMETHOD(call)) {
+			/* TODO: Handle hangup */
+			return;
+		}
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case ADB_REG_NOTIF:
+			adb_mouse_data(mouse, IPC_GET_ARG1(call));
+			break;
+		default:
+			retval = ENOENT;
+		}
+
+		async_answer_0(callid, retval);
+	}
+}
+
+/** Add ADB mouse device */
+int adb_mouse_add(adb_mouse_t *mouse)
+{
+	int rc;
+	bool bound = false;
+
+	mouse->fun = ddf_fun_create(mouse->dev, fun_exposed, "a");
+	if (mouse->fun == NULL) {
+		ddf_msg(LVL_ERROR, "Error creating function");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	mouse->parent_sess = ddf_dev_parent_sess_get(mouse->dev);
+	if (mouse->parent_sess == NULL) {
+		ddf_msg(LVL_ERROR, "Error connecting parent driver");
+		rc = EIO;
+		goto error;
+	}
+
+	async_exch_t *exch = async_exchange_begin(mouse->parent_sess);
+	if (exch == NULL) {
+		ddf_msg(LVL_ERROR, "Error starting exchange with parent");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	port_id_t port;
+	rc = async_create_callback_port(exch, INTERFACE_ADB_CB, 0, 0,
+	    adb_mouse_events, mouse, &port);
+
+	async_exchange_end(exch);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Error creating callback from device");
+		goto error;
+	}
+
+	ddf_fun_set_conn_handler(mouse->fun, adb_mouse_conn);
+
+	rc = ddf_fun_bind(mouse->fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Error binding function");
+		goto error;
+	}
+
+	bound = true;
+
+	rc = ddf_fun_add_to_category(mouse->fun, "mouse");
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Error adding function to category");
+		goto error;
+	}
+
+	return EOK;
+error:
+	if (bound)
+		ddf_fun_unbind(mouse->fun);
+
+	if (mouse->parent_sess != NULL) {
+		async_hangup(mouse->parent_sess);
+		mouse->parent_sess = NULL;
+	}
+
+	if (mouse->fun != NULL) {
+		ddf_fun_destroy(mouse->fun);
+		mouse->fun = NULL;
+	}
+
+	return rc;
+}
+
+/** Remove ADB mouse device */
+int adb_mouse_remove(adb_mouse_t *con)
+{
+	return ENOTSUP;
+}
+
+/** ADB mouse device gone */
+int adb_mouse_gone(adb_mouse_t *con)
+{
+	return ENOTSUP;
+}
+
+/** Handle client connection */
+static void adb_mouse_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	ipc_callid_t callid;
+	ipc_call_t call;
+	sysarg_t method;
+	adb_mouse_t *mouse;
+
+	/*
+	 * Answer the first IPC_M_CONNECT_ME_TO call.
+	 */
+	async_answer_0(iid, EOK);
+
+	mouse = (adb_mouse_t *)ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *)arg));
+
+	while (true) {
+		callid = async_get_call(&call);
+		method = IPC_GET_IMETHOD(call);
+
+		if (!method) {
+			/* The other side has hung up. */
+			async_answer_0(callid, EOK);
+			return;
+		}
+
+		async_sess_t *sess =
+		    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
+		if (sess != NULL) {
+			mouse->client_sess = sess;
+			async_answer_0(callid, EOK);
+		} else {
+			async_answer_0(callid, EINVAL);
+		}
+	}
+}
+
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/adb-mouse/adb-mouse.h
===================================================================
--- uspace/drv/hid/adb-mouse/adb-mouse.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-mouse/adb-mouse.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file ADB mouse driver
+ */
+
+#ifndef ADB_MOUSE_H
+#define ADB_MOUSE_H
+
+#include <async.h>
+#include <ddf/driver.h>
+#include <stdbool.h>
+
+/** ADB mouse */
+typedef struct {
+	ddf_dev_t *dev;
+	async_sess_t *parent_sess;
+	ddf_fun_t *fun;
+	async_sess_t *client_sess;
+	bool b1_pressed;
+	bool b2_pressed;
+} adb_mouse_t;
+
+extern int adb_mouse_add(adb_mouse_t *);
+extern int adb_mouse_remove(adb_mouse_t *);
+extern int adb_mouse_gone(adb_mouse_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/drv/hid/adb-mouse/adb-mouse.ma
===================================================================
--- uspace/drv/hid/adb-mouse/adb-mouse.ma	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-mouse/adb-mouse.ma	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,1 @@
+10 adb/mouse
Index: uspace/drv/hid/adb-mouse/main.c
===================================================================
--- uspace/drv/hid/adb-mouse/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
+++ uspace/drv/hid/adb-mouse/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup genarch
+ * @{
+ */
+/** @file ADB keyboard driver
+ */
+
+#include <ddf/driver.h>
+#include <ddf/log.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "adb-mouse.h"
+
+#define NAME  "adb-mouse"
+
+static int adb_mouse_dev_add(ddf_dev_t *dev);
+static int adb_mouse_dev_remove(ddf_dev_t *dev);
+static int adb_mouse_dev_gone(ddf_dev_t *dev);
+static int adb_mouse_fun_online(ddf_fun_t *fun);
+static int adb_mouse_fun_offline(ddf_fun_t *fun);
+
+static driver_ops_t driver_ops = {
+	.dev_add = adb_mouse_dev_add,
+	.dev_remove = adb_mouse_dev_remove,
+	.dev_gone = adb_mouse_dev_gone,
+	.fun_online = adb_mouse_fun_online,
+	.fun_offline = adb_mouse_fun_offline
+};
+
+static driver_t adb_mouse_driver = {
+	.name = NAME,
+	.driver_ops = &driver_ops
+};
+
+static int adb_mouse_dev_add(ddf_dev_t *dev)
+{
+	adb_mouse_t *adb_mouse;
+
+        ddf_msg(LVL_DEBUG, "adb_mouse_dev_add(%p)", dev);
+	adb_mouse = ddf_dev_data_alloc(dev, sizeof(adb_mouse_t));
+	if (adb_mouse == NULL) {
+		ddf_msg(LVL_ERROR, "Failed allocating soft state.");
+		return ENOMEM;
+	}
+
+	adb_mouse->dev = dev;
+
+	return adb_mouse_add(adb_mouse);
+}
+
+static int adb_mouse_dev_remove(ddf_dev_t *dev)
+{
+        adb_mouse_t *adb_mouse = (adb_mouse_t *)ddf_dev_data_get(dev);
+
+        ddf_msg(LVL_DEBUG, "adb_mouse_dev_remove(%p)", dev);
+
+        return adb_mouse_remove(adb_mouse);
+}
+
+static int adb_mouse_dev_gone(ddf_dev_t *dev)
+{
+        adb_mouse_t *adb_mouse = (adb_mouse_t *)ddf_dev_data_get(dev);
+
+        ddf_msg(LVL_DEBUG, "adb_mouse_dev_gone(%p)", dev);
+
+        return adb_mouse_gone(adb_mouse);
+}
+
+static int adb_mouse_fun_online(ddf_fun_t *fun)
+{
+        ddf_msg(LVL_DEBUG, "adb_mouse_fun_online()");
+        return ddf_fun_online(fun);
+}
+
+static int adb_mouse_fun_offline(ddf_fun_t *fun)
+{
+        ddf_msg(LVL_DEBUG, "adb_mouse_fun_offline()");
+        return ddf_fun_offline(fun);
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": ADB mouse driver\n");
+	ddf_log_init(NAME);
+	return ddf_driver_main(&adb_mouse_driver);
+}
+
+/** @}
+ */
Index: uspace/drv/hid/atkbd/atkbd.c
===================================================================
--- uspace/drv/hid/atkbd/atkbd.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/hid/atkbd/atkbd.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2017 Jiri Svoboda
  * Copyright (c) 2011 Jan Vesely
  * Copyright (c) 2009 Vineeth Pillai
@@ -201,18 +202,12 @@
 static int polling(void *arg)
 {
-	const at_kbd_t *kbd = arg;
-	
-	assert(kbd);
-	assert(kbd->parent_sess);
-	
-	async_exch_t *parent_exch = async_exchange_begin(kbd->parent_sess);
+	at_kbd_t *kbd = arg;
+	size_t nwr;
+	int rc;
 	
 	while (true) {
-		if (!parent_exch)
-			parent_exch = async_exchange_begin(kbd->parent_sess);
-
 		uint8_t code = 0;
-		ssize_t size = chardev_read(parent_exch, &code, 1);
-		if (size != 1)
+		rc = chardev_read(kbd->chardev, &code, 1, &nwr);
+		if (rc != EOK)
 			return EIO;
 		
@@ -224,46 +219,46 @@
 			map_size = sizeof(scanmap_e0) / sizeof(unsigned int);
 			
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nwr);
+			if (rc != EOK)
 				return EIO;
 		} else if (code == KBD_SCANCODE_SET_EXTENDED_SPECIAL) {
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nwr);
+			if (rc != EOK)
 				return EIO;
 			if (code != 0x14)
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nwr);
+			if (rc != EOK)
 				return EIO;
 			if (code != 0x77)
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nwr);
+			if (rc != EOK)
 				return EIO;
 			if (code != 0xe1)
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nwr);
+			if (rc != EOK)
 				return EIO;
 			if (code != 0xf0)
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nwr);
+			if (rc != EOK)
 				return EIO;
 			if (code != 0x14)
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nwr);
+			if (rc != EOK)
 				return EIO;
 			if (code != 0xf0)
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nwr);
+			if (rc != EOK)
 				return EIO;
 			if (code == 0x77)
@@ -279,6 +274,6 @@
 		if (code == KBD_SCANCODE_KEY_RELEASE) {
 			type = KEY_RELEASE;
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nwr);
+			if (rc != EOK)
 				return EIO;
 		} else {
@@ -362,12 +357,21 @@
 int at_kbd_init(at_kbd_t *kbd, ddf_dev_t *dev)
 {
+	async_sess_t *parent_sess;
+	int rc;
+	
 	assert(kbd);
 	assert(dev);
 	
 	kbd->client_sess = NULL;
-	kbd->parent_sess = ddf_dev_parent_sess_get(dev);
-	
-	if (!kbd->parent_sess) {
+	parent_sess = ddf_dev_parent_sess_get(dev);
+	if (parent_sess == NULL) {
 		ddf_msg(LVL_ERROR, "Failed creating parent session.");
+		rc = EIO;
+		goto error;
+	}
+	
+	rc = chardev_open(parent_sess, &kbd->chardev);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed opening character device.");
 		return EIO;
 	}
@@ -407,3 +411,7 @@
 	fibril_add_ready(kbd->polling_fibril);
 	return EOK;
+error:
+	chardev_close(kbd->chardev);
+	kbd->chardev = NULL;
+	return rc;
 }
Index: uspace/drv/hid/atkbd/atkbd.h
===================================================================
--- uspace/drv/hid/atkbd/atkbd.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/hid/atkbd/atkbd.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -34,16 +35,21 @@
  */
 
-#ifndef _AT_KBD_H_
-#define _AT_KBD_H_
+#ifndef AT_KBD_H_
+#define AT_KBD_H_
 
 #include <ddf/driver.h>
 #include <fibril.h>
+#include <io/chardev.h>
 
 /** PC/AT keyboard driver structure. */
 typedef struct {
-	ddf_fun_t *kbd_fun;        /**< Keyboard function. */
-	async_sess_t *parent_sess; /**< Connection to device providing data. */
-	async_sess_t *client_sess; /**< Callback connection to client. */
-	fid_t polling_fibril;      /**< Fibril retrieving an parsing data. */
+	/** Keyboard function */
+	ddf_fun_t *kbd_fun;
+	/** Device providing keyboard connection */
+	chardev_t *chardev;
+	/** Callback connection to client */
+	async_sess_t *client_sess; 
+	/** Fibril retrieving and parsing data */
+	fid_t polling_fibril;
 } at_kbd_t;
 
Index: uspace/drv/hid/ps2mouse/main.c
===================================================================
--- uspace/drv/hid/ps2mouse/main.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/hid/ps2mouse/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -30,5 +30,5 @@
  */
 /** @file
- * @brief ps/2 mouse driver
+ * @brief PS/2 mouse driver
  */
 
Index: uspace/drv/hid/ps2mouse/ps2mouse.c
===================================================================
--- uspace/drv/hid/ps2mouse/ps2mouse.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/hid/ps2mouse/ps2mouse.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -30,9 +31,10 @@
  */
 /** @file
- * @brief ps2 mouse driver.
+ * @brief PS/2 mouse driver.
  */
 
 #include <stdbool.h>
 #include <errno.h>
+#include <str_error.h>
 #include <ddf/log.h>
 #include <io/keycode.h>
@@ -70,12 +72,13 @@
 #define PS2_BUTTON_MASK(button) (1 << button)
 
-#define MOUSE_READ_BYTE_TEST(sess, value_) \
+#define MOUSE_READ_BYTE_TEST(mouse, value_) \
 do { \
 	uint8_t value = (value_); \
 	uint8_t data = 0; \
-	const ssize_t size = chardev_read(sess, &data, 1); \
-	if (size != 1) { \
-		ddf_msg(LVL_ERROR, "Failed reading byte: %zd)", size);\
-		return size < 0 ? size : EIO; \
+	size_t nread; \
+	const int rc = chardev_read((mouse)->chardev, &data, 1, &nread); \
+	if (rc != EOK) { \
+		ddf_msg(LVL_ERROR, "Failed reading byte: %s", str_error_name(rc));\
+		return rc; \
 	} \
 	if (data != value) { \
@@ -86,12 +89,13 @@
 } while (0)
 
-#define MOUSE_WRITE_BYTE(sess, value_) \
+#define MOUSE_WRITE_BYTE(mouse, value_) \
 do { \
 	uint8_t value = (value_); \
 	uint8_t data = (value); \
-	const ssize_t size = chardev_write(sess, &data, 1); \
-	if (size < 0 ) { \
-		ddf_msg(LVL_ERROR, "Failed writing byte: %hhx", value); \
-		return size; \
+	size_t nwr; \
+	const int rc = chardev_write((mouse)->chardev, &data, 1, &nwr); \
+	if (rc != EOK) { \
+		ddf_msg(LVL_ERROR, "Failed writing byte: %s", str_error_name(rc)); \
+		return rc; \
 	} \
 } while (0)
@@ -99,5 +103,5 @@
 static int polling_ps2(void *);
 static int polling_intellimouse(void *);
-static int probe_intellimouse(async_exch_t *, bool);
+static int probe_intellimouse(ps2_mouse_t *, bool);
 static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
 
@@ -108,71 +112,133 @@
 
 /** Initialize mouse driver structure.
+ *
+ * Connects to parent, creates keyboard function, starts polling fibril.
+ *
  * @param kbd Mouse driver structure to initialize.
  * @param dev DDF device structure.
  *
- * Connects to parent, creates keyboard function, starts polling fibril.
+ * @return EOK on success or non-zero error code
  */
 int ps2_mouse_init(ps2_mouse_t *mouse, ddf_dev_t *dev)
 {
+	async_sess_t *parent_sess;
+	bool bound = false;
+	int rc;
+
 	mouse->client_sess = NULL;
-	mouse->parent_sess = ddf_dev_parent_sess_get(dev);
-	if (!mouse->parent_sess)
-		return ENOMEM;
+
+	parent_sess = ddf_dev_parent_sess_get(dev);
+	if (parent_sess == NULL) {
+		ddf_msg(LVL_ERROR, "Failed getting parent session.");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	rc = chardev_open(parent_sess, &mouse->chardev);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed opening character device.");
+		goto error;
+	}
 
 	mouse->mouse_fun = ddf_fun_create(dev, fun_exposed, "mouse");
-	if (!mouse->mouse_fun) {
-		return ENOMEM;
-	}
+	if (mouse->mouse_fun == NULL) {
+		ddf_msg(LVL_ERROR, "Error creating mouse function.");
+		rc = ENOMEM;
+		goto error;
+	}
+
 	ddf_fun_set_ops(mouse->mouse_fun, &mouse_ops);
 
-	int ret = ddf_fun_bind(mouse->mouse_fun);
-	if (ret != EOK) {
-		ddf_fun_destroy(mouse->mouse_fun);
-		return ENOMEM;
-	}
-
-	ret = ddf_fun_add_to_category(mouse->mouse_fun, "mouse");
-	if (ret != EOK) {
-		ddf_fun_unbind(mouse->mouse_fun);
-		ddf_fun_destroy(mouse->mouse_fun);
-		return ENOMEM;
-	}
+	rc = ddf_fun_bind(mouse->mouse_fun);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed binding mouse function.");
+		goto error;
+	}
+
+	bound = true;
+
+	rc = ddf_fun_add_to_category(mouse->mouse_fun, "mouse");
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding mouse function to category.");
+		goto error;
+	}
+
 	/* Probe IntelliMouse extensions. */
 	int (*polling_f)(void*) = polling_ps2;
-	async_exch_t *exch = async_exchange_begin(mouse->parent_sess);
-	if (probe_intellimouse(exch, false) == EOK) {
+	if (probe_intellimouse(mouse, false) == EOK) {
 		ddf_msg(LVL_NOTE, "Enabled IntelliMouse extensions");
 		polling_f = polling_intellimouse;
-		if (probe_intellimouse(exch, true) == EOK)
+		if (probe_intellimouse(mouse, true) == EOK)
 			ddf_msg(LVL_NOTE, "Enabled 4th and 5th button.");
 	}
+
 	/* Enable mouse data reporting. */
 	uint8_t report = PS2_MOUSE_ENABLE_DATA_REPORT;
-	ssize_t size = chardev_write(exch, &report, 1);
-	if (size != 1) {
+	size_t nwr;
+	rc = chardev_write(mouse->chardev, &report, 1, &nwr);
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed to enable data reporting.");
-		async_exchange_end(exch);
-		ddf_fun_unbind(mouse->mouse_fun);
-		ddf_fun_destroy(mouse->mouse_fun);
-		return EIO;
-	}
-
-	size = chardev_read(exch, &report, 1);
-	async_exchange_end(exch);
-	if (size != 1 || report != PS2_MOUSE_ACK) {
+		rc = EIO;
+		goto error;
+	}
+
+	size_t nread;
+	rc = chardev_read(mouse->chardev, &report, 1, &nread);
+	if (rc != EOK || report != PS2_MOUSE_ACK) {
 		ddf_msg(LVL_ERROR, "Failed to confirm data reporting: %hhx.",
 		    report);
+		rc = EIO;
+		goto error;
+	}
+
+	mouse->polling_fibril = fibril_create(polling_f, mouse);
+	if (mouse->polling_fibril == 0) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	fibril_add_ready(mouse->polling_fibril);
+	return EOK;
+error:
+	if (bound)
 		ddf_fun_unbind(mouse->mouse_fun);
+	if (mouse->mouse_fun != NULL) {
 		ddf_fun_destroy(mouse->mouse_fun);
-		return EIO;
-	}
-
-	mouse->polling_fibril = fibril_create(polling_f, mouse);
-	if (!mouse->polling_fibril) {
-		ddf_fun_unbind(mouse->mouse_fun);
-		ddf_fun_destroy(mouse->mouse_fun);
-		return ENOMEM;
-	}
-	fibril_add_ready(mouse->polling_fibril);
+		mouse->mouse_fun = NULL;
+	}
+
+	chardev_close(mouse->chardev);
+	mouse->chardev = NULL;
+	return rc;
+}
+
+/** Read fixed-size mouse packet.
+ *
+ * Continue reading until entire packet is received.
+ *
+ * @param mouse Mouse device
+ * @param pbuf Buffer for storing packet
+ * @param psize Packet size
+ *
+ * @return EOK on success or non-zero error code
+ */
+static int ps2_mouse_read_packet(ps2_mouse_t *mouse, void *pbuf, size_t psize)
+{
+	int rc;
+	size_t pos;
+	size_t nread;
+
+	pos = 0;
+	while (pos < psize) {
+		rc = chardev_read(mouse->chardev, pbuf + pos, psize - pos,
+		    &nread);
+		if (rc != EOK) {
+			ddf_msg(LVL_WARN, "Error reading packet.");
+			return rc;
+		}
+
+		pos += nread;
+	}
+
 	return EOK;
 }
@@ -184,20 +250,14 @@
 int polling_ps2(void *arg)
 {
-	assert(arg);
-	const ps2_mouse_t *mouse = arg;
-
-	assert(mouse->parent_sess);
+	ps2_mouse_t *mouse = (ps2_mouse_t *) arg;
+	int rc;
+
 	bool buttons[PS2_BUTTON_COUNT] = {};
-	async_exch_t *parent_exch = async_exchange_begin(mouse->parent_sess);
 	while (1) {
-
 		uint8_t packet[PS2_BUFSIZE] = {};
-		const ssize_t size =
-		    chardev_read(parent_exch, packet, PS2_BUFSIZE);
-
-		if (size != PS2_BUFSIZE) {
-			ddf_msg(LVL_WARN, "Incorrect packet size: %zd.", size);
+		rc = ps2_mouse_read_packet(mouse, packet, PS2_BUFSIZE);
+		if (rc != EOK)
 			continue;
-		}
+
 		ddf_msg(LVL_DEBUG2, "Got packet: %hhx:%hhx:%hhx.",
 		    packet[0], packet[1], packet[2]);
@@ -232,5 +292,6 @@
 		async_exchange_end(exch);
 	}
-	async_exchange_end(parent_exch);
+
+	return 0;
 }
 
@@ -241,22 +302,14 @@
 static int polling_intellimouse(void *arg)
 {
-	assert(arg);
-	const ps2_mouse_t *mouse = arg;
-
-	assert(mouse->parent_sess);
+	ps2_mouse_t *mouse = (ps2_mouse_t *) arg;
+	int rc;
+
 	bool buttons[INTELLIMOUSE_BUTTON_COUNT] = {};
-	async_exch_t *parent_exch = NULL;
 	while (1) {
-		if (!parent_exch)
-			parent_exch = async_exchange_begin(mouse->parent_sess);
-
 		uint8_t packet[INTELLIMOUSE_BUFSIZE] = {};
-		const ssize_t size = chardev_read(
-		    parent_exch, packet, INTELLIMOUSE_BUFSIZE);
-
-		if (size != INTELLIMOUSE_BUFSIZE) {
-			ddf_msg(LVL_WARN, "Incorrect packet size: %zd.", size);
+		rc = ps2_mouse_read_packet(mouse, packet, INTELLIMOUSE_BUFSIZE);
+		if (rc != EOK)
 			continue;
-		}
+
 		ddf_msg(LVL_DEBUG2, "Got packet: %hhx:%hhx:%hhx:%hhx.",
 		    packet[0], packet[1], packet[2], packet[3]);
@@ -310,5 +363,6 @@
 		async_exchange_end(exch);
 	}
-	async_exchange_end(parent_exch);
+
+	return 0;
 }
 
@@ -319,26 +373,24 @@
  * See http://www.computer-engineering.org/ps2mouse/ for details.
  */
-static int probe_intellimouse(async_exch_t *exch, bool buttons)
-{
-	assert(exch);
-
-	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_SET_SAMPLE_RATE);
-	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
-	MOUSE_WRITE_BYTE(exch, 200);
-	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
-
-	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_SET_SAMPLE_RATE);
-	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
-	MOUSE_WRITE_BYTE(exch, buttons ? 200 : 100);
-	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
-
-	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_SET_SAMPLE_RATE);
-	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
-	MOUSE_WRITE_BYTE(exch, 80);
-	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
-
-	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_GET_DEVICE_ID);
-	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
-	MOUSE_READ_BYTE_TEST(exch, buttons ? 4 : 3);
+static int probe_intellimouse(ps2_mouse_t *mouse, bool buttons)
+{
+	MOUSE_WRITE_BYTE(mouse, PS2_MOUSE_SET_SAMPLE_RATE);
+	MOUSE_READ_BYTE_TEST(mouse, PS2_MOUSE_ACK);
+	MOUSE_WRITE_BYTE(mouse, 200);
+	MOUSE_READ_BYTE_TEST(mouse, PS2_MOUSE_ACK);
+
+	MOUSE_WRITE_BYTE(mouse, PS2_MOUSE_SET_SAMPLE_RATE);
+	MOUSE_READ_BYTE_TEST(mouse, PS2_MOUSE_ACK);
+	MOUSE_WRITE_BYTE(mouse, buttons ? 200 : 100);
+	MOUSE_READ_BYTE_TEST(mouse, PS2_MOUSE_ACK);
+
+	MOUSE_WRITE_BYTE(mouse, PS2_MOUSE_SET_SAMPLE_RATE);
+	MOUSE_READ_BYTE_TEST(mouse, PS2_MOUSE_ACK);
+	MOUSE_WRITE_BYTE(mouse, 80);
+	MOUSE_READ_BYTE_TEST(mouse, PS2_MOUSE_ACK);
+
+	MOUSE_WRITE_BYTE(mouse, PS2_MOUSE_GET_DEVICE_ID);
+	MOUSE_READ_BYTE_TEST(mouse, PS2_MOUSE_ACK);
+	MOUSE_READ_BYTE_TEST(mouse, buttons ? 4 : 3);
 
 	return EOK;
Index: uspace/drv/hid/ps2mouse/ps2mouse.h
===================================================================
--- uspace/drv/hid/ps2mouse/ps2mouse.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/hid/ps2mouse/ps2mouse.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -30,24 +31,30 @@
  */
 /** @file
- * @brief ps/2 mouse driver.
+ * @brief PS/2 mouse driver.
  */
 
-#ifndef _PS2MOUSE_H_
-#define _PS2MOUSE_H_
+#ifndef PS2MOUSE_H_
+#define PS2MOUSE_H_
 
 #include <ddf/driver.h>
 #include <fibril.h>
+#include <io/chardev.h>
 
 /** PS/2 mouse driver structure. */
 typedef struct {
-	ddf_fun_t *mouse_fun;      /**< Mouse function. */
-	async_sess_t *parent_sess; /**< Connection to device providing data. */
-	async_sess_t *client_sess;  /**< Callback connection to client. */
-	fid_t polling_fibril;      /**< Fibril retrieving an parsing data. */
+	/** Mouse function. */
+	ddf_fun_t *mouse_fun;
+	/** Device providing mouse connection */
+	chardev_t *chardev;
+	/** Callback connection to client. */
+	async_sess_t *client_sess;
+	/** Fibril retrieving an parsing data. */
+	fid_t polling_fibril;
 } ps2_mouse_t;
 
-int ps2_mouse_init(ps2_mouse_t *, ddf_dev_t *);
+extern int ps2_mouse_init(ps2_mouse_t *, ddf_dev_t *);
 
 #endif
+
 /**
  * @}
Index: uspace/drv/hid/xtkbd/xtkbd.c
===================================================================
--- uspace/drv/hid/xtkbd/xtkbd.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/hid/xtkbd/xtkbd.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -206,21 +207,15 @@
 static int polling(void *arg)
 {
-	const xt_kbd_t *kbd = arg;
-	
-	assert(kbd);
-	assert(kbd->parent_sess);
-	
-	async_exch_t *parent_exch = async_exchange_begin(kbd->parent_sess);
+	xt_kbd_t *kbd = arg;
+	size_t nread;
+	int rc;
 	
 	while (true) {
-		if (!parent_exch)
-			parent_exch = async_exchange_begin(kbd->parent_sess);
-		
 		const unsigned int *map = scanmap_simple;
 		size_t map_size = sizeof(scanmap_simple) / sizeof(unsigned int);
 		
 		uint8_t code = 0;
-		ssize_t size = chardev_read(parent_exch, &code, 1);
-		if (size != 1)
+		rc = chardev_read(kbd->chardev, &code, 1, &nread);
+		if (rc != EOK)
 			return EIO;
 		
@@ -234,6 +229,6 @@
 			map_size = sizeof(scanmap_e0) / sizeof(unsigned int);
 			
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nread);
+			if (rc != EOK)
 				return EIO;
 			
@@ -241,6 +236,6 @@
 			
 			if (code == 0x2a) {  /* Print Screen */
-				size = chardev_read(parent_exch, &code, 1);
-				if (size != 1)
+				rc = chardev_read(kbd->chardev, &code, 1, &nread);
+				if (rc != EOK)
 					return EIO;
 				
@@ -248,6 +243,6 @@
 					continue;
 				
-				size = chardev_read(parent_exch, &code, 1);
-				if (size != 1)
+				rc = chardev_read(kbd->chardev, &code, 1, &nread);
+				if (rc != EOK)
 					return EIO;
 				
@@ -259,6 +254,6 @@
 			
 			if (code == 0x46) {  /* Break */
-				size = chardev_read(parent_exch, &code, 1);
-				if (size != 1)
+				rc = chardev_read(kbd->chardev, &code, 1, &nread);
+				if (rc != EOK)
 					return EIO;
 				
@@ -266,6 +261,6 @@
 					continue;
 				
-				size = chardev_read(parent_exch, &code, 1);
-				if (size != 1)
+				rc = chardev_read(kbd->chardev, &code, 1, &nread);
+				if (rc != EOK)
 					return EIO;
 				
@@ -279,6 +274,6 @@
 		/* Extended special set */
 		if (code == KBD_SCANCODE_SET_EXTENDED_SPECIAL) {
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nread);
+			if (rc != EOK)
 				return EIO;
 			
@@ -286,6 +281,6 @@
 				continue;
 			
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nread);
+			if (rc != EOK)
 				return EIO;
 			
@@ -293,6 +288,6 @@
 				continue;
 			
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nread);
+			if (rc != EOK)
 				return EIO;
 			
@@ -300,6 +295,6 @@
 				continue;
 			
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nread);
+			if (rc != EOK)
 				return EIO;
 			
@@ -307,6 +302,6 @@
 				continue;
 			
-			size = chardev_read(parent_exch, &code, 1);
-			if (size != 1)
+			rc = chardev_read(kbd->chardev, &code, 1, &nread);
+			if (rc != EOK)
 				return EIO;
 			
@@ -357,9 +352,13 @@
 		uint8_t cmds[] = { KBD_CMD_SET_LEDS, status };
 		
-		async_exch_t *exch = async_exchange_begin(kbd->parent_sess);
-		const ssize_t size = chardev_write(exch, cmds, sizeof(cmds));
-		async_exchange_end(exch);
-		
-		async_answer_0(icallid, size < 0 ? size : EOK);
+		size_t nwr;
+		int rc = chardev_write(kbd->chardev, &cmds[0], 1, &nwr);
+		if (rc != EOK) {
+			async_answer_0(icallid, rc);
+			break;
+		}
+
+		rc = chardev_write(kbd->chardev, &cmds[1], 1, &nwr);
+		async_answer_0(icallid, rc);
 		break;
 	}
@@ -413,48 +412,60 @@
 int xt_kbd_init(xt_kbd_t *kbd, ddf_dev_t *dev)
 {
-	assert(kbd);
-	assert(dev);
+	async_sess_t *parent_sess;
+	bool bound = false;
+	int rc;
 	
 	kbd->client_sess = NULL;
-	kbd->parent_sess = ddf_dev_parent_sess_get(dev);
-	
-	if (!kbd->parent_sess) {
+	
+	parent_sess = ddf_dev_parent_sess_get(dev);
+	if (parent_sess == NULL) {
 		ddf_msg(LVL_ERROR, "Failed creating parent session.");
-		return EIO;
+		rc = EIO;
+		goto error;
+	}
+	
+	rc = chardev_open(parent_sess, &kbd->chardev);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed opening character device.");
+		goto error;
 	}
 	
 	kbd->kbd_fun = ddf_fun_create(dev, fun_exposed, "kbd");
-	if (!kbd->kbd_fun) {
+	if (kbd->kbd_fun == NULL) {
 		ddf_msg(LVL_ERROR, "Failed creating function 'kbd'.");
-		return ENOMEM;
+		rc = ENOMEM;
+		goto error;
 	}
 	
 	ddf_fun_set_ops(kbd->kbd_fun, &kbd_ops);
 	
-	int ret = ddf_fun_bind(kbd->kbd_fun);
-	if (ret != EOK) {
+	rc = ddf_fun_bind(kbd->kbd_fun);
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed binding function 'kbd'.");
-		ddf_fun_destroy(kbd->kbd_fun);
-		return EEXIST;
-	}
-	
-	ret = ddf_fun_add_to_category(kbd->kbd_fun, "keyboard");
-	if (ret != EOK) {
+		goto error;
+	}
+	
+	rc = ddf_fun_add_to_category(kbd->kbd_fun, "keyboard");
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed adding function 'kbd' to category "
 		    "'keyboard'.");
-		ddf_fun_unbind(kbd->kbd_fun);
-		ddf_fun_destroy(kbd->kbd_fun);
-		return ENOMEM;
+		goto error;
 	}
 	
 	kbd->polling_fibril = fibril_create(polling, kbd);
-	if (!kbd->polling_fibril) {
+	if (kbd->polling_fibril == 0) {
 		ddf_msg(LVL_ERROR, "Failed creating polling fibril.");
-		ddf_fun_unbind(kbd->kbd_fun);
-		ddf_fun_destroy(kbd->kbd_fun);
-		return ENOMEM;
+		rc = ENOMEM;
+		goto error;
 	}
 	
 	fibril_add_ready(kbd->polling_fibril);
 	return EOK;
+error:
+	if (bound)
+		ddf_fun_unbind(kbd->kbd_fun);
+	if (kbd->kbd_fun != NULL)
+		ddf_fun_destroy(kbd->kbd_fun);
+	chardev_close(kbd->chardev);
+	return rc;
 }
Index: uspace/drv/hid/xtkbd/xtkbd.h
===================================================================
--- uspace/drv/hid/xtkbd/xtkbd.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/hid/xtkbd/xtkbd.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -34,16 +35,22 @@
  */
 
-#ifndef _XT_KBD_H_
-#define _XT_KBD_H_
+#ifndef XT_KBD_H_
+#define XT_KBD_H_
 
+#include <async.h>
 #include <ddf/driver.h>
 #include <fibril.h>
+#include <io/chardev.h>
 
-/** PC/XT keyboard driver structure. */
+/** PC/XT keyboard driver structure */
 typedef struct {
-	ddf_fun_t *kbd_fun;        /**< Keyboard function. */
-	async_sess_t *parent_sess; /**< Connection to device providing data. */
-	async_sess_t *client_sess; /**< Callback connection to client. */
-	fid_t polling_fibril;      /**< Fibril retrieving an parsing data. */
+	/** Keyboard function */
+	ddf_fun_t *kbd_fun;
+	/** Device providing keyboard connection */
+	chardev_t *chardev;
+	/** Callback connection to client */
+	async_sess_t *client_sess;
+	/** Fibril retrieving an parsing data */
+	fid_t polling_fibril;
 } xt_kbd_t;
 
Index: uspace/drv/intctl/apic/apic.c
===================================================================
--- uspace/drv/intctl/apic/apic.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/intctl/apic/apic.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -45,4 +45,5 @@
 #include <stdbool.h>
 #include <errno.h>
+#include <str_error.h>
 #include <async.h>
 #include <stdio.h>
@@ -220,5 +221,5 @@
 	rc = pio_enable((void *) res->base, IO_APIC_SIZE, &regs);
 	if (rc != EOK) {
-		printf("%s: Failed to enable PIO for APIC: %d\n", NAME, rc);
+		printf("%s: Failed to enable PIO for APIC: %s\n", NAME, str_error(rc));
 		return EIO;
 	}
@@ -237,5 +238,5 @@
 	rc = ddf_fun_bind(fun_a);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed binding function 'a'. (%d)", rc);
+		ddf_msg(LVL_ERROR, "Failed binding function 'a': %s", str_error(rc));
 		goto error;
 	}
Index: uspace/drv/intctl/i8259/i8259.c
===================================================================
--- uspace/drv/intctl/i8259/i8259.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/intctl/i8259/i8259.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -45,4 +45,5 @@
 #include <stdbool.h>
 #include <errno.h>
+#include <str_error.h>
 #include <async.h>
 #include <stdio.h>
@@ -170,5 +171,5 @@
 	rc = ddf_fun_bind(fun_a);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed binding function 'a'. (%d)", rc);
+		ddf_msg(LVL_ERROR, "Failed binding function 'a': %s", str_error(rc));
 		goto error;
 	}
Index: uspace/drv/intctl/icp-ic/icp-ic.c
===================================================================
--- uspace/drv/intctl/icp-ic/icp-ic.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/intctl/icp-ic/icp-ic.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -41,4 +41,5 @@
 #include <ddf/log.h>
 #include <errno.h>
+#include <str_error.h>
 #include <ipc/irc.h>
 #include <stdint.h>
@@ -136,5 +137,5 @@
 	rc = ddf_fun_bind(fun_a);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed binding function 'a'. (%d)", rc);
+		ddf_msg(LVL_ERROR, "Failed binding function 'a': %s", str_error(rc));
 		goto error;
 	}
Index: uspace/drv/intctl/obio/obio.c
===================================================================
--- uspace/drv/intctl/obio/obio.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/intctl/obio/obio.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -42,6 +42,4 @@
  */
 
-#include <align.h>
-#include <as.h>
 #include <async.h>
 #include <ddf/driver.h>
@@ -49,4 +47,5 @@
 #include <ddi.h>
 #include <errno.h>
+#include <str_error.h>
 #include <inttypes.h>
 #include <ipc/irc.h>
@@ -118,15 +117,8 @@
 {
 	ddf_fun_t *fun_a = NULL;
-	int flags;
-	int retval;
 	int rc;
 
-	flags = AS_AREA_READ | AS_AREA_WRITE;
-	obio->regs = (ioport64_t *)AS_AREA_ANY;
-	retval = physmem_map(res->base,
-	    ALIGN_UP(OBIO_SIZE, PAGE_SIZE) >> PAGE_WIDTH, flags,
-	    (void *) &obio->regs);
-
-	if (retval < 0) {
+	rc = pio_enable((void *)res->base, OBIO_SIZE, (void **) &obio->regs);
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Error mapping OBIO registers");
 		rc = EIO;
@@ -134,5 +126,5 @@
 	}
 
-	ddf_msg(LVL_NOTE, "OBIO registers with base at 0x%" PRIun, res->base);
+	ddf_msg(LVL_NOTE, "OBIO registers with base at 0x%" PRIxn, res->base);
 
 	fun_a = ddf_fun_create(obio->dev, fun_exposed, "a");
@@ -147,5 +139,5 @@
 	rc = ddf_fun_bind(fun_a);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed binding function 'a'. (%d)", rc);
+		ddf_msg(LVL_ERROR, "Failed binding function 'a': %s", str_error(rc));
 		goto error;
 	}
Index: uspace/drv/nic/ar9271/ar9271.c
===================================================================
--- uspace/drv/nic/ar9271/ar9271.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/nic/ar9271/ar9271.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -33,4 +33,5 @@
  */
 
+#include <async.h>
 #include <ieee80211.h>
 #include <usb/classes/classes.h>
@@ -41,7 +42,7 @@
 #include <ddf/interrupt.h>
 #include <errno.h>
+#include <str_error.h>
 #include <nic.h>
 #include <macros.h>
-#include <thread.h>
 #include "ath_usb.h"
 #include "wmi.h"
@@ -733,5 +734,5 @@
  * @param ar9271 AR9271 device structure
  *
- * @return EOK if succeed, negative error code otherwise
+ * @return EOK if succeed, error code otherwise
  *
  */
@@ -784,5 +785,5 @@
 			free(buffer);
 			usb_log_error("Error while uploading firmware. "
-			    "Error: %d\n", rc);
+			    "Error: %s\n", str_error_name(rc));
 			return rc;
 		}
@@ -818,5 +819,5 @@
 	
 	/* Wait until firmware is ready - wait for 1 second to be sure. */
-	thread_sleep(1);
+	async_sleep(1);
 	
 	return rc;
@@ -836,5 +837,5 @@
 	if (rc != EOK) {
 		usb_log_error("Failed to create USB device: %s, "
-		    "ERR_NUM = %d\n", err_msg, rc);
+		    "ERR_NUM = %s\n", err_msg, str_error_name(rc));
 		return NULL;
 	}
@@ -853,6 +854,6 @@
 	if (rc != EOK) {
 		free(ar9271);
-		usb_log_error("Failed to initialize AR9271 structure: %d\n",
-		    rc);
+		usb_log_error("Failed to initialize AR9271 structure: %s\n",
+		    str_error_name(rc));
 		return NULL;
 	}
@@ -876,5 +877,5 @@
  * @param dev The device structure.
  *
- * @return EOK if succeed, negative error code otherwise
+ * @return EOK if succeed, error code otherwise
  */
 static int ar9271_add_device(ddf_dev_t *dev)
Index: uspace/drv/nic/ar9271/ath_usb.c
===================================================================
--- uspace/drv/nic/ar9271/ath_usb.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/nic/ar9271/ath_usb.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -35,5 +35,5 @@
 #include <usb/dev/pipes.h>
 #include <usb/debug.h>
-#include <malloc.h>
+#include <stdlib.h>
 #include <errno.h>
 #include "ath_usb.h"
@@ -56,5 +56,5 @@
  * @param usb_device  Connected USB device.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -107,5 +107,5 @@
  * @param buffer_size Buffer size.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -124,5 +124,5 @@
  * @param transferred_size Real size of read data.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -140,5 +140,5 @@
  * @param buffer_size Buffer size.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -173,5 +173,5 @@
  * @param transferred_size Real size of read data.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
Index: uspace/drv/nic/ar9271/htc.c
===================================================================
--- uspace/drv/nic/ar9271/htc.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/nic/ar9271/htc.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -36,4 +36,5 @@
 #include <byteorder.h>
 #include <errno.h>
+#include <str_error.h>
 #include "wmi.h"
 #include "htc.h"
@@ -149,5 +150,5 @@
  * @param endpoint_id Destination endpoint.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -172,5 +173,5 @@
  * @param endpoint_id Destination endpoint.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -195,5 +196,5 @@
  * @param transferred_size Real size of read data.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -215,5 +216,5 @@
  * @param transferred_size Real size of read data.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -235,5 +236,5 @@
  *
  * @return EOK if succeed, EINVAL when failed to connect service,
- *         negative error code otherwise.
+ *         error code otherwise.
  *
  */
@@ -264,5 +265,5 @@
 	if (rc != EOK) {
 		free(buffer);
-		usb_log_error("Failed to send HTC message. Error: %d\n", rc);
+		usb_log_error("Failed to send HTC message. Error: %s\n", str_error_name(rc));
 		return rc;
 	}
@@ -278,5 +279,5 @@
 		free(buffer);
 		usb_log_error("Failed to receive HTC service connect response. "
-		    "Error: %d\n", rc);
+		    "Error: %s\n", str_error_name(rc));
 		return rc;
 	}
@@ -308,5 +309,5 @@
  * @param htc_device HTC device structure.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -331,5 +332,5 @@
 		free(buffer);
 		usb_log_error("Failed to send HTC config message. "
-		    "Error: %d\n", rc);
+		    "Error: %s\n", str_error_name(rc));
 		return rc;
 	}
@@ -344,5 +345,5 @@
 	if (rc != EOK) {
 		usb_log_error("Failed to receive HTC config response message. "
-		    "Error: %d\n", rc);
+		    "Error: %s\n", str_error_name(rc));
 	}
 	
@@ -356,5 +357,5 @@
  * @param htc_device HTC device structure.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -376,5 +377,5 @@
 	if (rc != EOK)
 		usb_log_error("Failed to send HTC setup complete message. "
-		    "Error: %d\n", rc);
+		    "Error: %s\n", str_error_name(rc));
 	
 	free(buffer);
@@ -390,5 +391,5 @@
  *
  * @return EOK if succeed, EINVAL if response error,
- *         negative error code otherwise.
+ *         error code otherwise.
  *
  */
@@ -404,5 +405,5 @@
 		free(buffer);
 		usb_log_error("Failed to receive HTC check ready message. "
-		    "Error: %d\n", rc);
+		    "Error: %s\n", str_error_name(rc));
 		return rc;
 	}
@@ -426,5 +427,5 @@
  * @param htc_device HTC device structure to be initialized.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -447,5 +448,5 @@
  * @param htc_device HTC device structure.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
Index: uspace/drv/nic/ar9271/hw.c
===================================================================
--- uspace/drv/nic/ar9271/hw.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/nic/ar9271/hw.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -49,5 +49,5 @@
  *
  * @return EOK if succeed, ETIMEOUT on timeout,
- *         negative error code otherwise.
+ *         error code otherwise.
  *
  */
@@ -215,5 +215,5 @@
  * @param ar9271 Device structure.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -636,5 +636,5 @@
  * @param ar9271 Device structure.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  */
 int hw_init(ar9271_t *ar9271)
Index: uspace/drv/nic/ar9271/wmi.c
===================================================================
--- uspace/drv/nic/ar9271/wmi.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/nic/ar9271/wmi.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -35,5 +35,6 @@
 #include <usb/debug.h>
 #include <errno.h>
-#include <malloc.h>
+#include <str_error.h>
+#include <stdlib.h>
 #include <mem.h>
 #include <byteorder.h>
@@ -46,5 +47,5 @@
  * @param res        Stored result.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -78,5 +79,5 @@
  * @param val        Value to be written
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -111,5 +112,5 @@
  * @param clear_bit  Bit to be cleared.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -145,5 +146,5 @@
  * @param set_bit    Bit to be set.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -160,5 +161,5 @@
  * @param clear_bit  Bit to be cleared.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -175,5 +176,5 @@
  * @param elements   Number of elements in array.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -219,5 +220,5 @@
  * @param response_buffer Buffer with response data.
  *
- * @return EOK if succeed, negative error code otherwise.
+ * @return EOK if succeed, error code otherwise.
  *
  */
@@ -245,5 +246,5 @@
 	if (rc != EOK) {
 		free(buffer);
-		usb_log_error("Failed to send WMI message. Error: %d\n", rc);
+		usb_log_error("Failed to send WMI message. Error: %s\n", str_error_name(rc));
 		return rc;
 	}
@@ -268,5 +269,5 @@
 			free(buffer);
 			usb_log_error("Failed to receive WMI message response. "
-			    "Error: %d\n", rc);
+			    "Error: %s\n", str_error_name(rc));
 			return rc;
 		}
Index: uspace/drv/nic/e1k/e1k.c
===================================================================
--- uspace/drv/nic/e1k/e1k.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/nic/e1k/e1k.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -33,4 +33,5 @@
  */
 
+#include <async.h>
 #include <assert.h>
 #include <stdio.h>
@@ -38,5 +39,4 @@
 #include <adt/list.h>
 #include <align.h>
-#include <thread.h>
 #include <byteorder.h>
 #include <as.h>
@@ -372,5 +372,5 @@
 		fibril_mutex_unlock(&e1000->ctrl_lock);
 		
-		thread_usleep(10);
+		async_usleep(10);
 		
 		fibril_mutex_lock(&e1000->ctrl_lock);
@@ -1237,10 +1237,9 @@
 /** Handle device interrupt
  *
- * @param iid   IPC call id
  * @param icall IPC call structure
  * @param dev   E1000 device
  *
  */
-static void e1000_interrupt_handler(ipc_callid_t iid, ipc_call_t *icall,
+static void e1000_interrupt_handler(ipc_call_t *icall,
     ddf_dev_t *dev)
 {
@@ -1260,9 +1259,10 @@
  * @param nic Driver data
  *
- * @return IRQ capability handle if the handler was registered
- * @return Negative error code otherwise
- *
- */
-inline static int e1000_register_int_handler(nic_t *nic)
+ * @param[out] handle  IRQ capability handle if the handler was registered
+ *
+ * @return An error code otherwise
+ *
+ */
+inline static int e1000_register_int_handler(nic_t *nic, cap_handle_t *handle)
 {
 	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
@@ -1275,9 +1275,9 @@
 	e1000_irq_code.cmds[2].addr = e1000->reg_base_phys + E1000_IMC;
 	
-	int cap = register_interrupt_handler(nic_get_ddf_dev(nic), e1000->irq,
-	    e1000_interrupt_handler, &e1000_irq_code);
+	int rc = register_interrupt_handler(nic_get_ddf_dev(nic), e1000->irq,
+	    e1000_interrupt_handler, &e1000_irq_code, handle);
 	
 	fibril_mutex_unlock(&irq_reg_mutex);
-	return cap;
+	return rc;
 }
 
@@ -1370,5 +1370,5 @@
  *
  * @return EOK if succeed
- * @return Negative error code otherwise
+ * @return An error code otherwise
  *
  */
@@ -1524,5 +1524,5 @@
  *
  * @return EOK if succeed
- * @return Negative error code otherwise
+ * @return An error code otherwise
  *
  */
@@ -1725,5 +1725,5 @@
 	
 	/* Wait for the reset */
-	thread_usleep(20);
+	async_usleep(20);
 	
 	/* check if RST_BIT cleared */
@@ -1813,5 +1813,5 @@
 	 * transfers to descriptors.
 	 */
-	thread_usleep(100);
+	async_usleep(100);
 	
 	return EOK;
@@ -1940,5 +1940,5 @@
  *
  * @return EOK if succeed
- * @return Negative error code otherwise
+ * @return An error code otherwise
  *
  */
@@ -1965,5 +1965,5 @@
  *
  * @return EOK if succeed
- * @return Negative error code otherwise
+ * @return An error code otherwise
  *
  */
@@ -1993,5 +1993,5 @@
  *
  * @return EOK if succeed
- * @return Negative error code otherwise
+ * @return An error code otherwise
  *
  */
@@ -2107,5 +2107,5 @@
  *
  * @return EOK if successed
- * @return Negative error code otherwise
+ * @return An error code otherwise
  *
  */
@@ -2165,7 +2165,7 @@
 	ddf_fun_set_ops(fun, &e1000_dev_ops);
 	
-	int irq_cap = e1000_register_int_handler(nic);
-	if (irq_cap < 0) {
-		rc = irq_cap;
+	int irq_cap;
+	rc = e1000_register_int_handler(nic, &irq_cap);
+	if (rc != EOK) {
 		goto err_fun_create;
 	}
@@ -2239,5 +2239,5 @@
 	uint32_t eerd = E1000_REG_READ(e1000, E1000_EERD);
 	while ((eerd & e1000->info.eerd_done) == 0) {
-		thread_usleep(1);
+		async_usleep(1);
 		eerd = E1000_REG_READ(e1000, E1000_EERD);
 	}
@@ -2255,5 +2255,5 @@
  *
  * @return EOK if succeed
- * @return Negative error code otherwise
+ * @return An error code otherwise
  *
  */
@@ -2289,5 +2289,5 @@
  *
  * @return EOK if succeed
- * @return Negative error code otherwise
+ * @return An error code otherwise
  */
 static int e1000_set_addr(ddf_fun_t *fun, const nic_address_t *addr)
Index: uspace/drv/nic/ne2k/dp8390.c
===================================================================
--- uspace/drv/nic/ne2k/dp8390.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/nic/ne2k/dp8390.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -55,9 +55,9 @@
 
 #include <assert.h>
+#include <async.h>
 #include <byteorder.h>
 #include <errno.h>
 #include <stdio.h>
 #include <ddi.h>
-#include <thread.h>
 #include "dp8390.h"
 
@@ -172,7 +172,7 @@
 	/* Reset the ethernet card */
 	uint8_t val = pio_read_8(ne2k->port + NE2K_RESET);
-	thread_usleep(2000);
+	async_usleep(2000);
 	pio_write_8(ne2k->port + NE2K_RESET, val);
-	thread_usleep(2000);
+	async_usleep(2000);
 	
 	/* Reset the DP8390 */
Index: uspace/drv/nic/ne2k/ne2k.c
===================================================================
--- uspace/drv/nic/ne2k/ne2k.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/nic/ne2k/ne2k.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -122,7 +122,7 @@
 };
 
-static void ne2k_interrupt_handler(ipc_callid_t, ipc_call_t *, ddf_dev_t *);
-
-static int ne2k_register_interrupt(nic_t *nic_data)
+static void ne2k_interrupt_handler(ipc_call_t *, ddf_dev_t *);
+
+static int ne2k_register_interrupt(nic_t *nic_data, cap_handle_t *handle)
 {
 	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
@@ -160,7 +160,6 @@
 	}
 
-	int irq_cap = register_interrupt_handler(nic_get_ddf_dev(nic_data),
-		ne2k->irq, ne2k_interrupt_handler, &ne2k->code);
-	return irq_cap;
+	return register_interrupt_handler(nic_get_ddf_dev(nic_data),
+		ne2k->irq, ne2k_interrupt_handler, &ne2k->code, handle);
 }
 
@@ -228,6 +227,5 @@
 	ne2k->probed = true;
 	
-	int irq_cap = ne2k_register_interrupt(nic_data);
-	if (irq_cap < 0)
+	if (ne2k_register_interrupt(nic_data, NULL) != EOK)
 		return EINVAL;
 	
@@ -239,10 +237,8 @@
 }
 
-void ne2k_interrupt_handler(ipc_callid_t iid, ipc_call_t *call, ddf_dev_t *dev)
+void ne2k_interrupt_handler(ipc_call_t *call, ddf_dev_t *dev)
 {
 	nic_t *nic_data = DRIVER_DATA(dev);
 	ne2k_interrupt(nic_data, IRQ_GET_ISR(*call), IRQ_GET_TSR(*call));
-	
-	async_answer_0(iid, EOK);
 }
 
Index: uspace/drv/nic/rtl8139/driver.c
===================================================================
--- uspace/drv/nic/rtl8139/driver.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/nic/rtl8139/driver.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -28,7 +28,7 @@
 
 #include <assert.h>
+#include <async.h>
 #include <errno.h>
 #include <align.h>
-#include <thread.h>
 #include <byteorder.h>
 #include <libarch/barrier.h>
@@ -217,5 +217,5 @@
  *  @param address  The place to store the address
  *
- *  @return EOK if succeed, negative error code otherwise
+ *  @return EOK if succeed, error code otherwise
  */
 inline static void rtl8139_hw_get_addr(rtl8139_t *rtl8139,
@@ -435,5 +435,5 @@
 	memory_barrier();
 	while(pio_read_8(io_base + CR) & CR_RST) {
-		thread_usleep(1);
+		async_usleep(1);
 		read_barrier();
 	}
@@ -816,11 +816,9 @@
 /** Handle device interrupt
  *
- * @param iid    The IPC call id
  * @param icall  The IPC call structure
  * @param dev    The rtl8139 device
  *
  */
-static void rtl8139_interrupt_handler(ipc_callid_t iid, ipc_call_t *icall,
-    ddf_dev_t *dev)
+static void rtl8139_interrupt_handler(ipc_call_t *icall, ddf_dev_t *dev)
 {
 	assert(dev);
@@ -844,8 +842,9 @@
  *  @param nic_data  The driver data
  *
- *  @return IRQ capability handle if the handler was registered.
- *  @return Negative error code otherwise.
- */
-inline static int rtl8139_register_int_handler(nic_t *nic_data)
+ *  @param[out] handle  IRQ capability handle if the handler was registered.
+ *
+ *  @return An error code otherwise.
+ */
+inline static int rtl8139_register_int_handler(nic_t *nic_data, cap_handle_t *handle)
 {
 	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
@@ -858,10 +857,10 @@
 	rtl8139_irq_code.cmds[2].addr = rtl8139->io_addr + ISR;
 	rtl8139_irq_code.cmds[3].addr = rtl8139->io_addr + IMR;
-	int cap = register_interrupt_handler(nic_get_ddf_dev(nic_data),
-	    rtl8139->irq, rtl8139_interrupt_handler, &rtl8139_irq_code);
+	int rc = register_interrupt_handler(nic_get_ddf_dev(nic_data),
+	    rtl8139->irq, rtl8139_interrupt_handler, &rtl8139_irq_code, handle);
 
 	RTL8139_IRQ_STRUCT_UNLOCK();
 
-	return cap;
+	return rc;
 }
 
@@ -1026,5 +1025,5 @@
  *  @param hw_resources  Devices hardware resources
  *
- *  @return EOK if succeed, negative error code otherwise
+ *  @return EOK if succeed, error code otherwise
  */
 static int rtl8139_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t
@@ -1066,5 +1065,5 @@
  *  @param dev  The device structure
  *
- *  @return EOK if succeed, negative error code otherwise
+ *  @return EOK if succeed, error code otherwise
  */
 static int rtl8139_get_resource_info(ddf_dev_t *dev)
@@ -1148,5 +1147,5 @@
  *  @param dev  The device information
  *
- *  @return EOK if succeed, negative error code otherwise
+ *  @return EOK if succeed, error code otherwise
  */
 static int rtl8139_device_initialize(ddf_dev_t *dev)
@@ -1207,5 +1206,5 @@
  * @param dev  The RTL8139 device.
  *
- * @return EOK if successed, negative error code otherwise
+ * @return EOK if successed, error code otherwise
  */
 static int rtl8139_pio_enable(ddf_dev_t *dev)
@@ -1257,5 +1256,5 @@
  * @param dev  The RTL8139 device.
  *
- * @return EOK if added successfully, negative error code otherwise
+ * @return EOK if added successfully, error code otherwise
  */
 int rtl8139_dev_add(ddf_dev_t *dev)
@@ -1289,7 +1288,7 @@
 
 	/* Register interrupt handler */
-	int irq_cap = rtl8139_register_int_handler(nic_data);
-	if (irq_cap < 0) {
-		rc = irq_cap;
+	int irq_cap;
+	rc = rtl8139_register_int_handler(nic_data, &irq_cap);
+	if (rc != EOK) {
 		goto err_pio;
 	}
@@ -1340,5 +1339,5 @@
  *  @param max_len  Maximal addresss length to store
  *
- *  @return EOK if succeed, negative error code otherwise
+ *  @return EOK if succeed, error code otherwise
  */
 static int rtl8139_set_addr(ddf_fun_t *fun, const nic_address_t *addr)
Index: uspace/drv/nic/rtl8139/general.c
===================================================================
--- uspace/drv/nic/rtl8139/general.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/nic/rtl8139/general.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -81,5 +81,5 @@
  *  @param time        The requested time
  *
- *  @return EOK if succeed, negative error code otherwise
+ *  @return EOK if succeed, error code otherwise
  */
 int rtl8139_timer_act_init(rtl8139_timer_act_t * ta, uint32_t timer_freq,
Index: uspace/drv/nic/rtl8169/driver.c
===================================================================
--- uspace/drv/nic/rtl8169/driver.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/nic/rtl8169/driver.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -28,5 +28,7 @@
 
 #include <assert.h>
+#include <async.h>
 #include <errno.h>
+#include <str_error.h>
 #include <align.h>
 #include <byteorder.h>
@@ -34,5 +36,4 @@
 
 #include <as.h>
-#include <thread.h>
 #include <ddf/log.h>
 #include <ddf/interrupt.h>
@@ -42,7 +43,4 @@
 #include <nic.h>
 #include <pci_dev_iface.h>
-
-#include <sysinfo.h>
-#include <ipc/ns.h>
 
 #include <str.h>
@@ -75,7 +73,6 @@
 static int rtl8169_on_stopped(nic_t *nic_data);
 static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size);
-static void rtl8169_irq_handler(ipc_callid_t iid, ipc_call_t *icall,
-    ddf_dev_t *dev);
-static inline int rtl8169_register_int_handler(nic_t *nic_data);
+static void rtl8169_irq_handler(ipc_call_t *icall, ddf_dev_t *dev);
+static inline int rtl8169_register_int_handler(nic_t *nic_data, cap_handle_t *handle);
 static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr);
 static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, const nic_address_t *addr);
@@ -363,5 +360,5 @@
 }
 
-inline static int rtl8169_register_int_handler(nic_t *nic_data)
+inline static int rtl8169_register_int_handler(nic_t *nic_data, cap_handle_t *handle)
 {
 	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
@@ -371,8 +368,8 @@
 	rtl8169_irq_code.cmds[2].addr = rtl8169->regs + ISR;
 	rtl8169_irq_code.cmds[3].addr = rtl8169->regs + IMR;
-	int irq_cap = register_interrupt_handler(nic_get_ddf_dev(nic_data),
-	    rtl8169->irq, rtl8169_irq_handler, &rtl8169_irq_code);
-
-	return irq_cap;
+	int rc = register_interrupt_handler(nic_get_ddf_dev(nic_data),
+	    rtl8169->irq, rtl8169_irq_handler, &rtl8169_irq_code, handle);
+
+	return rc;
 }
 
@@ -431,8 +428,8 @@
 		goto err_pio;
 
-	int irq_cap = rtl8169_register_int_handler(nic_data);
-	if (irq_cap < 0) {
-		rc = irq_cap;
-		ddf_msg(LVL_ERROR, "Failed to register IRQ handler (%d)", rc);
+	int irq_cap;
+	rc = rtl8169_register_int_handler(nic_data, &irq_cap);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed to register IRQ handler (%s)", str_error_name(rc));
 		goto err_irq;
 	}
@@ -710,5 +707,5 @@
 	rc = rtl8169_allocate_buffers(rtl8169);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Error allocating buffers: %d", rc);
+		ddf_msg(LVL_ERROR, "Error allocating buffers: %s", str_error_name(rc));
 		return 0;
 	}
@@ -767,5 +764,5 @@
 	memory_barrier();
 	while (pio_read_8(rtl8169->regs + CR) & CR_RST) {
-		thread_usleep(1);
+		async_usleep(1);
 		read_barrier();
 	}
@@ -1035,6 +1032,5 @@
 }
 
-static void rtl8169_irq_handler(ipc_callid_t iid, ipc_call_t *icall,
-    ddf_dev_t *dev)
+static void rtl8169_irq_handler(ipc_call_t *icall, ddf_dev_t *dev)
 {
 	assert(dev);
@@ -1181,5 +1177,5 @@
 	do {
 		phyar = pio_read_32(rtl8169->regs + PHYAR);
-		thread_usleep(20);
+		async_usleep(20);
 	} while ((phyar & PHYAR_RW_WRITE) == 0);
 
@@ -1199,8 +1195,8 @@
 	do {
 		phyar = pio_read_32(rtl8169->regs + PHYAR);
-		thread_usleep(20);
+		async_usleep(20);
 	} while ((phyar & PHYAR_RW_WRITE) != 0);
 
-	thread_usleep(20);
+	async_usleep(20);
 }
 
Index: uspace/drv/platform/amdm37x/main.c
===================================================================
--- uspace/drv/platform/amdm37x/main.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/platform/amdm37x/main.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -209,5 +209,5 @@
  *            (both of HW and pseudo devices).
  *
- * @return Zero on success, negative error number otherwise.
+ * @return Zero on success, error number otherwise.
  *
  */
Index: uspace/drv/platform/mac/mac.c
===================================================================
--- uspace/drv/platform/mac/mac.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/platform/mac/mac.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -173,5 +173,5 @@
  *            (both of HW and pseudo devices).
  *
- * @return Zero on success, negative error number otherwise.
+ * @return Zero on success, error number otherwise.
  *
  */
Index: uspace/drv/platform/malta/malta.c
===================================================================
--- uspace/drv/platform/malta/malta.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/platform/malta/malta.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -221,5 +221,5 @@
  * @param dev		The device which is root of the whole device tree (both
  *			of HW and pseudo devices).
- * @return		Zero on success, negative error number otherwise.
+ * @return		Zero on success, error number otherwise.
  */
 static int malta_dev_add(ddf_dev_t *dev)
Index: uspace/drv/platform/msim/msim.c
===================================================================
--- uspace/drv/platform/msim/msim.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/platform/msim/msim.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -38,22 +38,22 @@
 
 #include <assert.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <macros.h>
-
-#include <ddi.h>
 #include <ddf/driver.h>
 #include <ddf/log.h>
+#include <errno.h>
 #include <ipc/dev_iface.h>
 #include <ops/hw_res.h>
 #include <ops/pio_window.h>
+#include <stdbool.h>
+#include <stdio.h>
 
 #define NAME "msim"
 
-#define MSIM_DISK_BASE	UINT32_C(0x10000200)
-#define MSIM_DISK_SIZE	UINT32_C(0x00000010)
+#define MSIM_DDISK_BASE	UINT32_C(0x10000200)
+#define MSIM_DDISK_SIZE	UINT32_C(0x00000010)
+#define MSIM_DDISK_IRQ 6
+
+#define MSIM_KBD_ADDRESS UINT32_C(0x10000000)
+#define MSIM_KBD_SIZE 1
+#define MSIM_KBD_IRQ 2
 
 typedef struct msim_fun {
@@ -65,10 +65,10 @@
 static void msim_init(void);
 
-/** The root device driver's standard operations. */
+/** Standard driver operations. */
 static driver_ops_t msim_ops = {
 	.dev_add = &msim_dev_add
 };
 
-/** The root device driver structure. */
+/** Driver structure. */
 static driver_t msim_driver = {
 	.name = NAME,
@@ -89,5 +89,5 @@
 		.type = INTERRUPT,
 		.res.interrupt = {
-			.irq = 6
+			.irq = MSIM_DDISK_IRQ
 		}
 	}
@@ -101,6 +101,37 @@
 	.pio_window = {
 		.mem = {
-			.base = MSIM_DISK_BASE,
-			.size = MSIM_DISK_SIZE
+			.base = MSIM_DDISK_BASE,
+			.size = MSIM_DDISK_SIZE
+		}
+	}
+};
+
+static hw_resource_t console_regs[] = {
+	{
+		.type = MEM_RANGE,
+		.res.mem_range = {
+			.address = 0,
+			.size = 1,
+			.relative = true,
+			.endianness = LITTLE_ENDIAN
+		}
+	},
+	{
+		.type = INTERRUPT,
+		.res.interrupt = {
+			.irq = MSIM_KBD_IRQ
+		}
+	}
+};
+
+static msim_fun_t console_data = {
+	.hw_resources = {
+		sizeof(console_regs) / sizeof(console_regs[0]),
+		console_regs
+	},
+	.pio_window = {
+		.mem = {
+			.base = MSIM_KBD_ADDRESS,
+			.size = MSIM_KBD_SIZE
 		}
 	}
@@ -125,5 +156,5 @@
 	/* Nothing to do. */
 
-	return true;
+	return EOK;
 }
 
@@ -163,4 +194,7 @@
 	
 	msim_fun_t *fun = ddf_fun_data_alloc(fnode, sizeof(msim_fun_t));
+	if (fun == NULL)
+		goto failure;
+	
 	*fun = *fun_proto;
 	
@@ -194,14 +228,13 @@
 	if (!msim_add_fun(dev, "disk0", "msim/ddisk", &disk_data))
 		return false;
-	if (!msim_add_fun(dev, "console", "msim/console", &disk_data))
+	if (!msim_add_fun(dev, "console", "msim/console", &console_data))
 		return false;
 	return true;
 }
 
-/** Get the root device.
- *
- * @param dev		The device which is root of the whole device tree (both
- *			of HW and pseudo devices).
- * @return		Zero on success, negative error number otherwise.
+/** Add MSIM platform device.
+ *
+ * @param dev DDF device
+ * @return Zero on success or non-zero error code.
  */
 static int msim_dev_add(ddf_dev_t *dev)
Index: uspace/drv/platform/pc/pc.c
===================================================================
--- uspace/drv/platform/pc/pc.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/platform/pc/pc.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -203,5 +203,5 @@
  * @param dev		The device which is root of the whole device tree (both
  *			of HW and pseudo devices).
- * @return		Zero on success, negative error number otherwise.
+ * @return		Zero on success, error number otherwise.
  */
 static int pc_dev_add(ddf_dev_t *dev)
Index: uspace/drv/platform/sun4u/sun4u.c
===================================================================
--- uspace/drv/platform/sun4u/sun4u.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/platform/sun4u/sun4u.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -240,5 +240,5 @@
  * @param dev		The device which is root of the whole device tree (both
  *			of HW and pseudo devices).
- * @return		Zero on success, negative error number otherwise.
+ * @return		Zero on success, error number otherwise.
  */
 static int sun4u_dev_add(ddf_dev_t *dev)
Index: uspace/drv/platform/sun4v/sun4v.c
===================================================================
--- uspace/drv/platform/sun4v/sun4v.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/platform/sun4v/sun4v.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -36,13 +36,22 @@
  */
 
+#include <as.h>
 #include <assert.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-
 #include <ddf/driver.h>
 #include <ddf/log.h>
+#include <errno.h>
+#include <str_error.h>
+#include <ops/hw_res.h>
+#include <ops/pio_window.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysinfo.h>
 
 #define NAME "sun4v"
+
+typedef struct sun4v_fun {
+	hw_resource_list_t hw_resources;
+	pio_window_t pio_window;
+} sun4v_fun_t;
 
 static int sun4v_dev_add(ddf_dev_t *dev);
@@ -57,5 +66,78 @@
 };
 
-static int sun4v_add_fun(ddf_dev_t *dev, const char *name, const char *str_match_id)
+static hw_resource_t console_res[] = {
+	{
+		.type = MEM_RANGE,
+		.res.mem_range = {
+			.address = 0,
+			.size = PAGE_SIZE,
+			.relative = true,
+			.endianness = LITTLE_ENDIAN
+		}
+	},
+	{
+		.type = MEM_RANGE,
+		.res.mem_range = {
+			.address = 0,
+			.size = PAGE_SIZE,
+			.relative = true,
+			.endianness = LITTLE_ENDIAN
+		}
+	},
+};
+
+static sun4v_fun_t console_data = {
+	.hw_resources = {
+		sizeof(console_res) / sizeof(console_res[0]),
+		console_res
+	},
+	.pio_window = {
+		.mem = {
+			.base = 0,
+			.size = PAGE_SIZE
+		}
+	}
+};
+
+/** Obtain function soft-state from DDF function node */
+static sun4v_fun_t *sun4v_fun(ddf_fun_t *fnode)
+{
+	return ddf_fun_data_get(fnode);
+}
+
+static hw_resource_list_t *sun4v_get_resources(ddf_fun_t *fnode)
+{
+	sun4v_fun_t *fun = sun4v_fun(fnode);
+
+	assert(fun != NULL);
+	return &fun->hw_resources;
+}
+
+static int sun4v_enable_interrupt(ddf_fun_t *fun, int irq)
+{
+	return EOK;
+}
+
+static pio_window_t *sun4v_get_pio_window(ddf_fun_t *fnode)
+{
+	sun4v_fun_t *fun = sun4v_fun(fnode);
+
+	assert(fun != NULL);
+	return &fun->pio_window;
+}
+
+static hw_res_ops_t fun_hw_res_ops = {
+	.get_resource_list = &sun4v_get_resources,
+	.enable_interrupt = &sun4v_enable_interrupt,
+};
+
+static pio_window_ops_t fun_pio_window_ops = {
+	.get_pio_window = &sun4v_get_pio_window
+};
+
+static ddf_dev_ops_t sun4v_fun_ops;
+
+static int sun4v_add_fun(ddf_dev_t *dev, const char *name,
+    const char *str_match_id, sun4v_fun_t *fun_proto)
 {
 	ddf_msg(LVL_NOTE, "Adding function '%s'.", name);
@@ -72,4 +154,12 @@
 	}
 
+	sun4v_fun_t *fun = ddf_fun_data_alloc(fnode, sizeof(sun4v_fun_t));
+	if (fun == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	*fun = *fun_proto;
+
 	/* Add match ID */
 	rc = ddf_fun_add_match_id(fnode, str_match_id, 100);
@@ -79,6 +169,10 @@
 	}
 
+	/* Set provided operations to the device. */
+	ddf_fun_set_ops(fnode, &sun4v_fun_ops);
+
 	/* Register function. */
-	if (ddf_fun_bind(fnode) != EOK) {
+	rc = ddf_fun_bind(fnode);
+	if (rc != EOK) {
 		ddf_msg(LVL_ERROR, "Failed binding function %s.", name);
 		goto error;
@@ -98,5 +192,5 @@
 	int rc;
 
-	rc = sun4v_add_fun(dev, "console", "sun4v/console");
+	rc = sun4v_add_fun(dev, "console", "sun4v/console", &console_data);
 	if (rc != EOK)
 		return rc;
@@ -108,5 +202,5 @@
 static int sun4v_dev_add(ddf_dev_t *dev)
 {
-	ddf_msg(LVL_NOTE, "sun4v_dev_add, device handle = %d",
+	ddf_msg(LVL_DEBUG, "sun4v_dev_add, device handle = %d",
 	    (int)ddf_dev_get_handle(dev));
 
@@ -119,4 +213,36 @@
 }
 
+static int sun4v_init(void)
+{
+	int rc;
+	sysarg_t paddr;
+
+	sun4v_fun_ops.interfaces[HW_RES_DEV_IFACE] = &fun_hw_res_ops;
+	sun4v_fun_ops.interfaces[PIO_WINDOW_DEV_IFACE] = &fun_pio_window_ops;
+
+	rc = ddf_log_init(NAME);
+	if (rc != EOK) {
+		printf(NAME ": Failed initializing logging service\n");
+		return rc;
+	}
+
+	rc = sysinfo_get_value("niagara.inbuf.address", &paddr);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "niagara.inbuf.address not set: %s", str_error(rc));
+		return rc;
+	}
+
+	console_res[0].res.mem_range.address = paddr;
+
+	rc = sysinfo_get_value("niagara.outbuf.address", &paddr);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "niagara.outbuf.address not set: %s", str_error(rc));
+		return rc;
+	}
+
+	console_res[1].res.mem_range.address = paddr;
+	return EOK;
+}
+
 int main(int argc, char *argv[])
 {
@@ -125,9 +251,7 @@
 	printf(NAME ": Sun4v platform driver\n");
 
-	rc = ddf_log_init(NAME);
-	if (rc != EOK) {
-		printf(NAME ": Failed initializing logging service");
+	rc = sun4v_init();
+	if (rc != EOK)
 		return 1;
-	}
 
 	return ddf_driver_main(&sun4v_driver);
Index: uspace/drv/root/root/root.c
===================================================================
--- uspace/drv/root/root/root.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/root/root/root.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -84,5 +84,5 @@
  *
  * @param dev	Device
- * @return	EOK on success or negative error code
+ * @return	EOK on success or an error code
  */
 static int add_virtual_root_fun(ddf_dev_t *dev)
@@ -125,5 +125,5 @@
  *
  * @param dev	Device
- * @return	EOK on success or negative error code
+ * @return	EOK on success or an error code
  */
 static int add_platform_fun(ddf_dev_t *dev)
Index: uspace/drv/root/virt/devices.def
===================================================================
--- uspace/drv/root/virt/devices.def	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/root/virt/devices.def	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -26,8 +26,4 @@
 },
 {
-	.name = "null",
-	.match_id = "virtual&test1"
-},
-{
 	.name = "test3",
 	.match_id = "virtual&test3"
Index: uspace/drv/root/virt/virt.c
===================================================================
--- uspace/drv/root/virt/virt.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/root/virt/virt.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -98,5 +98,5 @@
  * @param vdev		The virtual device
  * @param vfun		Virtual function description
- * @return		EOK on success or negative error code.
+ * @return		EOK on success or an error code.
  */
 static int virt_add_fun(virt_t *virt, virtual_function_t *vfun)
Index: uspace/drv/test/test1/Makefile
===================================================================
--- uspace/drv/test/test1/Makefile	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/test/test1/Makefile	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -32,5 +32,4 @@
 
 SOURCES = \
-	char.c \
 	test1.c
 
Index: uspace/drv/test/test1/char.c
===================================================================
--- uspace/drv/test/test1/char.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ 	(revision )
@@ -1,56 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @file
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <mem.h>
-#include <ops/char_dev.h>
-
-#include "test1.h"
-
-static int impl_char_read(ddf_fun_t *fun, char *buf, size_t count) {
-	memset(buf, 0, count);
-	return count;
-}
-
-static int imp_char_write(ddf_fun_t *fun, char *buf, size_t count) {
-	return count;
-}
-
-static char_dev_ops_t char_dev_ops = {
-	.read = &impl_char_read,
-	.write = &imp_char_write
-};
-
-ddf_dev_ops_t char_device_ops = {
-	.interfaces[CHAR_DEV_IFACE] = &char_dev_ops
-};
-
Index: uspace/drv/test/test1/test1.c
===================================================================
--- uspace/drv/test/test1/test1.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/test/test1/test1.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -177,8 +177,5 @@
 	ddf_fun_add_to_category(fun_a, "virtual");
 
-	if (str_cmp(dev_name, "null") == 0) {
-		ddf_fun_set_ops(fun_a,  &char_device_ops);
-		ddf_fun_add_to_category(fun_a, "virt-null");
-	} else if (str_cmp(dev_name, "test1") == 0) {
+	if (str_cmp(dev_name, "test1") == 0) {
 		(void) register_fun_verbose(dev,
 		    "cloning myself ;-)", "clone",
Index: uspace/drv/test/test1/test1.h
===================================================================
--- uspace/drv/test/test1/test1.h	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/test/test1/test1.h	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -36,5 +36,3 @@
 #define NAME "test1"
 
-extern ddf_dev_ops_t char_device_ops;
-
 #endif
Index: uspace/drv/test/test3/test3.c
===================================================================
--- uspace/drv/test/test3/test3.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/test/test3/test3.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -71,7 +71,7 @@
 	char *fun_name = NULL;
 	
-	rc = asprintf(&fun_name, "%s%zu", base_name, index);
-	if (rc < 0) {
-		ddf_msg(LVL_ERROR, "Failed to format string: %s", str_error(rc));
+	if (asprintf(&fun_name, "%s%zu", base_name, index) < 0) {
+		ddf_msg(LVL_ERROR, "Failed to format string: No memory");
+		rc = ENOMEM;
 		goto leave;
 	}
@@ -161,7 +161,6 @@
 
 	for (i = 0; i < NUM_FUNCS; i++) {
-		rc = asprintf(&fun_name, "test3_%zu", i);
-		if (rc < 0) {
-			ddf_msg(LVL_ERROR, "Failed to format string: %s", str_error(rc));
+		if (asprintf(&fun_name, "test3_%zu", i) < 0) {
+			ddf_msg(LVL_ERROR, "Failed to format string: No memory");
 			return ENOMEM;
 		}
Index: uspace/drv/time/cmos-rtc/cmos-rtc.c
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision 8bfb163a292928c29839d774b30ca9d0d0ee385e)
+++ uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision 132ab5d1e75253f9bae910b2748a4c13efe7e71f)
@@ -39,5 +39,4 @@
 #include <ddi.h>
 #include <as.h>
-#include <sysinfo.h>
 #include <libarch/barrier.h>
 #include <stdio.h>
@@ -191,5 +190,5 @@
  * @param rtc  Pointer to the RTC device
  *
- * @return  EOK on success or a negative error code
+ * @return  EOK on success or an error code
  */ 
 static int
@@ -315,5 +314,5 @@
  * @param t    Pointer to the time variable
  *
- * @return  EOK on success or a negative error code
+ * @return  EOK on success or an error code
  */
 static int
@@ -437,5 +436,5 @@
  * @param t    The time value to set
  *
- * @return  EOK or a negative error code
+ * @return  EOK or an error code
  */
 static int
@@ -545,5 +544,5 @@
  * @param status The status of the battery
  *
- * @return       EOK on success or a negative error code
+ * @return       EOK on success or an error code
  */
 static int
@@ -578,5 +577,5 @@
  * @param dev  The RTC device
  *
- * @return  EOK on success or a negative error code
+ * @return  EOK on success or an error code
  */
 static int
@@ -644,5 +643,5 @@
  * @param dev   The RTC device
  *
- * @return      EOK on success or a negative error code
+ * @return      EOK on success or an error code
  */
 static int
@@ -683,5 +682,5 @@
  * @param fun   The function node
  *
- * @return  EOK on success or a negative error code
+ * @return  EOK on success or an error code
  */
 static int
