Index: uspace/srv/hid/compositor/compositor.c
===================================================================
--- uspace/srv/hid/compositor/compositor.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/compositor/compositor.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -56,9 +56,9 @@
 #include <loc.h>
 
-#include <event.h>
 #include <io/keycode.h>
 #include <io/mode.h>
 #include <io/visualizer.h>
 #include <io/window.h>
+#include <io/console.h>
 
 #include <transform.h>
@@ -144,5 +144,8 @@
 /** Input server proxy */
 static input_t *input;
-
+static bool active = false;
+
+static int comp_active(input_t *);
+static int comp_deactive(input_t *);
 static int comp_key_press(input_t *, kbd_event_type_t, keycode_t, keymod_t, wchar_t);
 static int comp_mouse_move(input_t *, int, int);
@@ -151,4 +154,6 @@
 
 static input_ev_ops_t input_ev_ops = {
+	.active = comp_active,
+	.deactive = comp_deactive,
 	.key = comp_key_press,
 	.move = comp_mouse_move,
@@ -156,6 +161,4 @@
 	.button = comp_mouse_button
 };
-
-static void input_disconnect(void);
 
 static pointer_t *input_pointer(input_t *input)
@@ -567,10 +570,12 @@
 
 	/* Notify visualizers about updated regions. */
-	list_foreach(viewport_list, link, viewport_t, vp) {
-		sysarg_t x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp;
-		surface_get_damaged_region(vp->surface, &x_dmg_vp, &y_dmg_vp, &w_dmg_vp, &h_dmg_vp);
-		surface_reset_damaged_region(vp->surface);
-		visualizer_update_damaged_region(
-		    vp->sess, x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp, 0, 0);
+	if (active) {
+		list_foreach(viewport_list, link, viewport_t, vp) {
+			sysarg_t x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp;
+			surface_get_damaged_region(vp->surface, &x_dmg_vp, &y_dmg_vp, &w_dmg_vp, &h_dmg_vp);
+			surface_reset_damaged_region(vp->surface);
+			visualizer_update_damaged_region(vp->sess,
+			    x_dmg_vp, y_dmg_vp, w_dmg_vp, h_dmg_vp, 0, 0);
+		}
 	}
 	
@@ -1074,4 +1079,28 @@
 }
 
+#if 0
+static void comp_shutdown(void)
+{
+	loc_service_unregister(winreg_id);
+	input_disconnect();
+	
+	/* Close all clients and their windows. */
+	fibril_mutex_lock(&window_list_mtx);
+	list_foreach(window_list, link, window_t, win) {
+		window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
+		if (event) {
+			link_initialize(&event->link);
+			event->type = WINDOW_CLOSE;
+			prodcons_produce(&win->queue, &event->link);
+		}
+	}
+	fibril_mutex_unlock(&window_list_mtx);
+	
+	async_answer_0(iid, EOK);
+	
+	/* All fibrils of the compositor will terminate soon. */
+}
+#endif
+
 static void comp_visualizer_disconnect(viewport_t *vp, ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -1082,32 +1111,10 @@
 	viewport_destroy(vp);
 	
-	/* Terminate compositor if there are no more viewports. */
-	if (list_empty(&viewport_list)) {
-		fibril_mutex_unlock(&viewport_list_mtx);
-		loc_service_unregister(winreg_id);
-		input_disconnect();
-
-		/* Close all clients and their windows. */
-		fibril_mutex_lock(&window_list_mtx);
-		list_foreach(window_list, link, window_t, win) {
-			window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
-			if (event) {
-				link_initialize(&event->link);
-				event->type = WINDOW_CLOSE;
-				prodcons_produce(&win->queue, &event->link);
-			}
-		}
-		fibril_mutex_unlock(&window_list_mtx);
-
-		async_answer_0(iid, EOK);
-
-		/* All fibrils of the compositor will terminate soon. */
-	} else {
-		fibril_mutex_unlock(&viewport_list_mtx);
-		async_answer_0(iid, EOK);
-
-		comp_restrict_pointers();
-		comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
-	}
+	fibril_mutex_unlock(&viewport_list_mtx);
+	
+	async_answer_0(iid, EOK);
+	
+	comp_restrict_pointers();
+	comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
 }
 
@@ -1780,4 +1787,18 @@
 }
 
+static int comp_active(input_t *input)
+{
+	active = true;
+	comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
+	
+	return EOK;
+}
+
+static int comp_deactive(input_t *input)
+{
+	active = false;
+	return EOK;
+}
+
 static int comp_key_press(input_t *input, kbd_event_type_t type, keycode_t key,
     keymod_t mods, wchar_t c)
@@ -2068,5 +2089,6 @@
 		fibril_mutex_unlock(&viewport_list_mtx);
 	} else if (kconsole_switch) {
-		__SYSCALL0(SYS_DEBUG_CONSOLE);
+		if (console_kcon())
+			active = false;
 	} else {
 		window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
@@ -2137,28 +2159,21 @@
 }
 
