Index: uspace/srv/hid/remcons/remcons.c
===================================================================
--- uspace/srv/hid/remcons/remcons.c	(revision 09f41d3d60ae4abb40aff09edace1ef60c15b484)
+++ uspace/srv/hid/remcons/remcons.c	(revision c23a1fec0daac5c220e99d8504b30c1edb1d5fb1)
@@ -34,4 +34,5 @@
  */
 
+#include <as.h>
 #include <async.h>
 #include <errno.h>
@@ -94,4 +95,8 @@
 static void remcons_cursor_visibility(con_srv_t *, bool);
 static errno_t remcons_get_event(con_srv_t *, cons_event_t *);
+static errno_t remcons_map(con_srv_t *, sysarg_t, sysarg_t, charfield_t **);
+static void remcons_unmap(con_srv_t *);
+static void remcons_update(con_srv_t *, sysarg_t, sysarg_t, sysarg_t,
+    sysarg_t);
 
 static con_ops_t con_ops = {
@@ -110,5 +115,8 @@
 	.set_rgb_color = remcons_set_rgb_color,
 	.set_cursor_visibility = remcons_cursor_visibility,
-	.get_event = remcons_get_event
+	.get_event = remcons_get_event,
+	.map = remcons_map,
+	.unmap = remcons_unmap,
+	.update = remcons_update
 };
 
@@ -177,8 +185,12 @@
 static errno_t remcons_write(con_srv_t *srv, void *data, size_t size, size_t *nwritten)
 {
-	telnet_user_t *user = srv_to_user(srv);
+	remcons_t *remcons = srv_to_remcons(srv);
 	errno_t rc;
 
-	rc = telnet_user_send_data(user, data, size);
+	rc = telnet_user_send_data(remcons->user, data, size);
+	if (rc != EOK)
+		return rc;
+
+	rc = telnet_user_flush(remcons->user);
 	if (rc != EOK)
 		return rc;
@@ -214,4 +226,5 @@
 		remcons->user->cursor_x = col;
 		remcons->user->cursor_y = row;
+		(void)telnet_user_flush(remcons->user);
 	} else {
 		telnet_user_update_cursor_x(user, col);
@@ -306,6 +319,13 @@
 	remcons_t *remcons = srv_to_remcons(srv);
 
-	if (remcons->enable_ctl)
+	if (remcons->enable_ctl) {
+		if (!remcons->curs_visible && visible) {
+			vt100_set_pos(remcons->vt, remcons->user->cursor_x,
+			    remcons->user->cursor_y);
+		}
 		vt100_cursor_visibility(remcons->vt, visible);
+	}
+
+	remcons->curs_visible = visible;
 }
 
@@ -327,4 +347,97 @@
 
 	return EOK;
