Index: uspace/drv/hid/adb-kbd/adb-kbd.c
===================================================================
--- uspace/drv/hid/adb-kbd/adb-kbd.c	(revision efb9fd0817dd86f59aee7c1c554279f4cef14c8c)
+++ uspace/drv/hid/adb-kbd/adb-kbd.c	(revision 15c5418e4090a071bc8da1b205870222f20e574e)
@@ -34,4 +34,5 @@
 #include <ddf/log.h>
 #include <errno.h>
+#include <io/chardev.h>
 #include <io/console.h>
 #include <ipc/adb.h>
Index: uspace/drv/hid/atkbd/atkbd.c
===================================================================
--- uspace/drv/hid/atkbd/atkbd.c	(revision efb9fd0817dd86f59aee7c1c554279f4cef14c8c)
+++ uspace/drv/hid/atkbd/atkbd.c	(revision 15c5418e4090a071bc8da1b205870222f20e574e)
@@ -1,3 +1,4 @@
 /*
+ * Copyright (c) 2017 Jiri Svoboda
  * Copyright (c) 2011 Jan Vesely
  * Copyright (c) 2009 Vineeth Pillai
@@ -201,17 +202,9 @@
 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;
 	
 	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);
+		ssize_t size = chardev_read(kbd->chardev, &code, 1);
 		if (size != 1)
 			return EIO;
@@ -224,9 +217,9 @@
 			map_size = sizeof(scanmap_e0) / sizeof(unsigned int);
 			
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
 		} else if (code == KBD_SCANCODE_SET_EXTENDED_SPECIAL) {
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -234,5 +227,5 @@
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -240,5 +233,5 @@
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -246,5 +239,5 @@
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -252,5 +245,5 @@
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -258,5 +251,5 @@
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -264,5 +257,5 @@
 				continue;
 
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -279,5 +272,5 @@
 		if (code == KBD_SCANCODE_KEY_RELEASE) {
 			type = KEY_RELEASE;
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -362,12 +355,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 +409,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 efb9fd0817dd86f59aee7c1c554279f4cef14c8c)
+++ uspace/drv/hid/atkbd/atkbd.h	(revision 15c5418e4090a071bc8da1b205870222f20e574e)
@@ -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 efb9fd0817dd86f59aee7c1c554279f4cef14c8c)
+++ uspace/drv/hid/ps2mouse/main.c	(revision 15c5418e4090a071bc8da1b205870222f20e574e)
@@ -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 efb9fd0817dd86f59aee7c1c554279f4cef14c8c)
+++ uspace/drv/hid/ps2mouse/ps2mouse.c	(revision 15c5418e4090a071bc8da1b205870222f20e574e)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -30,5 +31,5 @@
  */
 /** @file
- * @brief ps2 mouse driver.
+ * @brief PS/2 mouse driver.
  */
 
@@ -70,9 +71,9 @@
 #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); \
+	const ssize_t size = chardev_read((mouse)->chardev, &data, 1); \
 	if (size != 1) { \
 		ddf_msg(LVL_ERROR, "Failed reading byte: %zd)", size);\
@@ -86,9 +87,9 @@
 } 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); \
