Index: uspace/srv/hid/input/port/chardev.c
===================================================================
--- uspace/srv/hid/input/port/chardev.c	(revision 74017cef2e4edaf9405cf38ba4b0958f664e700c)
+++ uspace/srv/hid/input/port/chardev.c	(revision ac307b25a02622848f9ee9d1bff85d6cd4c35ca2)
@@ -35,8 +35,9 @@
  */
 
-#include <ipc/char.h>
 #include <async.h>
+#include <errno.h>
+#include <fibril.h>
+#include <io/chardev.h>
 #include <loc.h>
-#include <errno.h>
 #include <stdio.h>
 #include "../input.h"
@@ -44,8 +45,8 @@
 #include "../kbd.h"
 
-static void kbd_port_events(ipc_callid_t iid, ipc_call_t *icall, void *arg);
+static int kbd_port_fibril(void *);
 
 static int chardev_port_init(kbd_dev_t *);
-static void chardev_port_write(uint8_t data);
+static void chardev_port_write(uint8_t);
 
 kbd_port_ops_t chardev_port = {
@@ -56,4 +57,5 @@
 static kbd_dev_t *kbd_dev;
 static async_sess_t *dev_sess;
+static chardev_t *chardev;
 
 /** List of devices to try connecting to. */
@@ -70,6 +72,6 @@
 {
 	service_id_t service_id;
-	async_exch_t *exch;
 	unsigned int i;
+	fid_t fid;
 	int rc;
 	
@@ -96,22 +98,20 @@
 	}
 	
-	exch = async_exchange_begin(dev_sess);
-	if (exch == NULL) {
-		printf("%s: Failed starting exchange with device\n", NAME);
+	rc = chardev_open(dev_sess, &chardev);
+	if (rc != EOK) {
+		printf("%s: Failed opening character device\n", NAME);
 		async_hangup(dev_sess);
 		return ENOMEM;
 	}
 	
-	port_id_t port;
-	rc = async_create_callback_port(exch, INTERFACE_CHAR_CB, 0, 0,
-	    kbd_port_events, NULL, &port);
-	
-	async_exchange_end(exch);
-	
-	if (rc != 0) {
-		printf("%s: Failed to create callback from device\n", NAME);
+	fid = fibril_create(kbd_port_fibril, NULL);
+	if (fid == 0) {
+		printf("%s: Failed creating fibril\n", NAME);
+		chardev_close(chardev);
 		async_hangup(dev_sess);
-		return -1;
+		return ENOMEM;
 	}
+
+	fibril_add_ready(fid);
 	
 	printf("%s: Found input device '%s'\n", NAME, in_devs[i]);
@@ -121,40 +121,32 @@
 static void chardev_port_write(uint8_t data)
 {
-	async_exch_t *exch = async_exchange_begin(dev_sess);
-	if (exch == NULL) {
-		printf("%s: Failed starting exchange with device\n", NAME);
+	int rc;
+	size_t nwr;
+
+	rc = chardev_write(chardev, &data, sizeof(data), &nwr);
+	if (rc != EOK || nwr != sizeof(data)) {
+		printf("%s: Failed writing to character device\n", NAME);
 		return;
-	}
-
-	async_msg_1(exch, CHAR_WRITE_BYTE, data);
-	async_exchange_end(exch);
-}
-
-static void kbd_port_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	/* Ignore parameters, the connection is already opened */
-	while (true) {
-
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call)) {
-			/* TODO: Handle hangup */
-			return;
-		}
-
-		int retval = EOK;
-
-		switch (IPC_GET_IMETHOD(call)) {
-		case CHAR_NOTIF_BYTE:
-			kbd_push_data(kbd_dev, IPC_GET_ARG1(call));
-			break;
-		default:
-			retval = ENOENT;
-		}
-		async_answer_0(callid, retval);
 	}
 }
 
+static int kbd_port_fibril(void *arg)
+{
+	int rc;
+	size_t nread;
+	uint8_t b;
+
+	while (true) {
+		rc = chardev_read(chardev, &b, sizeof(b), &nread);
+		if (rc != EOK || nread != sizeof(b)) {
+			printf("%s: Error reading data", NAME);
+			continue;
+		}
+
+		kbd_push_data(kbd_dev, b);
+	}
+
+	return 0;
+}
 
 /**
Index: uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c
===================================================================
--- uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision 74017cef2e4edaf9405cf38ba4b0958f664e700c)
+++ uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision ac307b25a02622848f9ee9d1bff85d6cd4c35ca2)
@@ -27,7 +27,4 @@
  */
 
-/** @addtogroup driver_serial
- * @{
- */
 /**
  * @file
@@ -37,13 +34,13 @@
  */
 
+#include <async.h>
 #include <ddi.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <io/chardev_srv.h>
 #include <loc.h>
-#include <ipc/char.h>
-#include <async.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sysinfo.h>
-#include <errno.h>
-#include <inttypes.h>
 #include "s3c24xx_uart.h"
 
@@ -72,9 +69,17 @@
 static void s3c24xx_uart_sendb(s3c24xx_uart_t *, uint8_t);
 
+static int s3c24xx_uart_read(chardev_srv_t *, void *, size_t, size_t *);
+static int s3c24xx_uart_write(chardev_srv_t *, const void *, size_t, size_t *);
+
+static chardev_ops_t s3c24xx_uart_chardev_ops = {
+	.read = s3c24xx_uart_read,
+	.write = s3c24xx_uart_write
+};
+
 int main(int argc, char *argv[])
 {
 	printf("%s: S3C24xx on-chip UART driver\n", NAME);
 	
-	async_set_fallback_port_handler(s3c24xx_uart_connection, NULL);
+	async_set_fallback_port_handler(s3c24xx_uart_connection, uart);
 	int rc = loc_server_register(NAME);
 	if (rc != EOK) {
@@ -111,44 +116,15 @@
     void *arg)
 {
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		sysarg_t 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) {
-			if (uart->client_sess == NULL) {
-				uart->client_sess = sess;
-				async_answer_0(callid, EOK);
-			} else
-				async_answer_0(callid, ELIMIT);
-		} else {
-			switch (method) {
-			case CHAR_WRITE_BYTE:
-				printf(NAME ": write %" PRIun " to device\n",
-				    IPC_GET_ARG1(call));
-				s3c24xx_uart_sendb(uart, (uint8_t) IPC_GET_ARG1(call));
-				async_answer_0(callid, EOK);
-				break;
-			default:
-				async_answer_0(callid, EINVAL);
-			}
-		}
-	}
-}
+	s3c24xx_uart_t *uart = (s3c24xx_uart_t *) arg;
+
+	chardev_conn(iid, icall, &uart->cds);
+}
+
 
 static void s3c24xx_uart_irq_handler(ipc_callid_t iid, ipc_call_t *call,
     void *arg)
 {
+	int rc;
+
 	(void) iid;
 	(void) call;
@@ -159,9 +135,12 @@
 		uint32_t status = pio_read_32(&uart->io->uerstat);
 
-		if (uart->client_sess != NULL) {
-			async_exch_t *exch = async_exchange_begin(uart->client_sess);
-			async_msg_1(exch, CHAR_NOTIF_BYTE, data);
-			async_exchange_end(exch);
-		}
+		fibril_mutex_lock(&uart->buf_lock);
+
+		rc = circ_buf_push(&uart->cbuf, &data);
+		if (rc != EOK)
+			printf(NAME ": Buffer overrun\n");
+
+		fibril_mutex_unlock(&uart->buf_lock);
+		fibril_condvar_broadcast(&uart->buf_cv);
 
 		if (status != 0)
@@ -176,4 +155,8 @@
 	sysarg_t inr;
 
+	circ_buf_init(&uart->cbuf, uart->buf, s3c24xx_uart_buf_size, 1);
+	fibril_mutex_initialize(&uart->buf_lock);
+	fibril_condvar_initialize(&uart->buf_cv);
+
 	if (sysinfo_get_value("s3c24xx_uart.address.physical",
 	    &uart->paddr) != EOK)
@@ -188,5 +171,4 @@
 
 	uart->io = vaddr;
-	uart->client_sess = NULL;
 
 	printf(NAME ": device at physical address %p, inr %" PRIun ".\n",
@@ -203,4 +185,8 @@
 	    pio_read_32(&uart->io->ucon) & ~UCON_RX_INT_LEVEL);
 
+	chardev_srvs_init(&uart->cds);
+	uart->cds.ops = &s3c24xx_uart_chardev_ops;
+	uart->cds.sarg = uart;
+
 	return EOK;
 }