+}
+
+static errno_t remcons_map(con_srv_t *srv, sysarg_t cols, sysarg_t rows,
+    charfield_t **rbuf)
+{
+	remcons_t *remcons = srv_to_remcons(srv);
+	void *buf;
+
+	if (!remcons->enable_ctl)
+		return ENOTSUP;
+
+	if (remcons->ubuf != NULL)
+		return EBUSY;
+
+	buf = as_area_create(AS_AREA_ANY, cols * rows * sizeof(charfield_t),
+	    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE, AS_AREA_UNPAGED);
+	if (buf == AS_MAP_FAILED)
+		return ENOMEM;
+
+	remcons->ucols = cols;
+	remcons->urows = rows;
+	remcons->ubuf = buf;
+
+	*rbuf = buf;
+	return EOK;
+
+}
+
+static void remcons_unmap(con_srv_t *srv)
+{
+	remcons_t *remcons = srv_to_remcons(srv);
+	void *buf;
+
+	buf = remcons->ubuf;
+	remcons->ubuf = NULL;
+
+	if (buf != NULL)
+		as_area_destroy(buf);
+}
+
+static void remcons_update(con_srv_t *srv, sysarg_t c0, sysarg_t r0,
+    sysarg_t c1, sysarg_t r1)
+{
+	remcons_t *remcons = srv_to_remcons(srv);
+	charfield_t *ch;
+	sysarg_t col, row;
+	sysarg_t old_x, old_y;
+
+	if (remcons->ubuf == NULL)
+		return;
+
+	/* Make sure we have meaningful coordinates, within bounds */
+
+	if (c1 > remcons->ucols)
+		c1 = remcons->ucols;
+	if (c1 > remcons->user->cols)
+		c1 = remcons->user->cols;
+	if (c0 >= c1)
+		return;
+
+	if (r1 > remcons->urows)
+		r1 = remcons->urows;
+	if (r1 > remcons->user->rows)
+		r1 = remcons->user->rows;
+	if (r0 >= r1)
+		return;
+
+	/* Update screen from user buffer */
+
+	old_x = remcons->user->cursor_x;
+	old_y = remcons->user->cursor_y;
+
+	if (remcons->curs_visible)
+		vt100_cursor_visibility(remcons->vt, false);
+
+	for (row = r0; row < r1; row++) {
+		for (col = c0; col < c1; col++) {
+			vt100_set_pos(remcons->vt, col, row);
+			ch = &remcons->ubuf[row * remcons->ucols + col];
+			vt100_set_attr(remcons->vt, ch->attrs);
+			vt100_putuchar(remcons->vt, ch->ch);
+		}
+	}
+
+	if (remcons->curs_visible) {
+		old_x = remcons->user->cursor_x = old_x;
+		remcons->user->cursor_y = old_y;
+		vt100_set_pos(remcons->vt, old_x, old_y);
+		vt100_cursor_visibility(remcons->vt, true);
+	}
+
+	/* Flush data */
+	(void)telnet_user_flush(remcons->user);
 }
 
@@ -425,5 +538,5 @@
 {
 	remcons_t *remcons = (remcons_t *)arg;
-	(void)remcons;
+	(void)telnet_user_flush(remcons->user);
 }
 
@@ -446,8 +559,12 @@
 
 	if (remcons->enable_ctl) {
+		user->cols = 80;
 		user->rows = 25;
 	} else {
+		user->cols = 100;
 		user->rows = 1;
 	}
+
+	remcons->curs_visible = true;
 
 	remcons->vt = vt100_state_create((void *)remcons, 80, 25,
Index: uspace/srv/hid/remcons/remcons.h
===================================================================
--- uspace/srv/hid/remcons/remcons.h	(revision 09f41d3d60ae4abb40aff09edace1ef60c15b484)
+++ uspace/srv/hid/remcons/remcons.h	(revision c23a1fec0daac5c220e99d8504b30c1edb1d5fb1)
@@ -44,9 +44,14 @@
 #define NAMESPACE  "term"
 
+/** Remote console */
 typedef struct {
-	telnet_user_t *user;
-	vt100_state_t *vt;
-	bool enable_ctl;
-	bool enable_rgb;
+	telnet_user_t *user;	/**< telnet user */
+	vt100_state_t *vt;	/**< virtual terminal driver */
+	bool enable_ctl;	/**< enable escape control sequences */
+	bool enable_rgb;	/**< enable RGB color setting */
+	sysarg_t ucols;		/**< number of columns in user buffer */
+	sysarg_t urows;		/**< number of rows in user buffer */
+	charfield_t *ubuf;	/**< user buffer */
+	bool curs_visible;	/**< cursor is visible */
 } remcons_t;
 
Index: uspace/srv/hid/remcons/user.c
===================================================================
--- uspace/srv/hid/remcons/user.c	(revision 09f41d3d60ae4abb40aff09edace1ef60c15b484)
+++ uspace/srv/hid/remcons/user.c	(revision c23a1fec0daac5c220e99d8504b30c1edb1d5fb1)
@@ -38,4 +38,5 @@
 #include <adt/prodcons.h>
 #include <errno.h>
+#include <macros.h>
 #include <mem.h>
 #include <str_error.h>
@@ -86,4 +87,5 @@
 	user->socket_buffer_len = 0;
 	user->socket_buffer_pos = 0;
+	user->send_buf_used = 0;
 
 	fibril_condvar_initialize(&user->refcount_cv);
@@ -370,4 +372,34 @@
 }
 
