Index: uspace/app/wacomdump/isdv4.c
===================================================================
--- uspace/app/wacomdump/isdv4.c	(revision 149956486aec381b969e725ecafbf5575e325e6e)
+++ uspace/app/wacomdump/isdv4.c	(revision 149956486aec381b969e725ecafbf5575e325e6e)
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2012 Martin Sucha
+ * 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 <device/char_dev.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <mem.h>
+
+#include "isdv4.h"
+
+#define BUF_SIZE 64
+
+#define START_OF_PACKET 128
+#define CONTROL_PACKET 64
+#define TOUCH_EVENT 16
+#define FINGER1 1
+#define FINGER2 2
+#define TIP 1
+#define BUTTON1 2
+#define BUTTON2 4
+#define PROXIMITY 32
+
+#define CMD_START '1'
+#define CMD_STOP '0'
+#define CMD_QUERY_STYLUS '*'
+#define CMD_QUERY_TOUCH '%'
+
+/* packet_consumer_fn(uint8_t *packet, size_t size, isdv4_state_t *state,
+   void *data)
+   return true if reading of packets should continue */
+typedef bool (*packet_consumer_fn)(uint8_t *, size_t, isdv4_state_t *);
+
+static void isdv4_event_init(isdv4_event_t *event)
+{
+	memset(event, 0, sizeof(isdv4_event_t));
+}
+
+/**
+ * Parse event packet and emit events
+ * @return true if reading of packets should continue
+ */
+static bool parse_event(uint8_t *packet, size_t size, isdv4_state_t *state)
+{
+	if (size < 1)
+		return false;
+
+	bool control_packet = ((packet[0] & CONTROL_PACKET) > 0);
+	if (control_packet)
+		return true;
+
+	/* This is an event initiated by the device */
+	isdv4_event_t event;
+	isdv4_event_init(&event);
+
+	if (packet[0] & TOUCH_EVENT) {
+		if (size != 5)
+			return true;
+
+		/* This is a touch event */
+		bool finger1 = (packet[0] & FINGER1) > 0;
+		event.x = ((packet[1] & 127) << 7) | (packet[2] & 127);
+		event.y = ((packet[3] & 127) << 7) | (packet[4] & 127);
+		event.source = TOUCH;
+
+		if (!state->stylus_in_proximity) {
+			if (!finger1 && state->finger1_pressed) {
+				state->finger1_pressed = false;
+
+				event.type = RELEASE;
+				event.button = 1;
+				state->emit_event_fn(&event);
+			}
+			else if (finger1 && !state->finger1_pressed) {
+				state->finger1_pressed = true;
+
+				event.type = PRESS;
+				event.button = 1;
+				state->emit_event_fn(&event);
+			}
+			else {
+				event.type = MOVE;
+				event.button = 1;
+				state->emit_event_fn(&event);
+			}
+		}
+	}
+	else {
+		if (size != 9)
+			return true;
+
+		/* This is a stylus event */
+		bool tip = packet[0] & TIP;
+		bool button1 = packet[0] & BUTTON1;
+		bool button2 = packet[0] & BUTTON2;
+		bool proximity = packet[0] & PROXIMITY;
+		event.x = ((packet[1] & 127) << 7) | (packet[2] & 124) | ((packet[6] >> 5) & 3);
+		event.y = ((packet[3] & 127) << 7) | (packet[4] & 124) | ((packet[6] >> 3) & 3);
+		event.pressure = (packet[5] & 127) | ((packet[6] & 7) << 7);
+
+		if (proximity && !state->stylus_in_proximity) {
+			/* Stylus came into proximity */
+			state->stylus_in_proximity = true;
+			state->stylus_is_eraser = !tip && button2;
+			event.source = (state->stylus_is_eraser ? STYLUS_ERASER : STYLUS_TIP);
+			event.type = PROXIMITY_IN;
+			state->emit_event_fn(&event);
+		}
+		else if (!proximity && state->stylus_in_proximity) {
+			/* Stylus came out of proximity */
+			state->stylus_in_proximity = false;
+			event.source = (state->stylus_is_eraser ? STYLUS_ERASER : STYLUS_TIP);
+			event.type = PROXIMITY_OUT;
+			state->emit_event_fn(&event);
+		}
+		else {
+			/* Proximity state didn't change, but we need to check if it is still eraser */
+			if (state->stylus_is_eraser && !button2) {
+				event.type = PROXIMITY_OUT;
+				event.source = STYLUS_ERASER;
+				state->emit_event_fn(&event);
+				event.type = PROXIMITY_IN;
+				event.source = STYLUS_TIP;
+				state->emit_event_fn(&event);
+				state->stylus_is_eraser = false;
+			}
+			else if (!state->stylus_is_eraser && !tip && button2) {
+				event.type = PROXIMITY_OUT;
+				event.source = STYLUS_TIP;
+				state->emit_event_fn(&event);
+				event.type = PROXIMITY_IN;
+				event.source = STYLUS_ERASER;
+				state->emit_event_fn(&event);
+				state->stylus_is_eraser = true;
+			}
+		}
+
+		if (!state->stylus_is_eraser) {
+			if (tip && !state->tip_pressed) {
+				state->tip_pressed = true;
+				event.type = PRESS;
+				event.source = STYLUS_TIP;
+				event.button = 1;
+				state->emit_event_fn(&event);
+			}
+			else if (!tip && state->tip_pressed) {
+				state->tip_pressed = false;
+				event.type = RELEASE;
+				event.source = STYLUS_TIP;
+				event.button = 1;
+				state->emit_event_fn(&event);
+			}
+			if (button1 && !state->button1_pressed) {
+				state->button1_pressed = true;
+				event.type = PRESS;
+				event.source = STYLUS_TIP;
+				event.button = 2;
+				state->emit_event_fn(&event);
+			}
+			else if (!button1 && state->button1_pressed) {
+				state->button1_pressed = false;
+				event.type = RELEASE;
+				event.source = STYLUS_TIP;
+				event.button = 2;
+				state->emit_event_fn(&event);
+			}
+			if (button2 && !state->button2_pressed) {
+				state->button2_pressed = true;
+				event.type = PRESS;
+				event.source = STYLUS_TIP;
+				event.button = 3;
+				state->emit_event_fn(&event);
+			}
+			else if (!button2 && state->button2_pressed) {
+				state->button2_pressed = false;
+				event.type = RELEASE;
+				event.source = STYLUS_TIP;
+				event.button = 3;
+				state->emit_event_fn(&event);
+			}
+			event.type = MOVE;
+			event.source = STYLUS_TIP;
+			event.button = 0;
+			state->emit_event_fn(&event);
+		}
+		else {
+			if (tip && !state->tip_pressed) {
+				state->tip_pressed = true;
+				event.type = PRESS;
+				event.source = STYLUS_ERASER;
+				event.button = 1;
+				state->emit_event_fn(&event);
+			}
+			else if (!tip && state->tip_pressed) {
+				state->tip_pressed = false;
+				event.type = RELEASE;
+				event.source = STYLUS_ERASER;
+				event.button = 1;
+				state->emit_event_fn(&event);
+			}
+			event.type = MOVE;
+			event.source = STYLUS_ERASER;
+			event.button = 0;
+			state->emit_event_fn(&event);
+		}
+	}
+
+	return true;
+}
+
+static bool parse_response_stylus(uint8_t *packet, size_t size,
+    isdv4_state_t *state)
+{
+	if (size < 1)
+		return false;
+
+	bool control_packet = ((packet[0] & CONTROL_PACKET) > 0);
+	if (!control_packet)
+		return true;
+
+	if (size != 11)
+		return false;
+
+	state->stylus_max_x = ((packet[1] & 127) << 7) | (packet[2] & 124) |
+	    ((packet[6] >> 5) & 3);
+	state->stylus_max_y = ((packet[3] & 127) << 7) | (packet[4] & 124) |
+	    ((packet[6] >> 3) & 3);
+	state->stylus_max_pressure = (packet[5] & 63) | ((packet[6] & 7) << 7);
+	state->stylus_max_xtilt = packet[8] & 127;
+	state->stylus_max_ytilt = packet[7] & 127;
+	state->stylus_tilt_supported = (state->stylus_max_xtilt &&
+	    state->stylus_max_ytilt);
+
+	return false;
+}
+
+static bool parse_response_touch(uint8_t *packet, size_t size,
+    isdv4_state_t *state)
+{
+	if (size < 1)
+		return false;
+
+	bool control_packet = ((packet[0] & CONTROL_PACKET) > 0);
+	if (!control_packet)
+		return true;
+
+	if (size != 11)
+		return false;
+
+	state->touch_type = (packet[0] & 63);
+
+	unsigned int touch_resolution = packet[1] & 127;
+	state->touch_max_x = ((packet[2] >> 5) & 3) | ((packet[3] & 127) << 7) |
+	    (packet[4] & 124);
+	state->touch_max_y = ((packet[2] >> 3) & 3) | ((packet[5] & 127) << 7) |
+	    (packet[6] & 124);
+	
+	if (touch_resolution == 0)
+		touch_resolution = 10;
+
+	if (state->touch_max_x == 0 || state->touch_max_y == 0) {
+		state->touch_max_x = (1 << touch_resolution);
+		state->touch_max_y = (1 << touch_resolution);
+	}
+
+	return false;
+}
+
+static int read_packets(isdv4_state_t *state, packet_consumer_fn consumer)
+{
+	bool reading = true;
+	while (reading) {
+		ssize_t read = char_dev_read(state->sess, state->buf + state->buf_end,
+		    state->buf_size - state->buf_end);
+		if (read < 0)
+			return EIO;
+		state->buf_end += read;
+
+		size_t i = 0;
+
+		/* Skip data until a start of packet is found */
+		while (i < state->buf_end && (state->buf[i] & START_OF_PACKET) == 0) i++;
+
+		size_t start = i;
+		size_t end = i;
+		size_t processed_end = i;
+
+		/* Process packets one by one */
+		while (reading && i < state->buf_end) {
+			/* Determine the packet length */
+			size_t packet_remaining;
+			if (state->buf[i] & CONTROL_PACKET) {
+				packet_remaining = 11;
+			}
+			else if (state->buf[i] & TOUCH_EVENT) {
+				packet_remaining = 5;
+			}
+			else {
+				packet_remaining = 9;
+			}
+
+			/* Find the end of the packet */
+			i++; /* We need to skip the first byte with START_OF_PACKET set */
+			packet_remaining--; 
+			while (packet_remaining > 0 && i < state->buf_end &&
+			    (state->buf[i] & START_OF_PACKET) == 0) {
+				i++;
+				packet_remaining--;
+			}
+			end = i;
+
+			/* If we have whole packet, process it */
+			if (end > start && packet_remaining == 0) {
+				reading = consumer(state->buf + start, end - start, state);
+				start = end;
+				processed_end = end;
+			}
+		}
+
+		if (processed_end == 0 && state->buf_end == state->buf_size) {
+			/* Packet too large, throw it away */
+			state->buf_end = 0;
+		}
+
+		/* Shift the buffer contents to the left */
+		size_t unprocessed_len = state->buf_end - processed_end;
+		memcpy(state->buf, state->buf + processed_end, unprocessed_len);
+		state->buf_end = unprocessed_len;
+	}
+	return EOK;
+}
+static bool write_command(async_sess_t *sess, uint8_t command)
+{
+	return char_dev_write(sess, &command, 1) == 1;
+}
+
+int isdv4_init(isdv4_state_t *state, async_sess_t *sess,
+    isdv4_event_fn event_fn)
+{
+	memset(state, 0, sizeof(isdv4_state_t));
+	state->sess = sess;
+	state->buf = malloc(BUF_SIZE);
+	if (state->buf == NULL)
+		return ENOMEM;
+	state->buf_size = BUF_SIZE;
+	state->emit_event_fn = event_fn;
+	return EOK;
+}
+
+int isdv4_init_tablet(isdv4_state_t *state)
+{
+	if (!write_command(state->sess, CMD_STOP))
+		return EIO;
+
+	usleep(250000); /* 250 ms */
+
+	// FIXME: Read all possible garbage before sending commands
+	if (!write_command(state->sess, CMD_QUERY_STYLUS))
+		return EIO;
+
+	int rc = read_packets(state, parse_response_stylus);
+	if (rc != EOK)
+		return rc;
+
+	if (!write_command(state->sess, CMD_QUERY_TOUCH))
+		return EIO;
+
+	rc = read_packets(state, parse_response_touch);
+	if (rc != EOK)
+		return rc;
+
+	if (!write_command(state->sess, CMD_START))
+		return EIO;
+
+	return EOK;
+}
+
+int isdv4_read_events(isdv4_state_t *state)
+{
+	return read_packets(state, parse_event);
+}
+
+void isdv4_fini(isdv4_state_t *state)
+{
+	free(state->buf);
+}
Index: uspace/app/wacomdump/isdv4.h
===================================================================
--- uspace/app/wacomdump/isdv4.h	(revision 149956486aec381b969e725ecafbf5575e325e6e)
+++ uspace/app/wacomdump/isdv4.h	(revision 149956486aec381b969e725ecafbf5575e325e6e)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012 Martin Sucha
+ * 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.
+ */
+
+#ifndef __ISDV4_H__
+#define __ISDV4_H__
+
+typedef struct isdv4_event isdv4_event_t;
+
+typedef void (*isdv4_event_fn)(const isdv4_event_t *);
+
+typedef struct {
+	/* Stylus information */
+	unsigned int stylus_max_x;
+	unsigned int stylus_max_y;
+	unsigned int stylus_max_pressure;
+	unsigned int stylus_max_xtilt;
+	unsigned int stylus_max_ytilt;
+	bool stylus_tilt_supported;
+
+	/* Touch information */
+	unsigned int touch_type;
+	unsigned int touch_max_x;
+	unsigned int touch_max_y;
+
+	/* Event state */
+	bool stylus_in_proximity;
+	bool stylus_is_eraser;
+	bool tip_pressed; /* Reported as stylus button 1 */
+	bool button1_pressed; /* Reported as stylus button 2 */
+	bool button2_pressed; /* Reported as stylus button 3 */
+	bool finger1_pressed; /* Reported as touch button 1 */
+
+	/* Session to the serial device */
+	async_sess_t *sess;
+
+	/* Receive buffer state */
+	uint8_t *buf;
+	size_t buf_size;
+	size_t buf_end;
+
+	/* Callbacks */
+	isdv4_event_fn emit_event_fn;
+} isdv4_state_t;
+
+typedef enum {
+	UNKNOWN, PRESS, RELEASE, PROXIMITY_IN, PROXIMITY_OUT, MOVE
+} isdv4_event_type_t;
+
+typedef enum {
+	STYLUS_TIP, STYLUS_ERASER, TOUCH
+} isdv4_source_type_t;
+
+typedef struct isdv4_event {
+	isdv4_event_type_t type;
+	isdv4_source_type_t source;
+	unsigned int x;
+	unsigned int y;
+	unsigned int pressure;
+	unsigned int button;
+} isdv4_event_t;
+
+extern int isdv4_init(isdv4_state_t *, async_sess_t *, isdv4_event_fn);
+extern int isdv4_init_tablet(isdv4_state_t *);
+extern int isdv4_read_events(isdv4_state_t *state);
+extern void isdv4_fini(isdv4_state_t *);
+
+#endif
Index: uspace/app/wacomdump/wacomdump.c
===================================================================
--- uspace/app/wacomdump/wacomdump.c	(revision 8a99c7ed8506480ce279d2129b1efc24cd26f307)
+++ uspace/app/wacomdump/wacomdump.c	(revision 149956486aec381b969e725ecafbf5575e325e6e)
@@ -32,13 +32,83 @@
 #include <loc.h>
 #include <stdio.h>
