Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ boot/arch/amd64/Makefile.inc	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -28,5 +28,4 @@
 
 RD_SRVS_ESSENTIAL += \
-	$(USPACE_PATH)/srv/hw/char/i8042/i8042 \
 	$(USPACE_PATH)/srv/hw/irc/apic/apic \
 	$(USPACE_PATH)/srv/hw/irc/i8259/i8259
@@ -39,5 +38,8 @@
 	bus/pci/pciintel \
 	bus/isa \
+	char/i8042 \
 	char/ns8250 \
+	char/ps2mouse \
+	char/xtkbd \
 	bus/usb/ehci\
 	bus/usb/ohci \
Index: boot/arch/ia64/Makefile.inc
===================================================================
--- boot/arch/ia64/Makefile.inc	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ boot/arch/ia64/Makefile.inc	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -37,6 +37,5 @@
 RD_SRVS_NON_ESSENTIAL +=
 
-RD_SRVS_ESSENTIAL += \
-	$(USPACE_PATH)/srv/hw/char/i8042/i8042
+RD_SRVS_ESSENTIAL +=
 
 SOURCES = \
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/Makefile	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -93,5 +93,4 @@
 	srv/hid/fb \
 	srv/hid/input \
-	srv/hw/char/i8042 \
 	srv/hw/char/s3c24xx_uart \
 	srv/net/il/arp \
@@ -105,4 +104,7 @@
 	drv/infrastructure/root \
 	drv/infrastructure/rootvirt \
+	drv/char/i8042 \
+	drv/char/ps2mouse \
+	drv/char/xtkbd \
 	drv/test/test1 \
 	drv/test/test2 \
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/app/init/init.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -302,5 +302,4 @@
 	spawn("/srv/obio");
 	srv_start("/srv/cuda_adb");
-	srv_start("/srv/i8042");
 	srv_start("/srv/s3c24ser");
 	srv_start("/srv/s3c24ts");
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/drv/bus/isa/isa.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -52,4 +52,8 @@
 #include <dirent.h>
 #include <fcntl.h>
+#include <ipc/irc.h>
+#include <ipc/services.h>
+#include <sysinfo.h>
+#include <ns.h>
 #include <sys/stat.h>
 #include <ipc/irc.h>
@@ -109,7 +113,7 @@
 	sysarg_t apic;
 	sysarg_t i8259;
-	
+
 	async_sess_t *irc_sess = NULL;
-	
+
 	if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
 	    || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))) {
@@ -117,8 +121,8 @@
 		    SERVICE_IRC, 0, 0);
 	}
-	
+
 	if (!irc_sess)
 		return false;
-	
+
 	assert(isa_fun);
 	const hw_resource_list_t *res = &isa_fun->hw_resources;
@@ -127,10 +131,10 @@
 		if (res->resources[i].type == INTERRUPT) {
 			const int irq = res->resources[i].res.interrupt.irq;
-			
+
 			async_exch_t *exch = async_exchange_begin(irc_sess);
 			const int rc =
 			    async_req_1_0(exch, IRC_ENABLE_INTERRUPT, irq);
 			async_exchange_end(exch);
-			
+
 			if (rc != EOK) {
 				async_hangup(irc_sess);
@@ -139,5 +143,5 @@
 		}
 	}
-	
+
 	async_hangup(irc_sess);
 	return true;
@@ -397,5 +401,5 @@
 
 	val = skip_spaces(val);
-	irq = (int)strtol(val, &end, 0x10);
+	irq = (int)strtol(val, &end, 10);
 
 	if (val != end)
Index: uspace/drv/bus/isa/isa.dev
===================================================================
--- uspace/drv/bus/isa/isa.dev	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/drv/bus/isa/isa.dev	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -9,8 +9,10 @@
 	io_range 2f8 8
 
-keyboard:
-	match 100 isa/keyboard
+i8042:
+	match 100 isa/i8042
 	irq 1
-	io_range 060 10
+	irq 12
+	io_range 060 5
+	
 
 ne2k:
Index: uspace/drv/bus/usb/usbhid/mouse/mousedev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -52,7 +52,4 @@
 #include "../usbhid.h"
 
-/** Number of simulated arrow-key presses for singel wheel step. */
-#define ARROWS_PER_SINGLE_WHEEL 3
-
 #define NAME "mouse"
 
@@ -69,7 +66,5 @@
 
 const char *HID_MOUSE_FUN_NAME = "mouse";
-const char *HID_MOUSE_WHEEL_FUN_NAME = "mouse-wheel";
 const char *HID_MOUSE_CATEGORY = "mouse";
-const char *HID_MOUSE_WHEEL_CATEGORY = "keyboard";
 
 /** Default idle rate for mouses. */
@@ -126,15 +121,12 @@
 
 	usb_log_debug("%s: fun->name: %s\n", __FUNCTION__, fun->name);
-	usb_log_debug("%s: mouse_sess: %p, wheel_sess: %p\n",
-	    __FUNCTION__, mouse_dev->mouse_sess, mouse_dev->wheel_sess);
-
-	async_sess_t **sess_ptr = (fun == mouse_dev->mouse_fun) ?
-	    &mouse_dev->mouse_sess : &mouse_dev->wheel_sess;
+	usb_log_debug("%s: mouse_sess: %p\n",
+	    __FUNCTION__, mouse_dev->mouse_sess);
 
 	async_sess_t *sess =
 	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
 	if (sess != NULL) {
-		if (*sess_ptr == NULL) {
-			*sess_ptr = sess;
+		if (mouse_dev->mouse_sess == NULL) {
+			mouse_dev->mouse_sess = sess;
 			usb_log_debug("Console session to %s set ok (%p).\n",
 			    fun->name, sess);
@@ -144,4 +136,5 @@
 			    fun->name);
 			async_answer_0(icallid, ELIMIT);
+			async_hangup(sess);
 		}
 	} else {
@@ -150,34 +143,5 @@
 	}
 }
-
-/*----------------------------------------------------------------------------*/
-
-static void usb_mouse_send_wheel(const usb_mouse_t *mouse_dev, int wheel)
-{
-	unsigned int key = (wheel > 0) ? KC_UP : KC_DOWN;
-
-	if (mouse_dev->wheel_sess == NULL) {
-		usb_log_warning(
-		    "Connection to console not ready, wheel roll discarded.\n");
-		return;
-	}
-
-	const unsigned count =
-	    ((wheel < 0) ? -wheel : wheel) * ARROWS_PER_SINGLE_WHEEL;
-	for (unsigned i = 0; i < count; i++) {
-		/* Send arrow press and release. */
-		usb_log_debug2("Sending key %d to the console\n", key);
-		
-		async_exch_t *exch = async_exchange_begin(mouse_dev->wheel_sess);
-		
-		async_msg_4(exch, KBDEV_EVENT, KEY_PRESS, key, 0, 0);
-		async_msg_4(exch, KBDEV_EVENT, KEY_RELEASE, key, 0, 0);
-		
-		async_exchange_end(exch);
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int get_mouse_axis_move_value(uint8_t rid, usb_hid_report_t *report,
     int32_t usage)
@@ -203,5 +167,5 @@
 	return result;
 }
-
+/*----------------------------------------------------------------------------*/
 static bool usb_mouse_process_report(usb_hid_dev_t *hid_dev,
     usb_mouse_t *mouse_dev)
@@ -221,15 +185,13 @@
 	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
 
-	if ((shift_x != 0) || (shift_y != 0)) {
+	if (shift_x || shift_y || wheel) {
 		async_exch_t *exch =
 		    async_exchange_begin(mouse_dev->mouse_sess);
 		if (exch != NULL) {
-			async_req_2_0(exch, MOUSEEV_MOVE_EVENT, shift_x, shift_y);
+			async_msg_3(exch, MOUSEEV_MOVE_EVENT,
+			    shift_x, shift_y, wheel);
 			async_exchange_end(exch);
 		}
 	}
-
-	if (wheel != 0)
-		usb_mouse_send_wheel(mouse_dev, wheel);
 
 	/* Buttons */
@@ -341,58 +303,7 @@
 	mouse->mouse_fun = fun;
 
-	/*
-	 * Special function for acting as keyboard (wheel)
-	 */
-	usb_log_debug("Creating DDF function %s...\n",
-	              HID_MOUSE_WHEEL_FUN_NAME);
-	fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
-	    HID_MOUSE_WHEEL_FUN_NAME);
-	if (fun == NULL) {
-		usb_log_error("Could not create DDF function node `%s'.\n",
-		    HID_MOUSE_WHEEL_FUN_NAME);
-		FUN_UNBIND_DESTROY(mouse->mouse_fun);
-		mouse->mouse_fun = NULL;
-		return ENOMEM;
-	}
-
-	/*
-	 * Store the initialized HID device and HID ops
-	 * to the DDF function.
-	 */
-	fun->ops = &mouse->ops;
-	fun->driver_data = mouse;
-
-	rc = ddf_fun_bind(fun);
-	if (rc != EOK) {
-		usb_log_error("Could not bind DDF function `%s': %s.\n",
-		    fun->name, str_error(rc));
-		FUN_UNBIND_DESTROY(mouse->mouse_fun);
-		mouse->mouse_fun = NULL;
-
-		fun->driver_data = NULL;
-		ddf_fun_destroy(fun);
-		return rc;
-	}
-
-	usb_log_debug("Adding DDF function to category %s...\n", 
-	    HID_MOUSE_WHEEL_CATEGORY);
-	rc = ddf_fun_add_to_category(fun, HID_MOUSE_WHEEL_CATEGORY);
-	if (rc != EOK) {
-		usb_log_error(
-		    "Could not add DDF function to category %s: %s.\n",
-		    HID_MOUSE_WHEEL_CATEGORY, str_error(rc));
-
-		FUN_UNBIND_DESTROY(mouse->mouse_fun);
-		mouse->mouse_fun = NULL;
-		FUN_UNBIND_DESTROY(fun);
-		return rc;
-	}
-	mouse->wheel_fun = fun;
-
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 /** Get highest index of a button mentioned in given report.
  *
@@ -516,13 +427,5 @@
 	}
 
-	if (mouse_dev->wheel_sess != NULL) {
-		const int ret = async_hangup(mouse_dev->wheel_sess);
-		if (ret != EOK)
-			usb_log_warning("Failed to hang up wheel session: "
-			    "%p, %s.\n", mouse_dev->wheel_sess, str_error(ret));
-	}
-
 	FUN_UNBIND_DESTROY(mouse_dev->mouse_fun);
-	FUN_UNBIND_DESTROY(mouse_dev->wheel_fun);
 
 	free(mouse_dev->buttons);
Index: uspace/drv/bus/usb/usbhid/mouse/mousedev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -48,5 +48,4 @@
 	/** IPC session to console (consumer). */
 	async_sess_t *mouse_sess;
-	async_sess_t *wheel_sess;
 
 	/* Mouse buttons statuses. */
@@ -57,6 +56,4 @@
 	/* DDF mouse function */
 	ddf_fun_t *mouse_fun;
-	/* DDF mouse function */
-	ddf_fun_t *wheel_fun;
 } usb_mouse_t;
 
