Index: .bzrignore
===================================================================
--- .bzrignore	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ .bzrignore	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -89,4 +89,5 @@
 ./uspace/drv/usbhid/usbhid
 ./uspace/drv/usbmid/usbmid
+./uspace/drv/usbmouse/usbmouse
 ./uspace/drv/vhc/vhc
 ./uspace/srv/bd/ata_bd/ata_bd
Index: Makefile
===================================================================
--- Makefile	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ Makefile	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -42,5 +42,5 @@
 CONFIG_HEADER = config.h
 
-.PHONY: all precheck cscope autotool config_auto config_default config distclean clean check
+.PHONY: all precheck cscope autotool config_auto config_default config distclean clean check distfile dist
 
 all: $(COMMON_MAKEFILE) $(COMMON_HEADER) $(CONFIG_MAKEFILE) $(CONFIG_HEADER)
@@ -64,4 +64,6 @@
 endif
 
+# Autotool (detects compiler features)
+
 $(COMMON_MAKEFILE): autotool
 $(COMMON_HEADER): autotool
@@ -70,4 +72,6 @@
 	$(AUTOTOOL)
 	-[ -f $(COMMON_HEADER_PREV) ] && diff -q $(COMMON_HEADER_PREV) $(COMMON_HEADER) && mv -f $(COMMON_HEADER_PREV) $(COMMON_HEADER)
+
+# Build-time configuration
 
 $(CONFIG_MAKEFILE): config_default
@@ -84,6 +88,16 @@
 	$(CONFIG) $<
 
+# Distribution files
+
+distfile: all
+	$(MAKE) -C dist distfile
+
+dist:
+	$(MAKE) -C dist dist
+
+# Cleaning
+
 distclean: clean
-	rm -f $(CSCOPE).out $(COMMON_MAKEFILE) $(COMMON_HEADER) $(COMMON_HEADER_PREV) $(CONFIG_MAKEFILE) $(CONFIG_HEADER) tools/*.pyc tools/checkers/*.pyc
+	rm -f $(CSCOPE).out $(COMMON_MAKEFILE) $(COMMON_HEADER) $(COMMON_HEADER_PREV) $(CONFIG_MAKEFILE) $(CONFIG_HEADER) tools/*.pyc tools/checkers/*.pyc dist/HelenOS-*
 
 clean:
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ boot/arch/amd64/Makefile.inc	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -48,4 +48,5 @@
 	usbhid \
 	usbmid \
+	usbmouse \
 	vhc
 
Index: boot/arch/sparc64/include/arch.h
===================================================================
--- boot/arch/sparc64/include/arch.h	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ boot/arch/sparc64/include/arch.h	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -41,4 +41,5 @@
 #define STACK_BIAS                   2047
 #define STACK_WINDOW_SAVE_AREA_SIZE  (16 * 8)
+#define STACK_ARG_SAVE_AREA_SIZE     (6 * 8)
 
 #define NWINDOWS  8
Index: boot/arch/sparc64/src/asm.S
===================================================================
--- boot/arch/sparc64/src/asm.S	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ boot/arch/sparc64/src/asm.S	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -152,5 +152,5 @@
 .global ofw
 ofw:
-	save %sp, -STACK_WINDOW_SAVE_AREA_SIZE, %sp
+	save %sp, -(STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE), %sp
 	set ofw_cif, %l0
 	ldx [%l0], %l0
Index: boot/arch/sparc64/src/main.c
===================================================================
--- boot/arch/sparc64/src/main.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ boot/arch/sparc64/src/main.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -190,4 +190,5 @@
 	bootinfo.memmap.zones[0].start += OBP_BIAS;
 	bootinfo.memmap.zones[0].size -= OBP_BIAS;
+	bootinfo.memmap.total -= OBP_BIAS;
 }
 
@@ -204,4 +205,7 @@
 	bootinfo.physmem_start = ofw_get_physmem_start();
 	ofw_memmap(&bootinfo.memmap);
+
+	if (arch == ARCH_SUN4V)
+		sun4v_fixups();
 	
 	void *bootinfo_pa = ofw_translate(&bootinfo);
@@ -253,21 +257,16 @@
 		
 		/*
-		 * At this point, we claim the physical memory that we are
-		 * going to use. We should be safe in case of the virtual
+		 * At this point, we claim and map the physical memory that we
+		 * are going to use. We should be safe in case of the virtual
 		 * address space because the OpenFirmware, according to its
-		 * SPARC binding, should restrict its use of virtual memory
-		 * to addresses from [0xffd00000; 0xffefffff] and
-		 * [0xfe000000; 0xfeffffff].
-		 *
-		 * We don't map this piece of memory. We simply rely on
-		 * SILO to have it done for us already in this case.
-		 *
-		 * XXX SILO only maps 8 MB for us here. We should improve
-		 *     this code to be totally independent on the behavior
-		 *     of SILO.
-		 *
+		 * SPARC binding, should restrict its use of virtual memory to
+		 * addresses from [0xffd00000; 0xffefffff] and [0xfe000000;
+		 * 0xfeffffff].
 		 */
 		ofw_claim_phys(bootinfo.physmem_start + dest[i - 1],
 		    ALIGN_UP(components[i - 1].inflated, PAGE_SIZE));
