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 a1732929ba941aba7936eef2d1f299b1f423d3b5)
+++ 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 a1732929ba941aba7936eef2d1f299b1f423d3b5)
+++ 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 a1732929ba941aba7936eef2d1f299b1f423d3b5)
+++ 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 a1732929ba941aba7936eef2d1f299b1f423d3b5)
+++ 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 a1732929ba941aba7936eef2d1f299b1f423d3b5)
+++ 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 a1732929ba941aba7936eef2d1f299b1f423d3b5)
+++ 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 a1732929ba941aba7936eef2d1f299b1f423d3b5)
+++ 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;
 