Index: uspace/drv/char/i8042/Makefile
===================================================================
--- uspace/drv/char/i8042/Makefile	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/i8042/Makefile	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = i8042
+
+SOURCES = \
+	i8042.c \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/char/i8042/buffer.h
===================================================================
--- uspace/drv/char/i8042/buffer.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/i8042/buffer.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @addtogroup kbd
+ * @{
+ */
+/** @file
+ * @brief Cyclic buffer structure.
+ */
+
+#ifndef BUFFER_H_
+#define BUFFER_H_
+
+#include <assert.h>
+#include <fibril_synch.h>
+
+/** Cyclic buffer that blocks on full/empty.
+ *
+ * read_head == write_head means that the buffer is empty.
+ * write_head + 1 == read_head means that the buffer is full.
+ * Attempt to insert byte into the full buffer will block until it can succeed.
+ * Attempt to read from empty buffer will block until it can succeed.
+ */
+typedef struct {
+	uint8_t *buffer;         /**< Storage space. */
+	uint8_t *buffer_end;     /**< End of storage place. */
+	fibril_mutex_t guard;    /**< Protects buffer structures. */
+	fibril_condvar_t change; /**< Indicates change (empty/full). */
+	uint8_t *read_head;      /**< Place of the next readable element. */
+	uint8_t *write_head;     /**< Pointer to the next writable place. */
+} buffer_t;
+
+/** Initialize cyclic buffer using provided memory space.
+ * @param buffer Cyclic buffer structure to initialize.
+ * @param data Memory space to use.
+ * @param size Size of the memory place.
+ */
+static inline void buffer_init(buffer_t *buffer, uint8_t *data, size_t size)
+{
+	assert(buffer);
+	fibril_mutex_initialize(&buffer->guard);
+	fibril_condvar_initialize(&buffer->change);
+	buffer->buffer = data;
+	buffer->buffer_end = data + size;
+	buffer->read_head = buffer->buffer;
+	buffer->write_head = buffer->buffer;
+	bzero(buffer->buffer, size);
+}
+
+/** Write byte to cyclic buffer.
+ * @param buffer Cyclic buffer to write to.
+ * @param data Data to write.
+ */
+static inline void buffer_write(buffer_t *buffer, uint8_t data)
+{
+	fibril_mutex_lock(&buffer->guard);
+
+	/* Next position. */
+	uint8_t *new_head = buffer->write_head + 1;
+	if (new_head == buffer->buffer_end)
+		new_head = buffer->buffer;
+
+	/* Buffer full. */
+	while (new_head == buffer->read_head)
+		fibril_condvar_wait(&buffer->change, &buffer->guard);
+
+	/* Write data. */
+	*buffer->write_head = data;
+
+	/* Buffer was empty. */
+	if (buffer->write_head == buffer->read_head)
+		fibril_condvar_broadcast(&buffer->change);
+
+	/* Move head */
+	buffer->write_head = new_head;
+	fibril_mutex_unlock(&buffer->guard);
+}
+
+/** Read byte from cyclic buffer.
+ * @param buffer Cyclic buffer to read from.
+ * @return Byte read.
+ */
+static inline uint8_t buffer_read(buffer_t *buffer)
+{
+	fibril_mutex_lock(&buffer->guard);
+	/* Buffer is empty. */
+	while (buffer->write_head == buffer->read_head)
+		fibril_condvar_wait(&buffer->change, &buffer->guard);
+
+	/* Next position. */
+	uint8_t *new_head = buffer->read_head + 1;
+	if (new_head == buffer->buffer_end)
+		new_head = buffer->buffer;
+
+	/* Read data. */
+	const uint8_t data = *buffer->read_head;
+
+	/* Buffer was full. */
+	uint8_t *new_write_head = buffer->write_head + 1;
+	if (new_write_head == buffer->buffer_end)
+		new_write_head = buffer->buffer;
+	if (new_write_head == buffer->read_head)
+		fibril_condvar_broadcast(&buffer->change);
+
+	/* Move head */
+	buffer->read_head = new_head;
+
+	fibril_mutex_unlock(&buffer->guard);
+	return data;
+}
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/char/i8042/i8042.c
===================================================================
--- uspace/drv/char/i8042/i8042.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/i8042/i8042.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2001-2004 Jakub Jermar
+ * Copyright (c) 2006 Josef Cejka
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup kbd_port
+ * @ingroup kbd
+ * @{
+ */
+/** @file
+ * @brief i8042 PS/2 port driver.
+ */
+
+#include <devman.h>
+#include <device/hw_res.h>
+#include <ddi.h>
+#include <libarch/ddi.h>
+#include <errno.h>
+#include <str_error.h>
+#include <inttypes.h>
+
+#include <ddf/log.h>
+#include <ddf/interrupt.h>
+
+#include "i8042.h"
+
+#define NAME       "i8042"
+
+void default_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+
+/** Port function operations. */
+static ddf_dev_ops_t ops = {
+	.default_handler = default_handler,
+};
+
+/* Interesting bits for status register */
+#define i8042_OUTPUT_FULL	0x01
+#define i8042_INPUT_FULL	0x02
+#define i8042_AUX_DATA		0x20
+
+/* Command constants */
+#define i8042_CMD_WRITE_CMDB	0x60	/**< write command byte */
+#define i8042_CMD_WRITE_AUX	0xd4	/**< write aux device */
+
+/* Command byte fields */
+#define i8042_KBD_IE		0x01
+#define i8042_AUX_IE		0x02
+#define i8042_KBD_DISABLE	0x10
+#define i8042_AUX_DISABLE	0x20
+#define i8042_KBD_TRANSLATE	0x40 /* Use this to switch to XT scancodes */
+
+/** i8042 Interrupt pseudo-code. */
+static const irq_cmd_t i8042_cmds[] = {
+	{
+		.cmd = CMD_PIO_READ_8,
+		.addr = NULL,	/* will be patched in run-time */
+		.dstarg = 1
+	},
+	{
+		.cmd = CMD_BTEST,
+		.value = i8042_OUTPUT_FULL,
+		.srcarg = 1,
+		.dstarg = 3
+	},
+	{
+		.cmd = CMD_PREDICATE,
+		.value = 2,
+		.srcarg = 3
+	},
+	{
+		.cmd = CMD_PIO_READ_8,
+		.addr = NULL,	/* will be patched in run-time */
+		.dstarg = 2
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+/** Wait until it is safe to write to the device. */
+static void wait_ready(i8042_t *dev)
+{
+	assert(dev);
+	while (pio_read_8(&dev->regs->status) & i8042_INPUT_FULL);
+}
+
+/** Interrupt handler routine.
+ * Writes new data to the corresponding buffer.
+ * @param dev Device that caued the interrupt.
+ * @param iid Call id.
+ * @param call pointerr to call data.
+ */
+static void i8042_irq_handler(
+    ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
+{
+	if (!dev || !dev->driver_data)
+		return;
+	i8042_t *controller = dev->driver_data;
+
+	const uint8_t status = IPC_GET_ARG1(*call);
+	const uint8_t data = IPC_GET_ARG2(*call);
+	buffer_t *buffer = (status & i8042_AUX_DATA) ?
+	    &controller->aux_buffer : &controller->kbd_buffer;
+	buffer_write(buffer, data);
+}
+
+/** Initialize i8042 driver structure.
+ * @param dev Driver structure to initialize.
+ * @param regs I/O address of registers.
+ * @param reg_size size of the reserved I/O address space.
+ * @param irq_kbd IRQ for primary port.
+ * @param irq_mouse IRQ for aux port.
+ * @param ddf_dev DDF device structure of the device.
+ * @return Error code.
+ */
+int i8042_init(i8042_t *dev, void *regs, size_t reg_size, int irq_kbd,
+    int irq_mouse, ddf_dev_t *ddf_dev)
+{
+	assert(ddf_dev);
+	assert(dev);
+
+	if (reg_size < sizeof(i8042_regs_t))
+		return EINVAL;
+
+	if (pio_enable(regs, sizeof(i8042_regs_t), (void**)&dev->regs) != 0)
+		return -1;
+
+	dev->kbd_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2a");
+	if (!dev->kbd_fun)
+		return ENOMEM;
+	int ret = ddf_fun_add_match_id(dev->kbd_fun, "char/xtkbd", 90);
+	if (ret != EOK) {
+		ddf_fun_destroy(dev->kbd_fun);
+		return ret;
+	}
+
+	dev->aux_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2b");
+	if (!dev->aux_fun) {
+		ddf_fun_destroy(dev->kbd_fun);
+		return ENOMEM;
+	}
+
+	ret = ddf_fun_add_match_id(dev->aux_fun, "char/ps2mouse", 90);
+	if (ret != EOK) {
+		ddf_fun_destroy(dev->kbd_fun);
+		ddf_fun_destroy(dev->aux_fun);
+		return ret;
+	}
+
+	dev->kbd_fun->ops = &ops;
+	dev->aux_fun->ops = &ops;
+	dev->kbd_fun->driver_data = dev;
+	dev->aux_fun->driver_data = dev;
+
+	buffer_init(&dev->kbd_buffer, dev->kbd_data, BUFFER_SIZE);
+	buffer_init(&dev->aux_buffer, dev->aux_data, BUFFER_SIZE);
+	fibril_mutex_initialize(&dev->write_guard);
+
+#define CHECK_RET_DESTROY(ret, msg...) \
+if  (ret != EOK) { \
+	ddf_msg(LVL_ERROR, msg); \
+	if (dev->kbd_fun) { \
+		dev->kbd_fun->driver_data = NULL; \
+		ddf_fun_destroy(dev->kbd_fun); \
+	} \
+	if (dev->aux_fun) { \
+		dev->aux_fun->driver_data = NULL; \
+		ddf_fun_destroy(dev->aux_fun); \
+	} \
+} else (void)0
+
+	ret = ddf_fun_bind(dev->kbd_fun);
+	CHECK_RET_DESTROY(ret,
+	    "Failed to bind keyboard function: %s.", str_error(ret));
+
+	ret = ddf_fun_bind(dev->aux_fun);
+	CHECK_RET_DESTROY(ret,
+	    "Failed to bind mouse function: %s.", str_error(ret));
+
+	/* Disable kbd and aux */
+	wait_ready(dev);
+	pio_write_8(&dev->regs->status, i8042_CMD_WRITE_CMDB);
+	wait_ready(dev);
+	pio_write_8(&dev->regs->data, i8042_KBD_DISABLE | i8042_AUX_DISABLE);
+
+	/* Flush all current IO */
+	while (pio_read_8(&dev->regs->status) & i8042_OUTPUT_FULL)
+		(void) pio_read_8(&dev->regs->data);
+
+#define CHECK_RET_UNBIND_DESTROY(ret, msg...) \
+if  (ret != EOK) { \
+	ddf_msg(LVL_ERROR, msg); \
+	if (dev->kbd_fun) { \
+		ddf_fun_unbind(dev->kbd_fun); \
+		dev->kbd_fun->driver_data = NULL; \
+		ddf_fun_destroy(dev->kbd_fun); \
+	} \
+	if (dev->aux_fun) { \
+		ddf_fun_unbind(dev->aux_fun); \
+		dev->aux_fun->driver_data = NULL; \
+		ddf_fun_destroy(dev->aux_fun); \
+	} \
+} else (void)0
+
+	const size_t cmd_count = sizeof(i8042_cmds) / sizeof(irq_cmd_t);
+	irq_cmd_t cmds[cmd_count];
+	memcpy(cmds, i8042_cmds, sizeof(i8042_cmds));
+	cmds[0].addr = (void *) &dev->regs->status;
+	cmds[3].addr = (void *) &dev->regs->data;
+
+	irq_code_t irq_code = { .cmdcount = cmd_count, .cmds = cmds };
+	ret = register_interrupt_handler(ddf_dev, irq_kbd, i8042_irq_handler,
+	    &irq_code);
+	CHECK_RET_UNBIND_DESTROY(ret,
+	    "Failed set handler for kbd: %s.", str_error(ret));
+
+	ret = register_interrupt_handler(ddf_dev, irq_mouse, i8042_irq_handler,
+	    &irq_code);
+	CHECK_RET_UNBIND_DESTROY(ret,
+	    "Failed set handler for mouse: %s.", str_error(ret));
+
+	/* Enable interrupts */
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, ddf_dev->handle,
+	    IPC_FLAG_BLOCKING);
+	ret = parent_sess ? EOK : ENOMEM;
+	CHECK_RET_UNBIND_DESTROY(ret, "Failed to create parent connection.");
+
+	const bool enabled = hw_res_enable_interrupt(parent_sess);
+	async_hangup(parent_sess);
+	ret = enabled ? EOK : EIO;
+	CHECK_RET_UNBIND_DESTROY(ret, "Failed to enable interrupts: %s.");
+
+	/* Enable port interrupts. */
+	wait_ready(dev);
+	pio_write_8(&dev->regs->status, i8042_CMD_WRITE_CMDB);
+	wait_ready(dev);
+	pio_write_8(&dev->regs->data, i8042_KBD_IE | i8042_KBD_TRANSLATE |
+	    i8042_AUX_IE);
+
+	return EOK;
+}
+
+// TODO use shared instead this
+enum {
+	IPC_CHAR_READ = DEV_FIRST_CUSTOM_METHOD,
+	IPC_CHAR_WRITE,
+};
+
+/** Write data to i8042 port.
+ * @param fun DDF function.
+ * @param buffer Data source.
+ * @param size Data size.
+ * @return Bytes written.
+ */
+static int i8042_write(ddf_fun_t *fun, char *buffer, size_t size)
+{
+	assert(fun);
+	assert(fun->driver_data);
+	i8042_t *controller = fun->driver_data;
+	fibril_mutex_lock(&controller->write_guard);
+	for (size_t i = 0; i < size; ++i) {
+		wait_ready(controller);
+		if (controller->aux_fun == fun)
+			pio_write_8(
+			    &controller->regs->status, i8042_CMD_WRITE_AUX);
+		pio_write_8(&controller->regs->data, buffer[i]);
+	}
+	fibril_mutex_unlock(&controller->write_guard);
+	return size;
+}
+
+/** Read data from i8042 port.
+ * @param fun DDF function.
+ * @param buffer Data place.
+ * @param size Data place size.
+ * @return Bytes read.
+ */
+static int i8042_read(ddf_fun_t *fun, char *data, size_t size)
+{
+	assert(fun);
+	assert(fun->driver_data);
+
+	i8042_t *controller = fun->driver_data;
+	buffer_t *buffer = (fun == controller->aux_fun) ?
+	    &controller->aux_buffer : &controller->kbd_buffer;
+	for (size_t i = 0; i < size; ++i) {
+		*data++ = buffer_read(buffer);
+	}
+	return size;
+}
+
+/** Handle data requests.
+ * @param fun ddf_fun_t function.
+ * @param id callid
+ * @param call IPC request.
+ */
+void default_handler(ddf_fun_t *fun, ipc_callid_t id, ipc_call_t *call)
+{
+	const sysarg_t method = IPC_GET_IMETHOD(*call);
+	const size_t size = IPC_GET_ARG1(*call);
+	switch (method) {
+	case IPC_CHAR_READ:
+		if (size <= 4 * sizeof(sysarg_t)) {
+			sysarg_t message[4] = {};
+			i8042_read(fun, (char*)message, size);
+			async_answer_4(id, size, message[0], message[1],
+			    message[2], message[3]);
+		} else {
+			async_answer_0(id, ELIMIT);
+		}
+		break;
+
+	case IPC_CHAR_WRITE:
+		if (size <= 3 * sizeof(sysarg_t)) {
+			const sysarg_t message[3] = {
+				IPC_GET_ARG2(*call), IPC_GET_ARG3(*call),
+				IPC_GET_ARG4(*call) };
+			i8042_write(fun, (char*)message, size);
+			async_answer_0(id, size);
+		} else {
+			async_answer_0(id, ELIMIT);
+		}
+
+	default:
+		async_answer_0(id, EINVAL);
+	}
+}
+/**
+ * @}
+ */
Index: uspace/drv/char/i8042/i8042.h
===================================================================
--- uspace/drv/char/i8042/i8042.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/i8042/i8042.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2006 Josef Cejka
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup kbd_port
+ * @ingroup  kbd
+ * @{
+ */
+/** @file
+ * @brief i8042 port driver.
+ */
+
+#ifndef i8042_H_
+#define i8042_H_
+
+#include <sys/types.h>
+#include <fibril_synch.h>
+#include <ddf/driver.h>
+
+#include "buffer.h"
+
+#define BUFFER_SIZE 12
+
+/** i8042 HW I/O interface */
+typedef struct {
+	ioport8_t data;
+	uint8_t pad[3];
+	ioport8_t status;
+} __attribute__ ((packed)) i8042_regs_t;
+
+/** i8042 driver structure. */
+typedef struct i8042 {
+	i8042_regs_t *regs;    /**< I/O registers. */
+	ddf_fun_t *kbd_fun;    /**< Pirmary port device function. */
+	ddf_fun_t *aux_fun;  /**< Auxiliary port device function. */
+	buffer_t kbd_buffer;   /**< Primary port buffer. */
+	buffer_t aux_buffer;   /**< Aux. port buffer. */
+	uint8_t aux_data[BUFFER_SIZE];  /**< Primary port buffer space. */
+	uint8_t kbd_data[BUFFER_SIZE];  /**< Aux. port buffer space. */
+	fibril_mutex_t write_guard;     /**< Prevents simultanous port writes.*/
+} i8042_t;
+
+int i8042_init(i8042_t *, void *, size_t, int, int, ddf_dev_t *);
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/char/i8042/i8042.ma
===================================================================
--- uspace/drv/char/i8042/i8042.ma	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/i8042/i8042.ma	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,1 @@
+100 isa/i8042
Index: uspace/drv/char/i8042/main.c
===================================================================
--- uspace/drv/char/i8042/main.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/i8042/main.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvi8042
+ * @{
+ */
+/** @file
+ * @brief i8042 driver DDF bits.
+ */
+
+#include <libarch/inttypes.h>
+#include <ddf/driver.h>
+#include <devman.h>
+#include <device/hw_res_parsed.h>
+#include <errno.h>
+#include <str_error.h>
+#include <ddf/log.h>
+#include <stdio.h>
+
+#include "i8042.h"
+
+#define NAME "i8042"
+
+static int get_my_registers(const ddf_dev_t *dev,
+    uintptr_t *io_reg_address, size_t *io_reg_size, int *kbd, int *mouse);
+static int i8042_dev_add(ddf_dev_t *device);
+
+/** DDF driver operations. */
+static driver_ops_t i8042_driver_ops = {
+	.dev_add = i8042_dev_add,
+};
+
+/** DDF driver. */
+static driver_t i8042_driver = {
+	.name = NAME,
+	.driver_ops = &i8042_driver_ops
+};
+
+/** Initialize global driver structures (NONE).
+ *
+ * @param[in] argc Nmber of arguments in argv vector (ignored).
+ * @param[in] argv Cmdline argument vector (ignored).
+ * @return Error code.
+ *
+ * Driver debug level is set here.
+ */
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS ps/2 driver.\n");
+	ddf_log_init(NAME, LVL_NOTE);
+	return ddf_driver_main(&i8042_driver);
+}
+
+/** Initialize a new ddf driver instance of i8042 driver
+ *
+ * @param[in] device DDF instance of the device to initialize.
+ * @return Error code.
+ */
+static int i8042_dev_add(ddf_dev_t *device)
+{
+	if (!device)
+		return EINVAL;
+
+#define CHECK_RET_RETURN(ret, message...) \
+if (ret != EOK) { \
+	ddf_msg(LVL_ERROR, message); \
+	return ret; \
+} else (void)0
+
+	uintptr_t io_regs = 0;
+	size_t io_size = 0;
+	int kbd = 0, mouse = 0;
+
+	int ret = get_my_registers(device, &io_regs, &io_size, &kbd, &mouse);
+	CHECK_RET_RETURN(ret,
+	    "Failed to get registers: %s.", str_error(ret));
+	ddf_msg(LVL_DEBUG,
+	    "I/O regs at %p (size %zuB), IRQ kbd %d, IRQ mouse %d.",
+	    (void *) io_regs, io_size, kbd, mouse);
+
+	i8042_t *i8042 = ddf_dev_data_alloc(device, sizeof(i8042_t));
+	ret = (i8042 == NULL) ? ENOMEM : EOK;
+	CHECK_RET_RETURN(ret, "Failed to allocate i8042 driver instance.");
+
+	ret = i8042_init(i8042, (void*)io_regs, io_size, kbd, mouse, device);
+	CHECK_RET_RETURN(ret,
+	    "Failed to initialize i8042 driver: %s.", str_error(ret));
+
+	ddf_msg(LVL_NOTE, "Controlling '%s' (%" PRIun ").",
+	    device->name, device->handle);
+	return EOK;
+}
+
+/** Get address of I/O registers.
+ *
+ * @param[in] dev Device asking for the addresses.
+ * @param[out] io_reg_address Base address of the memory range.
+ * @param[out] io_reg_size Size of the memory range.
+ * @param[out] kbd_irq Primary port IRQ.
+ * @param[out] mouse_irq Auxiliary port IRQ.
+ * @return Error code.
+ */
+int get_my_registers(const ddf_dev_t *dev, uintptr_t *io_reg_address,
+    size_t *io_reg_size, int *kbd_irq, int *mouse_irq)
+{
+	assert(dev);
+
+	async_sess_t *parent_sess =
+	    devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle,
+	    IPC_FLAG_BLOCKING);
+	if (!parent_sess)
+		return ENOMEM;
+
+	hw_res_list_parsed_t hw_resources;
+	hw_res_list_parsed_init(&hw_resources);
+	const int ret = hw_res_get_list_parsed(parent_sess, &hw_resources, 0);
+	async_hangup(parent_sess);
+	if (ret != EOK) {
+		return ret;
+	}
+
+	if (hw_resources.irqs.count != 2 || hw_resources.io_ranges.count != 1) {
+		hw_res_list_parsed_clean(&hw_resources);
+		return EINVAL;
+	}
+
+	if (io_reg_address)
+		*io_reg_address = hw_resources.io_ranges.ranges[0].address;
+
+	if (io_reg_size)
+		*io_reg_size = hw_resources.io_ranges.ranges[0].size;
+
+	if (kbd_irq)
+		*kbd_irq = hw_resources.irqs.irqs[0];
+
+	if (mouse_irq)
+		*mouse_irq = hw_resources.irqs.irqs[1];
+
+	hw_res_list_parsed_clean(&hw_resources);
+	return EOK;
+}
+/**
+ * @}
+ */
Index: uspace/drv/char/ps2mouse/Makefile
===================================================================
--- uspace/drv/char/ps2mouse/Makefile	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/ps2mouse/Makefile	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2011 Jan Vesely
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = ps2mouse
+
+SOURCES = \
+	chardev.c \
+	main.c \
+	ps2mouse.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/char/ps2mouse/chardev.c
===================================================================
--- uspace/drv/char/ps2mouse/chardev.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/ps2mouse/chardev.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <mem.h>
+#include <ipc/dev_iface.h>
+#include <ddf/log.h>
+
+#include "chardev.h"
+
+// TODO make this shared
+enum {
+	IPC_CHAR_READ = DEV_FIRST_CUSTOM_METHOD,
+	IPC_CHAR_WRITE,
+};
+
+ssize_t chardev_read(async_exch_t *exch, void *data, size_t size)
+{
+	if (!exch)
+		return EBADMEM;
+	if (size > 4 * sizeof(sysarg_t))
+		return ELIMIT;
+
+	sysarg_t message[4] = { 0 };
+	const ssize_t ret = async_req_1_4(exch, IPC_CHAR_READ, size,
+	    &message[0], &message[1], &message[2], &message[3]);
+	if (ret > 0 && (size_t)ret <= size)
+		memcpy(data, message, size);
+	return ret;
+}
+
+ssize_t chardev_write(async_exch_t *exch, const void *data, size_t size)
+{
+	if (!exch)
+		return EBADMEM;
+	if (size > 3 * sizeof(sysarg_t))
+		return ELIMIT;
+
+	sysarg_t message[3] = { 0 };
+	memcpy(message, data, size);
+	return async_req_4_0(exch, IPC_CHAR_WRITE, size,
+	    message[0], message[1], message[2]);
+}
Index: uspace/drv/char/ps2mouse/chardev.h
===================================================================
--- uspace/drv/char/ps2mouse/chardev.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/ps2mouse/chardev.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvmouse
+ * @{
+ */
+/** @file
+ * @brief ps/2 mouse driver.
+ */
+
+#ifndef _CHARDEV_H_
+#define _CHARDEV_H_
+
+#include <libarch/types.h>
+#include <async.h>
+
+ssize_t chardev_read(async_exch_t *, void *, size_t);
+ssize_t chardev_write(async_exch_t *, const void *, size_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/char/ps2mouse/main.c
===================================================================
--- uspace/drv/char/ps2mouse/main.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/ps2mouse/main.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvmouse
+ * @{
+ */
+/** @file
+ * @brief ps/2 mouse driver
+ */
+
+#include <libarch/inttypes.h>
+#include <ddf/driver.h>
+#include <devman.h>
+#include <device/hw_res_parsed.h>
+#include <errno.h>
+#include <str_error.h>
+#include <ddf/log.h>
+#include <stdio.h>
+
+#include "ps2mouse.h"
+
+#define NAME "ps2mouse"
+
+static int mouse_add(ddf_dev_t *device);
+
+/** DDF driver ops. */
+static driver_ops_t mouse_driver_ops = {
+	.dev_add = mouse_add,
+};
+
+/** DDF driver structure. */
+static driver_t mouse_driver = {
+	.name = NAME,
+	.driver_ops = &mouse_driver_ops
+};
+
+/** Initialize global driver structures (NONE).
+ *
+ * @param[in] argc Nmber of arguments in argv vector (ignored).
+ * @param[in] argv Cmdline argument vector (ignored).
+ * @return Error code.
+ *
+ * Driver debug level is set here.
+ */
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS ps/2 mouse driver.\n");
+	ddf_log_init(NAME, LVL_NOTE);
+	return ddf_driver_main(&mouse_driver);
+}
+
+/** Initialize a new ddf driver instance
+ *
+ * @param[in] device DDF instance of the device to initialize.
+ * @return Error code.
+ */
+static int mouse_add(ddf_dev_t *device)
+{
+	if (!device)
+		return EINVAL;
+
+#define CHECK_RET_RETURN(ret, message...) \
+if (ret != EOK) { \
+	ddf_msg(LVL_ERROR, message); \
+	return ret; \
+} else (void)0
+
+	ps2_mouse_t *mouse = ddf_dev_data_alloc(device, sizeof(ps2_mouse_t));
+	int ret = (mouse == NULL) ? ENOMEM : EOK;
+	CHECK_RET_RETURN(ret, "Failed to allocate mouse driver instance.");
+
+	ret = ps2_mouse_init(mouse, device);
+	CHECK_RET_RETURN(ret,
+	    "Failed to initialize mouse driver: %s.", str_error(ret));
+
+	ddf_msg(LVL_NOTE, "Controlling '%s' (%" PRIun ").",
+	    device->name, device->handle);
+	return EOK;
+}
+/**
+ * @}
+ */
Index: uspace/drv/char/ps2mouse/ps2mouse.c
===================================================================
--- uspace/drv/char/ps2mouse/ps2mouse.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/ps2mouse/ps2mouse.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvmouse
+ * @{
+ */
+/** @file
+ * @brief ps2 mouse driver.
+ */
+
+#include <bool.h>
+#include <errno.h>
+#include <devman.h>
+#include <ddf/log.h>
+#include <io/keycode.h>
+#include <io/console.h>
+#include <ipc/mouseev.h>
+#include <abi/ipc/methods.h>
+
+#include "ps2mouse.h"
+#include "chardev.h"
+
+#define PS2_MOUSE_GET_DEVICE_ID   0xf2
+#define PS2_MOUSE_SET_SAMPLE_RATE   0xf3
+#define PS2_MOUSE_ENABLE_DATA_REPORT   0xf4
+#define PS2_MOUSE_ACK   0xfa
+
+#define PS2_BUFSIZE 3
+#define INTELLIMOUSE_BUFSIZE 4
+
+#define Z_SIGN (1 << 3) /* 4th byte */
+#define X_SIGN (1 << 4) /* 1st byte */
+#define Y_SIGN (1 << 5) /* 1st byte */
+#define X_OVERFLOW (1 << 6) /* 1st byte */
+#define Y_OVERFLOW (1 << 7) /* 1st byte */
+
+#define BUTTON_LEFT   0
+#define BUTTON_RIGHT   1
+#define BUTTON_MIDDLE   2
+#define PS2_BUTTON_COUNT   3
+
+#define INTELLIMOUSE_ALWAYS_ZERO (0xc0)
+#define INTELLIMOUSE_BUTTON_4 (1 << 4) /* 4th byte */
+#define INTELLIMOUSE_BUTTON_5 (1 << 5) /* 4th byte */
+#define INTELLIMOUSE_BUTTON_COUNT 5
+
+#define PS2_BUTTON_MASK(button) (1 << button)
+
+#define MOUSE_READ_BYTE_TEST(sess, value) \
+do { \
+	uint8_t data = 0; \
+	const ssize_t size = chardev_read(sess, &data, 1); \
+	if (size != 1) { \
+		ddf_msg(LVL_ERROR, "Failed reading byte: %d)", size);\
+		return size < 0 ? size : EIO; \
+	} \
+	if (data != (value)) { \
+		ddf_msg(LVL_ERROR, "Failed testing byte: got %hhx vs. %hhx)", \
+		    data, (value)); \
+		return EIO; \
+	} \
+} while (0)
+
+#define MOUSE_WRITE_BYTE(sess, value) \
+do { \
+	uint8_t data = (value); \
+	const ssize_t size = chardev_write(sess, &data, 1); \
+	if (size < 0 ) { \
+		ddf_msg(LVL_ERROR, "Failed writing byte: %hhx", value); \
+		return size; \
+	} \
+} while (0)
+
+static int polling_ps2(void *);
+static int polling_intellimouse(void *);
+static int probe_intellimouse(async_exch_t *, bool);
+static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+
+/** ps/2 mouse driver ops. */
+static ddf_dev_ops_t mouse_ops = {
+	.default_handler = default_connection_handler
+};
+
+/** Initialize mouse driver structure.
+ * @param kbd Mouse driver structure to initialize.
+ * @param dev DDF device structure.
+ *
+ * Connects to parent, creates keyboard function, starts polling fibril.
+ */
+int ps2_mouse_init(ps2_mouse_t *mouse, ddf_dev_t *dev)
+{
+	assert(mouse);
+	assert(dev);
+	mouse->input_sess = NULL;
+	mouse->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
+	    dev->handle, IPC_FLAG_BLOCKING);
+	if (!mouse->parent_sess)
+		return ENOMEM;
+
+	mouse->mouse_fun = ddf_fun_create(dev, fun_exposed, "mouse");
+	if (!mouse->mouse_fun) {
+		async_hangup(mouse->parent_sess);
+		return ENOMEM;
+	}
+	mouse->mouse_fun->ops = &mouse_ops;
+	mouse->mouse_fun->driver_data = mouse;
+
+	int ret = ddf_fun_bind(mouse->mouse_fun);
+	if (ret != EOK) {
+		async_hangup(mouse->parent_sess);
+		mouse->mouse_fun->driver_data = NULL;
+		ddf_fun_destroy(mouse->mouse_fun);
+		return ENOMEM;
+	}
+
+	ret = ddf_fun_add_to_category(mouse->mouse_fun, "mouse");
+	if (ret != EOK) {
+		async_hangup(mouse->parent_sess);
+		ddf_fun_unbind(mouse->mouse_fun);
+		mouse->mouse_fun->driver_data = NULL;
+		ddf_fun_destroy(mouse->mouse_fun);
+		return ENOMEM;
+	}
+	/* Probe IntelliMouse extensions. */
+	int (*polling_f)(void*) = polling_ps2;
+	async_exch_t *exch = async_exchange_begin(mouse->parent_sess);
+	if (probe_intellimouse(exch, false) == EOK) {
+		ddf_msg(LVL_NOTE, "Enabled IntelliMouse extensions");
+		polling_f = polling_intellimouse;
+		if (probe_intellimouse(exch, true) == EOK)
+			ddf_msg(LVL_NOTE, "Enabled 4th and 5th button.");
+	}
+	/* Enable mouse data reporting. */
+	uint8_t report = PS2_MOUSE_ENABLE_DATA_REPORT;
+	ssize_t size = chardev_write(exch, &report, 1);
+	if (size != 1) {
+		ddf_msg(LVL_ERROR, "Failed to enable data reporting.");
+		async_exchange_end(exch);
+		async_hangup(mouse->parent_sess);
+		ddf_fun_unbind(mouse->mouse_fun);
+		mouse->mouse_fun->driver_data = NULL;
+		ddf_fun_destroy(mouse->mouse_fun);
+		return EIO;
+	}
+
+	size = chardev_read(exch, &report, 1);
+	async_exchange_end(exch);
+	if (size != 1 || report != PS2_MOUSE_ACK) {
+		ddf_msg(LVL_ERROR, "Failed to confirm data reporting: %hhx.",
+		    report);
+		async_hangup(mouse->parent_sess);
+		ddf_fun_unbind(mouse->mouse_fun);
+		mouse->mouse_fun->driver_data = NULL;
+		ddf_fun_destroy(mouse->mouse_fun);
+		return EIO;
+	}
+
+	mouse->polling_fibril = fibril_create(polling_f, mouse);
+	if (!mouse->polling_fibril) {
+		async_hangup(mouse->parent_sess);
+		ddf_fun_unbind(mouse->mouse_fun);
+		mouse->mouse_fun->driver_data = NULL;
+		ddf_fun_destroy(mouse->mouse_fun);
+		return ENOMEM;
+	}
+	fibril_add_ready(mouse->polling_fibril);
+	return EOK;
+}
+
+/** Get data and parse ps2 protocol packets.
+ * @param arg Pointer to ps2_mouse_t structure.
+ * @return Never.
+ */
+int polling_ps2(void *arg)
+{
+	assert(arg);
+	const ps2_mouse_t *mouse = arg;
+
+	assert(mouse->parent_sess);
+	bool buttons[PS2_BUTTON_COUNT] = {};
+	async_exch_t *parent_exch = async_exchange_begin(mouse->parent_sess);
+	while (1) {
+
+		uint8_t packet[PS2_BUFSIZE] = {};
+		const ssize_t size =
+		    chardev_read(parent_exch, packet, PS2_BUFSIZE);
+
+		if (size != PS2_BUFSIZE) {
+			ddf_msg(LVL_WARN, "Incorrect packet size: %zd.", size);
+			continue;
+		}
+		ddf_msg(LVL_DEBUG2, "Got packet: %hhx:%hhx:%hhx.",
+		    packet[0], packet[1], packet[2]);
+
+		async_exch_t *exch =
+		    async_exchange_begin(mouse->input_sess);
+		if (!exch) {
+			ddf_msg(LVL_ERROR,
+			    "Failed to create input exchange.");
+			continue;
+		}
+
+		/* Buttons */
+		for (unsigned i = 0; i < PS2_BUTTON_COUNT; ++i) {
+			const bool status = (packet[0] & PS2_BUTTON_MASK(i));
+			if (buttons[i] != status) {
+				buttons[i] = status;
+				async_msg_2(exch, MOUSEEV_BUTTON_EVENT, i + 1,
+				    buttons[i]);
+			}
+		}
+
+		/* Movement */
+		const int16_t move_x =
+		    ((packet[0] & X_SIGN) ? 0xff00 : 0) | packet[1];
+		const int16_t move_y =
+		    (((packet[0] & Y_SIGN) ? 0xff00 : 0) | packet[2]);
+		//TODO: Consider overflow bit
+		if (move_x != 0 || move_y != 0) {
+			async_msg_2(exch, MOUSEEV_MOVE_EVENT, move_x, -move_y);
+		}
+		async_exchange_end(exch);
+	}
+	async_exchange_end(parent_exch);
+}
+
+/** Get data and parse ps2 protocol with IntelliMouse extension packets.
+ * @param arg Pointer to ps2_mouse_t structure.
+ * @return Never.
+ */
+static int polling_intellimouse(void *arg)
+{
+	assert(arg);
+	const ps2_mouse_t *mouse = arg;
+
+	assert(mouse->parent_sess);
+	bool buttons[INTELLIMOUSE_BUTTON_COUNT] = {};
+	async_exch_t *parent_exch = NULL;
+	while (1) {
+		if (!parent_exch)
+			parent_exch = async_exchange_begin(mouse->parent_sess);
+
+		uint8_t packet[INTELLIMOUSE_BUFSIZE] = {};
+		const ssize_t size = chardev_read(
+		    parent_exch, packet, INTELLIMOUSE_BUFSIZE);
+
+		if (size != INTELLIMOUSE_BUFSIZE) {
+			ddf_msg(LVL_WARN, "Incorrect packet size: %zd.", size);
+			continue;
+		}
+		ddf_msg(LVL_DEBUG2, "Got packet: %hhx:%hhx:%hhx:%hhx.",
+		    packet[0], packet[1], packet[2], packet[3]);
+
+		async_exch_t *exch =
+		    async_exchange_begin(mouse->input_sess);
+		if (!exch) {
+			ddf_msg(LVL_ERROR,
+			    "Failed to create input exchange.");
+			continue;
+		}
+
+		/* Buttons */
+		/* NOTE: Parsing 4th and 5th button works even if this extension
+		 * is not supported and whole 4th byte should be interpreted
+		 * as Z-axis movement. the upper 4 bits are just a sign
+		 * extension then. + sign is interpreted as "button up"
+		 * (i.e no change since that is the default) and - sign fails
+		 * the "imb" condition. Thus 4th and 5th buttons are never
+		 * down on wheel only extension. */
+		const bool imb = (packet[3] & INTELLIMOUSE_ALWAYS_ZERO) == 0;
+		const bool status[] = {
+			[0] = packet[0] & PS2_BUTTON_MASK(0),
+			[1] = packet[0] & PS2_BUTTON_MASK(1),
+			[2] = packet[0] & PS2_BUTTON_MASK(2),
+			[3] = (packet[3] & INTELLIMOUSE_BUTTON_4) && imb,
+			[4] = (packet[3] & INTELLIMOUSE_BUTTON_5) && imb,
+		};
+		for (unsigned i = 0; i < INTELLIMOUSE_BUTTON_COUNT; ++i) {
+			if (buttons[i] != status[i]) {
+				buttons[i] = status[i];
+				async_msg_2(exch, MOUSEEV_BUTTON_EVENT, i + 1,
+				    buttons[i]);
+			}
+		}
+
+		/* Movement */
+		const int16_t move_x =
+		    ((packet[0] & X_SIGN) ? 0xff00 : 0) | packet[1];
+		const int16_t move_y =
+		    (((packet[0] & Y_SIGN) ? 0xff00 : 0) | packet[2]);
+		const int8_t move_z =
+		    (((packet[3] & Z_SIGN) ? 0xf0 : 0) | (packet[3] & 0xf));
+		ddf_msg(LVL_DEBUG2, "Parsed moves: %d:%d:%hhd", move_x, move_y,
+		    move_z);
+		//TODO: Consider overflow bit
+		if (move_x != 0 || move_y != 0 || move_z != 0) {
+			async_msg_3(exch, MOUSEEV_MOVE_EVENT,
+			    move_x, -move_y, -move_z);
+		}
+		async_exchange_end(exch);
+	}
+	async_exchange_end(parent_exch);
+}
+
+/** Send magic sequence to initialize IntelliMouse extensions.
+ * @param exch IPC exchange to the parent device.
+ * @param buttons True selects magic sequence for 4th and 5th button,
+ * false selects wheel support magic sequence.
+ * See http://www.computer-engineering.org/ps2mouse/ for details.
+ */
+static int probe_intellimouse(async_exch_t *exch, bool buttons)
+{
+	assert(exch);
+
+	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_SET_SAMPLE_RATE);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+	MOUSE_WRITE_BYTE(exch, 200);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+
+	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_SET_SAMPLE_RATE);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+	MOUSE_WRITE_BYTE(exch, buttons ? 200 : 100);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+
+	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_SET_SAMPLE_RATE);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+	MOUSE_WRITE_BYTE(exch, 80);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+
+	MOUSE_WRITE_BYTE(exch, PS2_MOUSE_GET_DEVICE_ID);
+	MOUSE_READ_BYTE_TEST(exch, PS2_MOUSE_ACK);
+	MOUSE_READ_BYTE_TEST(exch, buttons ? 4 : 3);
+
+	return EOK;
+}
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param fun Device function handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+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.", __FUNCTION__);
+		async_answer_0(icallid, EINVAL);
+		return;
+	}
+
+	const sysarg_t method = IPC_GET_IMETHOD(*icall);
+	ps2_mouse_t *mouse = fun->driver_data;
+
+	switch (method) {
+	/* 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 (mouse->input_sess == NULL) {
+			mouse->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.", (int)method);
+		async_answer_0(icallid, EINVAL);
+		break;
+	}
+}
Index: uspace/drv/char/ps2mouse/ps2mouse.h
===================================================================
--- uspace/drv/char/ps2mouse/ps2mouse.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/ps2mouse/ps2mouse.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvmouse
+ * @{
+ */
+/** @file
+ * @brief ps/2 mouse driver.
+ */
+
+#ifndef _PS2MOUSE_H_
+#define _PS2MOUSE_H_
+
+#include <ddf/driver.h>
+#include <fibril.h>
+
+/** PS/2 mouse driver structure. */
+typedef struct {
+	ddf_fun_t *mouse_fun;      /**< Mouse function. */
+	async_sess_t *parent_sess; /**< Connection to device providing data. */
+	async_sess_t *input_sess;  /**< Callback connection to consumer. */
+	fid_t polling_fibril;      /**< Fibril retrieving an parsing data. */
+} ps2_mouse_t;
+
+int ps2_mouse_init(ps2_mouse_t *, ddf_dev_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/char/ps2mouse/ps2mouse.ma
===================================================================
--- uspace/drv/char/ps2mouse/ps2mouse.ma	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/ps2mouse/ps2mouse.ma	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,1 @@
+100 char/ps2mouse
Index: uspace/drv/char/xtkbd/Makefile
===================================================================
--- uspace/drv/char/xtkbd/Makefile	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/xtkbd/Makefile	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2011 Jan Vesely
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = xtkbd
+
+SOURCES = \
+	chardev.c \
+	main.c \
+	xtkbd.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/char/xtkbd/chardev.c
===================================================================
--- uspace/drv/char/xtkbd/chardev.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/xtkbd/chardev.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <mem.h>
+#include <ipc/dev_iface.h>
+#include <ddf/log.h>
+
+#include "chardev.h"
+
+// TODO make this shared
+enum {
+	IPC_CHAR_READ = DEV_FIRST_CUSTOM_METHOD,
+	IPC_CHAR_WRITE,
+};
+
+ssize_t chardev_read(async_exch_t *exch, void *data, size_t size)
+{
+	if (!exch)
+		return EBADMEM;
+	if (size > 4 * sizeof(sysarg_t))
+		return ELIMIT;
+
+	sysarg_t message[4] = { 0 };
+	const ssize_t ret = async_req_1_4(exch, IPC_CHAR_READ, size,
+	    &message[0], &message[1], &message[2], &message[3]);
+	if (ret > 0 && (size_t)ret <= size)
+		memcpy(data, message, size);
+	return ret;
+}
+
+ssize_t chardev_write(async_exch_t *exch, const void *data, size_t size)
+{
+	if (!exch)
+		return EBADMEM;
+	if (size > 3 * sizeof(sysarg_t))
+		return ELIMIT;
+
+	sysarg_t message[3] = { 0 };
+	memcpy(message, data, size);
+	return async_req_4_0(exch, IPC_CHAR_WRITE, size,
+	    message[0], message[1], message[2]);
+}
Index: uspace/drv/char/xtkbd/chardev.h
===================================================================
--- uspace/drv/char/xtkbd/chardev.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/xtkbd/chardev.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvkbd
+ * @{
+ */
+/** @file
+ * @brief ps/2 mouse driver.
+ */
+
+#ifndef _CHARDEV_H_
+#define _CHARDEV_H_
+
+#include <libarch/types.h>
+#include <async.h>
+
+ssize_t chardev_read(async_exch_t *, void *, size_t);
+ssize_t chardev_write(async_exch_t *, const void *, size_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/char/xtkbd/main.c
===================================================================
--- uspace/drv/char/xtkbd/main.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/xtkbd/main.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvkbd
+ * @{
+ */
+/** @file
+ * @brief XT keyboard driver
+ */
+
+#include <libarch/inttypes.h>
+#include <ddf/driver.h>
+#include <devman.h>
+#include <device/hw_res_parsed.h>
+#include <errno.h>
+#include <str_error.h>
+#include <ddf/log.h>
+#include <stdio.h>
+
+#include "xtkbd.h"
+
+#define NAME "xtkbd"
+
+static int xt_kbd_add(ddf_dev_t *device);
+
+/** DDF driver ops. */
+static driver_ops_t kbd_driver_ops = {
+	.dev_add = xt_kbd_add,
+};
+
+/** DDF driver structure. */
+static driver_t kbd_driver = {
+	.name = NAME,
+	.driver_ops = &kbd_driver_ops
+};
+
+/** Initialize global driver structures (NONE).
+ *
+ * @param[in] argc Nmber of arguments in argv vector (ignored).
+ * @param[in] argv Cmdline argument vector (ignored).
+ * @return Error code.
+ *
+ * Driver debug level is set here.
+ */
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS XT keyboard driver.\n");
+	ddf_log_init(NAME, LVL_NOTE);
+	return ddf_driver_main(&kbd_driver);
+}
+
+/** Initialize a new ddf driver instance of the driver
+ *
+ * @param[in] device DDF instance of the device to initialize.
+ * @return Error code.
+ */
+static int xt_kbd_add(ddf_dev_t *device)
+{
+	if (!device)
+		return EINVAL;
+
+#define CHECK_RET_RETURN(ret, message...) \
+if (ret != EOK) { \
+	ddf_msg(LVL_ERROR, message); \
+	return ret; \
+} else (void)0
+
+	xt_kbd_t *kbd = ddf_dev_data_alloc(device, sizeof(xt_kbd_t));
+	int ret = (kbd == NULL) ? ENOMEM : EOK;
+	CHECK_RET_RETURN(ret, "Failed to allocate XT/KBD driver instance.");
+
+	ret = xt_kbd_init(kbd, device);
+	CHECK_RET_RETURN(ret,
+	    "Failed to initialize XT_KBD driver: %s.", str_error(ret));
+
+	ddf_msg(LVL_NOTE, "Controlling '%s' (%" PRIun ").",
+	    device->name, device->handle);
+	return EOK;
+}
+/**
+ * @}
+ */
Index: uspace/drv/char/xtkbd/xtkbd.c
===================================================================
--- uspace/drv/char/xtkbd/xtkbd.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/xtkbd/xtkbd.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvkbd
+ * @{
+ */
+/** @file
+ * @brief XT keyboard driver;
+ */
+
+#include <errno.h>
+#include <devman.h>
+#include <ddf/log.h>
+#include <io/keycode.h>
+#include <io/console.h>
+#include <ipc/kbdev.h>
+#include <abi/ipc/methods.h>
+
+#include "chardev.h"
+#include "xtkbd.h"
+
+/** Scancode set 1 table. */
+static const int scanmap_simple[] = {
+
+	[0x29] = KC_BACKTICK,
+
+	[0x02] = KC_1,
+	[0x03] = KC_2,
+	[0x04] = KC_3,
+	[0x05] = KC_4,
+	[0x06] = KC_5,
+	[0x07] = KC_6,
+	[0x08] = KC_7,
+	[0x09] = KC_8,
+	[0x0a] = KC_9,
+	[0x0b] = KC_0,
+
+	[0x0c] = KC_MINUS,
+	[0x0d] = KC_EQUALS,
+	[0x0e] = KC_BACKSPACE,
+
+	[0x0f] = KC_TAB,
+
+	[0x10] = KC_Q,
+	[0x11] = KC_W,
+	[0x12] = KC_E,
+	[0x13] = KC_R,
+	[0x14] = KC_T,
+	[0x15] = KC_Y,
+	[0x16] = KC_U,
+	[0x17] = KC_I,
+	[0x18] = KC_O,
+	[0x19] = KC_P,
+
+	[0x1a] = KC_LBRACKET,
+	[0x1b] = KC_RBRACKET,
+
+	[0x3a] = KC_CAPS_LOCK,
+
+	[0x1e] = KC_A,
+	[0x1f] = KC_S,
+	[0x20] = KC_D,
+	[0x21] = KC_F,
+	[0x22] = KC_G,
+	[0x23] = KC_H,
+	[0x24] = KC_J,
+	[0x25] = KC_K,
+	[0x26] = KC_L,
+
+	[0x27] = KC_SEMICOLON,
+	[0x28] = KC_QUOTE,
+	[0x2b] = KC_BACKSLASH,
+
+	[0x2a] = KC_LSHIFT,
+
+	[0x2c] = KC_Z,
+	[0x2d] = KC_X,
+	[0x2e] = KC_C,
+	[0x2f] = KC_V,
+	[0x30] = KC_B,
+	[0x31] = KC_N,
+	[0x32] = KC_M,
+
+	[0x33] = KC_COMMA,
+	[0x34] = KC_PERIOD,
+	[0x35] = KC_SLASH,
+
+	[0x36] = KC_RSHIFT,
+
+	[0x1d] = KC_LCTRL,
+	[0x38] = KC_LALT,
+	[0x39] = KC_SPACE,
+
+	[0x01] = KC_ESCAPE,
+
+	[0x3b] = KC_F1,
+	[0x3c] = KC_F2,
+	[0x3d] = KC_F3,
+	[0x3e] = KC_F4,
+	[0x3f] = KC_F5,
+	[0x40] = KC_F6,
+	[0x41] = KC_F7,
+
+	[0x42] = KC_F8,
+	[0x43] = KC_F9,
+	[0x44] = KC_F10,
+
+	[0x57] = KC_F11,
+	[0x58] = KC_F12,
+
+	[0x46] = KC_SCROLL_LOCK,
+
+	[0x1c] = KC_ENTER,
+
+	[0x45] = KC_NUM_LOCK,
+	[0x37] = KC_NTIMES,
+	[0x4a] = KC_NMINUS,
+	[0x4e] = KC_NPLUS,
+	[0x47] = KC_N7,
+	[0x48] = KC_N8,
+	[0x49] = KC_N9,
+	[0x4b] = KC_N4,
+	[0x4c] = KC_N5,
+	[0x4d] = KC_N6,
+	[0x4f] = KC_N1,
+	[0x50] = KC_N2,
+	[0x51] = KC_N3,
+	[0x52] = KC_N0,
+	[0x53] = KC_NPERIOD
+};
+
+#define KBD_ACK   0xfa
+#define KBD_RESEND   0xfe
+#define KBD_SCANCODE_SET_EXTENDED   0xe0
+/** Scancode set 1 extended codes table */
+static const int scanmap_e0[] = {
+	[0x38] = KC_RALT,
+	[0x1d] = KC_RSHIFT,
+
+	[0x37] = KC_PRTSCR,
+
+	[0x52] = KC_INSERT,
+	[0x47] = KC_HOME,
+	[0x49] = KC_PAGE_UP,
+
+	[0x53] = KC_DELETE,
+	[0x4f] = KC_END,
+	[0x51] = KC_PAGE_DOWN,
+
+	[0x48] = KC_UP,
+	[0x4b] = KC_LEFT,
+	[0x50] = KC_DOWN,
+	[0x4d] = KC_RIGHT,
+
+	[0x35] = KC_NSLASH,
+	[0x1c] = KC_NENTER
+};
+
+#define KBD_CMD_SET_LEDS 0xed
+enum led_indicators {
+	LI_SCROLL       = 0x01,
+	LI_NUM          = 0x02,
+	LI_CAPS         = 0x04,
+};
+
+static int polling(void *);
+static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+
+/** Keyboard function ops. */
+static ddf_dev_ops_t kbd_ops = {
+	.default_handler = default_connection_handler
+};
+
+/** Initialize keyboard driver structure.
+ * @param kbd Keyboard driver structure to initialize.
+ * @param dev DDF device structure.
+ *
+ * Connects to parent, creates mouse function, starts polling fibril.
+ */
+int xt_kbd_init(xt_kbd_t *kbd, ddf_dev_t *dev)
+{
+	assert(kbd);
+	assert(dev);
+	kbd->input_sess = NULL;
+	kbd->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
+	    dev->handle, IPC_FLAG_BLOCKING);
+	if (!kbd->parent_sess)
+		return ENOMEM;
+
+	kbd->kbd_fun = ddf_fun_create(dev, fun_exposed, "kbd");
+	if (!kbd->kbd_fun) {
+		async_hangup(kbd->parent_sess);
+		return ENOMEM;
+	}
+	kbd->kbd_fun->ops = &kbd_ops;
+	kbd->kbd_fun->driver_data = kbd;
+
+	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;
+	}
+
+	kbd->polling_fibril = fibril_create(polling, kbd);
+	if (!kbd->polling_fibril) {
+		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;
+	}
+	fibril_add_ready(kbd->polling_fibril);
+	return EOK;
+}
+
+/** Get data and parse scancodes.
+ * @param arg Pointer to xt_kbd_t structure.
+ * @return Never.
+ */
+int polling(void *arg)
+{
+	assert(arg);
+	const xt_kbd_t *kbd = arg;
+
+	assert(kbd->parent_sess);
+	async_exch_t *parent_exch = async_exchange_begin(kbd->parent_sess);
+	while (1) {
+		if (!parent_exch)
+			parent_exch = async_exchange_begin(kbd->parent_sess);
+
+		const int *map = scanmap_simple;
+		size_t map_size = sizeof(scanmap_simple) / sizeof(int);
+
+		uint8_t code = 0;
+		ssize_t size = chardev_read(parent_exch, &code, 1);
+
+		/** Ignore AT command reply */
+		if (code == KBD_ACK || code == KBD_RESEND) {
+			continue;
+		}
+
+		if (code == KBD_SCANCODE_SET_EXTENDED) {
+			map = scanmap_e0;
+			map_size = sizeof(scanmap_e0) / sizeof(int);
+			size = chardev_read(parent_exch, &code, 1);
+			// TODO handle print screen
+		}
+
+		/* Invalid read. */
+		if (size != 1) {
+			continue;
+		}
+
+
+		/* Bit 7 indicates press/release */
+		const kbd_event_type_t type =
+		    (code & 0x80) ? KEY_RELEASE : KEY_PRESS;
+		code &= ~0x80;
+
+		const unsigned key = (code < map_size) ? map[code] : 0;
+		if (key != 0) {
+			async_exch_t *exch =
+			    async_exchange_begin(kbd->input_sess);
+			if (!exch) {
+				ddf_msg(LVL_ERROR,
+				    "Failed to create input exchange.");
+				continue;
+			}
+			async_msg_4(exch, KBDEV_EVENT, type, key, 0, 0);
+			async_exchange_end(exch);
+		} else {
+			ddf_msg(LVL_WARN, "Unknown scancode: %hhx", code);
+		}
+	}
+}
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param fun Device function handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+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.", __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,
+		 * assume AT keyboard with Scan Code Set 1 */
+		const unsigned mods = IPC_GET_ARG1(*icall);
+		const uint8_t status = 0 |
+		    ((mods & KM_CAPS_LOCK) ? LI_CAPS : 0) |
+		    ((mods & KM_NUM_LOCK) ? LI_NUM : 0) |
+		    ((mods & KM_SCROLL_LOCK) ? LI_SCROLL : 0);
+		uint8_t cmds[] = { KBD_CMD_SET_LEDS, status };
+		async_exch_t *exch = async_exchange_begin(kbd->parent_sess);
+		const ssize_t size = chardev_write(exch, cmds, sizeof(cmds));
+		async_exchange_end(exch);
+		async_answer_0(icallid, size < 0 ? size : EOK);
+		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.", (int)method);
+			async_answer_0(icallid, EINVAL);
+			break;
+	}
+}
Index: uspace/drv/char/xtkbd/xtkbd.h
===================================================================
--- uspace/drv/char/xtkbd/xtkbd.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/xtkbd/xtkbd.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup drvkbd
+ * @{
+ */
+/** @file
+ * @brief XT keyboard driver
+ */
+
+#ifndef _XT_KBD_H_
+#define _XT_KBD_H_
+
+#include <ddf/driver.h>
+#include <fibril.h>
+
+/** PC/XT keyboard driver structure. */
+typedef struct {
+	ddf_fun_t *kbd_fun;        /**< Keyboard function. */
+	async_sess_t *parent_sess; /**< Connection to device providing data. */
+	async_sess_t *input_sess;  /**< Callback connection to consumer. */
+	fid_t polling_fibril;      /**< Fibril retrieving an parsing data. */
+} xt_kbd_t;
+
+int xt_kbd_init(xt_kbd_t *, ddf_dev_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/char/xtkbd/xtkbd.ma
===================================================================
--- uspace/drv/char/xtkbd/xtkbd.ma	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
+++ uspace/drv/char/xtkbd/xtkbd.ma	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -0,0 +1,1 @@
+100 char/xtkbd
Index: uspace/srv/hid/input/Makefile
===================================================================
--- uspace/srv/hid/input/Makefile	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/srv/hid/input/Makefile	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -43,5 +43,4 @@
 	port/adb_mouse.c \
 	port/chardev.c \
-	port/chardev_mouse.c \
 	port/gxemul.c \
 	port/msim.c \
@@ -52,5 +51,4 @@
 	proto/adb.c \
 	proto/mousedev.c \
-	proto/ps2.c \
 	ctl/apple.c \
 	ctl/gxe_fb.c \
Index: uspace/srv/hid/input/generic/input.c
===================================================================
--- uspace/srv/hid/input/generic/input.c	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/srv/hid/input/generic/input.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -172,8 +172,17 @@
 
 /** Mouse pointer has moved. */
-void mouse_push_event_move(mouse_dev_t *mdev, int dx, int dy)
+void mouse_push_event_move(mouse_dev_t *mdev, int dx, int dy, int dz)
 {
 	async_exch_t *exch = async_exchange_begin(client_sess);
-	async_msg_2(exch, INPUT_EVENT_MOVE, dx, dy);
+	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);
 }
@@ -397,7 +406,4 @@
 	 * them automatically.
 	 */
-#if defined(UARCH_amd64)
-	kbd_add_dev(&chardev_port, &pc_ctl);
-#endif
 #if defined(UARCH_arm32) && defined(MACHINE_gta02)
 	kbd_add_dev(&chardev_port, &stty_ctl);
@@ -411,10 +417,4 @@
 #if defined(UARCH_arm32) && defined(MACHINE_integratorcp)
 	kbd_add_dev(&pl050_port, &pc_ctl);
-#endif
-#if defined(UARCH_ia32)
-	kbd_add_dev(&chardev_port, &pc_ctl);
-#endif
-#if defined(MACHINE_i460GX)
-	kbd_add_dev(&chardev_port, &pc_ctl);
 #endif
 #if defined(MACHINE_ski)
@@ -450,13 +450,4 @@
 	 * them automatically.
 	 */
-#if defined(UARCH_amd64)
-	mouse_add_dev(&chardev_mouse_port, &ps2_proto);
-#endif
-#if defined(UARCH_ia32)
-	mouse_add_dev(&chardev_mouse_port, &ps2_proto);
-#endif
-#if defined(MACHINE_i460GX)
-	mouse_add_dev(&chardev_mouse_port, &ps2_proto);
-#endif
 #if defined(UARCH_ppc32)
 	mouse_add_dev(&adb_mouse_port, &adb_proto);
Index: uspace/srv/hid/input/include/mouse.h
===================================================================
--- uspace/srv/hid/input/include/mouse.h	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/srv/hid/input/include/mouse.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -62,5 +62,5 @@
 
 extern void mouse_push_data(mouse_dev_t *, sysarg_t);
-extern void mouse_push_event_move(mouse_dev_t *, int, int);
+extern void mouse_push_event_move(mouse_dev_t *, int, int, int);
 extern void mouse_push_event_button(mouse_dev_t *, int, int);
 
Index: uspace/srv/hid/input/include/mouse_proto.h
===================================================================
--- uspace/srv/hid/input/include/mouse_proto.h	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/srv/hid/input/include/mouse_proto.h	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -48,5 +48,4 @@
 
 extern mouse_proto_ops_t adb_proto;
-extern mouse_proto_ops_t ps2_proto;
 extern mouse_proto_ops_t mousedev_proto;
 
Index: uspace/srv/hid/input/port/chardev.c
===================================================================
--- uspace/srv/hid/input/port/chardev.c	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/srv/hid/input/port/chardev.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -63,5 +63,4 @@
 /** List of devices to try connecting to. */
 static const char *in_devs[] = {
-	"char/ps2a",
 	"char/s3c24ser"
 };
Index: pace/srv/hid/input/port/chardev_mouse.c
===================================================================
--- uspace/srv/hid/input/port/chardev_mouse.c	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ 	(revision )
@@ -1,157 +1,0 @@
-/*
- * Copyright (c) 2011 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup mouse_port
- * @ingroup mouse
- * @{
- */
-/** @file
- * @brief Chardev mouse port driver.
- */
-
-#include <ipc/char.h>
-#include <stdio.h>
-#include <async.h>
-#include <errno.h>
-#include <loc.h>
-#include <input.h>
-#include <mouse_port.h>
-#include <mouse.h>
-
-static mouse_dev_t *mouse_dev;
-static async_sess_t *dev_sess;
-
-/** List of devices to try connecting to. */
-static const char *in_devs[] = {
-	"char/ps2b",
-};
-
-static const unsigned int num_devs = sizeof(in_devs) / sizeof(in_devs[0]);
-
-static void mouse_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;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case CHAR_NOTIF_BYTE:
-			mouse_push_data(mouse_dev, IPC_GET_ARG1(call));
-			break;
-		default:
-			retval = ENOENT;
-		}
-		
-		async_answer_0(callid, retval);
-	}
-}
-
-static int chardev_port_init(mouse_dev_t *mdev)
-{
-	service_id_t service_id;
-	unsigned int i;
-	int rc;
-	
-	mouse_dev = mdev;
-	
-	for (i = 0; i < num_devs; i++) {
-		rc = loc_service_get_id(in_devs[i], &service_id, 0);
-		if (rc == EOK)
-			break;
-	}
-	
-	if (i >= num_devs) {
-		printf("%s: Could not find any suitable input device\n", NAME);
-		return -1;
-	}
-	
-	dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id,
-	    IPC_FLAG_BLOCKING);
-	if (dev_sess == NULL) {
-		printf("%s: Failed connecting to device\n", NAME);
-		return ENOENT;
-	}
-	
-	async_exch_t *exch = async_exchange_begin(dev_sess);
-	if (exch == NULL) {
-		printf("%s: Failed starting exchange with device\n", NAME);
-		async_hangup(dev_sess);
-		return ENOMEM;
-	}
-	
-	/* NB: The callback connection is slotted for removal */
-	rc = async_connect_to_me(exch, 0, 0, 0, mouse_port_events, NULL);
-	async_exchange_end(exch);
-	
-	if (rc != 0) {
-		printf("%s: Failed to create callback from device\n", NAME);
-		async_hangup(dev_sess);
-		return -1;
-	}
-	
-	return 0;
-}
-
-static void chardev_port_yield(void)
-{
-}
-
-static void chardev_port_reclaim(void)
-{
-}
-
-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);
-		return;
-	}
-
-	async_msg_1(exch, CHAR_WRITE_BYTE, data);
-	async_exchange_end(exch);
-}
-
-mouse_port_ops_t chardev_mouse_port = {
-	.init = chardev_port_init,
-	.yield = chardev_port_yield,
-	.reclaim = chardev_port_reclaim,
-	.write = chardev_port_write
-};
-
-/**
- * @}
- */
Index: uspace/srv/hid/input/proto/adb.c
===================================================================
--- uspace/srv/hid/input/proto/adb.c	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/srv/hid/input/proto/adb.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -82,5 +82,5 @@
 	
 	if (dx != 0 || dy != 0)