+#include <fibril_synch.h>
+#include <abi/ipc/methods.h>
+#include <ipc/mouseev.h>
 
 #include "isdv4.h"
 
+#define NAME "wacomdump"
+
+static async_sess_t *client_sess = NULL;
+static fibril_mutex_t client_mutex;
+static isdv4_state_t state;
+
 static void syntax_print(void)
 {
-	fprintf(stderr, "Usage: wacomdump [--baud=<baud>] [device_service]\n");
-}
-
-static void print_event(const isdv4_event_t *event)
+	fprintf(stderr, "Usage: wacomdump [--baud=<baud>] [--print-events] [device_service]\n");
+}
+
+static int read_fibril(void *unused)
+{
+	int rc = isdv4_read_events(&state);
+	if (rc != EOK) {
+		fprintf(stderr, "Failed reading events");
+		return rc;
+	}
+
+	isdv4_fini(&state);
+	return EOK;
+}
+
+static void mouse_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	async_answer_0(iid, EOK);
+	
+	async_sess_t *sess =
+	    async_callback_receive(EXCHANGE_SERIALIZE);
+	fibril_mutex_lock(&client_mutex);
+		if (client_sess == NULL) {
+			client_sess = sess;
+		}
+	fibril_mutex_unlock(&client_mutex);
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
+		async_answer_0(callid, ENOTSUP);
+	}
+}
+
+static void emit_event(const isdv4_event_t *event)
+{
+	fibril_mutex_lock(&client_mutex);
+	async_sess_t *sess = client_sess;
+	fibril_mutex_unlock(&client_mutex);
+	
+	if (!sess) return;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	if (exch) {
+		unsigned int max_x = state.stylus_max_x;
+		unsigned int max_y = state.stylus_max_y;
+		if (event->source == TOUCH) {
+			max_x = state.touch_max_x;
+			max_y = state.touch_max_y;
+		}
+		async_msg_4(exch, MOUSEEV_ABS_MOVE_EVENT, event->x, event->y,
+				    max_x, max_y);
+		if (event->type == PRESS || event->type == RELEASE) {
+			async_msg_2(exch, MOUSEEV_BUTTON_EVENT, event->button,
+				    event->type == PRESS);
+		}
+	}
+	async_exchange_end(exch);
+}
+
+static void print_and_emit_event(const isdv4_event_t *event)
 {
 	const char *type = NULL;
@@ -58,6 +128,6 @@
 		case MOVE:
 			type = "MOVE";
-			return;
-		case UNKNOWN:
+			break;
+		default:
 			type = "UNKNOWN";
 			break;
@@ -77,19 +147,8 @@
 	}
 
