Index: uspace/drv/char/xtkbd/xtkbd.c
===================================================================
--- uspace/drv/char/xtkbd/xtkbd.c	(revision 5b0de4ce2d8e19d24a50e2ae3818afe49db54517)
+++ uspace/drv/char/xtkbd/xtkbd.c	(revision 65ceb4b0b11afe7b38fe481dece020ddf973cfe3)
@@ -37,8 +37,16 @@
 #include <device/char_dev.h>
 #include <ddf/log.h>
+#include <ipc/kbdev.h>
+#include <abi/ipc/methods.h>
 
 #include "xtkbd.h"
 
 static int polling(void *);
+static void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall);
+
+static ddf_dev_ops_t kbd_ops = {
+	.default_handler = default_connection_handler
+};
 
 int xt_kbd_init(xt_kbd_t *kbd, ddf_dev_t *dev)
@@ -57,8 +65,20 @@
 		return ENOMEM;
 	}
+	kbd->kbd_fun->ops = &kbd_ops;
+	kbd->kbd_fun->driver_data = kbd;
 
-	const int ret = ddf_fun_bind(kbd->kbd_fun);
+	int ret = ddf_fun_bind(kbd->kbd_fun);
 	if (ret != EOK) {
 		async_hangup(kbd->parent_sess);
+		kbd->kbd_fun->driver_data = NULL;
+		ddf_fun_destroy(kbd->kbd_fun);
+		return ENOMEM;
+	}
+
+	ret = ddf_fun_add_to_category(kbd->kbd_fun, "keyboard");
+	if (ret != EOK) {
+		async_hangup(kbd->parent_sess);
+		ddf_fun_unbind(kbd->kbd_fun);
+		kbd->kbd_fun->driver_data = NULL;
 		ddf_fun_destroy(kbd->kbd_fun);
 		return ENOMEM;
@@ -69,4 +89,5 @@
 		async_hangup(kbd->parent_sess);
 		ddf_fun_unbind(kbd->kbd_fun);
+		kbd->kbd_fun->driver_data = NULL;
 		ddf_fun_destroy(kbd->kbd_fun);
 		return ENOMEM;
@@ -88,2 +109,49 @@
 	}
 }
+/*----------------------------------------------------------------------------*/
+void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	if (fun == NULL || fun->driver_data == NULL) {
+		ddf_msg(LVL_ERROR, "%s: Missing parameter.\n", __FUNCTION__);
+		async_answer_0(icallid, EINVAL);
+		return;
+	}
+
+	const sysarg_t method = IPC_GET_IMETHOD(*icall);
+	xt_kbd_t *kbd = fun->driver_data;
+
+	switch (method) {
+	case KBDEV_SET_IND:
+		/* XT keyboards do not support setting mods */
+		async_answer_0(icallid, ENOTSUP);
+		break;
+	/* This might be ugly but async_callback_receive_start makes no
+	 * difference for incorrect call and malloc failure. */
+	case IPC_M_CONNECT_TO_ME: {
+		async_sess_t *sess =
+		    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
+		/* Probably ENOMEM error, try again. */
+		if (sess == NULL) {
+			ddf_msg(LVL_WARN,
+			    "Failed to create start input session");
+			async_answer_0(icallid, EAGAIN);
+			break;
+		}
+		if (kbd->input_sess == NULL) {
+			kbd->input_sess = sess;
+			ddf_msg(LVL_DEBUG, "Set input session");
+			async_answer_0(icallid, EOK);
+		} else {
+			ddf_msg(LVL_ERROR, "Input session already set");
+			async_answer_0(icallid, ELIMIT);
+		}
+		break;
+	}
+	default:
+			ddf_msg(LVL_ERROR,
+			    "Unknown method: %d.\n", (int)method);
+			async_answer_0(icallid, EINVAL);
+			break;
+	}
+}