-static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
-{
-	comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
-}
-
-static int discover_viewports(void)
-{
+static void discover_viewports(void)
+{
+	fibril_mutex_lock(&discovery_mtx);
+	
 	/* Create viewports and connect them to visualizers. */
 	category_id_t cat_id;
 	int rc = loc_category_get_id("visualizer", &cat_id, IPC_FLAG_BLOCKING);
-	if (rc != EOK) {
-		printf("%s: Failed to get visualizer category.\n", NAME);
-		return -1;
-	}
+	if (rc != EOK)
+		goto ret;
 	
 	service_id_t *svcs;
 	size_t svcs_cnt = 0;
 	rc = loc_category_get_svcs(cat_id, &svcs, &svcs_cnt);
-	if (rc != EOK || svcs_cnt == 0) {
-		printf("%s: Failed to get visualizer category services.\n", NAME);
-		return -1;
-	}
-
-	fibril_mutex_lock(&viewport_list_mtx);	
+	if (rc != EOK)
+		goto ret;
+	
+	fibril_mutex_lock(&viewport_list_mtx);
 	for (size_t i = 0; i < svcs_cnt; ++i) {
 		bool exists = false;
@@ -2179,14 +2194,14 @@
 	fibril_mutex_unlock(&viewport_list_mtx);
 	
-	/* TODO damage only newly added viewports */
-	comp_damage(0, 0, UINT32_MAX, UINT32_MAX);
-	return EOK;
+	if (!list_empty(&viewport_list))
+		input_activate(input);
+	
+ret:
+	fibril_mutex_unlock(&discovery_mtx);
 }
 
 static void category_change_cb(void)
 {
-	fibril_mutex_lock(&discovery_mtx);
 	discover_viewports();
-	fibril_mutex_unlock(&discovery_mtx);
 }
 
@@ -2206,12 +2221,4 @@
 		printf("%s: Unable to register server (%s)\n", NAME, str_error(rc));
 		return -1;
-	}
-	
-	/* Register interrupt handler to switch back from kconsole. */
-	async_set_interrupt_received(interrupt_received);
-	rc = event_subscribe(EVENT_KCONSOLE, 0);
-	if (rc != EOK) {
-		printf("%s: Failed to register kconsole notifications (%s)\n",
-		    NAME, str_error(rc));
 	}
 	
@@ -2248,17 +2255,7 @@
 		input_disconnect();
 		return rc;
-	}	
-	
-	rc = discover_viewports();
-	if (rc != EOK) {
-		input_disconnect();
-		return rc;
-	}
-	
-	if (list_empty(&viewport_list)) {
-		printf("%s: Failed to get viewports.\n", NAME);
-		input_disconnect();
-		return -1;
-	}
+	}
+	
+	discover_viewports();
 	
 	comp_restrict_pointers();
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/console/console.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -41,5 +41,4 @@
 #include <str_error.h>
 #include <loc.h>
-#include <event.h>
 #include <io/con_srv.h>
 #include <io/kbd_event.h>
@@ -84,4 +83,5 @@
 /** Input server proxy */
 static input_t *input;
+static bool active = false;
 
 /** Session to the output server */
@@ -98,8 +98,8 @@
 static FIBRIL_MUTEX_INITIALIZE(switch_mtx);
 
-static console_t *prev_console = &consoles[0];
 static console_t *active_console = &consoles[0];
-static console_t *kernel_console = &consoles[KERNEL_CONSOLE];
-
+
+static int input_ev_active(input_t *);
+static int input_ev_deactive(input_t *);
 static int input_ev_key(input_t *, kbd_event_type_t, keycode_t, keymod_t, wchar_t);
 static int input_ev_move(input_t *, int, int);
