Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/Makefile	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -122,4 +122,5 @@
 		drv/usbhub \
 		drv/usbmid \
+		drv/usbmouse \
 		drv/vhc
 endif
@@ -138,4 +139,5 @@
 		drv/usbhub \
 		drv/usbmid \
+		drv/usbmouse \
 		drv/vhc
 endif
Index: uspace/app/bdsh/cmds/modules/mount/mount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -31,4 +31,5 @@
 #include <vfs/vfs.h>
 #include <errno.h>
+#include <getopt.h>
 #include "config.h"
 #include "util.h"
@@ -40,5 +41,11 @@
 static const char *cmdname = "mount";
 
-/* Dispays help for mount in various levels */
+static struct option const long_options[] = {
+	{ "help", no_argument, 0, 'h' },
+	{ 0, 0, 0, 0 }
+};
+
+
+/* Displays help for mount in various levels */
 void help_cmd_mount(unsigned int level)
 {
@@ -59,10 +66,19 @@
 	unsigned int argc;
 	const char *mopts = "";
-	int rc;
+	int rc, c, opt_ind;
 
 	argc = cli_count_args(argv);
 
+	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
+		c = getopt_long(argc, argv, "h", long_options, &opt_ind);
+		switch (c) {
+		case 'h':
+			help_cmd_mount(HELP_LONG);
+			return CMD_SUCCESS;
+		}
+	}
+
 	if ((argc < 4) || (argc > 5)) {
-		printf("%s: invalid number of arguments.\n",
+		printf("%s: invalid number of arguments. Try `mount --help'\n",
 		    cmdname);
 		return CMD_FAILURE;
Index: uspace/doc/doxygroups.h
===================================================================
--- uspace/doc/doxygroups.h	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/doc/doxygroups.h	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -245,4 +245,10 @@
 
 	/**
+	 * @defgroup drvusbmouse USB mouse driver
+	 * @ingroup usb
+	 * @brief USB driver for mouse with boot protocol.
+	 */
+
+	/**
 	 * @defgroup drvusbuhci UHCI driver
 	 * @ingroup usb
Index: uspace/drv/usbhid/hiddev.c
===================================================================
--- uspace/drv/usbhid/hiddev.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/drv/usbhid/hiddev.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -149,41 +149,14 @@
 	usb_log_info("Processing descriptors...\n");
 	
-	// get the first configuration descriptor
-	usb_standard_configuration_descriptor_t config_desc;
-	
 	int rc;
-	rc = usb_request_get_bare_configuration_descriptor(&hid_dev->ctrl_pipe,
-	    0, &config_desc);
-	
-	if (rc != EOK) {
-		usb_log_error("Failed to get bare config descriptor: %s.\n",
+
+	uint8_t *descriptors = NULL;
+	size_t descriptors_size;
+	rc = usb_request_get_full_configuration_descriptor_alloc(
+	    &hid_dev->ctrl_pipe, 0, (void **) &descriptors, &descriptors_size);
+	if (rc != EOK) {
+		usb_log_error("Failed to retrieve config descriptor: %s.\n",
 		    str_error(rc));
 		return rc;
-	}
-	
-	// prepare space for all underlying descriptors
-	uint8_t *descriptors = (uint8_t *)malloc(config_desc.total_length);
-	if (descriptors == NULL) {
-		usb_log_error("No memory!.\n");
-		return ENOMEM;
-	}
-	
-	size_t transferred = 0;
-	// get full configuration descriptor
-	rc = usb_request_get_full_configuration_descriptor(&hid_dev->ctrl_pipe,
-	    0, descriptors, config_desc.total_length, &transferred);
-	
-	if (rc != EOK) {
-		usb_log_error("Failed to get full config descriptor: %s.\n",
-		    str_error(rc));
-		free(descriptors);
-		return rc;
-	}
-	
-	if (transferred != config_desc.total_length) {
-		usb_log_error("Configuration descriptor has wrong size (%u, "
-		    "expected %u).\n", transferred, config_desc.total_length);
-		free(descriptors);
-		return ELIMIT;
 	}
 	
@@ -201,5 +174,5 @@
 	
 	rc = usb_endpoint_pipe_initialize_from_configuration(
-	    endpoint_mapping, 1, descriptors, config_desc.total_length,
+	    endpoint_mapping, 1, descriptors, descriptors_size,
 	    &hid_dev->wire);
 	
@@ -233,5 +206,6 @@
 	assert(endpoint_mapping[0].interface != NULL);
 	
-	rc = usbhid_dev_get_report_descriptor(hid_dev, descriptors, transferred,
+	rc = usbhid_dev_get_report_descriptor(hid_dev,
+	    descriptors, descriptors_size,
 	    (uint8_t *)endpoint_mapping[0].interface);
 	
Index: uspace/drv/usbhid/kbddev.c
===================================================================
--- uspace/drv/usbhid/kbddev.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/drv/usbhid/kbddev.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -289,5 +289,9 @@
 
 	usb_log_debug2("Sending key %d to the console\n", ev.key);
-	assert(kbd_dev->console_phone != -1);
+	if (kbd_dev->console_phone < 0) {
+		usb_log_warning(
+		    "Connection to console not ready, key discarded.\n");
+		return;
+	}
 	
 	async_msg_4(kbd_dev->console_phone, KBD_EVENT, ev.type, ev.key, 
Index: uspace/drv/usbhid/usbhid.ma
===================================================================
--- uspace/drv/usbhid/usbhid.ma	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/drv/usbhid/usbhid.ma	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -1,4 +1,2 @@
-10 usb&class=hid
-10 usb&class=HID
+100 usb&interface&class=HID&subclass=0x01&protocol=0x01
 10 usb&interface&class=HID
-10 usb&hid
Index: uspace/drv/usbhub/usbhub.c
===================================================================
--- uspace/drv/usbhub/usbhub.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/drv/usbhub/usbhub.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -149,48 +149,29 @@
 	}
 
-	//configuration descriptor
-	/// \TODO check other configurations?
-	usb_standard_configuration_descriptor_t config_descriptor;
-	opResult = usb_request_get_bare_configuration_descriptor(
+	/* Retrieve full configuration descriptor. */
+	uint8_t *descriptors = NULL;
+	size_t descriptors_size = 0;
+	opResult = usb_request_get_full_configuration_descriptor_alloc(
 	    &hub->endpoints.control, 0,
-        &config_descriptor);
-	if(opResult!=EOK){
-		dprintf(USB_LOG_LEVEL_ERROR, "could not get configuration descriptor, %d",opResult);
+	    (void **) &descriptors, &descriptors_size);
+	if (opResult != EOK) {
+		usb_log_error("Could not get configuration descriptor: %s.\n",
+		    str_error(opResult));
 		return opResult;
 	}
-	//set configuration
+	usb_standard_configuration_descriptor_t *config_descriptor
+	    = (usb_standard_configuration_descriptor_t *) descriptors;
+
+	/* Set configuration. */
 	opResult = usb_request_set_configuration(&hub->endpoints.control,
-		config_descriptor.configuration_number);
-
-	if (opResult != EOK) {
-		dprintf(USB_LOG_LEVEL_ERROR,
-				"something went wrong when setting hub`s configuration, %d",
-				opResult);
+	    config_descriptor->configuration_number);
+
+	if (opResult != EOK) {
+		usb_log_error("Failed to set hub configuration: %s.\n",
+		    str_error(opResult));
 		return opResult;
 	}
 	dprintf(USB_LOG_LEVEL_DEBUG, "\tused configuration %d",
-			config_descriptor.configuration_number);
-
-	//full configuration descriptor
-	size_t transferred = 0;
-	uint8_t * descriptors = (uint8_t *)malloc(config_descriptor.total_length);
-	if (descriptors == NULL) {
-		dprintf(USB_LOG_LEVEL_ERROR, "insufficient memory");
-		return ENOMEM;
-	}
-	opResult = usb_request_get_full_configuration_descriptor(&hub->endpoints.control,
-	    0, descriptors,
-	    config_descriptor.total_length, &transferred);
-	if(opResult!=EOK){
-		free(descriptors);
-		dprintf(USB_LOG_LEVEL_ERROR,
-				"could not get full configuration descriptor, %d",opResult);
-		return opResult;
-	}
-	if (transferred != config_descriptor.total_length) {
-		dprintf(USB_LOG_LEVEL_ERROR,
-				"received incorrect full configuration descriptor");
-		return ELIMIT;
-	}
+			config_descriptor->configuration_number);
 
 	usb_endpoint_mapping_t endpoint_mapping[1] = {
@@ -204,5 +185,5 @@
 	opResult = usb_endpoint_pipe_initialize_from_configuration(
 	    endpoint_mapping, 1,
-	    descriptors, config_descriptor.total_length,
+	    descriptors, descriptors_size,
 	    &hub->device_connection);
 	if (opResult != EOK) {
Index: uspace/drv/usbmid/explore.c
===================================================================
--- uspace/drv/usbmid/explore.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/drv/usbmid/explore.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -42,56 +42,4 @@
 #include "usbmid.h"
 
-/** Allocate and retrieve full configuration descriptor.
- *
- * @param[in] dev USB device.
- * @param[in] config_index Configuration index.
- * @param[out] size Pointer where to store size of the allocated buffer.
- * @return Allocated full configuration descriptor.
- * @retval NULL Error occured.
- */
-static void *get_configuration_descriptor(usbmid_device_t *dev,
-    size_t config_index, size_t *size)
-{
-	usb_standard_configuration_descriptor_t config_descriptor;
-	int rc = usb_request_get_bare_configuration_descriptor(&dev->ctrl_pipe,
-	    config_index, &config_descriptor);
-	if (rc != EOK) {
-		usb_log_error("Failed getting configuration descriptor: %s.\n",
-		    str_error(rc));
-		return NULL;
-	}
-
-	void *full_config_descriptor = malloc(config_descriptor.total_length);
-	if (full_config_descriptor == NULL) {
-		usb_log_fatal("Out of memory (wanted: %zuB).\n",
-		    (size_t) config_descriptor.total_length);
-		return NULL;
-	}
-
-	size_t full_config_descriptor_size;
-	rc = usb_request_get_full_configuration_descriptor(&dev->ctrl_pipe,
-	    config_index,
-	    full_config_descriptor, config_descriptor.total_length,
-	    &full_config_descriptor_size);
-	if (rc != EOK) {
-		usb_log_error("Failed getting configuration descriptor: %s.\n",
-		    str_error(rc));
-		free(full_config_descriptor);
-		return NULL;
-	}
-
-	if (full_config_descriptor_size != config_descriptor.total_length) {
-		usb_log_error("Failed getting full configuration descriptor.\n");
-		free(full_config_descriptor);
-		return NULL;
-	}
-
-	if (size != NULL) {
-		*size = full_config_descriptor_size;
-	}
-
-	return full_config_descriptor;
-}
-
 /** Find starting indexes of all interface descriptors in a configuration.
  *
@@ -178,7 +126,11 @@
 
 	size_t config_descriptor_size;
-	uint8_t *config_descriptor_raw = get_configuration_descriptor(dev, 0,
-	    &config_descriptor_size);
-	if (config_descriptor_raw == NULL) {
+	uint8_t *config_descriptor_raw = NULL;
+	rc = usb_request_get_full_configuration_descriptor_alloc(
+	    &dev->ctrl_pipe, 0,
+	    (void **) &config_descriptor_raw, &config_descriptor_size);
+	if (rc != EOK) {
+		usb_log_error("Failed getting full config descriptor: %s.\n",
+		    str_error(rc));
 		return false;
 	}
@@ -207,4 +159,17 @@
 	}
 
+	/* Select the first configuration */
+	rc = usb_request_set_configuration(&dev->ctrl_pipe,
+	    config_descriptor->configuration_number);
+	if (rc != EOK) {
+		usb_log_error("Failed to set device configuration: %s.\n",
+		    str_error(rc));
+		free(config_descriptor_raw);
+		free(interface_descriptors);
+		return false;
+	}
+
+
+	/* Create control function */
 	ddf_fun_t *ctl_fun = ddf_fun_create(dev->dev, fun_exposed, "ctl");
 	if (ctl_fun == NULL) {
@@ -223,4 +188,5 @@
 	}
 
+	/* Spawn interface children */
 	size_t i;
 	for (i = 0; i < interface_descriptors_count; i++) {
Index: uspace/drv/usbmouse/Makefile
===================================================================
--- uspace/drv/usbmouse/Makefile	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
+++ uspace/drv/usbmouse/Makefile	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2011 Vojtech Horky
+# 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 $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBUSB_PREFIX)/include -I.
+
+BINARY = usbmouse
+
+SOURCES = \
+	init.c \
+	main.c \
+	mouse.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbmouse/init.c
===================================================================
--- uspace/drv/usbmouse/init.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
+++ uspace/drv/usbmouse/init.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 drvusbmouse
+ * @{
+ */
+/**
+ * @file
+ * Initialization routines for USB mouse driver.
+ */
+#include "mouse.h"
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/hid.h>
+#include <usb/request.h>
+#include <errno.h>
+
+/** Mouse polling endpoint description for boot protocol subclass. */
+static usb_endpoint_description_t poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.interface_subclass = USB_HID_SUBCLASS_BOOT,
+	.interface_protocol = USB_HID_PROTOCOL_MOUSE,
+	.flags = 0
+};
+
+/** Initialize poll pipe.
+ *
+ * Expects that session is already started on control pipe zero.
+ *
+ * @param mouse Mouse device.
+ * @param my_interface Interface number.
+ * @return Error code.
+ */
+static int intialize_poll_pipe(usb_mouse_t *mouse, int my_interface)
+{
+	assert(usb_endpoint_pipe_is_session_started(&mouse->ctrl_pipe));
+
+	int rc;
+
+	void *config_descriptor;
+	size_t config_descriptor_size;
+
+	rc = usb_request_get_full_configuration_descriptor_alloc(
+	    &mouse->ctrl_pipe, 0, &config_descriptor, &config_descriptor_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	usb_endpoint_mapping_t endpoint_mapping[1] = {
+		{
+			.pipe = &mouse->poll_pipe,
+			.description = &poll_endpoint_description,
+			.interface_no = my_interface
+		}
+	};
+
+	rc = usb_endpoint_pipe_initialize_from_configuration(endpoint_mapping,
+	    1, config_descriptor, config_descriptor_size, &mouse->wire);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if (!endpoint_mapping[0].present) {
+		return ENOENT;
+	}
+
+	mouse->poll_interval_us = 1000 * endpoint_mapping[0].descriptor->poll_interval;
+
+	usb_log_debug("prepared polling endpoint %d (interval %zu).\n",
+	    mouse->poll_pipe.endpoint_no, mouse->poll_interval_us);
+
+	return EOK;
+}
+
+static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+static ddf_dev_ops_t mouse_ops = {
+	.default_handler = default_connection_handler
+};
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param dev Device 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)
+{
+	sysarg_t method = IPC_GET_IMETHOD(*icall);
+
+	usb_mouse_t *mouse = (usb_mouse_t *) fun->driver_data;
+	assert(mouse != NULL);
+
+	if (method == IPC_M_CONNECT_TO_ME) {
+		int callback = IPC_GET_ARG5(*icall);
+
+		if (mouse->console_phone != -1) {
+			async_answer_0(icallid, ELIMIT);
+			return;
+		}
+
+		mouse->console_phone = callback;
+		async_answer_0(icallid, EOK);
+		return;
+	}
+
+	async_answer_0(icallid, EINVAL);
+}
+
+
+int usb_mouse_create(ddf_dev_t *dev)
+{
+	usb_mouse_t *mouse = malloc(sizeof(usb_mouse_t));
+	if (mouse == NULL) {
+		return ENOMEM;
+	}
+	mouse->device = dev;
+	mouse->console_phone = -1;
+
+	int rc;
+
+	/* Initialize the backing connection. */
+	rc = usb_device_connection_initialize_from_device(&mouse->wire, dev);
+	if (rc != EOK) {
+		goto leave;
+	}
+
+	/* Initialize the default control pipe. */
+	rc = usb_endpoint_pipe_initialize_default_control(&mouse->ctrl_pipe,
+	    &mouse->wire);
+	if (rc != EOK) {
+		goto leave;
+	}
+
+	rc = usb_endpoint_pipe_start_session(&mouse->ctrl_pipe);
+	if (rc != EOK) {
+		goto leave;
+	}
+
+	rc = intialize_poll_pipe(mouse, usb_device_get_assigned_interface(dev));
+
+	/* We can ignore error here. */
+	usb_endpoint_pipe_end_session(&mouse->ctrl_pipe);
+
+	if (rc != EOK) {
+		goto leave;
+	}
+
+	/* Create DDF function. */
+	mouse->mouse_fun = ddf_fun_create(dev, fun_exposed, "mouse");
+	if (mouse->mouse_fun == NULL) {
+		rc = ENOMEM;
+		goto leave;
+	}
+
+	mouse->mouse_fun->ops = &mouse_ops;
+
+	rc = ddf_fun_bind(mouse->mouse_fun);
+	if (rc != EOK) {
+		goto leave;
+	}
+
+	/* Add the function to mouse class. */
+	rc = ddf_fun_add_to_class(mouse->mouse_fun, "mouse");
+	if (rc != EOK) {
+		goto leave;
+	}
+
+	/* Everything allright. */
+	dev->driver_data = mouse;
+	mouse->mouse_fun->driver_data = mouse;
+
+	return EOK;
+
+leave:
+	free(mouse);
+
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmouse/main.c
===================================================================
--- uspace/drv/usbmouse/main.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
+++ uspace/drv/usbmouse/main.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 drvusbmouse
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB boot protocol mouse driver.
+ */
+#include "mouse.h"
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+
+static int usbmouse_add_device(ddf_dev_t *dev)
+{
+	int rc = usb_mouse_create(dev);
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize device driver: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+
+	fid_t poll_fibril = fibril_create(usb_mouse_polling_fibril, dev);
+	if (poll_fibril == 0) {
+		usb_log_error("Failed to initialize polling fibril.\n");
+		/* FIXME: free allocated resources. */
+		return ENOMEM;
+	}
+
+	fibril_add_ready(poll_fibril);
+
+	usb_log_info("controlling new mouse (handle %llu).\n",
+	    dev->handle);
+
+	return EOK;
+}
+
+static driver_ops_t mouse_driver_ops = {
+	.add_device = usbmouse_add_device,
+};
+
+static driver_t mouse_driver = {
+	.name = NAME,
+	.driver_ops = &mouse_driver_ops
+};
+
+int main(int argc, char *argv[])
+{
+	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
+
+	return ddf_driver_main(&mouse_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmouse/mouse.c
===================================================================
--- uspace/drv/usbmouse/mouse.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
+++ uspace/drv/usbmouse/mouse.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 drvusbmouse
+ * @{
+ */
+/**
+ * @file
+ * Actual handling of USB mouse protocol.
+ */
+#include "mouse.h"
+#include <usb/debug.h>
+#include <errno.h>
+#include <ipc/mouse.h>
+
+int usb_mouse_polling_fibril(void *arg)
+{
+	assert(arg != NULL);
+	ddf_dev_t *dev = (ddf_dev_t *) arg;
+	usb_mouse_t *mouse = (usb_mouse_t *) dev->driver_data;
+
+	assert(mouse);
+
+	size_t buffer_size = mouse->poll_pipe.max_packet_size;
+
+	if (buffer_size < 4) {
+		usb_log_error("Weird mouse, results will be skewed.\n");
+		buffer_size = 4;
+	}
+
+	uint8_t *buffer = malloc(buffer_size);
+	if (buffer == NULL) {
+		usb_log_error("Out of memory, poll fibril aborted.\n");
+		return ENOMEM;
+	}
+
+	while (true) {
+		async_usleep(mouse->poll_interval_us);
+
+		size_t actual_size;
+
+		/* FIXME: check for errors. */
+		usb_endpoint_pipe_start_session(&mouse->poll_pipe);
+
+		usb_endpoint_pipe_read(&mouse->poll_pipe,
+		    buffer, buffer_size, &actual_size);
+
+		usb_endpoint_pipe_end_session(&mouse->poll_pipe);
+
+		uint8_t butt = buffer[0];
+		char str_buttons[4] = {
+			butt & 1 ? '#' : '.',
+			butt & 2 ? '#' : '.',
+			butt & 4 ? '#' : '.',
+			0
+		};
+
+		int shift_x = ((int) buffer[1]) - 127;
+		int shift_y = ((int) buffer[2]) - 127;
+		int wheel = ((int) buffer[3]) - 127;
+
+		if (buffer[1] == 0) {
+			shift_x = 0;
+		}
+		if (buffer[2] == 0) {
+			shift_y = 0;
+		}
+		if (buffer[3] == 0) {
+			wheel = 0;
+		}
+
+		if (mouse->console_phone >= 0) {
+			if ((shift_x != 0) || (shift_y != 0)) {
+				/* FIXME: guessed for QEMU */
+				async_req_2_0(mouse->console_phone,
+				    MEVENT_MOVE,
+				    - shift_x / 10,  - shift_y / 10);
+			}
+			if (butt) {
+				/* FIXME: proper button clicking. */
+				async_req_2_0(mouse->console_phone,
+				    MEVENT_BUTTON, 1, 1);
+				async_req_2_0(mouse->console_phone,
+				    MEVENT_BUTTON, 1, 0);
+			}
+		}
+
+		usb_log_debug("buttons=%s  dX=%+3d  dY=%+3d  wheel=%+3d\n",
+		   str_buttons, shift_x, shift_y, wheel);
+	}
+
+	return EOK;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmouse/mouse.h
===================================================================
--- uspace/drv/usbmouse/mouse.h	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
+++ uspace/drv/usbmouse/mouse.h	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 drvusbmouse
+ * @{
+ */
+/**
+ * @file
+ * Common definitions for USB mouse driver.
+ */
+#ifndef USBMOUSE_MOUSE_H_
+#define USBMOUSE_MOUSE_H_
+
+#include <ddf/driver.h>
+#include <usb/pipes.h>
+#include <time.h>
+
+#define NAME "usbmouse"
+
+typedef struct {
+	ddf_dev_t *device;
+	ddf_fun_t *mouse_fun;
+	usb_device_connection_t wire;
+	usb_endpoint_pipe_t ctrl_pipe;
+	usb_endpoint_pipe_t poll_pipe;
+	suseconds_t poll_interval_us;
+	int console_phone;
+} usb_mouse_t;
+
+int usb_mouse_create(ddf_dev_t *);
+
+int usb_mouse_polling_fibril(void *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/usbmouse/usbmouse.ma
===================================================================
--- uspace/drv/usbmouse/usbmouse.ma	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
+++ uspace/drv/usbmouse/usbmouse.ma	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -0,0 +1,1 @@
+100 usb&interface&class=HID&subclass=0x01&protocol=0x02
Index: uspace/lib/c/generic/loader.c
===================================================================
--- uspace/lib/c/generic/loader.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/lib/c/generic/loader.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -160,4 +160,5 @@
 	int rc = async_data_write_start(ldr->phone_id, (void *) pa, pa_len);
 	if (rc != EOK) {
+		free(pa);
 		async_wait_for(req, NULL);
 		return rc;
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -69,4 +69,5 @@
 	char *ncwd_path;
 	char *ncwd_path_nc;
+	size_t total_size; 
 
 	fibril_mutex_lock(&cwd_mutex);
@@ -77,14 +78,16 @@
 			return NULL;
 		}
-		ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
+		total_size = cwd_size + 1 + size + 1;
+		ncwd_path_nc = malloc(total_size);
 		if (!ncwd_path_nc) {
 			fibril_mutex_unlock(&cwd_mutex);
 			return NULL;
 		}
-		str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
+		str_cpy(ncwd_path_nc, total_size, cwd_path);
 		ncwd_path_nc[cwd_size] = '/';
 		ncwd_path_nc[cwd_size + 1] = '\0';
 	} else {
-		ncwd_path_nc = malloc(size + 1);
+		total_size = size + 1;
+		ncwd_path_nc = malloc(total_size);
 		if (!ncwd_path_nc) {
 			fibril_mutex_unlock(&cwd_mutex);
@@ -93,5 +96,5 @@
 		ncwd_path_nc[0] = '\0';
 	}
-	str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
+	str_append(ncwd_path_nc, total_size, path);
 	ncwd_path = canonify(ncwd_path_nc, retlen);
 	if (!ncwd_path) {
Index: uspace/lib/usb/include/usb/request.h
===================================================================
--- uspace/lib/usb/include/usb/request.h	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/lib/usb/include/usb/request.h	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -106,4 +106,6 @@
 int usb_request_get_full_configuration_descriptor(usb_endpoint_pipe_t *, int,
     void *, size_t, size_t *);
+int usb_request_get_full_configuration_descriptor_alloc(usb_endpoint_pipe_t *,
+    int, void **, size_t *);
 int usb_request_set_configuration(usb_endpoint_pipe_t *, uint8_t);
 
Index: uspace/lib/usb/src/request.c
===================================================================
--- uspace/lib/usb/src/request.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/lib/usb/src/request.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -412,4 +412,69 @@
 }
 
+/** Retrieve full configuration descriptor, allocate space for it.
+ *
+ * The function takes care that full configuration descriptor is returned
+ * (i.e. the function will fail when less data then descriptor.totalLength
+ * is returned).
+ *
+ * @param[in] pipe Control endpoint pipe (session must be already started).
+ * @param[in] index Configuration index.
+ * @param[out] descriptor_ptr Where to store pointer to allocated buffer.
+ * @param[out] descriptor_size Where to store the size of the descriptor.
+ * @return Error code.
+ */
+int usb_request_get_full_configuration_descriptor_alloc(
+    usb_endpoint_pipe_t *pipe, int index,
+    void **descriptor_ptr, size_t *descriptor_size)
+{
+	int rc;
+
+	if (descriptor_ptr == NULL) {
+		return EBADMEM;
+	}
+
+	usb_standard_configuration_descriptor_t bare_config;
+	rc = usb_request_get_bare_configuration_descriptor(pipe, index,
+	    &bare_config);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if (bare_config.descriptor_type != USB_DESCTYPE_CONFIGURATION) {
+		return ENOENT;
+	}
+	if (bare_config.total_length < sizeof(bare_config)) {
+		return ELIMIT;
+	}
+
+	void *buffer = malloc(bare_config.total_length);
+	if (buffer == NULL) {
+		return ENOMEM;
+	}
+
+	size_t transferred = 0;
+	rc = usb_request_get_full_configuration_descriptor(pipe, index,
+	    buffer, bare_config.total_length, &transferred);
+	if (rc != EOK) {
+		free(buffer);
+		return rc;
+	}
+
+	if (transferred != bare_config.total_length) {
+		free(buffer);
+		return ELIMIT;
+	}
+
+	/* Everything looks okay, copy the pointers. */
+
+	*descriptor_ptr = buffer;
+
+	if (descriptor_size != NULL) {
+		*descriptor_size = bare_config.total_length;
+	}
+
+	return EOK;
+}
+
 /** Set configuration of USB device.
  *
@@ -504,5 +569,6 @@
  *
  * @param[in] pipe Control endpoint pipe (session must be already started).
- * @param[in] index String index (in native endianess).
+ * @param[in] index String index (in native endianess),
+ *	first index has number 1 (index from descriptors can be used directly).
  * @param[in] lang String language (in native endianess).
  * @param[out] string_ptr Where to store allocated string in native encoding.
@@ -515,6 +581,9 @@
 		return EBADMEM;
 	}
-	/* Index is actually one byte value. */
-	if (index > 0xFF) {
+	/*
+	 * Index is actually one byte value and zero index is used
+	 * to retrieve list of supported languages.
+	 */
+	if ((index < 1) || (index > 0xFF)) {
 		return ERANGE;
 	}
Index: uspace/srv/devmap/devmap.c
===================================================================
--- uspace/srv/devmap/devmap.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/srv/devmap/devmap.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -123,4 +123,10 @@
 static devmap_handle_t last_handle = 0;
 static devmap_device_t *null_devices[NULL_DEVICES];
+
+/*
+ * Dummy list for null devices. This is necessary so that null devices can
+ * be used just as any other devices, e.g. in devmap_device_unregister_core().
+ */
+static LIST_INITIALIZE(dummy_null_driver_devices);
 
 static devmap_handle_t devmap_create_handle(void)
@@ -953,7 +959,11 @@
 	device->name = dev_name;
 	
-	/* Insert device into list of all devices
-	   and into null devices array */
+	/*
+	 * Insert device into list of all devices and into null devices array.
+	 * Insert device into a dummy list of null driver's devices so that it
+	 * can be safely removed later.
+	 */
 	list_append(&device->devices, &devices_list);
+	list_append(&device->driver_devices, &dummy_null_driver_devices);
 	null_devices[i] = device;
 	
Index: uspace/srv/fs/fat/fat_dentry.c
===================================================================
--- uspace/srv/fs/fat/fat_dentry.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/srv/fs/fat/fat_dentry.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -42,5 +42,5 @@
 static bool is_d_char(const char ch)
 {
-	if (isalnum(ch) || ch == '_')
+	if (isalnum(ch) || ch == '_' || ch == '-')
 		return true;
 	else
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -325,4 +325,5 @@
 		    uint16_t_le2host(d->firstc));
 		if (rc != EOK) {
+			(void) block_put(b);
 			(void) fat_node_put(FS_NODE(nodep));
 			return rc;
@@ -811,4 +812,5 @@
 	fibril_mutex_unlock(&childp->idx->lock);
 	childp->lnkcnt = 0;
+	childp->refcnt++;	/* keep the node in memory until destroyed */
 	childp->dirty = true;
 	fibril_mutex_unlock(&childp->lock);
@@ -1488,4 +1490,5 @@
 	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
 	fs_node_t *fn;
+	fat_node_t *nodep;
 	int rc;
 
@@ -1499,4 +1502,11 @@
 		return;
 	}
+
+	nodep = FAT_NODE(fn);
+	/*
+	 * We should have exactly two references. One for the above
+	 * call to fat_node_get() and one from fat_unlink().
+	 */
+	assert(nodep->refcnt == 2);
 
 	rc = fat_destroy_node(fn);
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ uspace/srv/hid/console/console.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -41,4 +41,5 @@
 #include <ipc/ns.h>
 #include <errno.h>
+#include <str_error.h>
 #include <ipc/console.h>
 #include <unistd.h>
@@ -64,4 +65,6 @@
 #define NAME       "console"
 #define NAMESPACE  "term"
+/** Interval for checking for new keyboard (1/4s). */
+#define HOTPLUG_WATCH_INTERVAL (1000 * 250)
 
 /** Phone to the keyboard driver. */
@@ -712,5 +715,6 @@
 }
 
-static int connect_keyboard(char *path)
+static int connect_keyboard_or_mouse(const char *devname,
+    async_client_conn_t handler, const char *path)
 {
 	int fd = open(path, O_RDONLY);
@@ -725,96 +729,53 @@
 	}
 	
-	/* NB: The callback connection is slotted for removal */
-	sysarg_t phonehash;
-	sysarg_t taskhash;
-	int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, SERVICE_CONSOLE,
-	    0, 0, NULL, NULL, NULL, &taskhash, &phonehash);
+	int rc = async_connect_to_me(phone, SERVICE_CONSOLE, 0, 0, handler);
 	if (rc != EOK) {
-		printf(NAME ": Failed to create callback from input device\n");
+		printf(NAME ": " \
+		    "Failed to create callback from input device: %s.\n",
+		    str_error(rc));
 		return rc;
 	}
 	
-	async_new_connection(taskhash, phonehash, 0, NULL, keyboard_events);
-
-	printf(NAME ": we got a hit (new keyboard \"%s\").\n", path);
+	printf(NAME ": found %s \"%s\".\n", devname, path);
 
 	return phone;
 }
 
-/** Try to connect to given keyboard, bypassing provided libc routines.
+static int connect_keyboard(const char *path)
+{
+	return connect_keyboard_or_mouse("keyboard", keyboard_events, path);
+}
+
+static int connect_mouse(const char *path)
+{
+	return connect_keyboard_or_mouse("mouse", mouse_events, path);
+}
+
+struct hid_class_info {
+	char *classname;
+	int (*connection_func)(const char *);
+};
+
+/** Periodically check for new keyboards in /dev/class/.
  *
- * @param devmap_path Path to keyboard without /dev prefix.
- * @return Phone or error code.
+ * @param arg Class name.
+ * @return This function should never exit.
  */
-static int connect_keyboard_bypass(char *devmap_path)
-{
-	int devmap_phone = async_connect_me_to_blocking(PHONE_NS,
-	    SERVICE_DEVMAP, DEVMAP_CLIENT, 0);
-	if (devmap_phone < 0) {
-		return devmap_phone;
-	}
-	ipc_call_t answer;
-	aid_t req = async_send_2(devmap_phone, DEVMAP_DEVICE_GET_HANDLE,
-	    0, 0,  &answer);
-
-	sysarg_t retval = async_data_write_start(devmap_phone,
-	    devmap_path, str_size(devmap_path));
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		async_hangup(devmap_phone);
-		return retval;
-	}
-
-	async_wait_for(req, &retval);
-
-	if (retval != EOK) {
-		async_hangup(devmap_phone);
-		return retval;
-	}
-
-	devmap_handle_t handle = (devmap_handle_t) IPC_GET_ARG1(answer);
-
-	async_hangup(devmap_phone);
-
-	int phone = async_connect_me_to(PHONE_NS,
-	    SERVICE_DEVMAP, DEVMAP_CONNECT_TO_DEVICE, handle);
-	if (phone < 0) {
-		return phone;
-	}
-
-	/* NB: The callback connection is slotted for removal */
-	sysarg_t phonehash;
-	sysarg_t taskhash;
-	int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, SERVICE_CONSOLE,
-	    0, 0, NULL, NULL, NULL, &taskhash, &phonehash);
-	if (rc != EOK) {
-		printf(NAME ": Failed to create callback from input device\n");
-		return rc;
-	}
-
-	async_new_connection(taskhash, phonehash, 0, NULL, keyboard_events);
-
-	printf(NAME ": we got a hit (new keyboard \"/dev/%s\").\n",
-	    devmap_path);
-
-	return phone;
-}
-
-
-static int check_new_keyboards(void *arg)
-{
-	char *class_name = (char *) arg;
-
-	int index = 1;
+static int check_new_device_fibril(void *arg)
+{
+	struct hid_class_info *dev_info = arg;
+
+	size_t index = 1;
 
 	while (true) {
-		async_usleep(1 * 500 * 1000);
+		async_usleep(HOTPLUG_WATCH_INTERVAL);
 		char *path;
-		int rc = asprintf(&path, "class/%s\\%d", class_name, index);
+		int rc = asprintf(&path, "/dev/class/%s\\%zu",
+		    dev_info->classname, index);
 		if (rc < 0) {
 			continue;
 		}
 		rc = 0;
-		rc = connect_keyboard_bypass(path);
+		rc = dev_info->connection_func(path);
 		if (rc > 0) {
 			/* We do not allow unplug. */
@@ -831,9 +792,28 @@
 /** Start a fibril monitoring hot-plugged keyboards.
  */
-static void check_new_keyboards_in_background()
-{
-	fid_t fid = fibril_create(check_new_keyboards, (void *)"keyboard");
+static void check_new_devices_in_background(int (*connection_func)(const char *),
+    const char *classname)
+{
+	struct hid_class_info *dev_info = malloc(sizeof(struct hid_class_info));
+	if (dev_info == NULL) {
+		printf(NAME ": " \
+		    "out of memory, will not start hot-plug-watch fibril.\n");
+		return;
+	}
+	int rc;
+
+	rc = asprintf(&dev_info->classname, "%s", classname);
+	if (rc < 0) {
+		printf(NAME ": failed to format classname: %s.\n",
+		    str_error(rc));
+		return;
+	}
+	dev_info->connection_func = connection_func;
+
+	fid_t fid = fibril_create(check_new_device_fibril, (void *)dev_info);
 	if (!fid) {
-		printf(NAME ": failed to create hot-plug-watch fibril.\n");
+		printf(NAME
+		    ": failed to create hot-plug-watch fibril for %s.\n",
+		    classname);
 		return;
 	}
@@ -849,27 +829,9 @@
 	}
 
-	/* Connect to mouse device */
-	mouse_phone = -1;
-	int mouse_fd = open("/dev/hid_in/mouse", O_RDONLY);
-	
-	if (mouse_fd < 0) {
-		printf(NAME ": Notice - failed opening %s\n", "/dev/hid_in/mouse");
-		goto skip_mouse;
-	}
-	
-	mouse_phone = fd_phone(mouse_fd);
+	mouse_phone = connect_mouse("/dev/hid_in/mouse");
 	if (mouse_phone < 0) {
-		printf(NAME ": Failed to connect to mouse device\n");
-		goto skip_mouse;
-	}
-	
-	if (async_connect_to_me(mouse_phone, SERVICE_CONSOLE, 0, 0, mouse_events)
-	    != 0) {
-		printf(NAME ": Failed to create callback from mouse device\n");
-		mouse_phone = -1;
-		goto skip_mouse;
-	}
-	
-skip_mouse:
+		printf(NAME ": Failed to connect to mouse device: %s.\n",
+		    str_error(mouse_phone));
+	}
 	
 	/* Connect to framebuffer driver */
@@ -955,5 +917,6 @@
 	
 	/* Start fibril for checking on hot-plugged keyboards. */
-	check_new_keyboards_in_background();
+	check_new_devices_in_background(connect_keyboard, "keyboard");
+	check_new_devices_in_background(connect_mouse, "mouse");
 
 	return true;