+	const ssize_t size = chardev_write((mouse)->chardev, &data, 1); \
 	if (size < 0 ) { \
 		ddf_msg(LVL_ERROR, "Failed writing byte: %hhx", value); \
@@ -99,5 +100,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,72 +109,101 @@
 
 /** 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);
+	ssize_t size = chardev_write(mouse->chardev, &report, 1);
 	if (size != 1) {
 		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);
+		rc = EIO;
+		goto error;
+	}
+
+	size = chardev_read(mouse->chardev, &report, 1);
 	if (size != 1 || report != PS2_MOUSE_ACK) {
 		ddf_msg(LVL_ERROR, "Failed to confirm data reporting: %hhx.",
 		    report);
-		ddf_fun_unbind(mouse->mouse_fun);
-		ddf_fun_destroy(mouse->mouse_fun);
-		return EIO;
+		rc = EIO;
+		goto error;
 	}
 
 	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;
-	}
+	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);
+		mouse->mouse_fun = NULL;
+	}
+
+	chardev_close(mouse->chardev);
+	mouse->chardev = NULL;
+	return rc;
 }
 
@@ -184,15 +214,11 @@
 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;
+
 	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);
+		    chardev_read(mouse->chardev, packet, PS2_BUFSIZE);
 
 		if (size != PS2_BUFSIZE) {
@@ -232,5 +258,6 @@
 		async_exchange_end(exch);
 	}
-	async_exchange_end(parent_exch);
+
+	return 0;
 }
 
@@ -241,17 +268,11 @@
 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;
+
 	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);
+		    mouse->chardev, packet, INTELLIMOUSE_BUFSIZE);
 
 		if (size != INTELLIMOUSE_BUFSIZE) {
@@ -310,5 +331,6 @@
 		async_exchange_end(exch);
 	}
-	async_exchange_end(parent_exch);
+
+	return 0;
 }
 
@@ -319,26 +341,24 @@
  * See http://www.computer-engineering.org/ps2mouse/ for details.
  */
-static int probe_intellimouse(async_exch_t *exch, bool buttons)
+static int probe_intellimouse(ps2_mouse_t *mouse, 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);
+	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 efb9fd0817dd86f59aee7c1c554279f4cef14c8c)
+++ uspace/drv/hid/ps2mouse/ps2mouse.h	(revision 15c5418e4090a071bc8da1b205870222f20e574e)
@@ -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 efb9fd0817dd86f59aee7c1c554279f4cef14c8c)
+++ uspace/drv/hid/xtkbd/xtkbd.c	(revision 15c5418e4090a071bc8da1b205870222f20e574e)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -206,20 +207,12 @@
 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;
 	
 	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);
+		ssize_t size = chardev_read(kbd->chardev, &code, 1);
 		if (size != 1)
 			return EIO;