@@ -216,4 +202,46 @@
 }
 
+static int s3c24xx_uart_read(chardev_srv_t *srv, void *buf, size_t size,
+    size_t *nread)
+{
+	s3c24xx_uart_t *uart = (s3c24xx_uart_t *) srv->srvs->sarg;
+	size_t p;
+	uint8_t *bp = (uint8_t *) buf;
+	int rc;
+
+	fibril_mutex_lock(&uart->buf_lock);
+
+	while (circ_buf_nused(&uart->cbuf) == 0)
+		fibril_condvar_wait(&uart->buf_cv, &uart->buf_lock);
+
+	p = 0;
+	while (p < size) {
+		rc = circ_buf_pop(&uart->cbuf, &bp[p]);
+		if (rc != EOK)
+			break;
+		++p;
+	}
+
+	fibril_mutex_unlock(&uart->buf_lock);
+
+	*nread = p;
+	return EOK;
+}
+
+static int s3c24xx_uart_write(chardev_srv_t *srv, const void *data, size_t size,
+    size_t *nwr)
+{
+	s3c24xx_uart_t *uart = (s3c24xx_uart_t *) srv->srvs->sarg;
+	size_t i;
+	uint8_t *dp = (uint8_t *) data;
+
+	for (i = 0; i < size; i++)
+		s3c24xx_uart_sendb(uart, dp[i]); 
+
+	*nwr = size;
+	return EOK;
+}
+
+
 /** @}
  */
Index: uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.h
===================================================================
--- uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.h	(revision 74017cef2e4edaf9405cf38ba4b0958f664e700c)
+++ uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.h	(revision ac307b25a02622848f9ee9d1bff85d6cd4c35ca2)
@@ -38,6 +38,9 @@
 #define S3C24XX_UART_H_
 
+#include <adt/circ_buf.h>
+#include <async.h>
+#include <fibril_synch.h>
+#include <io/chardev_srv.h>
 #include <stdint.h>
-#include <async.h>
 
 /** S3C24xx UART I/O */
@@ -76,4 +79,7 @@
 #define UFCON_FIFO_ENABLE		0x01
 
+enum {
+	s3c24xx_uart_buf_size = 64
+};
 
 /** S3C24xx UART instance */
@@ -85,9 +91,18 @@
 	s3c24xx_uart_io_t *io;
 
-	/** Callback session to the client */
-	async_sess_t *client_sess;
+	/** Character device service */
+	chardev_srvs_t cds;
 
 	/** Service ID */
 	service_id_t service_id;
+
+	/** Circular buffer */
+	circ_buf_t cbuf;
+	/** Buffer */
+	uint8_t buf[s3c24xx_uart_buf_size];
+	/** Buffer lock */
+	fibril_mutex_t buf_lock;
+	/** Signal newly added data in buffer */
+	fibril_condvar_t buf_cv;
 } s3c24xx_uart_t;
 