+static errno_t telnet_user_send_raw(telnet_user_t *user,
+    const void *data, size_t size)
+{
+	size_t remain;
+	size_t now;
+	errno_t rc;
+
+	remain = sizeof(user->send_buf) - user->send_buf_used;
+	while (size > 0) {
+		if (remain == 0) {
+			rc = tcp_conn_send(user->conn, user->send_buf,
+			    sizeof(user->send_buf));
+			if (rc != EOK)
+				return rc;
+
+			user->send_buf_used = 0;
+			remain = sizeof(user->send_buf);
+		}
+
+		now = min(remain, size);
+		memcpy(user->send_buf + user->send_buf_used, data, now);
+		user->send_buf_used += now;
+		remain -= now;
+		data += now;
+		size -= now;
+	}
+
+	return EOK;
+}
+
 /** Send data (convert them first) to the socket, no locking.
  *
@@ -389,5 +421,5 @@
 			converted[converted_size++] = 10;
 			user->cursor_x = 0;
-			if (user->cursor_y < user->rows - 1)
+			if (user->cursor_y < (int)user->rows - 1)
 				++user->cursor_y;
 		} else {
@@ -401,5 +433,5 @@
 	}
 
-	errno_t rc = tcp_conn_send(user->conn, converted, converted_size);
+	errno_t rc = telnet_user_send_raw(user, converted, converted_size);
 	free(converted);
 
@@ -423,4 +455,21 @@
 
 	return rc;
+}
+
+errno_t telnet_user_flush(telnet_user_t *user)
+{
+	errno_t rc;
+
+	fibril_mutex_lock(&user->guard);
+	rc = tcp_conn_send(user->conn, user->send_buf, user->send_buf_used);
+
+	if (rc != EOK) {
+		fibril_mutex_unlock(&user->guard);
+		return rc;
+	}
+
+	user->send_buf_used = 0;
+	fibril_mutex_unlock(&user->guard);
+	return EOK;
 }
 
Index: uspace/srv/hid/remcons/user.h
===================================================================
--- uspace/srv/hid/remcons/user.h	(revision 09f41d3d60ae4abb40aff09edace1ef60c15b484)
+++ uspace/srv/hid/remcons/user.h	(revision c23a1fec0daac5c220e99d8504b30c1edb1d5fb1)
@@ -44,4 +44,5 @@
 
 #define BUFFER_SIZE 32
+#define SEND_BUF_SIZE 512
 
 /** Representation of a connected (human) user. */
@@ -67,4 +68,6 @@
 	size_t socket_buffer_len;
 	size_t socket_buffer_pos;
+	char send_buf[SEND_BUF_SIZE];
+	size_t send_buf_used;
 
 	/** Task id of the launched application. */
@@ -81,6 +84,8 @@
 	/** Y position of the cursor. */
 	int cursor_y;
+	/** Total number of columns */
+	unsigned cols;
 	/** Total number of rows */
-	int rows;
+	unsigned rows;
 } telnet_user_t;
 
@@ -93,4 +98,5 @@
 extern errno_t telnet_user_get_next_keyboard_event(telnet_user_t *, kbd_event_t *);
 extern errno_t telnet_user_send_data(telnet_user_t *, const char *, size_t);
+extern errno_t telnet_user_flush(telnet_user_t *);
 extern errno_t telnet_user_recv(telnet_user_t *, void *, size_t, size_t *);
 extern void telnet_user_update_cursor_x(telnet_user_t *, int);