-	const char *buttons = "none";
-	switch (event->button) {
-		case 1:
-			buttons = "button1";
-			break;
-		case 2:
-			buttons = "button2";
-			break;
-		case 3:
-			buttons = "both";
-			break;
-	}
-
-	printf("%s %s %u %u %u %s\n", type, source, event->x, event->y,
-	    event->pressure, buttons);
+	printf("%s %s %u %u %u %u\n", type, source, event->x, event->y,
+	    event->pressure, event->button);
+	
+	emit_event(event);
 }
 
@@ -120,4 +179,6 @@
 	int rc;
 
+	isdv4_event_fn event_fn = emit_event;
+
 	if (argc > arg && str_test_prefix(argv[arg], "--baud=")) {
 		size_t arg_offset = str_lsize(argv[arg], 7);
@@ -138,4 +199,9 @@
 	}
 
+	if (argc > arg && str_cmp(argv[arg], "--print-events") == 0) {
+		event_fn = print_and_emit_event;
+		arg++;
+	}
+
 	if (argc > arg) {
 		rc = loc_service_get_id(argv[arg], &svc_id, 0);
@@ -181,4 +247,6 @@
 	}
 
+	fibril_mutex_initialize(&client_mutex);
+
 	async_sess_t *sess = loc_service_connect(EXCHANGE_SERIALIZE, svc_id,
 	    IPC_FLAG_BLOCKING);