@@ -234,5 +227,5 @@
 			map_size = sizeof(scanmap_e0) / sizeof(unsigned int);
 			
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -241,5 +234,5 @@
 			
 			if (code == 0x2a) {  /* Print Screen */
-				size = chardev_read(parent_exch, &code, 1);
+				size = chardev_read(kbd->chardev, &code, 1);
 				if (size != 1)
 					return EIO;
@@ -248,5 +241,5 @@
 					continue;
 				
-				size = chardev_read(parent_exch, &code, 1);
+				size = chardev_read(kbd->chardev, &code, 1);
 				if (size != 1)
 					return EIO;
@@ -259,5 +252,5 @@
 			
 			if (code == 0x46) {  /* Break */
-				size = chardev_read(parent_exch, &code, 1);
+				size = chardev_read(kbd->chardev, &code, 1);
 				if (size != 1)
 					return EIO;
@@ -266,5 +259,5 @@
 					continue;
 				
-				size = chardev_read(parent_exch, &code, 1);
+				size = chardev_read(kbd->chardev, &code, 1);
 				if (size != 1)
 					return EIO;
@@ -279,5 +272,5 @@
 		/* Extended special set */
 		if (code == KBD_SCANCODE_SET_EXTENDED_SPECIAL) {
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -286,5 +279,5 @@
 				continue;
 			
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -293,5 +286,5 @@
 				continue;
 			
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -300,5 +293,5 @@
 				continue;
 			
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -307,5 +300,5 @@
 				continue;
 			
-			size = chardev_read(parent_exch, &code, 1);
+			size = chardev_read(kbd->chardev, &code, 1);
 			if (size != 1)
 				return EIO;
@@ -357,7 +350,5 @@
 		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);
+		ssize_t size = chardev_write(kbd->chardev, cmds, sizeof(cmds));
 		
 		async_answer_0(icallid, size < 0 ? size : EOK);
@@ -413,48 +404,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 efb9fd0817dd86f59aee7c1c554279f4cef14c8c)
+++ uspace/drv/hid/xtkbd/xtkbd.h	(revision 15c5418e4090a071bc8da1b205870222f20e574e)
@@ -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/lib/c/generic/io/chardev.c
===================================================================
--- uspace/lib/c/generic/io/chardev.c	(revision efb9fd0817dd86f59aee7c1c554279f4cef14c8c)
+++ uspace/lib/c/generic/io/chardev.c	(revision 15c5418e4090a071bc8da1b205870222f20e574e)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -27,19 +28,62 @@
  */
 
+/** @addtogroup libc
+ * @{
+ */
+/**
+ * @file
+ * @brief Character device client interface
+ */
+
 #include <errno.h>
 #include <mem.h>
 #include <io/chardev.h>
 #include <ipc/chardev.h>
+#include <stdlib.h>
 
-ssize_t chardev_read(async_exch_t *exch, void *data, size_t size)
+/** Open character device.
+ *
+ * @param sess Session with the character device
+ * @param rchardev Place to store pointer to the new character device structure
+ *
+ * @return EOK on success, ENOMEM if out of memory, EIO on I/O error
+ */
+int chardev_open(async_sess_t *sess, chardev_t **rchardev)
 {
-	if (!exch)
-		return EBADMEM;
+	chardev_t *chardev;
+
+	chardev = calloc(1, sizeof(chardev_t));
+	if (chardev == NULL)
+		return ENOMEM;
+
+	chardev->sess = sess;
+	*rchardev = chardev;
+
+	/* EIO might be used in a future implementation */
+	return EOK;
+}
+
+/** Close character device.
+ *
+ * Frees the character device structure. The underlying session is
+ * not affected.
+ *
+ * @param chardev Character device or @c NULL
+ */
+void chardev_close(chardev_t *chardev)
+{
+	free(chardev);
+}
+
+ssize_t chardev_read(chardev_t *chardev, void *data, size_t size)
+{
 	if (size > 4 * sizeof(sysarg_t))
 		return ELIMIT;
 
+	async_exch_t *exch = async_exchange_begin(chardev->sess);
 	sysarg_t message[4] = { 0 };
 	const ssize_t ret = async_req_1_4(exch, CHARDEV_READ, size,
 	    &message[0], &message[1], &message[2], &message[3]);
+	async_exchange_end(exch);
 	if (ret > 0 && (size_t)ret <= size)
 		memcpy(data, message, size);
@@ -47,14 +91,20 @@
 }
 
-ssize_t chardev_write(async_exch_t *exch, const void *data, size_t size)
+ssize_t chardev_write(chardev_t *chardev, const void *data, size_t size)
 {
-	if (!exch)
-		return EBADMEM;
+	int ret;
+
 	if (size > 3 * sizeof(sysarg_t))
 		return ELIMIT;
 
+	async_exch_t *exch = async_exchange_begin(chardev->sess);
 	sysarg_t message[3] = { 0 };
 	memcpy(message, data, size);
-	return async_req_4_0(exch, CHARDEV_WRITE, size,
+	ret = async_req_4_0(exch, CHARDEV_WRITE, size,
 	    message[0], message[1], message[2]);
+	async_exchange_end(exch);
+	return ret;
 }
+
+/** @}
+ */
Index: uspace/lib/c/include/io/chardev.h
===================================================================
--- uspace/lib/c/include/io/chardev.h	(revision efb9fd0817dd86f59aee7c1c554279f4cef14c8c)
+++ uspace/lib/c/include/io/chardev.h	(revision 15c5418e4090a071bc8da1b205870222f20e574e)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2011 Jan Vesely
+ * Copyright (c) 2017 Jiri Svoboda
  * All rights reserved.
  *
@@ -33,9 +34,15 @@
 #define LIBC_IO_CHARDEV_H_
 
+#include <async.h>
 #include <types/common.h>
-#include <async.h>
 
-ssize_t chardev_read(async_exch_t *, void *, size_t);
-ssize_t chardev_write(async_exch_t *, const void *, size_t);
+typedef struct {
+	async_sess_t *sess;
+} chardev_t;
+
+extern int chardev_open(async_sess_t *, chardev_t **);
+extern void chardev_close(chardev_t *);
+extern ssize_t chardev_read(chardev_t *, void *, size_t);
+extern ssize_t chardev_write(chardev_t *, const void *, size_t);
 
 #endif