-		mouse_push_event_move(mouse_dev, dx, dy);
+		mouse_push_event_move(mouse_dev, dx, dy, 0);
 }
 
Index: uspace/srv/hid/input/proto/mousedev.c
===================================================================
--- uspace/srv/hid/input/proto/mousedev.c	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ uspace/srv/hid/input/proto/mousedev.c	(revision f991b6babc87e0deb9b4bf9442366643a976866e)
@@ -91,11 +91,12 @@
 		switch (IPC_GET_IMETHOD(call)) {
 		case MOUSEEV_MOVE_EVENT:
-			mouse_push_event_move(mousedev->mouse_dev, IPC_GET_ARG1(call),
-			    IPC_GET_ARG2(call));
+			mouse_push_event_move(mousedev->mouse_dev,
+			    IPC_GET_ARG1(call), IPC_GET_ARG2(call),
+			    IPC_GET_ARG3(call));
 			retval = EOK;
 			break;
 		case MOUSEEV_BUTTON_EVENT:
-			mouse_push_event_button(mousedev->mouse_dev, IPC_GET_ARG1(call),
-			    IPC_GET_ARG2(call));
+			mouse_push_event_button(mousedev->mouse_dev,
+			    IPC_GET_ARG1(call), IPC_GET_ARG2(call));
 			retval = EOK;
 			break;
Index: pace/srv/hid/input/proto/ps2.c
===================================================================
--- uspace/srv/hid/input/proto/ps2.c	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ 	(revision )
@@ -1,139 +1,0 @@
-/*
- * Copyright (c) 2011 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup mouse_proto
- * @ingroup input
- * @{
- */
-/**
- * @file
- * @brief PS/2 protocol driver.
- */
-
-#include <mouse.h>
-#include <mouse_port.h>
-#include <mouse_proto.h>
-
-#define PS2_MOUSE_OUT_INIT  0xf4
-#define PS2_MOUSE_ACK       0xfa
-
-#define BUFSIZE 3
-
-typedef struct {
-	union {
-		unsigned char data[BUFSIZE];
-		struct {
-			unsigned int leftbtn : 1;
-			unsigned int rightbtn : 1;
-			unsigned int middlebtn : 1;
-			unsigned int isone : 1; /* Always one */
-			unsigned int xsign : 1;
-			unsigned int ysign : 1;
-			unsigned int xovfl : 1;
-			unsigned int yovfl : 1;
-			unsigned char x;
-			unsigned char y;
-		} val;
-	} u;
-} ps2packet_t;
-
-static ps2packet_t buf;
-static unsigned int bufpos;
-static unsigned int leftbtn;
-static unsigned int rightbtn;
-static unsigned int middlebtn;
-
-static mouse_dev_t *mouse_dev;
-
-static int ps2_proto_init(mouse_dev_t *mdev)
-{
-	mouse_dev = mdev;
-	bufpos = 0;
-	leftbtn = 0;
-	rightbtn = 0;
-	
-	mouse_dev->port_ops->write(PS2_MOUSE_OUT_INIT);
-	return 0;
-}
-
-/** Convert 9-bit 2-complement signed number to integer */
-static int bit9toint(int sign, unsigned char data)
-{
-	int tmp;
-	
-	if (!sign)
-		return data;
-	
-	tmp = ((unsigned char) ~data) + 1;
-	return -tmp;
-}
-
-/** Process mouse data */
-static void ps2_proto_parse(sysarg_t data)
-{
-	int x, y;
-	
-	/* Check that we have not lost synchronization */
-	if (bufpos == 0 && !(data & 0x8))
-		return; /* Synchro lost, ignore byte */
-	
-	buf.u.data[bufpos++] = data;
-	if (bufpos == BUFSIZE) {
-		bufpos = 0;
-		
-		if (buf.u.val.leftbtn ^ leftbtn) {
-			leftbtn = buf.u.val.leftbtn;
-			mouse_push_event_button(mouse_dev, 1, leftbtn);
-		}
-		
-		if (buf.u.val.rightbtn ^ rightbtn) {
-			rightbtn = buf.u.val.rightbtn;
-			mouse_push_event_button(mouse_dev, 2, rightbtn);
-		}
-		
-		if (buf.u.val.middlebtn ^ middlebtn) {
-			middlebtn = buf.u.val.middlebtn;
-			mouse_push_event_button(mouse_dev, 3, middlebtn);
-		}
-		
-		x = bit9toint(buf.u.val.xsign, buf.u.val.x);
-		y = -bit9toint(buf.u.val.ysign, buf.u.val.y);
-		
-		if (x != 0 || y != 0)
-			mouse_push_event_move(mouse_dev, x, y);
-	}
-}
-
-mouse_proto_ops_t ps2_proto = {
-	.parse = ps2_proto_parse,
-	.init = ps2_proto_init
-};
-
-/**
- * @}
- */
Index: pace/srv/hw/char/i8042/Makefile
===================================================================
--- uspace/srv/hw/char/i8042/Makefile	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ 	(revision )
@@ -1,36 +1,0 @@
-#
-# Copyright (c) 2005 Martin Decky
-# Copyright (c) 2007 Jakub Jermar
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# - Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-# - Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-# - The name of the author may not be used to endorse or promote products
-#   derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-USPACE_PREFIX = ../../../..
-BINARY = i8042
-
-SOURCES = \
-	i8042.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: pace/srv/hw/char/i8042/i8042.c
===================================================================
--- uspace/srv/hw/char/i8042/i8042.c	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ 	(revision )
@@ -1,315 +1,0 @@
-/*
- * Copyright (c) 2001-2004 Jakub Jermar
- * Copyright (c) 2006 Josef Cejka
- * Copyright (c) 2009 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup kbd_port
- * @ingroup kbd
- * @{
- */
-/** @file
- * @brief i8042 PS/2 port driver.
- */
-
-#include <ddi.h>
-#include <libarch/ddi.h>
-#include <loc.h>
-#include <async.h>
-#include <unistd.h>
-#include <sysinfo.h>
-#include <stdio.h>
-#include <errno.h>
-#include <inttypes.h>
-#include "i8042.h"
-
-#define NAME       "i8042"
-#define NAMESPACE  "char"
-
-/* Interesting bits for status register */
-#define i8042_OUTPUT_FULL	0x01
-#define i8042_INPUT_FULL	0x02
-#define i8042_AUX_DATA		0x20
-
-/* Command constants */
-#define i8042_CMD_WRITE_CMDB	0x60	/**< write command byte */
-#define i8042_CMD_WRITE_AUX	0xd4	/**< write aux device */
-
-/* Command byte fields */
-#define i8042_KBD_IE		0x01
-#define i8042_AUX_IE		0x02
-#define i8042_KBD_DISABLE	0x10
-#define i8042_AUX_DISABLE	0x20
-#define i8042_KBD_TRANSLATE	0x40
-
-
-enum {
-	DEVID_PRI = 0, /**< primary device */
-        DEVID_AUX = 1, /**< AUX device */
-	MAX_DEVS  = 2
-};
-
-static irq_cmd_t i8042_cmds[] = {
-	{
-		.cmd = CMD_PIO_READ_8,
-		.addr = NULL,	/* will be patched in run-time */
-		.dstarg = 1
-	},
-	{
-		.cmd = CMD_BTEST,
-		.value = i8042_OUTPUT_FULL,
-		.srcarg = 1,
-		.dstarg = 3
-	},
-	{
-		.cmd = CMD_PREDICATE,
-		.value = 2,
-		.srcarg = 3
-	},
-	{
-		.cmd = CMD_PIO_READ_8,
-		.addr = NULL,	/* will be patched in run-time */
-		.dstarg = 2
-	},
-	{
-		.cmd = CMD_ACCEPT
-	}
-};
-
-static irq_code_t i8042_kbd = {
-	sizeof(i8042_cmds) / sizeof(irq_cmd_t),
-	i8042_cmds
-};
-
-static uintptr_t i8042_physical;
-static uintptr_t i8042_kernel;
-static i8042_t * i8042;
-
-static i8042_port_t i8042_port[MAX_DEVS];
-
-static void wait_ready(void)
-{
-	while (pio_read_8(&i8042->status) & i8042_INPUT_FULL);
-}
-
-static void i8042_irq_handler(ipc_callid_t iid, ipc_call_t *call);
-static void i8042_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
-static int i8042_init(void);
-static void i8042_port_write(int devid, uint8_t data);
-
-
-int main(int argc, char *argv[])
-{
-	char name[16];
-	int i, rc;
-	char dchar[MAX_DEVS] = { 'a', 'b' };
-
-	printf(NAME ": i8042 PS/2 port driver\n");
-
-	rc = loc_server_register(NAME, i8042_connection);
-	if (rc < 0) {
-		printf(NAME ": Unable to register server.\n");
-		return rc;
-	}
-
-	if (i8042_init() != EOK)
-		return -1;
-
-	for (i = 0; i < MAX_DEVS; i++) {
-		i8042_port[i].client_sess = NULL;
-
-		snprintf(name, 16, "%s/ps2%c", NAMESPACE, dchar[i]);
-		rc = loc_service_register(name, &i8042_port[i].service_id);
-		if (rc != EOK) {
-			printf(NAME ": Unable to register device %s.\n", name);
-			return rc;
-		}
-		printf(NAME ": Registered device %s\n", name);
-	}
-
-	printf(NAME ": Accepting connections\n");
-	task_retval(0);
-	async_manager();
-
-	/* Not reached */
-	return 0;
-}
-
-static int i8042_init(void)
-{
-	if (sysinfo_get_value("i8042.address.physical", &i8042_physical) != EOK)
-		return -1;
-	
-	if (sysinfo_get_value("i8042.address.kernel", &i8042_kernel) != EOK)
-		return -1;
-	
-	void *vaddr;
-	if (pio_enable((void *) i8042_physical, sizeof(i8042_t), &vaddr) != 0)
-		return -1;
-	
-	i8042 = vaddr;
-	
-	sysarg_t inr_a;
-	sysarg_t inr_b;
-	
-	if (sysinfo_get_value("i8042.inr_a", &inr_a) != EOK)
-		return -1;
-	
-	if (sysinfo_get_value("i8042.inr_b", &inr_b) != EOK)
-		return -1;
-	
-	async_set_interrupt_received(i8042_irq_handler);
-	
-	/* Disable kbd and aux */
-	wait_ready();
-	pio_write_8(&i8042->status, i8042_CMD_WRITE_CMDB);
-	wait_ready();
-	pio_write_8(&i8042->data, i8042_KBD_DISABLE | i8042_AUX_DISABLE);
-
-	/* Flush all current IO */
-	while (pio_read_8(&i8042->status) & i8042_OUTPUT_FULL)
-		(void) pio_read_8(&i8042->data);
-
-	i8042_kbd.cmds[0].addr = (void *) &((i8042_t *) i8042_kernel)->status;
-	i8042_kbd.cmds[3].addr = (void *) &((i8042_t *) i8042_kernel)->data;
-	irq_register(inr_a, device_assign_devno(), 0, &i8042_kbd);
-	irq_register(inr_b, device_assign_devno(), 0, &i8042_kbd);
-	printf("%s: registered for interrupts %" PRIun " and %" PRIun "\n",
-	    NAME, inr_a, inr_b);
-
-	wait_ready();
-	pio_write_8(&i8042->status, i8042_CMD_WRITE_CMDB);
-	wait_ready();
-	pio_write_8(&i8042->data, i8042_KBD_IE | i8042_KBD_TRANSLATE |
-	    i8042_AUX_IE);
-
-	return 0;
-}
-
-/** Character device connection handler */
-static void i8042_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	ipc_callid_t callid;
-	ipc_call_t call;
-	sysarg_t method;
-	service_id_t dsid;
-	int retval;
-	int dev_id, i;
-
-	printf(NAME ": connection handler\n");
-
-	/* Get the device handle. */
-	dsid = IPC_GET_ARG1(*icall);
-
-	/* Determine which disk device is the client connecting to. */
-	dev_id = -1;
-	for (i = 0; i < MAX_DEVS; i++) {
-		if (i8042_port[i].service_id == dsid)
-			dev_id = i;
-	}
-
-	if (dev_id < 0) {
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-
-	/* Answer the IPC_M_CONNECT_ME_TO call. */
-	async_answer_0(iid, EOK);
-
-	printf(NAME ": accepted connection\n");
-
-	while (1) {
-		callid = async_get_call(&call);
-		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 (i8042_port[dev_id].client_sess == NULL) {
-				i8042_port[dev_id].client_sess = sess;
-				retval = EOK;
-			} else
-				retval = ELIMIT;
-		} else {
-			switch (method) {
-			case IPC_FIRST_USER_METHOD:
-				printf(NAME ": write %" PRIun " to devid %d\n",
-				    IPC_GET_ARG1(call), dev_id);
-				i8042_port_write(dev_id, IPC_GET_ARG1(call));
-				retval = 0;
-				break;
-			default:
-				retval = EINVAL;
-				break;
-			}
-		}
-		
-		async_answer_0(callid, retval);
-	}
-}
-
-void i8042_port_write(int devid, uint8_t data)
-{
-	if (devid == DEVID_AUX) {
-		wait_ready();
-		pio_write_8(&i8042->status, i8042_CMD_WRITE_AUX);
-	}
-	wait_ready();
-	pio_write_8(&i8042->data, data);
-}
-
-static void i8042_irq_handler(ipc_callid_t iid, ipc_call_t *call)
-{
-	int status, data;
-	int devid;
-
-	status = IPC_GET_ARG1(*call);
-	data = IPC_GET_ARG2(*call);
-
-	if ((status & i8042_AUX_DATA)) {
-		devid = DEVID_AUX;
-	} else {
-		devid = DEVID_PRI;
-	}
-
-	if (i8042_port[devid].client_sess != NULL) {
-		async_exch_t *exch =
-		    async_exchange_begin(i8042_port[devid].client_sess);
-		async_msg_1(exch, IPC_FIRST_USER_METHOD, data);
-		async_exchange_end(exch);
-	}
-}
-
-/**
- * @}
- */
Index: pace/srv/hw/char/i8042/i8042.h
===================================================================
--- uspace/srv/hw/char/i8042/i8042.h	(revision 0a549cc8ecfa1c41b89499c38cda3b5b201367c8)
+++ 	(revision )
@@ -1,63 +1,0 @@
-/*
- * Copyright (c) 2006 Josef Cejka
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup kbd_port
- * @ingroup  kbd
- * @{
- */
-
-/** @file
- * @brief i8042 port driver.
- */
-
-#ifndef i8042_H_
-#define i8042_H_
-
-#include <sys/types.h>
-#include <libarch/ddi.h>
-#include <async.h>
-
-/** i8042 HW I/O interface */
-struct i8042 {
-	ioport8_t data;
-	uint8_t pad[3];
-	ioport8_t status;
-} __attribute__ ((packed));
-typedef struct i8042 i8042_t;
-
-/** Softstate structure, one for each serial port (primary and aux). */
-typedef struct {
-	service_id_t service_id;
-	async_sess_t *client_sess;
-} i8042_port_t;
-
-#endif
-
-/**
- * @}
- */
