Index: uspace/drv/usbkbd/main.c
===================================================================
--- uspace/drv/usbkbd/main.c	(revision 77cea413471a73ddff9936193e89cbdbbd7af0ec)
+++ uspace/drv/usbkbd/main.c	(revision 700af6229bd9b63bccacc969d5e27b85208f191f)
@@ -29,4 +29,7 @@
 #include <driver.h>
 #include <ipc/driver.h>
+#include <ipc/kbd.h>
+#include <io/keycode.h>
+#include <io/console.h>
 #include <errno.h>
 #include <fibril.h>
@@ -41,4 +44,49 @@
 #define GUESSED_POLL_ENDPOINT 1
 
+static void default_connection_handler(device_t *, ipc_callid_t, ipc_call_t *);
+static device_ops_t keyboard_ops = {
+	.default_handler = default_connection_handler
+};
+
+static int console_callback_phone = -1;
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param dev Device handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+void default_connection_handler(device_t *dev,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	sysarg_t method = IPC_GET_IMETHOD(*icall);
+
+	if (method == IPC_M_CONNECT_TO_ME) {
+		int callback = IPC_GET_ARG5(*icall);
+
+		if (console_callback_phone != -1) {
+			ipc_answer_0(icallid, ELIMIT);
+			return;
+		}
+
+		console_callback_phone = callback;
+		ipc_answer_0(icallid, EOK);
+		return;
+	}
+
+	ipc_answer_0(icallid, EINVAL);
+}
+
+static void send_key(int key, int type, wchar_t c) {
+	async_msg_4(console_callback_phone, KBD_EVENT, type, key,
+	    KM_NUM_LOCK, c);
+}
+
+static void send_alnum(int key, wchar_t c) {
+	printf(NAME ": sending key '%lc' to console\n", c);
+	send_key(key, KEY_PRESS, c);
+	send_key(key, KEY_RELEASE, c);
+}
+
 /*
  * Callbacks for parser
@@ -183,4 +231,13 @@
 		sizeof(usb_hid_report_in_callbacks_t));
 	callbacks->keyboard = usbkbd_process_keycodes;
+
+	if (console_callback_phone != -1) {
+		static size_t counter = 0;
+		counter++;
+		if (counter > 3) {
+			counter = 0;
+			send_alnum(KC_A, L'a');
+		}
+	}
 
 	usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks, 
@@ -289,4 +346,8 @@
 	fibril_add_ready(fid);
 
+	dev->ops = &keyboard_ops;
+
+	add_device_to_class(dev, "keyboard");
+
 	/*
 	 * Hurrah, device is initialized.
Index: uspace/lib/c/include/ipc/kbd.h
===================================================================
--- uspace/lib/c/include/ipc/kbd.h	(revision 77cea413471a73ddff9936193e89cbdbbd7af0ec)
+++ uspace/lib/c/include/ipc/kbd.h	(revision 700af6229bd9b63bccacc969d5e27b85208f191f)
@@ -39,7 +39,8 @@
 
 #include <ipc/ipc.h>
+#include <ipc/dev_iface.h>
 
 typedef enum {
-	KBD_YIELD = IPC_FIRST_USER_METHOD,
+	KBD_YIELD = DEV_FIRST_CUSTOM_METHOD,
 	KBD_RECLAIM
 } kbd_request_t;
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision 77cea413471a73ddff9936193e89cbdbbd7af0ec)
+++ uspace/srv/hid/console/console.c	(revision 700af6229bd9b63bccacc969d5e27b85208f191f)
@@ -317,6 +317,7 @@
 static void change_console(console_t *cons)
 {
-	if (cons == active_console)
+	if (cons == active_console) {
 		return;
+	}
 	
 	fb_pending_flush();
@@ -458,6 +459,7 @@
 			if (IPC_GET_ARG1(call) == 1) {
 				int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
-				if (newcon != -1)
+				if (newcon != -1) {
 					change_console(&consoles[newcon]);
+				}
 			}
 			retval = 0;
@@ -710,28 +712,81 @@
 }
 
-static bool console_init(char *input)
-{
-	/* Connect to input device */
-	int input_fd = open(input, O_RDONLY);
-	if (input_fd < 0) {
-		printf(NAME ": Failed opening %s\n", input);
-		return false;
-	}
-	
-	kbd_phone = fd_phone(input_fd);
-	if (kbd_phone < 0) {
+static int connect_keyboard(char *path)
+{
+	int fd = open(path, O_RDONLY);
+	if (fd < 0) {
+		return fd;
+	}
+	
+	int phone = fd_phone(fd);
+	if (phone < 0) {
 		printf(NAME ": Failed to connect to input device\n");
-		return false;
+		return phone;
 	}
 	
 	/* NB: The callback connection is slotted for removal */
 	sysarg_t phonehash;
-	if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
+	int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, SERVICE_CONSOLE,
+	    0, 0, NULL, NULL, NULL, NULL, &phonehash);
+	if (rc != EOK) {
 		printf(NAME ": Failed to create callback from input device\n");
+		return rc;
+	}
+	
+	async_new_connection(phonehash, 0, NULL, keyboard_events);
+
+	printf(NAME ": we got a hit (new keyboard \"%s\").\n", path);
+
+	return phone;
+}
+
+
+static int check_new_keyboards(void *arg)
+{
+	char *class_name = (char *) arg;
+
+	int index = 1;
+
+	while (true) {
+		async_usleep(1 * 500 * 1000);
+		char *path;
+		int rc = asprintf(&path, "/dev/class/%s\\%d", class_name, index);
+		if (rc < 0) {
+			continue;
+		}
+		rc = 0;
+		rc = connect_keyboard(path);
+		if (rc > 0) {
+			/* We do not allow unplug. */
+			index++;
+		}
+
+		free(path);
+	}
+
+	return EOK;
+}
+
+
+/** Start a fibril monitoring hot-plugged keyboards.
+ */
+static void check_new_keyboards_in_background()
+{
+	fid_t fid = fibril_create(check_new_keyboards, (void *)"keyboard");
+	if (!fid) {
+		printf(NAME ": failed to create hot-plug-watch fibril.\n");
+		return;
+	}
+	fibril_add_ready(fid);
+}
+
+static bool console_init(char *input)
+{
+	/* Connect to input device */
+	kbd_phone = connect_keyboard(input);
+	if (kbd_phone < 0) {
 		return false;
 	}
-	
-	async_new_connection(phonehash, 0, NULL, keyboard_events);
-	
+
 	/* Connect to mouse device */
 	mouse_phone = -1;
@@ -749,4 +804,5 @@
 	}
 	
+	sysarg_t phonehash;
 	if (ipc_connect_to_me(mouse_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
 		printf(NAME ": Failed to create callback from mouse device\n");
@@ -841,4 +897,7 @@
 	async_set_interrupt_received(interrupt_received);
 	
+	/* Start fibril for checking on hot-plugged keyboards. */
+	check_new_keyboards_in_background();
+
 	return true;
 }
@@ -860,5 +919,5 @@
 	if (!console_init(argv[1]))
 		return -1;
-	
+
 	printf(NAME ": Accepting connections\n");
 	async_manager();