@@ -197,6 +265,5 @@
 	}
 
-	isdv4_state_t state;
-	rc = isdv4_init(&state, sess, print_event);
+	rc = isdv4_init(&state, sess, event_fn);
 	if (rc != EOK) {
 		fprintf(stderr, "Failed initializing isdv4 state");
@@ -221,13 +288,40 @@
 	printf(" Touch: %ux%u type: %s\n", state.touch_max_x, state.touch_max_y,
 		touch_type(state.touch_type));
-
-	rc = isdv4_read_events(&state);
-	if (rc != EOK) {
-		fprintf(stderr, "Failed reading events");
-		return 2;
-	}
-
-	isdv4_fini(&state);
-
+	
+	fid_t fibril = fibril_create(read_fibril, NULL);
+	/* From this on, state is to be used only by read_fibril */
+	fibril_add_ready(fibril);
+
+	async_set_client_connection(mouse_connection);
+	rc = loc_server_register(NAME);
+	if (rc != EOK) {
+		printf("%s: Unable to register driver.\n", NAME);
+		return rc;
+	}
+
+	service_id_t service_id;
+	rc = loc_service_register("mouse/wacom", &service_id);
+	if (rc != EOK) {
+		printf(NAME ": Unable to register device mouse/wacom.\n");
+		return rc;
+	}
+
+	category_id_t mouse_category;
+	rc = loc_category_get_id("mouse", &mouse_category, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		printf(NAME ": Unable to get mouse category id.\n");
+	}
+	else {
+		rc = loc_service_add_to_cat(service_id, mouse_category);
+		if (rc != EOK) {
+			printf(NAME ": Unable to add device to mouse category.\n");
+		}
+	}
+
+	printf("%s: Accepting connections\n", NAME);
+	task_retval(0);
+	async_manager();
+
+	/* Not reached */
 	return 0;
 }