+		
+		ofw_map(bootinfo.physmem_start + dest[i - 1], dest[i - 1],
+		    ALIGN_UP(components[i - 1].inflated, PAGE_SIZE), -1);
 		
 		int err = inflate(components[i - 1].start, components[i - 1].size,
@@ -304,7 +303,4 @@
 		sun4u_smp();
 	
-	if (arch == ARCH_SUN4V)
-		sun4v_fixups();
-	
 	printf("Booting the kernel ...\n");
 	jump_to_kernel(bootinfo.physmem_start | BSP_PROCESSOR, &bootinfo, subarch,
Index: boot/generic/src/balloc.c
===================================================================
--- boot/generic/src/balloc.c	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ boot/generic/src/balloc.c	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -65,4 +65,4 @@
 void *balloc_rebase(void *ptr)
 {
-	return (void *) ((uintptr_t) ptr - phys_base + ballocs->base);
+	return (void *) (((uintptr_t) ptr - phys_base) + ballocs->base);
 }
Index: dist/Makefile
===================================================================
--- dist/Makefile	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
+++ dist/Makefile	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2011 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.
+#
+
+-include ../version
+-include ../Makefile.config
+-include ../boot/arch/$(BARCH)/Makefile.inc
+-include ../boot/Makefile.common
+
+PROFILES = amd64 arm32/GXemul arm32/integratorcp arm32/gta02 ia32 \
+    ia64/i460GX ia64/ski mips32/GXemul mips32/msim sparc64/niagara \
+    sparc64/serengeti sparc64/ultra
+
+ifdef POST_OUTPUT
+	IMGFILE = $(POST_OUTPUT)
+else
+	IMGFILE = $(BOOT_OUTPUT)
+endif
+
+SUFFIX = $(suffix $(IMGFILE))
+DISTFILE = HelenOS-$(RELEASE)-$(PLATFORM)-$(MACHINE)-$(PROCESSOR)$(SUFFIX)
+
+.PHONY: all clean dist distfile
+
+all: distfile
+distfile: $(DISTFILE)
+
+$(DISTFILE): $(IMGFILE)
+	cp $< $@
+
+dist:
+	for profile in $(PROFILES); do \
+		$(MAKE) -C .. clean ; \
+		$(MAKE) -C .. PROFILE=$$profile distfile ; \
+	done
+
+clean:
+	rm -f $(DISTFILE)
Index: kernel/arch/sparc64/src/sun4v/asm.S
===================================================================
--- kernel/arch/sparc64/src/sun4v/asm.S	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ kernel/arch/sparc64/src/sun4v/asm.S	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -41,6 +41,5 @@
 .global switch_to_userspace
 switch_to_userspace:
-	wrpr PSTATE_PRIV_BIT, %pstate
-	save %o1, -STACK_WINDOW_SAVE_AREA_SIZE, %sp
+	save %o1, -(STACK_WINDOW_SAVE_AREA_SIZE + STACK_ARG_SAVE_AREA_SIZE), %sp
 	flushw
 	wrpr %g0, 0, %cleanwin		! avoid information leak
Index: tools/toolchain.sh
===================================================================
--- tools/toolchain.sh	(revision bdc8ab120bb3fc10b404dab299f0a4f51ad6cf00)
+++ tools/toolchain.sh	(revision 9445aad4b777c461479b233a5e9bedc578eb22b5)
@@ -28,4 +28,74 @@
 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
+
+GMP_MAIN=<<EOF
+#define GCC_GMP_VERSION_NUM(a, b, c) \
+	(((a) << 16L) | ((b) << 8) | (c))
+
+#define GCC_GMP_VERSION \
+	GCC_GMP_VERSION_NUM(__GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, __GNU_MP_VERSION_PATCHLEVEL)
+
+#if GCC_GMP_VERSION < GCC_GMP_VERSION_NUM(4,3,2)
+	choke me
+#endif
+EOF
+
+MPFR_MAIN=<<EOF
+#if MPFR_VERSION < MPFR_VERSION_NUM(2, 4, 2)
+choke me
+	#endif
+EOF
+
+MPC_MAIN=<<EOF
+#if MPC_VERSION < MPC_VERSION_NUM(0, 8, 1)
+	choke me
+#endif
+EOF
+
+#
+# Check if the library described in the argument
+# exists and has acceptable version.
+#
+check_dependency() {
+	DEPENDENCY="$1"
+	HEADER="$2"
+	BODY="$3"
+	
+	FNAME="/tmp/conftest-$$"
+	
+	echo "#include ${HEADER}" > "${FNAME}.c"
+	echo >> "${FNAME}.c"
+	echo "int main()" >> "${FNAME}.c"
+	echo "{" >> "${FNAME}.c"
+	echo "${BODY}" >> "${FNAME}.c"
+	echo "	return 0;" >> "${FNAME}.c"
+	echo "}" >> "${FNAME}.c"
+	
+	cc -c -o "${FNAME}.o" "${FNAME}.c" 2> "${FNAME}.log"
+	RC="$?"
+	
+	if [ "$RC" -ne "0" ] ; then
+		echo " ${DEPENDENCY} not found, too old or compiler error."
+		echo " Please recheck manually the source file \"${FNAME}.c\"."
+		echo " The compilation of the toolchain is probably going to fail,"
+		echo " you have been warned."
+		echo
+		echo " ===== Compiler output ====="
+		cat "${FNAME}.log"
+		echo " ==========================="
+		echo
+	else
+		echo " ${DEPENDENCY} found"
+		rm -f "${FNAME}.log" "${FNAME}.o" "${FNAME}.c"
+	fi
+}
+
+check_dependecies() {
+	echo ">>> Basic dependency check"
+	check_dependency "GMP" "<gmp.h>" "${GMP_MAIN}"
+	check_dependency "MPFR" "<mpfr.h>" "${MPFR_MAIN}"
+	check_dependency "MPC" "<mpc.h>" "${MPC_MAIN}"
+	echo
+}
 
 check_error() {
@@ -69,4 +139,8 @@
 	echo " sparc64    SPARC V9"
 	echo " all        build all targets"
+	echo
+	echo "The toolchain will be installed to the directory specified by"
+	echo "the CROSS_PREFIX environment variable. If the variable is not"
+	echo "defined, /usr/local will be used by default."
 	echo
 	
@@ -118,6 +192,4 @@
 	echo " - native C library with headers"
 	echo
-	
-	show_countdown 10
 }
 
@@ -281,4 +353,6 @@
 
 show_dependencies
+check_dependecies
+show_countdown 10
 
 case "$1" in
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;