@@ -108,4 +108,6 @@
 
 static input_ev_ops_t input_ev_ops = {
+	.active = input_ev_active,
+	.deactive = input_ev_deactive,
 	.key = input_ev_key,
 	.move = input_ev_move,
@@ -159,5 +161,5 @@
 	fibril_mutex_lock(&cons->mtx);
 	
-	if ((cons == active_console) && (active_console != kernel_console)) {
+	if ((active) && (cons == active_console)) {
 		output_update(output_sess, cons->fbid);
 		output_cursor_update(output_sess, cons->fbid);
@@ -173,5 +175,5 @@
 	fibril_mutex_lock(&cons->mtx);
 	
-	if ((cons == active_console) && (active_console != kernel_console))
+	if ((active) && (cons == active_console))
 		output_cursor_update(output_sess, cons->fbid);
 	
@@ -185,5 +187,5 @@
 	fibril_mutex_lock(&cons->mtx);
 	
-	if ((cons == active_console) && (active_console != kernel_console)) {
+	if ((active) && (cons == active_console)) {
 		output_damage(output_sess, cons->fbid, 0, 0, cons->cols,
 		    cons->rows);
@@ -195,6 +197,22 @@
 }
 
-static void cons_switch(console_t *cons)
-{
+static void cons_switch(unsigned int index)
+{
+	/*
+	 * The first undefined index is reserved
+	 * for switching to the kernel console.
+	 */
+	if (index == CONSOLE_COUNT) {
+		if (console_kcon())
+			active = false;
+		
+		return;
+	}
+	
+	if (index > CONSOLE_COUNT)
+		return;
+	
+	console_t *cons = &consoles[index];
+	
 	fibril_mutex_lock(&switch_mtx);
 	
@@ -204,17 +222,4 @@
 	}
 	
-	if (cons == kernel_console) {
-		output_yield(output_sess);
-		if (!console_kcon()) {
-			output_claim(output_sess);
-			fibril_mutex_unlock(&switch_mtx);
-			return;
-		}
-	}
-	
-	if (active_console == kernel_console)
-		output_claim(output_sess);
-	
-	prev_console = active_console;
 	active_console = cons;
 	
@@ -224,17 +229,19 @@
 }
 
-static console_t *cons_get_active_uspace(void)
-{
-	fibril_mutex_lock(&switch_mtx);
-	
-	console_t *active_uspace = active_console;
-	if (active_uspace == kernel_console)
-		active_uspace = prev_console;
-	
-	assert(active_uspace != kernel_console);
-	
-	fibril_mutex_unlock(&switch_mtx);
-	
-	return active_uspace;
+static int input_ev_active(input_t *input)
+{
+	active = true;
+	output_claim(output_sess);
+	cons_damage(active_console);
+	
+	return EOK;
+}
+
+static int input_ev_deactive(input_t *input)
+{
+	active = false;
+	output_yield(output_sess);
+	
+	return EOK;
 }
 
@@ -242,7 +249,7 @@
     keymod_t mods, wchar_t c)
 {
-	if ((key >= KC_F1) && (key < KC_F1 + CONSOLE_COUNT) &&
+	if ((key >= KC_F1) && (key <= KC_F1 + CONSOLE_COUNT) &&
 	    ((mods & KM_CTRL) == 0)) {
-		cons_switch(&consoles[key - KC_F1]);
+		cons_switch(key - KC_F1);
 	} else {
 		/* Got key press/release event */
@@ -259,13 +266,5 @@
 		event->c = c;
 		
-		/*
-		 * Kernel console does not read events
-		 * from us, so we will redirect them
-		 * to the (last) active userspace console
-		 * if necessary.
-		 */
-		console_t *target_console = cons_get_active_uspace();
-		
-		prodcons_produce(&target_console->input_pc,
+		prodcons_produce(&active_console->input_pc,
 		    &event->link);
 	}
@@ -509,7 +508,4 @@
 	
 	for (size_t i = 0; i < CONSOLE_COUNT; i++) {
-		if (i == KERNEL_CONSOLE)
-			continue;
-		
 		if (consoles[i].dsid == (service_id_t) IPC_GET_ARG1(*icall)) {
 			cons = &consoles[i];
@@ -556,9 +552,4 @@
 	
 	return EOK;
-}
-
-static void interrupt_received(ipc_callid_t callid, ipc_call_t *call)
-{
-	cons_switch(prev_console);
 }
 
@@ -609,54 +600,49 @@
 	output_get_caps(output_sess, &ccaps);
 	
-	/* Inititalize consoles */
-	for (size_t i = 0; i < CONSOLE_COUNT; i++) {
-		consoles[i].index = i;
-		atomic_set(&consoles[i].refcnt, 0);
-		fibril_mutex_initialize(&consoles[i].mtx);
-		prodcons_initialize(&consoles[i].input_pc);
-		consoles[i].char_remains_len = 0;
-		
-		if (i == KERNEL_CONSOLE)
-			continue;
-		
-		consoles[i].cols = cols;
-		consoles[i].rows = rows;
-		consoles[i].ccaps = ccaps;
-		consoles[i].frontbuf =
-		    chargrid_create(cols, rows, CHARGRID_FLAG_SHARED);
-		
-		if (consoles[i].frontbuf == NULL) {
-			printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
-			return false;
+	/*
+	 * Inititalize consoles only if there are
+	 * actually some output devices.
+	 */
+	if (ccaps != 0) {
+		for (size_t i = 0; i < CONSOLE_COUNT; i++) {
+			consoles[i].index = i;
+			atomic_set(&consoles[i].refcnt, 0);
+			fibril_mutex_initialize(&consoles[i].mtx);
+			prodcons_initialize(&consoles[i].input_pc);
+			consoles[i].char_remains_len = 0;
+			
+			consoles[i].cols = cols;
+			consoles[i].rows = rows;
+			consoles[i].ccaps = ccaps;
+			consoles[i].frontbuf =
+			    chargrid_create(cols, rows, CHARGRID_FLAG_SHARED);
+			
+			if (consoles[i].frontbuf == NULL) {
+				printf("%s: Unable to allocate frontbuffer %zu\n", NAME, i);
+				return false;
+			}
+			
+			consoles[i].fbid = output_frontbuf_create(output_sess,
+			    consoles[i].frontbuf);
+			if (consoles[i].fbid == 0) {
+				printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
+				return false;
+			}
+			
+			con_srvs_init(&consoles[i].srvs);
+			consoles[i].srvs.ops = &con_ops;
+			consoles[i].srvs.sarg = &consoles[i];
+			
+			char vc[LOC_NAME_MAXLEN + 1];
+			snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
+			
+			if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
+				printf("%s: Unable to register device %s\n", NAME, vc);
+				return false;
+			}
 		}
 		
-		consoles[i].fbid = output_frontbuf_create(output_sess,
-		    consoles[i].frontbuf);
-		if (consoles[i].fbid == 0) {
-			printf("%s: Unable to create frontbuffer %zu\n", NAME, i);
-			return false;
-		}
-		
-		con_srvs_init(&consoles[i].srvs);
-		consoles[i].srvs.ops = &con_ops;
-		consoles[i].srvs.sarg = &consoles[i];
-		
-		char vc[LOC_NAME_MAXLEN + 1];
-		snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
-		
-		if (loc_service_register(vc, &consoles[i].dsid) != EOK) {
-			printf("%s: Unable to register device %s\n", NAME, vc);
-			return false;
-		}
-	}
-	
-	cons_damage(active_console);
-	
-	/* Receive kernel notifications */
-	async_set_interrupt_received(interrupt_received);
-	rc = event_subscribe(EVENT_KCONSOLE, 0);
-	if (rc != EOK)
-		printf("%s: Failed to register kconsole notifications (%s)\n",
-		    NAME, str_error(rc));
+		input_activate(input);
+	}
 	
 	return true;
Index: uspace/srv/hid/console/console.h
===================================================================
--- uspace/srv/hid/console/console.h	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/console/console.h	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -36,6 +36,5 @@
 #define CONSOLE_CONSOLE_H__
 
-#define CONSOLE_COUNT   12
-#define KERNEL_CONSOLE  11
+#define CONSOLE_COUNT   11
 
 #endif
Index: uspace/srv/hid/input/input.c
===================================================================
--- uspace/srv/hid/input/input.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/input.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -54,4 +54,6 @@
 #include <io/keycode.h>
 #include <loc.h>
+#include <event.h>
+#include <str_error.h>
 #include "layout.h"
 #include "kbd.h"
@@ -62,4 +64,7 @@
 #include "input.h"
 
+bool irc_service = false;
+async_sess_t *irc_sess = NULL;
+
 #define NUM_LAYOUTS  4
 
@@ -71,8 +76,18 @@
 };
 
-static void kbd_devs_yield(void);
-static void kbd_devs_reclaim(void);
-
-async_sess_t *client_sess = NULL;
+typedef struct {
+	/** Link into the list of clients */
+	link_t link;
+	
+	/** Indicate whether the client is active */
+	bool active;
+	
+	/** Client callback session */
+	async_sess_t *sess;
+} client_t;
+
+/** List of clients */
+static list_t clients;
+static client_t *active_client = NULL;
 
 /** List of keyboard devices */
@@ -82,8 +97,28 @@
 static list_t mouse_devs;
 
-bool irc_service = false;
-async_sess_t *irc_sess = NULL;
-
 static FIBRIL_MUTEX_INITIALIZE(discovery_lock);
+
+static void *client_data_create(void)
+{
+	client_t *client = (client_t *) calloc(1, sizeof(client_t));
+	if (client == NULL)
+		return NULL;
+	
+	link_initialize(&client->link);
+	client->active = false;
+	client->sess = NULL;
+	
+	list_append(&client->link, &clients);
+	
+	return client;
+}
+
+static void client_data_destroy(void *data)
+{
+	client_t *client = (client_t *) data;
+	
+	list_remove(&client->link);
+	free(client);
+}
 
 void kbd_push_data(kbd_dev_t *kdev, sysarg_t data)
@@ -199,34 +234,50 @@
 	ev.c = layout_parse_ev(kdev->active_layout, &ev);
 	
-	async_exch_t *exch = async_exchange_begin(client_sess);
-	async_msg_4(exch, INPUT_EVENT_KEY, ev.type, ev.key, ev.mods, ev.c);
-	async_exchange_end(exch);
-}
-
-/** Mouse pointer has moved. */
+	list_foreach(clients, link, client_t, client) {
+		if (client->active) {
+			async_exch_t *exch = async_exchange_begin(client->sess);
+			async_msg_4(exch, INPUT_EVENT_KEY, ev.type, ev.key, ev.mods, ev.c);
+			async_exchange_end(exch);
+		}
+	}
+}
+
+/** Mouse pointer has moved (relative mode). */
 void mouse_push_event_move(mouse_dev_t *mdev, int dx, int dy, int dz)
 {
-	async_exch_t *exch = async_exchange_begin(client_sess);
-	if (dx || dy)
-		async_msg_2(exch, INPUT_EVENT_MOVE, dx, dy);
-	if (dz) {
-		// TODO: Implement proper wheel support
-		keycode_t code = dz > 0 ? KC_UP : KC_DOWN;
-		for (int i = 0; i < 3; ++i) {
-			async_msg_4(exch, INPUT_EVENT_KEY, KEY_PRESS, code, 0, 0);
-		}
-		async_msg_4(exch, INPUT_EVENT_KEY, KEY_RELEASE, code, 0, 0);
-	}
-	async_exchange_end(exch);
-}
-
-/** Mouse pointer has moved in absolute mode. */
+	list_foreach(clients, link, client_t, client) {
+		if (client->active) {
+			async_exch_t *exch = async_exchange_begin(client->sess);
+			
+			if ((dx) || (dy))
+				async_msg_2(exch, INPUT_EVENT_MOVE, dx, dy);
+			
+			if (dz) {
+				// TODO: Implement proper wheel support
+				keycode_t code = dz > 0 ? KC_UP : KC_DOWN;
+				
+				for (unsigned int i = 0; i < 3; i++)
+					async_msg_4(exch, INPUT_EVENT_KEY, KEY_PRESS, code, 0, 0);
+				
+				async_msg_4(exch, INPUT_EVENT_KEY, KEY_RELEASE, code, 0, 0);
+			}
+			
+			async_exchange_end(exch);
+		}
+	}
+}
+
+/** Mouse pointer has moved (absolute mode). */
 void mouse_push_event_abs_move(mouse_dev_t *mdev, unsigned int x, unsigned int y,
     unsigned int max_x, unsigned int max_y)
 {
-	if (max_x && max_y) {
-		async_exch_t *exch = async_exchange_begin(client_sess);
-		async_msg_4(exch, INPUT_EVENT_ABS_MOVE, x, y, max_x, max_y);
-		async_exchange_end(exch);
+	list_foreach(clients, link, client_t, client) {
+		if (client->active) {
+			if ((max_x) && (max_y)) {
+				async_exch_t *exch = async_exchange_begin(client->sess);
+				async_msg_4(exch, INPUT_EVENT_ABS_MOVE, x, y, max_x, max_y);
+				async_exchange_end(exch);
+			}
+		}
 	}
 }
@@ -235,11 +286,38 @@
 void mouse_push_event_button(mouse_dev_t *mdev, int bnum, int press)
 {
-	async_exch_t *exch = async_exchange_begin(client_sess);
-	async_msg_2(exch, INPUT_EVENT_BUTTON, bnum, press);
-	async_exchange_end(exch);
-}
-
+	list_foreach(clients, link, client_t, client) {
+		if (client->active) {
+			async_exch_t *exch = async_exchange_begin(client->sess);
+			async_msg_2(exch, INPUT_EVENT_BUTTON, bnum, press);
+			async_exchange_end(exch);
+		}
+	}
+}
+
+/** Arbitrate client actiovation */
+static void client_arbitration(client_t *req)
+{
+	/* Mutual exclusion of active clients */
+	list_foreach(clients, link, client_t, client)
+		client->active = (client == req);
+	
+	/* Notify clients about the arbitration */
+	list_foreach(clients, link, client_t, client) {
+		async_exch_t *exch = async_exchange_begin(client->sess);
+		async_msg_0(exch, client->active ?
+		    INPUT_EVENT_ACTIVE : INPUT_EVENT_DEACTIVE);
+		async_exchange_end(exch);
+	}
+}
+
+/** New client connection */
 static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
+	client_t *client = (client_t *) async_get_client_data();
+	if (client == NULL) {
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
 	async_answer_0(iid, EOK);
 	
@@ -249,7 +327,7 @@
 		
 		if (!IPC_GET_IMETHOD(call)) {
-			if (client_sess != NULL) {
-				async_hangup(client_sess);
-				client_sess = NULL;
+			if (client->sess != NULL) {
+				async_hangup(client->sess);
+				client->sess = NULL;
 			}
 			
@@ -261,6 +339,6 @@
 		    async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
 		if (sess != NULL) {
-			if (client_sess == NULL) {
-				client_sess = sess;
+			if (client->sess == NULL) {
+				client->sess = sess;
 				async_answer_0(callid, EOK);
 			} else
@@ -268,10 +346,7 @@
 		} else {
 			switch (IPC_GET_IMETHOD(call)) {
-			case INPUT_YIELD:
-				kbd_devs_yield();
-				async_answer_0(callid, EOK);
-				break;
-			case INPUT_RECLAIM:
-				kbd_devs_reclaim();
+			case INPUT_ACTIVATE:
+				active_client = client;
+				client_arbitration(client);
 				async_answer_0(callid, EOK);
 				break;
@@ -283,4 +358,15 @@
 }
 
+static void kconsole_event_received(ipc_callid_t callid, ipc_call_t *call)
+{
+	if (IPC_GET_ARG1(*call)) {
+		/* Kernel console activated */
+		client_arbitration(NULL);
+	} else {
+		/* Kernel console deactivated */
+		client_arbitration(active_client);
+	}
+}
+
 static kbd_dev_t *kbd_dev_new(void)
 {
@@ -292,5 +378,5 @@
 	}
 	
-	link_initialize(&kdev->kbd_devs);
+	link_initialize(&kdev->link);
 	
 	kdev->mods = KM_NUM_LOCK;
@@ -310,5 +396,5 @@
 	}
 	
-	link_initialize(&mdev->mouse_devs);
+	link_initialize(&mdev->link);
 	
 	return mdev;
@@ -336,5 +422,5 @@
 	}
 	
-	list_append(&kdev->kbd_devs, &kbd_devs);
+	list_append(&kdev->link, &kbd_devs);
 	return;
 	
@@ -364,5 +450,5 @@
 	}
 	
-	list_append(&mdev->mouse_devs, &mouse_devs);
+	list_append(&mdev->link, &mouse_devs);
 	return;
 	
@@ -373,5 +459,5 @@
 /** Add new kbdev device.
  *
- * @param service_id	Service ID of the keyboard device
+ * @param service_id Service ID of the keyboard device
  *
  */
@@ -397,5 +483,5 @@
 	}
 	
-	list_append(&kdev->kbd_devs, &kbd_devs);
+	list_append(&kdev->link, &kbd_devs);
 	*kdevp = kdev;
 	return EOK;
@@ -410,5 +496,5 @@
 /** Add new mousedev device.
  *
- * @param service_id	Service ID of the mouse device
+ * @param service_id Service ID of the mouse device
  *
  */
@@ -434,5 +520,5 @@
 	}
 	
-	list_append(&mdev->mouse_devs, &mouse_devs);
+	list_append(&mdev->link, &mouse_devs);
 	*mdevp = mdev;
 	return EOK;
@@ -489,24 +575,4 @@
 }
 
-static void kbd_devs_yield(void)
-{
-	/* For each keyboard device */
-	list_foreach(kbd_devs, kbd_devs, kbd_dev_t, kdev) {
-		/* Yield port */
-		if (kdev->port_ops != NULL)
-			(*kdev->port_ops->yield)();
-	}
-}
-
-static void kbd_devs_reclaim(void)
-{
-	/* For each keyboard device */
-	list_foreach(kbd_devs, kbd_devs, kbd_dev_t, kdev) {
-		/* Reclaim port */
-		if (kdev->port_ops != NULL)
-			(*kdev->port_ops->reclaim)();
-	}
-}
-
 static int dev_check_new_kbdevs(void)
 {
@@ -537,5 +603,5 @@
 		
 		/* Determine whether we already know this device. */
-		list_foreach(kbd_devs, kbd_devs, kbd_dev_t, kdev) {
+		list_foreach(kbd_devs, link, kbd_dev_t, kdev) {
 			if (kdev->svc_id == svcs[i]) {
 				already_known = true;
@@ -588,5 +654,5 @@
 		
 		/* Determine whether we already know this device. */
-		list_foreach(mouse_devs, mouse_devs, mouse_dev_t, mdev) {
+		list_foreach(mouse_devs, link, mouse_dev_t, mdev) {
 			if (mdev->svc_id == svcs[i]) {
 				already_known = true;
@@ -668,4 +734,5 @@
 	sysarg_t obio;
 	
+	list_initialize(&clients);
 	list_initialize(&kbd_devs);
 	list_initialize(&mouse_devs);
@@ -687,4 +754,6 @@
 	
 	/* Register driver */
+	async_set_client_data_constructor(client_data_create);
+	async_set_client_data_destructor(client_data_destroy);
 	async_set_client_connection(client_connection);
 	
@@ -701,4 +770,11 @@
 		return rc;
 	}
+	
+	/* Receive kernel notifications */
+	async_set_interrupt_received(kconsole_event_received);
+	rc = event_subscribe(EVENT_KCONSOLE, 0);
+	if (rc != EOK)
+		printf("%s: Failed to register kconsole notifications (%s)\n",
+		    NAME, str_error(rc));
 	
 	/* Start looking for new input devices */
Index: uspace/srv/hid/input/kbd.h
===================================================================
--- uspace/srv/hid/input/kbd.h	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/kbd.h	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -48,5 +48,5 @@
 typedef struct kbd_dev {
 	/** Link to kbd_devs list */
-	link_t kbd_devs;
+	link_t link;
 
 	/** Service ID (only for kbdev devices) */
Index: uspace/srv/hid/input/kbd_port.h
===================================================================
--- uspace/srv/hid/input/kbd_port.h	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/kbd_port.h	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -44,6 +44,4 @@
 typedef struct kbd_port_ops {
 	int (*init)(struct kbd_dev *);
-	void (*yield)(void);
-	void (*reclaim)(void);
 	void (*write)(uint8_t);
 } kbd_port_ops_t;
Index: uspace/srv/hid/input/mouse.h
===================================================================
--- uspace/srv/hid/input/mouse.h	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/mouse.h	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -46,5 +46,5 @@
 typedef struct mouse_dev {
 	/** Link to mouse_devs list */
-	link_t mouse_devs;
+	link_t link;
 	
 	/** Service ID (only for mousedev devices) */
Index: uspace/srv/hid/input/mouse_port.h
===================================================================
--- uspace/srv/hid/input/mouse_port.h	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/mouse_port.h	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -44,6 +44,4 @@
 typedef struct mouse_port_ops {
 	int (*init)(struct mouse_dev *);
-	void (*yield)(void);
-	void (*reclaim)(void);
 	void (*write)(uint8_t);
 } mouse_port_ops_t;
Index: uspace/srv/hid/input/port/adb.c
===================================================================
--- uspace/srv/hid/input/port/adb.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/port/adb.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -49,12 +49,8 @@
 
 static int adb_port_init(kbd_dev_t *);
-static void adb_port_yield(void);
-static void adb_port_reclaim(void);
-static void adb_port_write(uint8_t data);
+static void adb_port_write(uint8_t);
 
 kbd_port_ops_t adb_port = {
 	.init = adb_port_init,
-	.yield = adb_port_yield,
-	.reclaim = adb_port_reclaim,
 	.write = adb_port_write
 };
@@ -95,12 +91,4 @@
 	
 	return EOK;
-}
-
-static void adb_port_yield(void)
-{
-}
-
-static void adb_port_reclaim(void)
-{
 }
 
Index: uspace/srv/hid/input/port/adb_mouse.c
===================================================================
--- uspace/srv/hid/input/port/adb_mouse.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/port/adb_mouse.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -109,12 +109,4 @@
 }
 
-static void adb_port_yield(void)
-{
-}
-
-static void adb_port_reclaim(void)
-{
-}
-
 static void adb_port_write(uint8_t data)
 {
@@ -123,6 +115,4 @@
 mouse_port_ops_t adb_mouse_port = {
 	.init = adb_port_init,
-	.yield = adb_port_yield,
-	.reclaim = adb_port_reclaim,
 	.write = adb_port_write
 };
Index: uspace/srv/hid/input/port/chardev.c
===================================================================
--- uspace/srv/hid/input/port/chardev.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/port/chardev.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -47,12 +47,8 @@
 
 static int chardev_port_init(kbd_dev_t *);
-static void chardev_port_yield(void);
-static void chardev_port_reclaim(void);
 static void chardev_port_write(uint8_t data);
 
 kbd_port_ops_t chardev_port = {
 	.init = chardev_port_init,
-	.yield = chardev_port_yield,
-	.reclaim = chardev_port_reclaim,
 	.write = chardev_port_write
 };
@@ -115,12 +111,4 @@
 }
 
-static void chardev_port_yield(void)
-{
-}
-
-static void chardev_port_reclaim(void)
-{
-}
-
 static void chardev_port_write(uint8_t data)
 {
Index: uspace/srv/hid/input/port/msim.c
===================================================================
--- uspace/srv/hid/input/port/msim.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/port/msim.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -44,12 +44,8 @@
 
 static int msim_port_init(kbd_dev_t *);
-static void msim_port_yield(void);
-static void msim_port_reclaim(void);
 static void msim_port_write(uint8_t data);
 
 kbd_port_ops_t msim_port = {
 	.init = msim_port_init,
-	.yield = msim_port_yield,
-	.reclaim = msim_port_reclaim,
 	.write = msim_port_write
 };
@@ -104,12 +100,4 @@
 }
 
-static void msim_port_yield(void)
-{
-}
-
-static void msim_port_reclaim(void)
-{
-}
-
 static void msim_port_write(uint8_t data)
 {
Index: uspace/srv/hid/input/port/niagara.c
===================================================================
--- uspace/srv/hid/input/port/niagara.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/port/niagara.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -48,12 +48,8 @@
 
 static int niagara_port_init(kbd_dev_t *);
-static void niagara_port_yield(void);
-static void niagara_port_reclaim(void);
 static void niagara_port_write(uint8_t data);
 
 kbd_port_ops_t niagara_port = {
 	.init = niagara_port_init,
-	.yield = niagara_port_yield,
-	.reclaim = niagara_port_reclaim,
 	.write = niagara_port_write
 };
@@ -79,5 +75,4 @@
 static input_buffer_t input_buffer = (input_buffer_t) AS_AREA_ANY;
 
-static volatile bool polling_disabled = false;
 static void niagara_thread_impl(void *arg);
 
@@ -108,14 +103,4 @@
 	
 	return 0;
-}
-
-static void niagara_port_yield(void)
-{
-	polling_disabled = true;
-}
-
-static void niagara_port_reclaim(void)
-{
-	polling_disabled = false;
 }
 
@@ -149,6 +134,5 @@
 
 	while (1) {
-		if (polling_disabled == false)
-			niagara_key_pressed();
+		niagara_key_pressed();
 		usleep(POLL_INTERVAL);
 	}
Index: uspace/srv/hid/input/port/ns16550.c
===================================================================
--- uspace/srv/hid/input/port/ns16550.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/port/ns16550.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -46,12 +46,8 @@
 
 static int ns16550_port_init(kbd_dev_t *);
-static void ns16550_port_yield(void);
-static void ns16550_port_reclaim(void);
 static void ns16550_port_write(uint8_t data);
 
 kbd_port_ops_t ns16550_port = {
 	.init = ns16550_port_init,
-	.yield = ns16550_port_yield,
-	.reclaim = ns16550_port_reclaim,
 	.write = ns16550_port_write
 };
@@ -146,12 +142,4 @@
 }
 
-static void ns16550_port_yield(void)
-{
-}
-
-static void ns16550_port_reclaim(void)
-{
-}
-
 static void ns16550_port_write(uint8_t data)
 {
Index: uspace/srv/hid/input/port/pl050.c
===================================================================
--- uspace/srv/hid/input/port/pl050.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/port/pl050.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -46,12 +46,8 @@
 
 static int pl050_port_init(kbd_dev_t *);
-static void pl050_port_yield(void);
-static void pl050_port_reclaim(void);
 static void pl050_port_write(uint8_t data);
 
 kbd_port_ops_t pl050_port = {
 	.init = pl050_port_init,
-	.yield = pl050_port_yield,
-	.reclaim = pl050_port_reclaim,
 	.write = pl050_port_write
 };
@@ -129,12 +125,4 @@
 }
 
-static void pl050_port_yield(void)
-{
-}
-
-static void pl050_port_reclaim(void)
-{
-}
-
 static void pl050_port_write(uint8_t data)
 {
Index: uspace/srv/hid/input/port/ski.c
===================================================================
--- uspace/srv/hid/input/port/ski.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/input/port/ski.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -45,12 +45,8 @@
 
 static int ski_port_init(kbd_dev_t *);
-static void ski_port_yield(void);
-static void ski_port_reclaim(void);
 static void ski_port_write(uint8_t data);
 
 kbd_port_ops_t ski_port = {
 	.init = ski_port_init,
-	.yield = ski_port_yield,
-	.reclaim = ski_port_reclaim,
 	.write = ski_port_write
 };
@@ -64,6 +60,4 @@
 static void ski_thread_impl(void *arg);
 static int32_t ski_getchar(void);
-
-static volatile bool polling_disabled = false;
 
 /** Initialize Ski port driver. */
@@ -81,14 +75,4 @@
 
 	return 0;
-}
-
-static void ski_port_yield(void)
-{
-	polling_disabled = true;
-}
-
-static void ski_port_reclaim(void)
-{
-	polling_disabled = false;
 }
 
Index: uspace/srv/hid/remcons/remcons.c
===================================================================
--- uspace/srv/hid/remcons/remcons.c	(revision ce3efa072661e7cca5ddc305768f65fce320e41c)
+++ uspace/srv/hid/remcons/remcons.c	(revision 593e0237afd3144ed94431340aab1dd29fc7f612)
@@ -226,12 +226,11 @@
 	telnet_user_t *user = arg;
 	
-	char term[LOC_NAME_MAXLEN];
-	snprintf(term, LOC_NAME_MAXLEN, "%s/%s", "/loc", user->service_name);
-	
 	task_id_t task;
-	int rc = task_spawnl(&task, APP_GETTERM, APP_GETTERM, "-w", term, APP_SHELL, NULL);
-	if (rc != EOK) {
-		telnet_user_error(user, "Spawning `%s -w %s %s' failed: %s.",
-		    APP_GETTERM, term, APP_SHELL, str_error(rc));
+	int rc = task_spawnl(&task, APP_GETTERM, APP_GETTERM, user->service_name,
+	    "/loc", "--msg", "--", APP_SHELL, NULL);
+	if (rc != EOK) {
+		telnet_user_error(user, "Spawning `%s %s /loc --msg -- %s' "
+		    "failed: %s.", APP_GETTERM, user->service_name, APP_SHELL,
+		    str_error(rc));
 		fibril_mutex_lock(&user->guard);
 		user->task_finished = true;
