Index: .bzrignore
===================================================================
--- .bzrignore	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ .bzrignore	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -281,4 +281,5 @@
 uspace/drv/block/ata_bd/ata_bd
 uspace/drv/block/ddisk/ddisk
+uspace/drv/block/usbmast/usbmast
 uspace/drv/bus/adb/cuda_adb/cuda_adb
 uspace/drv/bus/isa/isa
@@ -288,7 +289,5 @@
 uspace/drv/bus/usb/uhci/uhci
 uspace/drv/bus/usb/usbflbk/usbflbk
-uspace/drv/bus/usb/usbhid/usbhid
 uspace/drv/bus/usb/usbhub/usbhub
-uspace/drv/bus/usb/usbmast/usbmast
 uspace/drv/bus/usb/usbmid/usbmid
 uspace/drv/bus/usb/vhc/vhc
@@ -304,4 +303,5 @@
 uspace/drv/hid/xtkbd/xtkbd
 uspace/drv/hid/ps2mouse/ps2mouse
+uspace/drv/hid/usbhid/usbhid
 uspace/drv/intctl/apic/apic
 uspace/drv/intctl/i8259/i8259
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ boot/arch/amd64/Makefile.inc	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -51,8 +51,8 @@
 	bus/usb/usbflbk \
 	bus/usb/usbhub \
-	bus/usb/usbhid \
-	bus/usb/usbmast \
 	bus/usb/usbmid \
-	bus/usb/vhc
+	bus/usb/vhc \
+	block/usbmast \
+	hid/usbhid
 
 RD_DRV_CFG += \
Index: boot/arch/arm32/Makefile.inc
===================================================================
--- boot/arch/arm32/Makefile.inc	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ boot/arch/arm32/Makefile.inc	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -85,7 +85,7 @@
 	bus/usb/usbflbk \
 	bus/usb/usbhub \
-	bus/usb/usbhid \
-	bus/usb/usbmast \
-	bus/usb/usbmid
+	bus/usb/usbmid \
+	block/usbmast \
+	hid/usbhid
 
 SOURCES = \
Index: boot/arch/ia64/Makefile.inc
===================================================================
--- boot/arch/ia64/Makefile.inc	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ boot/arch/ia64/Makefile.inc	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -82,8 +82,8 @@
 	bus/usb/usbflbk \
 	bus/usb/usbhub \
-	bus/usb/usbhid \
-	bus/usb/usbmast \
 	bus/usb/usbmid \
-	bus/usb/vhc
+	bus/usb/vhc \
+	block/usbmast \
+	hid/usbhid
 
 RD_DRV_CFG += \
Index: boot/arch/ppc32/Makefile.inc
===================================================================
--- boot/arch/ppc32/Makefile.inc	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ boot/arch/ppc32/Makefile.inc	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -49,8 +49,8 @@
 	bus/usb/usbflbk \
 	bus/usb/usbhub \
-	bus/usb/usbhid \
-	bus/usb/usbmast \
 	bus/usb/usbmid \
-	bus/usb/vhc
+	bus/usb/vhc \
+	block/usbmast \
+	hid/usbhid
 
 SOURCES = \
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ uspace/Makefile	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -143,4 +143,5 @@
 	drv/block/ata_bd \
 	drv/block/ddisk \
+	drv/block/usbmast \
 	drv/bus/adb/cuda_adb \
 	drv/bus/isa \
@@ -150,7 +151,5 @@
 	drv/bus/usb/uhci \
 	drv/bus/usb/usbflbk \
-	drv/bus/usb/usbhid \
 	drv/bus/usb/usbhub \
-	drv/bus/usb/usbmast \
 	drv/bus/usb/usbmid \
 	drv/bus/usb/vhc \
@@ -161,11 +160,9 @@
 	drv/char/ski-con \
 	drv/char/sun4v-con \
-	drv/test/test1 \
-	drv/test/test2 \
-	drv/test/test3 \
 	drv/fb/amdm37x_dispc \
 	drv/fb/kfb \
 	drv/hid/atkbd \
 	drv/hid/ps2mouse \
+	drv/hid/usbhid \
 	drv/hid/xtkbd \
 	drv/intctl/apic \
@@ -186,4 +183,7 @@
 	drv/platform/ski \
 	drv/platform/sun4v \
+	drv/test/test1 \
+	drv/test/test2 \
+	drv/test/test3 \
 	drv/time/cmos-rtc
 
Index: uspace/drv/block/usbmast/Makefile
===================================================================
--- uspace/drv/block/usbmast/Makefile	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/block/usbmast/Makefile	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,41 @@
+#
+# 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 = usbdev usb drv scsi
+
+BINARY = usbmast
+
+SOURCES = \
+	bo_trans.c \
+	cmdw.c \
+	main.c \
+	scsi_ms.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/block/usbmast/bo_trans.c
===================================================================
--- uspace/drv/block/usbmast/bo_trans.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/block/usbmast/bo_trans.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,272 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * USB mass storage bulk-only transport.
+ */
+
+#include <stdbool.h>
+#include <errno.h>
+#include <str_error.h>
+#include <usb/debug.h>
+#include <usb/dev/request.h>
+
+#include "bo_trans.h"
+#include "cmdw.h"
+#include "usbmast.h"
+
+
+#define MASTLOG(format, ...) \
+	usb_log_debug2("USB cl08: " format, ##__VA_ARGS__)
+
+/** Send command via bulk-only transport.
+ *
+ * @param mfun		Mass storage function
+ * @param tag		Command block wrapper tag (automatically compared
+ *			with answer)
+ * @param cmd		SCSI command
+ *
+ * @return		Error code
+ */
+int usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, scsi_cmd_t *cmd)
+{
+	int rc;
+
+	if (cmd->data_in && cmd->data_out)
+		return EINVAL;
+
+	usb_pipe_t *bulk_in_pipe = mfun->mdev->bulk_in_pipe;
+	usb_pipe_t *bulk_out_pipe = mfun->mdev->bulk_out_pipe;
+
+	usb_pipe_t *dpipe = bulk_out_pipe;
+	usb_direction_t ddir = USB_DIRECTION_OUT;
+	size_t dbuf_size = cmd->data_out_size;
+
+	if (cmd->data_in) {
+		ddir = USB_DIRECTION_IN;
+		dbuf_size = cmd->data_in_size;
+		dpipe = bulk_in_pipe;
+	}
+
+	/* Prepare CBW - command block wrapper */
+	usb_massstor_cbw_t cbw;
+	usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, mfun->lun,
+	    cmd->cdb_size, cmd->cdb);
+
+	/* Send the CBW. */
+	MASTLOG("Sending CBW.\n");
+	rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
+	MASTLOG("CBW '%s' sent: %s.\n",
+	    usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
+	    str_error(rc));
+	if (rc != EOK) {
+		usb_log_error("Bulk out write failed: %s\n", str_error(rc));
+		return EIO;
+	}
+
+	MASTLOG("Transferring data.\n");
+	if (cmd->data_in) {
+		size_t act_size;
+		/* Recieve data from the device. */
+		rc = usb_pipe_read(dpipe, cmd->data_in, cmd->data_in_size,
+		    &act_size);
+		MASTLOG("Received %zu bytes (%s): %s.\n", act_size,
+		    usb_debug_str_buffer(cmd->data_in, act_size, 0),
+		    str_error(rc));
+	}
+	if (cmd->data_out) {
+		/* Send data to the device. */
+		rc = usb_pipe_write(dpipe, cmd->data_out, cmd->data_out_size);
+		MASTLOG("Sent %zu bytes (%s): %s.\n", cmd->data_out_size,
+		    usb_debug_str_buffer(cmd->data_out, cmd->data_out_size, 0),
+		    str_error(rc));
+	}
+
+	if (rc == ESTALL) {
+		/* Clear stall condition and continue below to read CSW. */
+		usb_pipe_clear_halt(
+		    usb_device_get_default_pipe(mfun->mdev->usb_dev), dpipe);
+        } else if (rc != EOK) {
+		usb_log_error("Failed to transfer data: %s", str_error(rc));
+		return EIO;
+	}
+
+	/* Read CSW. */
+	usb_massstor_csw_t csw;
+	size_t csw_size;
+	MASTLOG("Reading CSW.\n");
+	rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
+	MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
+	    usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
+	    str_error(rc));
+	if (rc != EOK) {
+		usb_log_error("Failed to read CSW: %s", str_error(rc));
+		return EIO;
+	}
+
+	if (csw_size != sizeof(csw)) {
+		usb_log_error("Received CSW of incorrect size.");
+		return EIO;
+	}
+
+	if (csw.dCSWTag != tag) {
+		usb_log_error("Received CSW with incorrect tag. (expected: %"
+		    PRIX32" received: %"PRIx32, tag, csw.dCSWTag);
+		return EIO;
+	}
+
+	/*
+	 * Determine the actual return value from the CSW.
+	 */
+	switch (csw.dCSWStatus) {
+	case cbs_passed:
+		cmd->status = CMDS_GOOD;
+		break;
+	case cbs_failed:
+		cmd->status = CMDS_FAILED;
+		usb_log_error("CBS Failed.\n");
+		break;
+	case cbs_phase_error:
+		usb_log_error("CBS phase error.\n");
+		rc = EIO;
+		break;
+	default:
+		usb_log_error("CBS other error.\n");
+		rc = EIO;
+		break;
+	}
+
+	const size_t residue = uint32_usb2host(csw.dCSWDataResidue);
+	if (residue > dbuf_size) {
+		usb_log_error("Residue > buffer size (%zu > %zu).\n",
+		    residue, dbuf_size);
+		return EIO;
+	}
+
+	/*
+	 * When the device has less data to send than requested (or cannot
+	 * receive moredata), it can either stall the pipe or send garbage
+	 * (ignore data) and indicate that via the residue field in CSW.
+	 * That means dbuf_size - residue is the authoritative size of data
+	 * received (sent).
+	 */
+
+	if (cmd->data_in)
+		cmd->rcvd_size = dbuf_size - residue;
+
+	return rc;
+}
+
+/** Perform bulk-only mass storage reset.
+ *
+ * @param mfun		Mass storage function
+ * @return		Error code
+ */
+int usb_massstor_reset(usbmast_dev_t *mdev)
+{
+	return usb_control_request_set(
+	    usb_device_get_default_pipe(mdev->usb_dev),
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
+	    0xFF, 0, usb_device_get_iface_number(mdev->usb_dev), NULL, 0);
+}
+
+/** Perform complete reset recovery of bulk-only mass storage.
+ *
+ * Notice that no error is reported because if this fails, the error
+ * would reappear on next transaction somehow.
+ *
+ * @param mfun		Mass storage function
+ */
+void usb_massstor_reset_recovery(usbmast_dev_t *mdev)
+{
+	/* We would ignore errors here because if this fails
+	 * we are doomed anyway and any following transaction would fail.
+	 */
+	usb_massstor_reset(mdev);
+	usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
+	    mdev->bulk_in_pipe);
+	usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
+	    mdev->bulk_out_pipe);
+}
+
+/** Get max LUN of a mass storage device.
+ *
+ * @see usb_masstor_get_lun_count
+ *
+ * @warning Error from this command does not necessarily indicate malfunction
+ * of the device. Device does not need to support this request.
+ * You shall rather use usb_masstor_get_lun_count.
+ *
+ * @param mfun		Mass storage function
+ * @return		Error code of maximum LUN (index, not count)
+ */
+int usb_massstor_get_max_lun(usbmast_dev_t *mdev)
+{
+	uint8_t max_lun;
+	size_t data_recv_len;
+	int rc = usb_control_request_get(
+	    usb_device_get_default_pipe(mdev->usb_dev),
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
+	    0xFE, 0, usb_device_get_iface_number(mdev->usb_dev), &max_lun, 1,
+	    &data_recv_len);
+	if (rc != EOK) {
+		return rc;
+	}
+	if (data_recv_len != 1) {
+		return EEMPTY;
+	}
+	return (int) max_lun;
+}
+
+/** Get number of LUNs supported by mass storage device.
+ *
+ * @warning This function hides any error during the request
+ * (typically that shall not be a problem).
+ *
+ * @param mfun		Mass storage function
+ * @return		Number of LUNs
+ */
+size_t usb_masstor_get_lun_count(usbmast_dev_t *mdev)
+{
+	int max_lun = usb_massstor_get_max_lun(mdev);
+	if (max_lun < 0) {
+		max_lun = 1;
+	} else {
+		max_lun++;
+	}
+
+	return (size_t) max_lun;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/block/usbmast/bo_trans.h
===================================================================
--- uspace/drv/block/usbmast/bo_trans.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/block/usbmast/bo_trans.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,98 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * USB mass storage bulk-only transport.
+ */
+
+#ifndef BO_TRANS_H_
+#define BO_TRANS_H_
+
+#include <scsi/spc.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <usb/usb.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/driver.h>
+#include "usbmast.h"
+
+typedef enum cmd_status {
+	CMDS_GOOD,
+	CMDS_FAILED
+} cmd_status_t;
+
+/** SCSI command.
+ *
+ * Contains (a subset of) the input and output arguments of SCSI
+ * Execute Command procedure call (see SAM-4 chapter 5.1)
+ */
+typedef struct {
+	/*
+	 * Related to IN fields
+	 */
+
+	/** Command Descriptor Block */
+	const void *cdb;
+	/** CDB size in bytes */
+	size_t cdb_size;
+
+	/** Outgoing data */
+	const void *data_out;
+	/** Size of outgoing data in bytes */
+	size_t data_out_size;
+
+	/*
+	 * Related to OUT fields
+	 */
+
+	/** Buffer for incoming data */
+	void *data_in;
+	/** Size of input buffer in bytes */
+	size_t data_in_size;
+
+	/** Number of bytes actually received */
+	size_t rcvd_size;
+
+	/** Status */
+	cmd_status_t status;
+} scsi_cmd_t;
+
+extern int usb_massstor_cmd(usbmast_fun_t *, uint32_t, scsi_cmd_t *);
+extern int usb_massstor_reset(usbmast_dev_t *);
+extern void usb_massstor_reset_recovery(usbmast_dev_t *);
+extern int usb_massstor_get_max_lun(usbmast_dev_t *);
+extern size_t usb_masstor_get_lun_count(usbmast_dev_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/block/usbmast/cmdw.c
===================================================================
--- uspace/drv/block/usbmast/cmdw.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/block/usbmast/cmdw.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,66 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * USB mass storage commands.
+ */
+
+#include <byteorder.h>
+#include <mem.h>
+#include <stdint.h>
+#include <usb/usb.h>
+#include "cmdw.h"
+
+void usb_massstor_cbw_prepare(usb_massstor_cbw_t *cbw,
+    uint32_t tag, uint32_t transfer_length, usb_direction_t dir,
+    uint8_t lun, uint8_t cmd_len, const uint8_t *cmd)
+{
+	cbw->dCBWSignature = uint32_host2usb(0x43425355);
+	cbw->dCBWTag = tag;
+	cbw->dCBWDataTransferLength = transfer_length;
+
+	cbw->bmCBWFlags = 0;
+	if (dir == USB_DIRECTION_IN) {
+		cbw->bmCBWFlags |= (1 << 7);
+	}
+
+	/* Only lowest 4 bits. */
+	cbw->bCBWLUN = lun & 0x0F;
+
+	/* Only lowest 5 bits. */
+	cbw->bCBWBLength = cmd_len & 0x1F;
+
+	memcpy(cbw->CBWCB, cmd, cbw->bCBWBLength);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/block/usbmast/cmdw.h
===================================================================
--- uspace/drv/block/usbmast/cmdw.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/block/usbmast/cmdw.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,72 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * USB mass storage commands.
+ */
+
+#ifndef CMDW_H_
+#define CMDW_H_
+
+#include <stdint.h>
+#include <usb/usb.h>
+
+typedef struct {
+	uint32_t dCBWSignature;
+	uint32_t dCBWTag;
+	uint32_t dCBWDataTransferLength;
+	uint8_t bmCBWFlags;
+	uint8_t bCBWLUN;
+	uint8_t bCBWBLength;
+	uint8_t CBWCB[16];
+} __attribute__((packed)) usb_massstor_cbw_t;
+
+typedef struct {
+	uint32_t dCSWSignature;
+	uint32_t dCSWTag;
+	uint32_t dCSWDataResidue;
+	uint8_t dCSWStatus;
+} __attribute__((packed)) usb_massstor_csw_t;
+
+enum cmd_block_status {
+	cbs_passed	= 0x00,
+	cbs_failed	= 0x01,
+	cbs_phase_error = 0x02
+};
+
+extern void usb_massstor_cbw_prepare(usb_massstor_cbw_t *, uint32_t, uint32_t,
+    usb_direction_t, uint8_t, uint8_t, const uint8_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/block/usbmast/main.c
===================================================================
--- uspace/drv/block/usbmast/main.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/block/usbmast/main.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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.
+ */
+
+/** @addtogroup drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB mass storage driver.
+ */
+
+#include <as.h>
+#include <async.h>
+#include <bd_srv.h>
+#include <macros.h>
+#include <usb/dev/driver.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/classes/massstor.h>
+#include <errno.h>
+#include <io/logctl.h>
+#include <str_error.h>
+#include "cmdw.h"
+#include "bo_trans.h"
+#include "scsi_ms.h"
+#include "usbmast.h"
+
+#define NAME "usbmast"
+
+static const usb_endpoint_description_t bulk_in_ep = {
+	.transfer_type = USB_TRANSFER_BULK,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_MASS_STORAGE,
+	.interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
+	.interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
+	.flags = 0
+};
+static const usb_endpoint_description_t bulk_out_ep = {
+	.transfer_type = USB_TRANSFER_BULK,
+	.direction = USB_DIRECTION_OUT,
+	.interface_class = USB_CLASS_MASS_STORAGE,
+	.interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
+	.interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
+	.flags = 0
+};
+
+static const usb_endpoint_description_t *mast_endpoints[] = {
+	&bulk_in_ep,
+	&bulk_out_ep,
+	NULL
+};
+
+static int usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun);
+static void usbmast_bd_connection(ipc_callid_t iid, ipc_call_t *icall,
+    void *arg);
+
+static int usbmast_bd_open(bd_srvs_t *, bd_srv_t *);
+static int usbmast_bd_close(bd_srv_t *);
+static int usbmast_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
+static int usbmast_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);
+static int usbmast_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
+static int usbmast_bd_get_block_size(bd_srv_t *, size_t *);
+static int usbmast_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
+
+static bd_ops_t usbmast_bd_ops = {
+	.open = usbmast_bd_open,
+	.close = usbmast_bd_close,
+	.read_blocks = usbmast_bd_read_blocks,
+	.sync_cache = usbmast_bd_sync_cache,
+	.write_blocks = usbmast_bd_write_blocks,
+	.get_block_size = usbmast_bd_get_block_size,
+	.get_num_blocks = usbmast_bd_get_num_blocks
+};
+
+static usbmast_fun_t *bd_srv_usbmast(bd_srv_t *bd)
+{
+	return (usbmast_fun_t *) bd->srvs->sarg;
+}
+
+/** Callback when a device is removed from the system.
+ *
+ * @param dev Representation of USB device.
+ * @return Error code.
+ */
+static int usbmast_device_gone(usb_device_t *dev)
+{
+	usbmast_dev_t *mdev = usb_device_data_get(dev);
+	assert(mdev);
+
+	for (size_t i = 0; i < mdev->lun_count; ++i) {
+		const int rc = ddf_fun_unbind(mdev->luns[i]);
+		if (rc != EOK) {
+			usb_log_error("Failed to unbind LUN function %zu: "
+			    "%s\n", i, str_error(rc));
+			return rc;
+		}
+		ddf_fun_destroy(mdev->luns[i]);
+		mdev->luns[i] = NULL;
+	}
+	free(mdev->luns);
+	return EOK;
+}
+
+/** Callback when a device is about to be removed.
+ *
+ * @param dev Representation of USB device.
+ * @return Error code.
+ */
+static int usbmast_device_remove(usb_device_t *dev)
+{
+	//TODO: flush buffers, or whatever.
+	//TODO: remove device
+	return ENOTSUP;
+}
+
+/** Callback when new device is attached and recognized as a mass storage.
+ *
+ * @param dev Representation of USB device.
+ * @return Error code.
+ */
+static int usbmast_device_add(usb_device_t *dev)
+{
+	int rc;
+	usbmast_dev_t *mdev = NULL;
+	unsigned i;
+
+	usb_endpoint_mapping_t *epm_in =
+	    usb_device_get_mapped_ep_desc(dev, &bulk_in_ep);
+	usb_endpoint_mapping_t *epm_out =
+	    usb_device_get_mapped_ep_desc(dev, &bulk_out_ep);
+	if (!epm_in || !epm_out || !epm_in->present || !epm_out->present) {
+		usb_log_error("Required EPs were not mapped.\n");
+		return ENOENT;
+	}
+
+	/* Allocate softstate */
+	mdev = usb_device_data_alloc(dev, sizeof(usbmast_dev_t));
+	if (mdev == NULL) {
+		usb_log_error("Failed allocating softstate.\n");
+		return ENOMEM;
+	}
+
+	mdev->usb_dev = dev;
+
+	usb_log_info("Initializing mass storage `%s'.\n",
+	    usb_device_get_name(dev));
+	usb_log_debug("Bulk in endpoint: %d [%zuB].\n",
+	    epm_in->pipe.endpoint_no, epm_in->pipe.max_packet_size);
+	usb_log_debug("Bulk out endpoint: %d [%zuB].\n",
+	    epm_out->pipe.endpoint_no, epm_out->pipe.max_packet_size);
+
+	usb_log_debug("Get LUN count...\n");
+	mdev->lun_count = usb_masstor_get_lun_count(mdev);
+	mdev->luns = calloc(mdev->lun_count, sizeof(ddf_fun_t*));
+	if (mdev->luns == NULL) {
+		rc = ENOMEM;
+		usb_log_error("Failed allocating luns table.\n");
+		goto error;
+	}
+
+	mdev->bulk_in_pipe = &epm_in->pipe;
+	mdev->bulk_out_pipe = &epm_out->pipe;
+	for (i = 0; i < mdev->lun_count; i++) {
+		rc = usbmast_fun_create(mdev, i);
+		if (rc != EOK)
+			goto error;
+	}
+
+	return EOK;
+error:
+	/* Destroy functions */
+	for (size_t i = 0; i < mdev->lun_count; ++i) {
+		if (mdev->luns[i] == NULL)
+			continue;
+		const int rc = ddf_fun_unbind(mdev->luns[i]);
+		if (rc != EOK) {
+			usb_log_warning("Failed to unbind LUN function %zu: "
+			    "%s.\n", i, str_error(rc));
+		}
+		ddf_fun_destroy(mdev->luns[i]);
+	}
+	free(mdev->luns);
+	return rc;
+}
+
+/** Create mass storage function.
+ *
+ * Called once for each LUN.
+ *
+ * @param mdev		Mass storage device
+ * @param lun		LUN
+ * @return		EOK on success or negative error code.
+ */
+static int usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun)
+{
+	int rc;
+	char *fun_name = NULL;
+	ddf_fun_t *fun = NULL;
+	usbmast_fun_t *mfun = NULL;
+
+	if (asprintf(&fun_name, "l%u", lun) < 0) {
+		usb_log_error("Out of memory.\n");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	fun = usb_device_ddf_fun_create(mdev->usb_dev, fun_exposed, fun_name);
+	if (fun == NULL) {
+		usb_log_error("Failed to create DDF function %s.\n", fun_name);
+		rc = ENOMEM;
+		goto error;
+	}
+
+	/* Allocate soft state */
+	mfun = ddf_fun_data_alloc(fun, sizeof(usbmast_fun_t));
+	if (mfun == NULL) {
+		usb_log_error("Failed allocating softstate.\n");
+		rc = ENOMEM;
+		goto error;
+	}
+
+	mfun->ddf_fun = fun;
+	mfun->mdev = mdev;
+	mfun->lun = lun;
+
+	bd_srvs_init(&mfun->bds);
+	mfun->bds.ops = &usbmast_bd_ops;
+	mfun->bds.sarg = mfun;
+
+	/* Set up a connection handler. */
+	ddf_fun_set_conn_handler(fun, usbmast_bd_connection);
+
+	usb_log_debug("Inquire...\n");
+	usbmast_inquiry_data_t inquiry;
+	rc = usbmast_inquiry(mfun, &inquiry);
+	if (rc != EOK) {
+		usb_log_warning("Failed to inquire device `%s': %s.\n",
+		    usb_device_get_name(mdev->usb_dev), str_error(rc));
+		rc = EIO;
+		goto error;
+	}
+
+	usb_log_info("Mass storage `%s' LUN %u: " \
+	    "%s by %s rev. %s is %s (%s).\n",
+	    usb_device_get_name(mdev->usb_dev),
+	    lun,
+	    inquiry.product,
+	    inquiry.vendor,
+	    inquiry.revision,
+	    usbmast_scsi_dev_type_str(inquiry.device_type),
+	    inquiry.removable ? "removable" : "non-removable");
+
+	uint32_t nblocks, block_size;
+
+	rc = usbmast_read_capacity(mfun, &nblocks, &block_size);
+	if (rc != EOK) {
+		usb_log_warning("Failed to read capacity, device `%s': %s.\n",
+		    usb_device_get_name(mdev->usb_dev), str_error(rc));
+		rc = EIO;
+		goto error;
+	}
+
+	usb_log_info("Read Capacity: nblocks=%" PRIu32 ", "
+	    "block_size=%" PRIu32 "\n", nblocks, block_size);
+
+	mfun->nblocks = nblocks;
+	mfun->block_size = block_size;
+
+	rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		usb_log_error("Failed to bind DDF function %s: %s.\n",
+		    fun_name, str_error(rc));
+		goto error;
+	}
+
+	ddf_fun_add_to_category(fun, "disk");
+
+	free(fun_name);
+	mdev->luns[lun] = fun;
+
+	return EOK;
+
+	/* Error cleanup */
+error:
+	if (fun != NULL)
+		ddf_fun_destroy(fun);
+	if (fun_name != NULL)
+		free(fun_name);
+	return rc;
+}
+
+/** Blockdev client connection handler. */
+static void usbmast_bd_connection(ipc_callid_t iid, ipc_call_t *icall,
+    void *arg)
+{
+	usbmast_fun_t *mfun;
+
+	mfun = (usbmast_fun_t *) ddf_fun_data_get((ddf_fun_t *)arg);
+	bd_conn(iid, icall, &mfun->bds);
+}
+
+/** Open device. */
+static int usbmast_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
+{
+	return EOK;
+}
+
+/** Close device. */
+static int usbmast_bd_close(bd_srv_t *bd)
+{
+	return EOK;
+}
+
+/** Read blocks from the device. */
+static int usbmast_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, void *buf,
+    size_t size)
+{
+	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
+
+	if (size < cnt * mfun->block_size)
+		return EINVAL;
+
+	return usbmast_read(mfun, ba, cnt, buf);
+}
+
+/** Synchronize blocks to nonvolatile storage. */
+static int usbmast_bd_sync_cache(bd_srv_t *bd, uint64_t ba, size_t cnt)
+{
+	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
+
+	return usbmast_sync_cache(mfun, ba, cnt);
+}
+
+/** Write blocks to the device. */
+static int usbmast_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
+    const void *buf, size_t size)
+{
+	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
+
+	if (size < cnt * mfun->block_size)
+		return EINVAL;
+
+	return usbmast_write(mfun, ba, cnt, buf);
+}
+
+/** Get device block size. */
+static int usbmast_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
+{
+	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
+	*rsize = mfun->block_size;
+	return EOK;
+}
+
+/** Get number of blocks on device. */
+static int usbmast_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
+{
+	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
+	*rnb = mfun->nblocks;
+	return EOK;
+}
+
+
+/** USB mass storage driver ops. */
+static const usb_driver_ops_t usbmast_driver_ops = {
+	.device_add = usbmast_device_add,
+	.device_rem = usbmast_device_remove,
+	.device_gone = usbmast_device_gone,
+};
+
+/** USB mass storage driver. */
+static const usb_driver_t usbmast_driver = {
+	.name = NAME,
+	.ops = &usbmast_driver_ops,
+	.endpoints = mast_endpoints
+};
+
+int main(int argc, char *argv[])
+{
+	log_init(NAME);
+	logctl_set_log_level(NAME, LVL_NOTE);
+	return usb_driver_main(&usbmast_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/block/usbmast/scsi_ms.c
===================================================================
--- uspace/drv/block/usbmast/scsi_ms.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/block/usbmast/scsi_ms.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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.
+ */
+
+/** @addtogroup drvusbmast
+ * @{
+ */
+/**
+ * @file
+ * SCSI functions for USB mass storage driver.
+ */
+
+#include <bitops.h>
+#include <byteorder.h>
+#include <inttypes.h>
+#include <macros.h>
+#include <usb/dev/driver.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+#include <str.h>
+#include <scsi/sbc.h>
+#include <scsi/spc.h>
+#include "cmdw.h"
+#include "bo_trans.h"
+#include "scsi_ms.h"
+#include "usbmast.h"
+
+/** Get string representation for SCSI peripheral device type.
+ *
+ * @param type		SCSI peripheral device type code.
+ * @return		String representation.
+ */
+const char *usbmast_scsi_dev_type_str(unsigned type)
+{
+	return scsi_get_dev_type_str(type);
+}
+
+static void usbmast_dump_sense(scsi_sense_data_t *sense_buf)
+{
+	const unsigned sense_key = sense_buf->flags_key & 0x0f;
+	printf("Got sense data. Sense key: 0x%x (%s), ASC 0x%02x, "
+	    "ASCQ 0x%02x.\n", sense_key,
+	    scsi_get_sense_key_str(sense_key),
+	    sense_buf->additional_code,
+	    sense_buf->additional_cqual);
+}
+
+static int usb_massstor_unit_ready(usbmast_fun_t *mfun)
+{
+	scsi_cmd_t cmd;
+	scsi_cdb_test_unit_ready_t cdb;
+	int rc;
+
+	memset(&cdb, 0, sizeof(cdb));
+	cdb.op_code = SCSI_CMD_TEST_UNIT_READY;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+
+	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
+
+        if (rc != EOK) {
+		usb_log_error("Test Unit Ready failed on device %s: %s.",
+		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
+		return rc;
+	}
+	/* Ignore command error here. If there's something wrong
+	 * with the device the following commands will fail too.
+	 */
+	if (cmd.status != CMDS_GOOD)
+		usb_log_warning("Test Unit Ready command failed on device %s.",
+		   usb_device_get_name(mfun->mdev->usb_dev));
+
+	return EOK;
+}
+
+/** Run SCSI command.
+ *
+ * Run command and repeat in case of unit attention.
+ * XXX This is too simplified.
+ */
+static int usbmast_run_cmd(usbmast_fun_t *mfun, scsi_cmd_t *cmd)
+{
+	uint8_t sense_key;
+	scsi_sense_data_t sense_buf;
+	int rc;
+
+	do {
+		rc = usb_massstor_unit_ready(mfun);
+		if (rc != EOK) {
+			usb_log_error("Inquiry transport failed, device %s: %s.\n",
+			   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
+			return rc;
+		}
+
+		rc = usb_massstor_cmd(mfun, 0xDEADBEEF, cmd);
+		if (rc != EOK) {
+			usb_log_error("Inquiry transport failed, device %s: %s.\n",
+			   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
+			return rc;
+		}
+
+		if (cmd->status == CMDS_GOOD)
+			return EOK;
+
+		usb_log_error("SCSI command failed, device %s.\n",
+		    usb_device_get_name(mfun->mdev->usb_dev));
+
+		rc = usbmast_request_sense(mfun, &sense_buf, sizeof(sense_buf));
+		if (rc != EOK) {
+			usb_log_error("Failed to read sense data.\n");
+			return EIO;
+		}
+
+		/* Dump sense data to log */
+		usbmast_dump_sense(&sense_buf);
+
+		/* Get sense key */
+		sense_key = sense_buf.flags_key & 0x0f;
+
+		if (sense_key == SCSI_SK_UNIT_ATTENTION) {
+			printf("Got unit attention. Re-trying command.\n");
+		}
+
+	} while (sense_key == SCSI_SK_UNIT_ATTENTION);
+
+	/* Command status is not good, nevertheless transport succeeded. */
+	return EOK;
+}
+
+/** Perform SCSI Inquiry command on USB mass storage device.
+ *
+ * @param mfun		Mass storage function
+ * @param inquiry_result Where to store parsed inquiry result
+ * @return		Error code
+ */
+int usbmast_inquiry(usbmast_fun_t *mfun, usbmast_inquiry_data_t *inq_res)
+{
+	scsi_std_inquiry_data_t inq_data;
+	scsi_cmd_t cmd;
+	scsi_cdb_inquiry_t cdb;
+	int rc;
+
+	memset(&cdb, 0, sizeof(cdb));
+	cdb.op_code = SCSI_CMD_INQUIRY;
+	cdb.alloc_len = host2uint16_t_be(sizeof(inq_data));
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = &inq_data;
+	cmd.data_in_size = sizeof(inq_data);
+
+	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
+
+	if (rc != EOK) {
+		usb_log_error("Inquiry transport failed, device %s: %s.\n",
+		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
+		return rc;
+	}
+
+	if (cmd.status != CMDS_GOOD) {
+		usb_log_error("Inquiry command failed, device %s.\n",
+		   usb_device_get_name(mfun->mdev->usb_dev));
+		return EIO;
+	}
+
+	if (cmd.rcvd_size < SCSI_STD_INQUIRY_DATA_MIN_SIZE) {
+		usb_log_error("SCSI Inquiry response too short (%zu).\n",
+		    cmd.rcvd_size);
+		return EIO;
+	}
+
+	/*
+	 * Parse inquiry data and fill in the result structure.
+	 */
+
+	memset(inq_res, 0, sizeof(*inq_res));
+
+	inq_res->device_type = BIT_RANGE_EXTRACT(uint8_t,
+	    inq_data.pqual_devtype, SCSI_PQDT_DEV_TYPE_h, SCSI_PQDT_DEV_TYPE_l);
+
+	inq_res->removable = BIT_RANGE_EXTRACT(uint8_t,
+	    inq_data.rmb, SCSI_RMB_RMB, SCSI_RMB_RMB);
+
+	spascii_to_str(inq_res->vendor, SCSI_INQ_VENDOR_STR_BUFSIZE,
+	    inq_data.vendor, sizeof(inq_data.vendor));
+
+	spascii_to_str(inq_res->product, SCSI_INQ_PRODUCT_STR_BUFSIZE,
+	    inq_data.product, sizeof(inq_data.product));
+
+	spascii_to_str(inq_res->revision, SCSI_INQ_REVISION_STR_BUFSIZE,
+	    inq_data.revision, sizeof(inq_data.revision));
+
+	return EOK;
+}
+
+/** Perform SCSI Request Sense command on USB mass storage device.
+ *
+ * @param mfun		Mass storage function
+ * @param buf		Destination buffer
+ * @param size		Size of @a buf
+ *
+ * @return		Error code.
+ */
+int usbmast_request_sense(usbmast_fun_t *mfun, void *buf, size_t size)
+{
+	scsi_cmd_t cmd;
+	scsi_cdb_request_sense_t cdb;
+	int rc;
+
+	memset(&cdb, 0, sizeof(cdb));
+	cdb.op_code = SCSI_CMD_REQUEST_SENSE;
+	cdb.alloc_len = min(size, SCSI_SENSE_DATA_MAX_SIZE);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = buf;
+	cmd.data_in_size = size;
+
+	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
+
+        if (rc != EOK || cmd.status != CMDS_GOOD) {
+		usb_log_error("Request Sense failed, device %s: %s.\n",
+		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
+		return rc;
+	}
+
+	if (cmd.rcvd_size < SCSI_SENSE_DATA_MIN_SIZE) {
+		/* The missing bytes should be considered to be zeroes. */
+		memset((uint8_t *)buf + cmd.rcvd_size, 0,
+		    SCSI_SENSE_DATA_MIN_SIZE - cmd.rcvd_size);
+	}
+
+	return EOK;
+}
+
+/** Perform SCSI Read Capacity command on USB mass storage device.
+ *
+ * @param mfun		Mass storage function
+ * @param nblocks	Output, number of blocks
+ * @param block_size	Output, block size in bytes
+ *
+ * @return		Error code.
+ */
+int usbmast_read_capacity(usbmast_fun_t *mfun, uint32_t *nblocks,
+    uint32_t *block_size)
+{
+	scsi_cmd_t cmd;
+	scsi_cdb_read_capacity_10_t cdb;
+	scsi_read_capacity_10_data_t data;
+	int rc;
+
+	memset(&cdb, 0, sizeof(cdb));
+	cdb.op_code = SCSI_CMD_READ_CAPACITY_10;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = &data;
+	cmd.data_in_size = sizeof(data);
+
+	rc = usbmast_run_cmd(mfun, &cmd);
+
+        if (rc != EOK) {
+		usb_log_error("Read Capacity (10) transport failed, device %s: %s.\n",
+		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
+		return rc;
+	}
+
+	if (cmd.status != CMDS_GOOD) {
+		usb_log_error("Read Capacity (10) command failed, device %s.\n",
+		   usb_device_get_name(mfun->mdev->usb_dev));
+		return EIO;
+	}
+
+	if (cmd.rcvd_size < sizeof(data)) {
+		usb_log_error("SCSI Read Capacity response too short (%zu).\n",
+		    cmd.rcvd_size);
+		return EIO;
+	}
+
+	*nblocks = uint32_t_be2host(data.last_lba) + 1;
+	*block_size = uint32_t_be2host(data.block_size);
+
+	return EOK;
+}
+
+/** Perform SCSI Read command on USB mass storage device.
+ *
+ * @param mfun		Mass storage function
+ * @param ba		Address of first block
+ * @param nblocks	Number of blocks to read
+ *
+ * @return		Error code
+ */
+int usbmast_read(usbmast_fun_t *mfun, uint64_t ba, size_t nblocks, void *buf)
+{
+	scsi_cmd_t cmd;
+	scsi_cdb_read_10_t cdb;
+	int rc;
+
+	if (ba > UINT32_MAX)
+		return ELIMIT;
+
+	if (nblocks > UINT16_MAX)
+		return ELIMIT;
+
+	memset(&cdb, 0, sizeof(cdb));
+	cdb.op_code = SCSI_CMD_READ_10;
+	cdb.lba = host2uint32_t_be(ba);
+	cdb.xfer_len = host2uint16_t_be(nblocks);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_in = buf;
+	cmd.data_in_size = nblocks * mfun->block_size;
+
+	rc = usbmast_run_cmd(mfun, &cmd);
+
+        if (rc != EOK) {
+		usb_log_error("Read (10) transport failed, device %s: %s.\n",
+		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
+		return rc;
+	}
+
+	if (cmd.status != CMDS_GOOD) {
+		usb_log_error("Read (10) command failed, device %s.\n",
+		   usb_device_get_name(mfun->mdev->usb_dev));
+		return EIO;
+	}
+
+	if (cmd.rcvd_size < nblocks * mfun->block_size) {
+		usb_log_error("SCSI Read response too short (%zu).\n",
+		    cmd.rcvd_size);
+		return EIO;
+	}
+
+	return EOK;
+}
+
+/** Perform SCSI Write command on USB mass storage device.
+ *
+ * @param mfun		Mass storage function
+ * @param ba		Address of first block
+ * @param nblocks	Number of blocks to read
+ * @param data		Data to write
+ *
+ * @return		Error code
+ */
+int usbmast_write(usbmast_fun_t *mfun, uint64_t ba, size_t nblocks,
+    const void *data)
+{
+	scsi_cmd_t cmd;
+	scsi_cdb_write_10_t cdb;
+	int rc;
+
+	if (ba > UINT32_MAX)
+		return ELIMIT;
+
+	if (nblocks > UINT16_MAX)
+		return ELIMIT;
+
+	memset(&cdb, 0, sizeof(cdb));
+	cdb.op_code = SCSI_CMD_WRITE_10;
+	cdb.lba = host2uint32_t_be(ba);
+	cdb.xfer_len = host2uint16_t_be(nblocks);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cdb = &cdb;
+	cmd.cdb_size = sizeof(cdb);
+	cmd.data_out = data;
+	cmd.data_out_size = nblocks * mfun->block_size;
+
+	rc = usbmast_run_cmd(mfun, &cmd);
+
+        if (rc != EOK) {
+		usb_log_error("Write (10) transport failed, device %s: %s.\n",
+		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
+		return rc;
+	}
+
+	if (cmd.status != CMDS_GOOD) {
+		usb_log_error("Write (10) command failed, device %s.\n",
+		   usb_device_get_name(mfun->mdev->usb_dev));
+		return EIO;
+	}
+
+	return EOK;
+}
+
+/** Perform SCSI Synchronize Cache command on USB mass storage device.
+ *
+ * @param mfun		Mass storage function
+ * @param ba		Address of first block
+ * @param nblocks	Number of blocks to read
+ * @param data		Data to write
+ *
+ * @return		Error code
+ */
+int usbmast_sync_cache(usbmast_fun_t *mfun, uint64_t ba, size_t nblocks)
+{
+	if (ba > UINT32_MAX)
+		return ELIMIT;
+
+	if (nblocks > UINT16_MAX)
+		return ELIMIT;
+
+	const scsi_cdb_sync_cache_10_t cdb = {
+		.op_code = SCSI_CMD_SYNC_CACHE_10,
+		.lba = host2uint32_t_be(ba),
+		.numlb = host2uint16_t_be(nblocks),
+	};
+
+	scsi_cmd_t cmd = {
+		.cdb = &cdb,
+		.cdb_size = sizeof(cdb),
+	};
+
+	const int rc = usbmast_run_cmd(mfun, &cmd);
+
+        if (rc != EOK) {
+		usb_log_error("Synchronize Cache (10) transport failed, device %s: %s.\n",
+		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
+		return rc;
+	}
+
+	if (cmd.status != CMDS_GOOD) {
+		usb_log_error("Synchronize Cache (10) command failed, device %s.\n",
+		   usb_device_get_name(mfun->mdev->usb_dev));
+		return EIO;
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/block/usbmast/scsi_ms.h
===================================================================
--- uspace/drv/block/usbmast/scsi_ms.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/block/usbmast/scsi_ms.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,74 @@
+/*
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * SCSI functions for USB mass storage.
+ */
+
+#ifndef USB_USBMAST_SCSI_MS_H_
+#define USB_USBMAST_SCSI_MS_H_
+
+#include <scsi/spc.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <usb/usb.h>
+#include <usb/dev/driver.h>
+
+/** Result of SCSI Inquiry command.
+ * This is already parsed structure, not the original buffer returned by
+ * the device.
+ */
+typedef struct {
+	/** SCSI peripheral device type */
+	unsigned device_type;
+	/** Whether the device is removable */
+	bool removable;
+	/** Vendor ID string */
+	char vendor[SCSI_INQ_VENDOR_STR_BUFSIZE];
+	/** Product ID string */
+	char product[SCSI_INQ_PRODUCT_STR_BUFSIZE];
+	/** Revision string */
+	char revision[SCSI_INQ_REVISION_STR_BUFSIZE];
+} usbmast_inquiry_data_t;
+
+extern int usbmast_inquiry(usbmast_fun_t *, usbmast_inquiry_data_t *);
+extern int usbmast_request_sense(usbmast_fun_t *, void *, size_t);
+extern int usbmast_read_capacity(usbmast_fun_t *, uint32_t *, uint32_t *);
+extern int usbmast_read(usbmast_fun_t *, uint64_t, size_t, void *);
+extern int usbmast_write(usbmast_fun_t *, uint64_t, size_t, const void *);
+extern int usbmast_sync_cache(usbmast_fun_t *, uint64_t, size_t);
+extern const char *usbmast_scsi_dev_type_str(unsigned);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/block/usbmast/usbmast.h
===================================================================
--- uspace/drv/block/usbmast/usbmast.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/block/usbmast/usbmast.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+/** @addtogroup drvusbmast
+ * @{
+ */
+/** @file
+ * USB mass storage commands.
+ */
+
+#ifndef USBMAST_H_
+#define USBMAST_H_
+
+#include <bd_srv.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <usb/usb.h>
+
+/** Mass storage device. */
+typedef struct usbmast_dev {
+	/** USB device */
+	usb_device_t *usb_dev;
+	/** Number of LUNs */
+	unsigned lun_count;
+	/** LUN functions */
+	ddf_fun_t **luns;
+	/** Data read pipe */
+	usb_pipe_t *bulk_in_pipe;
+	/** Data write pipe */
+	usb_pipe_t *bulk_out_pipe;
+} usbmast_dev_t;
+
+
+/** Mass storage function.
+ *
+ * Serves as soft state for function/LUN.
+ */
+typedef struct {
+	/** Mass storage device the function belongs to */
+	usbmast_dev_t *mdev;
+	/** DDF function */
+	ddf_fun_t *ddf_fun;
+	/** LUN */
+	unsigned lun;
+	/** Total number of blocks */
+	uint64_t nblocks;
+	/** Block size in bytes */
+	size_t block_size;
+	/** Block device service structure */
+	bd_srvs_t bds;
+} usbmast_fun_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/block/usbmast/usbmast.ma
===================================================================
--- uspace/drv/block/usbmast/usbmast.ma	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/block/usbmast/usbmast.ma	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,1 @@
+50 usb&interface&class=mass-storage&subclass=0x06&protocol=0x50
Index: pace/drv/bus/usb/usbhid/Makefile
===================================================================
--- uspace/drv/bus/usb/usbhid/Makefile	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,53 +1,0 @@
-#
-# Copyright (c) 2010-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 = usbhid usbdev usb drv
-
-EXTRA_CFLAGS += -I.
-
-BINARY = usbhid
-
-SUBDRIVER_SOURCES = \
-	kbd/conv.c \
-	kbd/kbddev.c \
-	kbd/kbdrepeat.c \
-	mouse/mousedev.c \
-	multimedia/multimedia.c \
-	multimedia/keymap.c \
-	blink1/blink1.c
-
-SOURCES = \
-	main.c \
-	usbhid.c \
-	subdrivers.c \
-	generic/hiddev.c \
-	$(SUBDRIVER_SOURCES)
-
-include $(USPACE_PREFIX)/Makefile.common
Index: pace/drv/bus/usb/usbhid/blink1/blink1.c
===================================================================
--- uspace/drv/bus/usb/usbhid/blink1/blink1.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,173 +1,0 @@
-/*
- * Copyright (c) 2014 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbhid
- * @{
- */
-/**
- * @file
- * USB blink(1) subdriver.
- */
-
-#include <errno.h>
-#include <str_error.h>
-#include <usb/debug.h>
-#include <ops/led_dev.h>
-#include <usb/hid/request.h>
-#include "blink1.h"
-
-const char *HID_BLINK1_FUN_NAME = "blink1";
-const char *HID_BLINK1_CATEGORY = "led";
-
-#define BLINK1_REPORT_ID  0x0001
-
-#define BLINK1_COMMAND_SET  0x006e
-
-typedef struct {
-	uint8_t id;
-	uint8_t command;
-	uint8_t arg0;
-	uint8_t arg1;
-	uint8_t arg2;
-	uint8_t arg3;
-	uint8_t arg4;
-	uint8_t arg5;
-} blink1_report_t;
-
-static int usb_blink1_color_set(ddf_fun_t *fun, pixel_t pixel)
-{
-	usb_blink1_t *blink1_dev = (usb_blink1_t *) ddf_fun_data_get(fun);
-	if (blink1_dev == NULL) {
-		usb_log_debug("Missing parameters.\n");
-		return EINVAL;
-	}
-	
-	blink1_report_t report;
-	
-	report.id = BLINK1_REPORT_ID;
-	report.command = BLINK1_COMMAND_SET;
-	report.arg0 = RED(pixel);
-	report.arg1 = GREEN(pixel);
-	report.arg2 = BLUE(pixel);
-	report.arg3 = 0;
-	report.arg4 = 0;
-	report.arg5 = 0;
-	
-	return usbhid_req_set_report(
-	    usb_device_get_default_pipe(blink1_dev->hid_dev->usb_dev),
-	    usb_device_get_iface_number(blink1_dev->hid_dev->usb_dev),
-	    USB_HID_REPORT_TYPE_FEATURE, (uint8_t *) &report, sizeof(report));
-}
-
-static led_dev_ops_t usb_blink1_iface = {
-	.color_set = usb_blink1_color_set
-};
-
-static ddf_dev_ops_t blink1_ops = {
-	.interfaces[LED_DEV_IFACE] = &usb_blink1_iface
-};
-
-int usb_blink1_init(usb_hid_dev_t *hid_dev, void **data)
-{
-	if (hid_dev == NULL) {
-		usb_log_error("Failed to init blink(1) structure: no structure "
-		    "given.\n");
-		return EINVAL;
-	}
-	
-	/* Create the exposed function. */
-	ddf_fun_t *fun = usb_device_ddf_fun_create(hid_dev->usb_dev,
-	    fun_exposed, HID_BLINK1_FUN_NAME);
-	if (fun == NULL) {
-		usb_log_error("Could not create DDF function node `%s'.\n",
-		    HID_BLINK1_FUN_NAME);
-		return ENOMEM;
-	}
-	
-	usb_blink1_t *blink1_dev = (usb_blink1_t *)
-	    ddf_fun_data_alloc(fun, sizeof(usb_blink1_t));
-	if (blink1_dev == NULL) {
-		usb_log_error("Error while creating USB/HID blink(1) device "
-		    "structure.\n");
-		ddf_fun_destroy(fun);
-		return ENOMEM;
-	}
-	
-	ddf_fun_set_ops(fun, &blink1_ops);
-	
-	int rc = ddf_fun_bind(fun);
-	if (rc != EOK) {
-		usb_log_error("Could not bind DDF function `%s': %s.\n",
-		    ddf_fun_get_name(fun), str_error(rc));
-		ddf_fun_destroy(fun);
-		return rc;
-	}
-	
-	rc = ddf_fun_add_to_category(fun, HID_BLINK1_CATEGORY);
-	if (rc != EOK) {
-		usb_log_error("Could not add DDF function to category %s: %s.\n",
-		    HID_BLINK1_CATEGORY, str_error(rc));
-		
-		rc = ddf_fun_unbind(fun);
-		if (rc != EOK) {
-			usb_log_error("Could not unbind function `%s', it "
-			    "will not be destroyed.\n", ddf_fun_get_name(fun));
-			return rc;
-		}
-		
-		ddf_fun_destroy(fun);
-		return rc;
-	}
-	
-	blink1_dev->fun = fun;
-	blink1_dev->hid_dev = hid_dev;
-	*data = blink1_dev;
-	
-	return EOK;
-}
-
-void usb_blink1_deinit(usb_hid_dev_t *hid_dev, void *data)
-{
-	if (data == NULL)
-		return;
-	
-	usb_blink1_t *blink1_dev = (usb_blink1_t *) data;
-	
-	int rc = ddf_fun_unbind(blink1_dev->fun);
-	if (rc != EOK) {
-		usb_log_error("Could not unbind function `%s', it "
-		    "will not be destroyed.\n", ddf_fun_get_name(blink1_dev->fun));
-		return;
-	}
-	
-	ddf_fun_destroy(blink1_dev->fun);
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/blink1/blink1.h
===================================================================
--- uspace/drv/bus/usb/usbhid/blink1/blink1.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,61 +1,0 @@
-/*
- * Copyright (c) 2014 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbhid
- * @{
- */
-/** @file
- * USB blink(1) subdriver.
- */
-
-#ifndef USB_HID_BLINK1_H_
-#define USB_HID_BLINK1_H_
-
-#include <usb/dev/driver.h>
-#include "../usbhid.h"
-
-/** Container for USB blink(1) device. */
-typedef struct {
-	/** DDF blink(1) function */
-	ddf_fun_t *fun;
-	
-	/** USB HID device */
-	usb_hid_dev_t *hid_dev;
-} usb_blink1_t;
-
-extern const char *HID_BLINK1_FUN_NAME;
-extern const char *HID_BLINK1_CATEGORY;
-
-extern int usb_blink1_init(usb_hid_dev_t *, void **);
-extern void usb_blink1_deinit(usb_hid_dev_t *, void *);
-
-#endif // USB_HID_BLINK1_H_
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/generic/hiddev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/generic/hiddev.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,226 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/**
- * @file
- * USB HID driver API.
- */
-
-#include <usb/debug.h>
-#include <usb/classes/classes.h>
-#include <errno.h>
-#include <str_error.h>
-#include <stdbool.h>
-
-#include <usbhid_iface.h>
-
-#include "hiddev.h"
-#include "usbhid.h"
-
-const usb_endpoint_description_t usb_hid_generic_poll_endpoint_description = {
-	.transfer_type = USB_TRANSFER_INTERRUPT,
-	.direction = USB_DIRECTION_IN,
-	.interface_class = USB_CLASS_HID,
-	.interface_subclass = -1,
-	.interface_protocol = -1,
-	.flags = 0
-};
-
-const char *HID_GENERIC_FUN_NAME = "hid";
-const char *HID_GENERIC_CATEGORY = "hid";
-
-
-static size_t usb_generic_hid_get_event_length(ddf_fun_t *fun);
-static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer,
-    size_t size, size_t *act_size, int *event_nr, unsigned int flags);
-static int usb_generic_hid_client_connected(ddf_fun_t *fun);
-static size_t usb_generic_get_report_descriptor_length(ddf_fun_t *fun);
-static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc,
-    size_t size, size_t *actual_size);
-
-static usbhid_iface_t usb_generic_iface = {
-	.get_event = usb_generic_hid_get_event,
-	.get_event_length = usb_generic_hid_get_event_length,
-	.get_report_descriptor_length = usb_generic_get_report_descriptor_length,
-	.get_report_descriptor = usb_generic_get_report_descriptor
-};
-
-static ddf_dev_ops_t usb_generic_hid_ops = {
-	.interfaces[USBHID_DEV_IFACE] = &usb_generic_iface,
-	.open = usb_generic_hid_client_connected
-};
-
-/** Return hid_dev_t * for generic HID function node.
- *
- * For the generic HID subdriver the 'hid' function has usb_hid_gen_fun_t
- * as soft state. Through that we can get to the usb_hid_dev_t.
- */
-static usb_hid_dev_t *fun_hid_dev(ddf_fun_t *fun)
-{
-	return ((usb_hid_gen_fun_t *)ddf_fun_data_get(fun))->hid_dev;
-}
-
-static size_t usb_generic_hid_get_event_length(ddf_fun_t *fun)
-{
-	usb_log_debug2("Generic HID: Get event length (fun: %p, "
-	    "fun->driver_data: %p.\n", fun, ddf_fun_data_get(fun));
-
-	const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
-
-	usb_log_debug2("hid_dev: %p, Max input report size (%zu).\n",
-	    hid_dev, hid_dev->max_input_report_size);
-
-	return hid_dev->max_input_report_size;
-}
-
-static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer,
-    size_t size, size_t *act_size, int *event_nr, unsigned int flags)
-{
-	usb_log_debug2("Generic HID: Get event.\n");
-
-	if (buffer == NULL || act_size == NULL || event_nr == NULL) {
-		usb_log_debug("No function");
-		return EINVAL;
-	}
-
-	const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
-
-	if (hid_dev->input_report_size > size) {
-		usb_log_debug("input_report_size > size (%zu, %zu)\n",
-		    hid_dev->input_report_size, size);
-		return EINVAL;	// TODO: other error code
-	}
-
-	/*! @todo This should probably be somehow atomic. */
-	memcpy(buffer, hid_dev->input_report,
-	    hid_dev->input_report_size);
-	*act_size = hid_dev->input_report_size;
-	*event_nr = usb_hid_report_number(hid_dev);
-
-	usb_log_debug2("OK\n");
-
-	return EOK;
-}
-
-static size_t usb_generic_get_report_descriptor_length(ddf_fun_t *fun)
-{
-	usb_log_debug("Generic HID: Get report descriptor length.\n");
-
-	const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
-
-	usb_log_debug2("hid_dev->report_desc_size = %zu\n",
-	    hid_dev->report_desc_size);
-
-	return hid_dev->report_desc_size;
-}
-
-static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc,
-    size_t size, size_t *actual_size)
-{
-	usb_log_debug2("Generic HID: Get report descriptor.\n");
-
-	const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
-
-	if (hid_dev->report_desc_size > size) {
-		return EINVAL;
-	}
-
-	memcpy(desc, hid_dev->report_desc, hid_dev->report_desc_size);
-	*actual_size = hid_dev->report_desc_size;
-
-	return EOK;
-}
-
-static int usb_generic_hid_client_connected(ddf_fun_t *fun)
-{
-	usb_log_debug("Generic HID: Client connected.\n");
-	return EOK;
-}
-
-void usb_generic_hid_deinit(usb_hid_dev_t *hid_dev, void *data)
-{
-	ddf_fun_t *fun = data;
-	if (fun == NULL)
-		return;
-
-	if (ddf_fun_unbind(fun) != EOK) {
-		usb_log_error("Failed to unbind generic hid fun.\n");
-		return;
-	}
-	usb_log_debug2("%s unbound.\n", ddf_fun_get_name(fun));
-	ddf_fun_destroy(fun);
-}
-
-int usb_generic_hid_init(usb_hid_dev_t *hid_dev, void **data)
-{
-	usb_hid_gen_fun_t *hid_fun;
-
-	if (hid_dev == NULL) {
-		return EINVAL;
-	}
-
-	/* Create the exposed function. */
-	usb_log_debug("Creating DDF function %s...\n", HID_GENERIC_FUN_NAME);
-	ddf_fun_t *fun = usb_device_ddf_fun_create(hid_dev->usb_dev,
-	    fun_exposed, HID_GENERIC_FUN_NAME);
-	if (fun == NULL) {
-		usb_log_error("Could not create DDF function node.\n");
-		return ENOMEM;
-	}
-
-	/* Create softstate */
-	hid_fun = ddf_fun_data_alloc(fun, sizeof(usb_hid_gen_fun_t));
-	hid_fun->hid_dev = hid_dev;
-	ddf_fun_set_ops(fun, &usb_generic_hid_ops);
-
-	int rc = ddf_fun_bind(fun);
-	if (rc != EOK) {
-		usb_log_error("Could not bind DDF function: %s.\n",
-		    str_error(rc));
-		ddf_fun_destroy(fun);
-		return rc;
-	}
-
-	usb_log_debug("HID function created. Handle: %" PRIun "\n",
-	    ddf_fun_get_handle(fun));
-	*data = fun;
-
-	return EOK;
-}
-
-bool usb_generic_hid_polling_callback(usb_hid_dev_t *hid_dev, void *data)
-{
-	return true;
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/generic/hiddev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/generic/hiddev.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,61 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * USB HID driver API.
- */
-
-#ifndef USB_HID_HIDDDEV_H_
-#define USB_HID_HIDDDEV_H_
-
-#include <usb/dev/driver.h>
-#include "../usbhid.h"
-
-extern const usb_endpoint_description_t
-    usb_hid_generic_poll_endpoint_description;
-
-extern const char *HID_GENERIC_FUN_NAME;
-extern const char *HID_GENERIC_CATEGORY;
-
-/** The USB HID generic 'hid' function softstate */
-typedef struct {
-	usb_hid_dev_t *hid_dev;
-} usb_hid_gen_fun_t;
-
-extern int usb_generic_hid_init(usb_hid_dev_t *, void **);
-extern void usb_generic_hid_deinit(usb_hid_dev_t *, void *);
-extern bool usb_generic_hid_polling_callback(usb_hid_dev_t *, void *);
-
-#endif // USB_HID_HIDDDEV_H_
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/kbd/conv.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/conv.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,187 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * USB scancode parser.
- */
-
-#include <io/keycode.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <usb/debug.h>
-#include "conv.h"
-
-/**
- * Mapping between USB HID key codes (from HID Usage Tables) and corresponding
- * HelenOS key codes.
- */
-static int scanmap_simple[255] = {
-	[0x04] = KC_A,
-	[0x05] = KC_B,
-	[0x06] = KC_C,
-	[0x07] = KC_D,
-	[0x08] = KC_E,
-	[0x09] = KC_F,
-	[0x0a] = KC_G,
-	[0x0b] = KC_H,
-	[0x0c] = KC_I,
-	[0x0d] = KC_J,
-	[0x0e] = KC_K,
-	[0x0f] = KC_L,
-	[0x10] = KC_M,
-	[0x11] = KC_N,
-	[0x12] = KC_O,
-	[0x13] = KC_P,
-	[0x14] = KC_Q,
-	[0x15] = KC_R,
-	[0x16] = KC_S,
-	[0x17] = KC_T,
-	[0x18] = KC_U,
-	[0x19] = KC_V,
-	[0x1a] = KC_W,
-	[0x1b] = KC_X,
-	[0x1c] = KC_Y,
-	[0x1d] = KC_Z,
-
-	[0x1e] = KC_1,
-	[0x1f] = KC_2,
-	[0x20] = KC_3,
-	[0x21] = KC_4,
-	[0x22] = KC_5,
-	[0x23] = KC_6,
-	[0x24] = KC_7,
-	[0x25] = KC_8,
-	[0x26] = KC_9,
-	[0x27] = KC_0,
-
-	[0x28] = KC_ENTER,
-	[0x29] = KC_ESCAPE,
-	[0x2a] = KC_BACKSPACE,
-	[0x2b] = KC_TAB,
-	[0x2c] = KC_SPACE,
-
-	[0x2d] = KC_MINUS,
-	[0x2e] = KC_EQUALS,
-	[0x2f] = KC_LBRACKET,
-	[0x30] = KC_RBRACKET,
-	[0x31] = KC_BACKSLASH,
-	[0x32] = KC_HASH,
-	[0x33] = KC_SEMICOLON,
-	[0x34] = KC_QUOTE,
-	[0x35] = KC_BACKTICK,
-	[0x36] = KC_COMMA,
-	[0x37] = KC_PERIOD,
-	[0x38] = KC_SLASH,
-
-	[0x39] = KC_CAPS_LOCK,
-
-	[0x3a] = KC_F1,
-	[0x3b] = KC_F2,
-	[0x3c] = KC_F3,
-	[0x3d] = KC_F4,
-	[0x3e] = KC_F5,
-	[0x3f] = KC_F6,
-	[0x40] = KC_F7,
-	[0x41] = KC_F8,
-	[0x42] = KC_F9,
-	[0x43] = KC_F10,
-	[0x44] = KC_F11,
-	[0x45] = KC_F12,
-
-	[0x46] = KC_PRTSCR,
-	[0x47] = KC_SCROLL_LOCK,
-	[0x48] = KC_PAUSE,
-	[0x49] = KC_INSERT,
-	[0x4a] = KC_HOME,
-	[0x4b] = KC_PAGE_UP,
-	[0x4c] = KC_DELETE,
-	[0x4d] = KC_END,
-	[0x4e] = KC_PAGE_DOWN,
-	[0x4f] = KC_RIGHT,
-	[0x50] = KC_LEFT,
-	[0x51] = KC_DOWN,
-	[0x52] = KC_UP,
-
-	[0x53] = KC_NUM_LOCK,
-	[0x54] = KC_NSLASH,
-	[0x55] = KC_NTIMES,
-	[0x56] = KC_NMINUS,
-	[0x57] = KC_NPLUS,
-	[0x58] = KC_NENTER,
-	[0x59] = KC_N1,
-	[0x5a] = KC_N2,
-	[0x5b] = KC_N3,
-	[0x5c] = KC_N4,
-	[0x5d] = KC_N5,
-	[0x5e] = KC_N6,
-	[0x5f] = KC_N7,
-	[0x60] = KC_N8,
-	[0x61] = KC_N9,
-	[0x62] = KC_N0,
-	[0x63] = KC_NPERIOD,
-
-	[0x64] = KC_BACKSLASH,
-
-	[0x9a] = KC_SYSREQ,
-
-	[0xe0] = KC_LCTRL,
-	[0xe1] = KC_LSHIFT,
-	[0xe2] = KC_LALT,
-	[0xe4] = KC_RCTRL,
-	[0xe5] = KC_RSHIFT,
-	[0xe6] = KC_RALT,
-};
-
-/**
- * Translate USB HID key codes (from HID Usage Tables) to generic key codes
- * recognized by HelenOS.
- *
- * @param scancode USB HID key code (from HID Usage Tables).
- *
- * @retval HelenOS key code corresponding to the given USB HID key code.
- */
-unsigned int usbhid_parse_scancode(int scancode)
-{
-	unsigned int key;
-	int *map = scanmap_simple;
-	size_t map_length = sizeof(scanmap_simple) / sizeof(int);
-
-	if ((scancode < 0) || ((size_t) scancode >= map_length))
-		return -1;
-
-	key = map[scancode];
-
-	return key;
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/kbd/conv.h
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/conv.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * USB scancode parser.
- */
-
-#ifndef USB_HID_CONV_H_
-#define USB_HID_CONV_H_
-
-unsigned int usbhid_parse_scancode(int scancode);
-
-#endif /* USB_HID_CONV_H_ */
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/kbd/kbddev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbddev.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,805 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/**
- * @file
- * USB HID keyboard device structure and API.
- */
-
-#include <errno.h>
-#include <str_error.h>
-#include <stdio.h>
-
-#include <io/keycode.h>
-#include <io/console.h>
-#include <abi/ipc/methods.h>
-#include <ipc/kbdev.h>
-#include <async.h>
-#include <fibril.h>
-#include <fibril_synch.h>
-
-#include <ddf/log.h>
-
-#include <usb/usb.h>
-#include <usb/dev/dp.h>
-#include <usb/dev/request.h>
-#include <usb/hid/hid.h>
-#include <usb/dev/pipes.h>
-#include <usb/debug.h>
-#include <usb/hid/hidparser.h>
-#include <usb/classes/classes.h>
-#include <usb/hid/usages/core.h>
-#include <usb/hid/request.h>
-#include <usb/hid/hidreport.h>
-#include <usb/hid/usages/led.h>
-
-#include <usb/dev/driver.h>
-
-#include "kbddev.h"
-
-#include "conv.h"
-#include "kbdrepeat.h"
-
-#include "../usbhid.h"
-
-static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
-static ddf_dev_ops_t kbdops = { .default_handler = default_connection_handler };
-
-
-static const unsigned DEFAULT_ACTIVE_MODS = KM_NUM_LOCK;
-
-static const uint8_t ERROR_ROLLOVER = 1;
-
-/** Default idle rate for keyboards. */
-static const uint8_t IDLE_RATE = 0;
-
-/** Delay before a pressed key starts auto-repeating. */
-static const unsigned int DEFAULT_DELAY_BEFORE_FIRST_REPEAT = 500 * 1000;
-
-/** Delay between two repeats of a pressed key when auto-repeating. */
-static const unsigned int DEFAULT_REPEAT_DELAY = 50 * 1000;
-
-
-/** Keyboard polling endpoint description for boot protocol class. */
-const usb_endpoint_description_t usb_hid_kbd_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_KEYBOARD,
-	.flags = 0
-};
-
-const char *HID_KBD_FUN_NAME = "keyboard";
-const char *HID_KBD_CATEGORY_NAME = "keyboard";
-
-static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev);
-
-static const uint8_t USB_KBD_BOOT_REPORT_DESCRIPTOR[] = {
-	0x05, 0x01,  /* Usage Page (Generic Desktop), */
-	0x09, 0x06,  /* Usage (Keyboard), */
-	0xA1, 0x01,  /* Collection (Application), */
-	0x75, 0x01,  /*   Report Size (1), */
-	0x95, 0x08,  /*   Report Count (8), */
-	0x05, 0x07,  /*   Usage Page (Key Codes); */
-	0x19, 0xE0,  /*   Usage Minimum (224), */
-	0x29, 0xE7,  /*   Usage Maximum (231), */
-	0x15, 0x00,  /*   Logical Minimum (0), */
-	0x25, 0x01,  /*   Logical Maximum (1), */
-	0x81, 0x02,  /*   Input (Data, Variable, Absolute),  ; Modifier byte */
-	0x95, 0x01,  /*   Report Count (1), */
-	0x75, 0x08,  /*   Report Size (8), */
-	0x81, 0x01,  /*   Input (Constant),                  ; Reserved byte */
-	0x95, 0x05,  /*   Report Count (5), */
-	0x75, 0x01,  /*   Report Size (1), */
-	0x05, 0x08,  /*   Usage Page (Page# for LEDs), */
-	0x19, 0x01,  /*   Usage Minimum (1), */
-	0x29, 0x05,  /*   Usage Maxmimum (5), */
-	0x91, 0x02,  /*   Output (Data, Variable, Absolute),  ; LED report */
-	0x95, 0x01,  /*   Report Count (1), */
-	0x75, 0x03,  /*   Report Size (3), */
-	0x91, 0x01,  /*   Output (Constant),            ; LED report padding */
-	0x95, 0x06,  /*   Report Count (6), */
-	0x75, 0x08,  /*   Report Size (8), */
-	0x15, 0x00,  /*   Logical Minimum (0), */
-	0x25, 0xff,  /*   Logical Maximum (255), */
-	0x05, 0x07,  /*   Usage Page (Key Codes), */
-	0x19, 0x00,  /*   Usage Minimum (0), */
-	0x29, 0xff,  /*   Usage Maximum (255), */
-	0x81, 0x00,  /*   Input (Data, Array),   ; Key arrays (6 bytes) */
-	0xC0         /* End Collection */
-};
-
-typedef enum usb_kbd_flags {
-	USB_KBD_STATUS_UNINITIALIZED = 0,
-	USB_KBD_STATUS_INITIALIZED = 1,
-	USB_KBD_STATUS_TO_DESTROY = -1
-} usb_kbd_flags;
-
-/* IPC method handler                                                         */
-
-/**
- * Default handler for IPC methods not handled by DDF.
- *
- * Currently recognizes only two methods (IPC_M_CONNECT_TO_ME and KBDEV_SET_IND)
- * IPC_M_CONNECT_TO_ME assumes the caller is the console and  stores IPC
- * session to it for later use by the driver to notify about key events.
- * KBDEV_SET_IND sets LED keyboard indicators.
- *
- * @param fun Device function handling the call.
- * @param icallid Call id.
- * @param icall Call data.
- */
-static void default_connection_handler(ddf_fun_t *fun,
-    ipc_callid_t icallid, ipc_call_t *icall)
-{
-	const sysarg_t method = IPC_GET_IMETHOD(*icall);
-	usb_kbd_t *kbd_dev = ddf_fun_data_get(fun);
-
-	switch (method) {
-	case KBDEV_SET_IND:
-		kbd_dev->mods = IPC_GET_ARG1(*icall);
-		usb_kbd_set_led(kbd_dev->hid_dev, kbd_dev);
-		async_answer_0(icallid, EOK);
-		break;
-	/* This might be ugly but async_callback_receive_start makes no
-	 * difference for incorrect call and malloc failure. */
-	case IPC_M_CONNECT_TO_ME: {
-		async_sess_t *sess =
-		    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
-		/* Probably ENOMEM error, try again. */
-		if (sess == NULL) {
-			usb_log_warning(
-			    "Failed to create start console session.\n");
-			async_answer_0(icallid, EAGAIN);
-			break;
-		}
-		if (kbd_dev->client_sess == NULL) {
-			kbd_dev->client_sess = sess;
-			usb_log_debug("%s: OK\n", __FUNCTION__);
-			async_answer_0(icallid, EOK);
-		} else {
-			usb_log_error("%s: console session already set\n",
-			   __FUNCTION__);
-			async_answer_0(icallid, ELIMIT);
-		}
-		break;
-	}
-	default:
-			usb_log_error("%s: Unknown method: %d.\n",
-			    __FUNCTION__, (int) method);
-			async_answer_0(icallid, EINVAL);
-			break;
-	}
-
-}
-
-/* Key processing functions                                                   */
-
-/**
- * Handles turning of LED lights on and off.
- *
- * As with most other keyboards, the LED indicators in USB keyboards are
- * driven by software. When state of some modifier changes, the input server
- * will call us and tell us to update the LED state and what the new state
- * should be.
- *
- * This functions sets the LED lights according to current settings of modifiers
- * kept in the keyboard device structure.
- *
- * @param kbd_dev Keyboard device structure.
- */
-static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev)
-{
-	if (kbd_dev->output_size == 0) {
-		return;
-	}
-
-	/* Reset the LED data. */
-	memset(kbd_dev->led_data, 0, kbd_dev->led_output_size * sizeof(int32_t));
-	usb_log_debug("Creating output report:\n");
-
-	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    &hid_dev->report, NULL, kbd_dev->led_path,
-	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
-	    USB_HID_REPORT_TYPE_OUTPUT);
-
-	while (field != NULL) {
-
-		if ((field->usage == USB_HID_LED_NUM_LOCK)
-		    && (kbd_dev->mods & KM_NUM_LOCK)){
-			field->value = 1;
-		}
-
-		if ((field->usage == USB_HID_LED_CAPS_LOCK)
-		    && (kbd_dev->mods & KM_CAPS_LOCK)){
-			field->value = 1;
-		}
-
-		if ((field->usage == USB_HID_LED_SCROLL_LOCK)
-		    && (kbd_dev->mods & KM_SCROLL_LOCK)){
-			field->value = 1;
-		}
-
-		field = usb_hid_report_get_sibling(
-		    &hid_dev->report, field, kbd_dev->led_path,
-		USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
-		    USB_HID_REPORT_TYPE_OUTPUT);
-	}
-
-	// TODO: what about the Report ID?
-	int rc = usb_hid_report_output_translate(&hid_dev->report, 0,
-	    kbd_dev->output_buffer, kbd_dev->output_size);
-
-	if (rc != EOK) {
-		usb_log_warning("Could not translate LED output to output"
-		    "report.\n");
-		return;
-	}
-
-	usb_log_debug("Output report buffer: %s\n",
-	    usb_debug_str_buffer(kbd_dev->output_buffer, kbd_dev->output_size,
-	        0));
-
-	rc = usbhid_req_set_report(
-	    usb_device_get_default_pipe(hid_dev->usb_dev),
-	    usb_device_get_iface_number(hid_dev->usb_dev),
-	    USB_HID_REPORT_TYPE_OUTPUT,
-	    kbd_dev->output_buffer, kbd_dev->output_size);
-	if (rc != EOK) {
-		usb_log_warning("Failed to set kbd indicators.\n");
-	}
-}
-
-/** Send key event.
- *
- * @param kbd_dev Keyboard device structure.
- * @param type Type of the event (press / release). Recognized values:
- *             KEY_PRESS, KEY_RELEASE
- * @param key Key code
- */
-void usb_kbd_push_ev(usb_kbd_t *kbd_dev, int type, unsigned key)
-{
-	usb_log_debug2("Sending kbdev event %d/%d to the console\n", type, key);
-	if (kbd_dev->client_sess == NULL) {
-		usb_log_warning(
-		    "Connection to console not ready, key discarded.\n");
-		return;
-	}
-
-	async_exch_t *exch = async_exchange_begin(kbd_dev->client_sess);
-	if (exch != NULL) {
-		async_msg_2(exch, KBDEV_EVENT, type, key);
-		async_exchange_end(exch);
-	} else {
-		usb_log_warning("Failed to send key to console.\n");
-	}
-}
-
-static inline int usb_kbd_is_lock(unsigned int key_code)
-{
-	return (key_code == KC_NUM_LOCK
-	    || key_code == KC_SCROLL_LOCK
-	    || key_code == KC_CAPS_LOCK);
-}
-
-static size_t find_in_array_int32(int32_t val, int32_t *arr, size_t arr_size)
-{
-	for (size_t i = 0; i < arr_size; i++) {
-		if (arr[i] == val) {
-			return i;
-		}
-	}
-
-	return (size_t) -1;
-}
-
-/**
- * Checks if some keys were pressed or released and generates key events.
- *
- * An event is created only when key is pressed or released. Besides handling
- * the events (usb_kbd_push_ev()), the auto-repeat fibril is notified about
- * key presses and releases (see usb_kbd_repeat_start() and 
- * usb_kbd_repeat_stop()).
- *
- * @param kbd_dev Keyboard device structure.
- * @param key_codes Parsed keyboard report - codes of currently pressed keys 
- *                  according to HID Usage Tables.
- * @param count Number of key codes in report (size of the report).
- *
- * @sa usb_kbd_push_ev(), usb_kbd_repeat_start(), usb_kbd_repeat_stop()
- */
-static void usb_kbd_check_key_changes(usb_hid_dev_t *hid_dev,
-    usb_kbd_t *kbd_dev)
-{
-
-	/*
-	 * First of all, check if the kbd have reported phantom state.
-	 *
-	 * As there is no way to distinguish keys from modifiers, we do not have
-	 * a way to check that 'all keys report Error Rollover'. We thus check
-	 * if there is at least one such error and in such case we ignore the
-	 * whole input report.
-	 */
-	size_t i = find_in_array_int32(ERROR_ROLLOVER, kbd_dev->keys,
-	    kbd_dev->key_count);
-	if (i != (size_t) -1) {
-		usb_log_error("Detected phantom state.\n");
-		return;
-	}
-
-	/*
-	 * Key releases
-	 */
-	for (i = 0; i < kbd_dev->key_count; i++) {
-		const int32_t old_key = kbd_dev->keys_old[i];
-		/* Find the old key among currently pressed keys. */
-		const size_t pos = find_in_array_int32(old_key, kbd_dev->keys,
-		    kbd_dev->key_count);
-		/* If the key was not found, we need to signal release. */
-		if (pos == (size_t) -1) {
-			const unsigned key = usbhid_parse_scancode(old_key);
-			if (!usb_kbd_is_lock(key)) {
-				usb_kbd_repeat_stop(kbd_dev, key);
-			}
-			usb_kbd_push_ev(kbd_dev, KEY_RELEASE, key);
-			usb_log_debug2("Key released: %u "
-			    "(USB code %" PRIu32 ")\n", key, old_key);
-		}
-	}
-
-	/*
-	 * Key presses
-	 */
-	for (i = 0; i < kbd_dev->key_count; ++i) {
-		const int32_t new_key = kbd_dev->keys[i];
-		/* Find the new key among already pressed keys. */
-		const size_t pos = find_in_array_int32(new_key,
-		    kbd_dev->keys_old, kbd_dev->key_count);
-		/* If the key was not found, we need to signal press. */
-		if (pos == (size_t) -1) {
-			unsigned key = usbhid_parse_scancode(kbd_dev->keys[i]);
-			if (!usb_kbd_is_lock(key)) {
-				usb_kbd_repeat_start(kbd_dev, key);
-			}
-			usb_kbd_push_ev(kbd_dev, KEY_PRESS, key);
-			usb_log_debug2("Key pressed: %u "
-			    "(USB code %" PRIu32 ")\n", key, new_key);
-		}
-	}
-
-	memcpy(kbd_dev->keys_old, kbd_dev->keys, kbd_dev->key_count * 4);
-
-	// TODO Get rid of this
-	char key_buffer[512];
-	ddf_dump_buffer(key_buffer, 512,
-	    kbd_dev->keys_old, 4, kbd_dev->key_count, 0);
-	usb_log_debug2("Stored keys %s.\n", key_buffer);
-}
-
-/* General kbd functions                                                      */
-
-/**
- * Processes data received from the device in form of report.
- *
- * This function uses the HID report parser to translate the data received from
- * the device into generic USB HID key codes and into generic modifiers bitmap.
- * The parser then calls the given callback (usb_kbd_process_keycodes()).
- *
- * @note Currently, only the boot protocol is supported.
- *
- * @param kbd_dev Keyboard device structure (must be initialized).
- * @param buffer Data from the keyboard (i.e. the report).
- * @param actual_size Size of the data from keyboard (report size) in bytes.
- *
- * @sa usb_kbd_process_keycodes(), usb_hid_boot_keyboard_input_report(),
- *     usb_hid_parse_report().
- */
-static void usb_kbd_process_data(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev)
-{
-	assert(hid_dev != NULL);
-	assert(kbd_dev != NULL);
-
-	usb_hid_report_path_t *path = usb_hid_report_path();
-	if (path == NULL) {
-		usb_log_error("Failed to create hid/kbd report path.\n");
-		return;
-	}
-
-	int ret =
-	   usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
-	if (ret != EOK) {
-		usb_log_error("Failed to append to hid/kbd report path.\n");
-		return;
-	}
-
-	usb_hid_report_path_set_report_id(path, hid_dev->report_id);
-
-	/* Fill in the currently pressed keys. */
-	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    &hid_dev->report, NULL, path,
-	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
-	    USB_HID_REPORT_TYPE_INPUT);
-	unsigned i = 0;
-
-	while (field != NULL) {
-		usb_log_debug2("FIELD (%p) - VALUE(%d) USAGE(%u)\n",
-		    field, field->value, field->usage);
-
-		assert(i < kbd_dev->key_count);
-
-		/* Save the key usage. */
-		if (field->value != 0) {
-			kbd_dev->keys[i] = field->usage;
-		}
-		else {
-			kbd_dev->keys[i] = 0;
-		}
-		usb_log_debug2("Saved %u. key usage %d\n", i, kbd_dev->keys[i]);
-
-		++i;
-		field = usb_hid_report_get_sibling(
-		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
-		        | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
-		    USB_HID_REPORT_TYPE_INPUT);
-	}
-
-	usb_hid_report_path_free(path);
-
-	usb_kbd_check_key_changes(hid_dev, kbd_dev);
-}
-
-/* HID/KBD structure manipulation                                             */
-
-static int kbd_dev_init(usb_kbd_t *kbd_dev, usb_hid_dev_t *hid_dev)
-{
-	assert(kbd_dev);
-	assert(hid_dev);
-
-	/* Default values */
-	fibril_mutex_initialize(&kbd_dev->repeat_mtx);
-	kbd_dev->initialized = USB_KBD_STATUS_UNINITIALIZED;
-
-	/* Store link to HID device */
-	kbd_dev->hid_dev = hid_dev;
-
-	/* Modifiers and locks */
-	kbd_dev->mods = DEFAULT_ACTIVE_MODS;
-
-	/* Autorepeat */
-	kbd_dev->repeat.delay_before = DEFAULT_DELAY_BEFORE_FIRST_REPEAT;
-	kbd_dev->repeat.delay_between = DEFAULT_REPEAT_DELAY;
-
-	// TODO: make more general
-	usb_hid_report_path_t *path = usb_hid_report_path();
-	if (path == NULL) {
-		usb_log_error("Failed to create kbd report path.\n");
-		usb_kbd_destroy(kbd_dev);
-		return ENOMEM;
-	}
-
-	int ret =
-	    usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
-	if (ret != EOK) {
-		usb_log_error("Failed to append item to kbd report path.\n");
-		usb_hid_report_path_free(path);
-		usb_kbd_destroy(kbd_dev);
-		return ret;
-	}
-
-	usb_hid_report_path_set_report_id(path, 0);
-
-	kbd_dev->key_count =
-	    usb_hid_report_size(&hid_dev->report, 0, USB_HID_REPORT_TYPE_INPUT);
-
-	usb_hid_report_path_free(path);
-
-	usb_log_debug("Size of the input report: %zu\n", kbd_dev->key_count);
-
-	kbd_dev->keys = calloc(kbd_dev->key_count, sizeof(int32_t));
-	if (kbd_dev->keys == NULL) {
-		usb_log_error("Failed to allocate key buffer.\n");
-		usb_kbd_destroy(kbd_dev);
-		return ENOMEM;
-	}
-
-	kbd_dev->keys_old = calloc(kbd_dev->key_count, sizeof(int32_t));
-	if (kbd_dev->keys_old == NULL) {
-		usb_log_error("Failed to allocate old_key buffer.\n");
-		usb_kbd_destroy(kbd_dev);
-		return ENOMEM;
-	}
-
-	/* Output report */
-	kbd_dev->output_size = 0;
-	kbd_dev->output_buffer = usb_hid_report_output(&hid_dev->report,
-	    &kbd_dev->output_size, 0);
-	if (kbd_dev->output_buffer == NULL) {
-		usb_log_error("Error creating output report buffer.\n");
-		usb_kbd_destroy(kbd_dev);
-		return ENOMEM;
-	}
-
-	usb_log_debug("Output buffer size: %zu\n", kbd_dev->output_size);
-
-	kbd_dev->led_path = usb_hid_report_path();
-	if (kbd_dev->led_path == NULL) {
-		usb_log_error("Failed to create kbd led report path.\n");
-		usb_kbd_destroy(kbd_dev);
-		return ENOMEM;
-	}
-
-	ret = usb_hid_report_path_append_item(
-	    kbd_dev->led_path, USB_HIDUT_PAGE_LED, 0);
-	if (ret != EOK) {
-		usb_log_error("Failed to append to kbd/led report path.\n");
-		usb_kbd_destroy(kbd_dev);
-		return ret;
-	}
-
-	kbd_dev->led_output_size = usb_hid_report_size(
-	    &hid_dev->report, 0, USB_HID_REPORT_TYPE_OUTPUT);
-
-	usb_log_debug("Output report size (in items): %zu\n",
-	    kbd_dev->led_output_size);
-
-	kbd_dev->led_data = calloc(kbd_dev->led_output_size, sizeof(int32_t));
-	if (kbd_dev->led_data == NULL) {
-		usb_log_error("Error creating buffer for LED output report.\n");
-		usb_kbd_destroy(kbd_dev);
-		return ENOMEM;
-	}
-
-	/* Set LEDs according to initial setup.
-	 * Set Idle rate */
-	usb_kbd_set_led(hid_dev, kbd_dev);
-
-	usbhid_req_set_idle(usb_device_get_default_pipe(hid_dev->usb_dev),
-	    usb_device_get_iface_number(hid_dev->usb_dev), IDLE_RATE);
-
-
-	kbd_dev->initialized = USB_KBD_STATUS_INITIALIZED;
-	usb_log_debug("HID/KBD device structure initialized.\n");
-
-	return EOK;
-}
-
-
-/* API functions                                                              */
-
-/**
- * Initialization of the USB/HID keyboard structure.
- *
- * This functions initializes required structures from the device's descriptors.
- *
- * During initialization, the keyboard is switched into boot protocol, the idle
- * rate is set to 0 (infinity), resulting in the keyboard only reporting event
- * when a key is pressed or released. Finally, the LED lights are turned on
- * according to the default setup of lock keys.
- *
- * @note By default, the keyboards is initialized with Num Lock turned on and
- *       other locks turned off.
- *
- * @param kbd_dev Keyboard device structure to be initialized.
- * @param dev DDF device structure of the keyboard.
- *
- * @retval EOK if successful.
- * @retval EINVAL if some parameter is not given.
- * @return Other value inherited from function usbhid_dev_init().
- */
-int usb_kbd_init(usb_hid_dev_t *hid_dev, void **data)
-{
-	usb_log_debug("Initializing HID/KBD structure...\n");
-
-	if (hid_dev == NULL) {
-		usb_log_error(
-		    "Failed to init keyboard structure: no structure given.\n");
-		return EINVAL;
-	}
-
-	/* Create the exposed function. */
-	usb_log_debug("Creating DDF function %s...\n", HID_KBD_FUN_NAME);
-	ddf_fun_t *fun = usb_device_ddf_fun_create(hid_dev->usb_dev,
-	    fun_exposed, HID_KBD_FUN_NAME);
-	if (fun == NULL) {
-		usb_log_error("Could not create DDF function node.\n");
-		return ENOMEM;
-	}
-
-	usb_kbd_t *kbd_dev = ddf_fun_data_alloc(fun, sizeof(usb_kbd_t));
-	if (kbd_dev == NULL) {
-		usb_log_error("Failed to allocate KBD device structure.\n");
-		ddf_fun_destroy(fun);
-		return ENOMEM;
-	}
-
-	int ret = kbd_dev_init(kbd_dev, hid_dev);
-	if (ret != EOK) {
-		usb_log_error("Failed to initialize KBD device  structure.\n");
-		ddf_fun_destroy(fun);
-		return ret;
-	}
-
-	/* Store the initialized HID device and HID ops
-	 * to the DDF function. */
-	ddf_fun_set_ops(fun, &kbdops);
-
-	ret = ddf_fun_bind(fun);
-	if (ret != EOK) {
-		usb_log_error("Could not bind DDF function: %s.\n",
-		    str_error(ret));
-		usb_kbd_destroy(kbd_dev);
-		ddf_fun_destroy(fun);
-		return ret;
-	}
-
-	usb_log_debug("%s function created. Handle: %" PRIun "\n",
-	    HID_KBD_FUN_NAME, ddf_fun_get_handle(fun));
-
-	usb_log_debug("Adding DDF function to category %s...\n",
-	    HID_KBD_CATEGORY_NAME);
-	ret = ddf_fun_add_to_category(fun, HID_KBD_CATEGORY_NAME);
-	if (ret != EOK) {
-		usb_log_error(
-		    "Could not add DDF function to category %s: %s.\n",
-		    HID_KBD_CATEGORY_NAME, str_error(ret));
-		usb_kbd_destroy(kbd_dev);
-		if (ddf_fun_unbind(fun) == EOK) {
-			ddf_fun_destroy(fun);
-		} else {
-			usb_log_error(
-			    "Failed to unbind `%s', will not destroy.\n",
-			    ddf_fun_get_name(fun));
-		}
-		return ret;
-	}
-
-	/* Create new fibril for auto-repeat. */
-	fid_t fid = fibril_create(usb_kbd_repeat_fibril, kbd_dev);
-	if (fid == 0) {
-		usb_log_error("Failed to start fibril for KBD auto-repeat");
-		usb_kbd_destroy(kbd_dev);
-		return ENOMEM;
-	}
-	fibril_add_ready(fid);
-	kbd_dev->fun = fun;
-	/* Save the KBD device structure into the HID device structure. */
-	*data = kbd_dev;
-
-	return EOK;
-}
-
-bool usb_kbd_polling_callback(usb_hid_dev_t *hid_dev, void *data)
-{
-	if (hid_dev == NULL || data == NULL) {
-		/* This means something serious */
-		return false;
-	}
-
-	usb_kbd_t *kbd_dev = data;
-	// TODO: add return value from this function
-	usb_kbd_process_data(hid_dev, kbd_dev);
-
-	return true;
-}
-
-int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev)
-{
-	return (kbd_dev->initialized == USB_KBD_STATUS_INITIALIZED);
-}
-
-int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev)
-{
-	return (kbd_dev->initialized == USB_KBD_STATUS_TO_DESTROY);
-}
-
-/**
- * Properly destroys the USB/HID keyboard structure.
- *
- * @param kbd_dev Pointer to the structure to be destroyed.
- */
-void usb_kbd_destroy(usb_kbd_t *kbd_dev)
-{
-	if (kbd_dev == NULL) {
-		return;
-	}
-
-	/* Hangup session to the console. */
-	if (kbd_dev->client_sess)
-		async_hangup(kbd_dev->client_sess);
-
-	//assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
-	// FIXME - the fibril_mutex_is_locked may not cause
-	// fibril scheduling
-	while (fibril_mutex_is_locked(&kbd_dev->repeat_mtx)) {}
-
-	/* Free all buffers. */
-	free(kbd_dev->keys);
-	free(kbd_dev->keys_old);
-	free(kbd_dev->led_data);
-
-	usb_hid_report_path_free(kbd_dev->led_path);
-	usb_hid_report_output_free(kbd_dev->output_buffer);
-
-	if (kbd_dev->fun) {
-		if (ddf_fun_unbind(kbd_dev->fun) != EOK) {
-			usb_log_warning("Failed to unbind %s.\n",
-			    ddf_fun_get_name(kbd_dev->fun));
-		} else {
-			usb_log_debug2("%s unbound.\n",
-			    ddf_fun_get_name(kbd_dev->fun));
-			ddf_fun_destroy(kbd_dev->fun);
-		}
-	}
-}
-
-void usb_kbd_deinit(usb_hid_dev_t *hid_dev, void *data)
-{
-	if (data != NULL) {
-		usb_kbd_t *kbd_dev = data;
-		if (usb_kbd_is_initialized(kbd_dev)) {
-			kbd_dev->initialized = USB_KBD_STATUS_TO_DESTROY;
-			/* Wait for autorepeat */
-			async_usleep(CHECK_DELAY);
-		}
-		usb_kbd_destroy(kbd_dev);
-	}
-}
-
-int usb_kbd_set_boot_protocol(usb_hid_dev_t *hid_dev)
-{
-	assert(hid_dev);
-	int rc = usb_hid_parse_report_descriptor(
-	    &hid_dev->report, USB_KBD_BOOT_REPORT_DESCRIPTOR,
-	    sizeof(USB_KBD_BOOT_REPORT_DESCRIPTOR));
-
-	if (rc != EOK) {
-		usb_log_error("Failed to parse boot report descriptor: %s\n",
-		    str_error(rc));
-		return rc;
-	}
-
-	rc = usbhid_req_set_protocol(
-	    usb_device_get_default_pipe(hid_dev->usb_dev),
-	    usb_device_get_iface_number(hid_dev->usb_dev),
-	    USB_HID_PROTOCOL_BOOT);
-
-	if (rc != EOK) {
-		usb_log_warning("Failed to set boot protocol to the device: "
-		    "%s\n", str_error(rc));
-		return rc;
-	}
-
-	return EOK;
-}
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/kbd/kbddev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbddev.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,130 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * USB HID keyboard device structure and API.
- */
-
-#ifndef USB_HID_KBDDEV_H_
-#define USB_HID_KBDDEV_H_
-
-#include <stdint.h>
-#include <async.h>
-#include <fibril_synch.h>
-#include <usb/hid/hid.h>
-#include <usb/hid/hidparser.h>
-#include <ddf/driver.h>
-#include <usb/dev/pipes.h>
-#include <usb/dev/driver.h>
-#include "../usbhid.h"
-#include "kbdrepeat.h"
-
-/**
- * USB/HID keyboard device type.
- *
- * Holds a reference to generic USB/HID device structure and keyboard-specific
- * data, such as currently pressed keys, modifiers and lock keys.
- *
- * Also holds a IPC session to the console (since there is now no other way to 
- * communicate with it).
- *
- * @note Storing active lock keys in this structure results in their setting
- *       being device-specific.
- */
-typedef struct usb_kbd_t {
-	/** Link to HID device structure */
-	usb_hid_dev_t *hid_dev;
-	
-	/** Previously pressed keys (not translated to key codes). */
-	int32_t *keys_old;
-	/** Currently pressed keys (not translated to key codes). */
-	int32_t *keys;
-	/** Count of stored keys (i.e. number of keys in the report). */
-	size_t key_count;
-	/** Currently pressed modifiers (bitmap). */
-	uint8_t modifiers;
-	
-	/** Currently active modifiers including locks. Sent to the console. */
-	unsigned int mods;
-	
-	/** Currently active lock keys. */
-	unsigned int lock_keys;
-	
-	/** IPC session to client (for sending key events). */
-	async_sess_t *client_sess;
-	
-	/** Information for auto-repeat of keys. */
-	usb_kbd_repeat_t repeat;
-	
-	/** Mutex for accessing the information about auto-repeat. */
-	fibril_mutex_t repeat_mtx;
-	
-	uint8_t *output_buffer;
-	
-	size_t output_size;
-	
-	size_t led_output_size;
-	
-	usb_hid_report_path_t *led_path;
-	
-	int32_t *led_data;
-	
-	/** State of the structure (for checking before use). 
-	 *
-	 * 0 - not initialized
-	 * 1 - initialized
-	 * -1 - ready for destroying
-	 */
-	int initialized;
-	
-	/** DDF function */
-	ddf_fun_t *fun;
-} usb_kbd_t;
-
-extern const usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description;
-
-extern const char *HID_KBD_FUN_NAME;
-extern const char *HID_KBD_CATEGORY;
-
-extern int usb_kbd_init(usb_hid_dev_t *, void **);
-extern bool usb_kbd_polling_callback(usb_hid_dev_t *, void *);
-extern int usb_kbd_is_initialized(const usb_kbd_t *);
-extern int usb_kbd_is_ready_to_destroy(const usb_kbd_t *);
-extern void usb_kbd_destroy(usb_kbd_t *);
-extern void usb_kbd_push_ev(usb_kbd_t *, int, unsigned int);
-extern void usb_kbd_deinit(usb_hid_dev_t *, void *);
-extern int usb_kbd_set_boot_protocol(usb_hid_dev_t *);
-
-#endif /* USB_HID_KBDDEV_H_ */
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/kbd/kbdrepeat.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbdrepeat.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,172 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/**
- * @file
- * USB HID keyboard autorepeat facilities
- */
-
-#include <fibril_synch.h>
-#include <io/keycode.h>
-#include <io/console.h>
-#include <errno.h>
-
-#include <usb/debug.h>
-
-#include "kbdrepeat.h"
-#include "kbddev.h"
-
-/**
- * Main loop handling the auto-repeat of keys.
- *
- * This functions periodically checks if there is some key to be auto-repeated.
- *
- * If a new key is to be repeated, it uses the delay before first repeat stored
- * in the keyboard structure to wait until the key has to start repeating.
- *
- * If the same key is still pressed, it uses the delay between repeats stored
- * in the keyboard structure to wait until the key should be repeated.
- *
- * If the currently repeated key is not pressed any more (
- * usb_kbd_repeat_stop() was called), it stops repeating it and starts
- * checking again.
- *
- * @note For accessing the keyboard device auto-repeat information a fibril
- *       mutex (repeat_mtx) from the @a kbd structure is used.
- *
- * @param kbd Keyboard device structure.
- */
-static void usb_kbd_repeat_loop(usb_kbd_t *kbd)
-{
-	unsigned int delay = 0;
-
-	usb_log_debug("Starting autorepeat loop.\n");
-
-	while (true) {
-		/* Check if the kbd structure is usable. */
-		if (!usb_kbd_is_initialized(kbd)) {
-			usb_log_warning("kbd not ready, exiting autorepeat.\n");
-			return;
-		}
-
-		fibril_mutex_lock(&kbd->repeat_mtx);
-
-		if (kbd->repeat.key_new > 0) {
-			if (kbd->repeat.key_new == kbd->repeat.key_repeated) {
-				usb_log_debug2("Repeating key: %u.\n",
-				    kbd->repeat.key_repeated);
-				usb_kbd_push_ev(kbd, KEY_PRESS,
-				    kbd->repeat.key_repeated);
-				delay = kbd->repeat.delay_between;
-			} else {
-				usb_log_debug2("New key to repeat: %u.\n",
-				    kbd->repeat.key_new);
-				kbd->repeat.key_repeated = kbd->repeat.key_new;
-				delay = kbd->repeat.delay_before;
-			}
-		} else {
-			if (kbd->repeat.key_repeated > 0) {
-				usb_log_debug2("Stopping to repeat key: %u.\n",
-				    kbd->repeat.key_repeated);
-				kbd->repeat.key_repeated = 0;
-			}
-			delay = CHECK_DELAY;
-		}
-		fibril_mutex_unlock(&kbd->repeat_mtx);
-		async_usleep(delay);
-	}
-}
-
-/**
- * Main routine to be executed by a fibril for handling auto-repeat.
- *
- * Starts the loop for checking changes in auto-repeat.
- *
- * @param arg User-specified argument. Expects pointer to the keyboard device
- *            structure representing the keyboard.
- *
- * @retval EOK if the routine has finished.
- * @retval EINVAL if no argument is supplied.
- */
-int usb_kbd_repeat_fibril(void *arg)
-{
-	usb_log_debug("Autorepeat fibril spawned.\n");
-
-	if (arg == NULL) {
-		usb_log_error("No device!\n");
-		return EINVAL;
-	}
-
-	usb_kbd_t *kbd = arg;
-
-	usb_kbd_repeat_loop(kbd);
-
-	return EOK;
-}
-
-/**
- * Start repeating particular key.
- *
- * @note Only one key is repeated at any time, so calling this function 
- *       effectively cancels auto-repeat of the current repeated key (if any)
- *       and 'schedules' another key for auto-repeat.
- *
- * @param kbd Keyboard device structure.
- * @param key Key to start repeating.
- */
-void usb_kbd_repeat_start(usb_kbd_t *kbd, unsigned int key)
-{
-	fibril_mutex_lock(&kbd->repeat_mtx);
-	kbd->repeat.key_new = key;
-	fibril_mutex_unlock(&kbd->repeat_mtx);
-}
-
-/**
- * Stop repeating particular key.
- *
- * @note Only one key is repeated at any time, but this function may be called
- *       even with key that is not currently repeated (in that case nothing
- *       happens).
- *
- * @param kbd Keyboard device structure.
- * @param key Key to stop repeating.
- */
-void usb_kbd_repeat_stop(usb_kbd_t *kbd, unsigned int key)
-{
-	fibril_mutex_lock(&kbd->repeat_mtx);
-	if (key == kbd->repeat.key_new) {
-		kbd->repeat.key_new = 0;
-	}
-	fibril_mutex_unlock(&kbd->repeat_mtx);
-}
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/kbd/kbdrepeat.h
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbdrepeat.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,71 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * USB HID keyboard autorepeat facilities
- */
-
-#ifndef USB_HID_KBDREPEAT_H_
-#define USB_HID_KBDREPEAT_H_
-
-/** Delay between auto-repeat state checks when no key is being repeated. */
-#define CHECK_DELAY 10000
-
-struct usb_kbd_t;
-
-
-/**
- * Structure for keeping information needed for auto-repeat of keys.
- */
-typedef struct {
-	/** Last pressed key. */
-	unsigned int key_new;
-	/** Key to be repeated. */
-	unsigned int key_repeated;
-	/** Delay before first repeat in microseconds. */
-	unsigned int delay_before;
-	/** Delay between repeats in microseconds. */
-	unsigned int delay_between;
-} usb_kbd_repeat_t;
-
-
-
-int usb_kbd_repeat_fibril(void *arg);
-
-void usb_kbd_repeat_start(struct usb_kbd_t *kbd, unsigned int key);
-
-void usb_kbd_repeat_stop(struct usb_kbd_t *kbd, unsigned int key);
-
-#endif /* USB_HID_KBDREPEAT_H_ */
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/main.c
===================================================================
--- uspace/drv/bus/usb/usbhid/main.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,181 +1,0 @@
-/*
- * Copyright (c) 2010 Vojtech Horky
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/**
- * @file
- * Main routines of USB HID driver.
- */
-
-#include <ddf/driver.h>
-#include <usb/debug.h>
-#include <errno.h>
-#include <str_error.h>
-
-#include <usb/dev/driver.h>
-#include <usb/dev/poll.h>
-
-#include "usbhid.h"
-
-#define NAME "usbhid"
-
-/**
- * Callback for passing a new device to the driver.
- *
- * @note Currently, only boot-protocol keyboards are supported by this driver.
- *
- * @param dev Structure representing the new device.
- * @return Error code.
- */
-static int usb_hid_device_add(usb_device_t *dev)
-{
-	usb_log_debug("%s\n", __FUNCTION__);
-
-	if (dev == NULL) {
-		usb_log_error("Wrong parameter given for add_device().\n");
-		return EINVAL;
-	}
-
-	if (usb_device_get_iface_number(dev) < 0) {
-		usb_log_error("Failed to add HID device: endpoints not found."
-		    "\n");
-		return ENOTSUP;
-	}
-	usb_hid_dev_t *hid_dev =
-	    usb_device_data_alloc(dev, sizeof(usb_hid_dev_t));
-	if (hid_dev == NULL) {
-		usb_log_error("Failed to create USB/HID device structure.\n");
-		return ENOMEM;
-	}
-
-	int rc = usb_hid_init(hid_dev, dev);
-	if (rc != EOK) {
-		usb_log_error("Failed to initialize USB/HID device.\n");
-		usb_hid_deinit(hid_dev);
-		return rc;
-	}
-
-	usb_log_debug("USB/HID device structure initialized.\n");
-
-	/* Start automated polling function.
-	 * This will create a separate fibril that will query the device
-	 * for the data continuously. */
-	rc = usb_device_auto_poll_desc(dev,
-	   /* Index of the polling pipe. */
-	   hid_dev->poll_pipe_mapping->description,
-	   /* Callback when data arrives. */
-	   usb_hid_polling_callback,
-	   /* How much data to request. */
-	   hid_dev->poll_pipe_mapping->pipe.max_packet_size,
-	   /* Delay */
-	   -1,
-	   /* Callback when the polling ends. */
-	   usb_hid_polling_ended_callback,
-	   /* Custom argument. */
-	   hid_dev);
-
-	if (rc != EOK) {
-		usb_log_error("Failed to start polling fibril for `%s'.\n",
-		    usb_device_get_name(dev));
-		usb_hid_deinit(hid_dev);
-		return rc;
-	}
-	hid_dev->running = true;
-
-	usb_log_info("HID device `%s' ready.\n", usb_device_get_name(dev));
-
-	return EOK;
-}
-
-/**
- * Callback for a device about to be removed from the driver.
- *
- * @param dev Structure representing the device.
- * @return Error code.
- */
-static int usb_hid_device_rem(usb_device_t *dev)
-{
-	// TODO: Stop device polling
-	// TODO: Call deinit (stops autorepeat too)
-	return ENOTSUP;
-}
-
-/**
- * Callback for removing a device from the driver.
- *
- * @param dev Structure representing the device.
- * @return Error code.
- */
-static int usb_hid_device_gone(usb_device_t *dev)
-{
-	assert(dev);
-	usb_hid_dev_t *hid_dev = usb_device_data_get(dev);
-	assert(hid_dev);
-	unsigned tries = 100;
-	/* Wait for fail. */
-	while (hid_dev->running && tries--) {
-		async_usleep(100000);
-	}
-	if (hid_dev->running) {
-		usb_log_error("Can't remove hid, still running.\n");
-		return EBUSY;
-	}
-
-	usb_hid_deinit(hid_dev);
-	usb_log_debug2("%s destruction complete.\n", usb_device_get_name(dev));
-	return EOK;
-}
-
-/** USB generic driver callbacks */
-static const usb_driver_ops_t usb_hid_driver_ops = {
-	.device_add = usb_hid_device_add,
-	.device_rem = usb_hid_device_rem,
-	.device_gone = usb_hid_device_gone,
-};
-
-/** The driver itself. */
-static const usb_driver_t usb_hid_driver = {
-        .name = NAME,
-        .ops = &usb_hid_driver_ops,
-        .endpoints = usb_hid_endpoints
-};
-
-int main(int argc, char *argv[])
-{
-	printf(NAME ": HelenOS USB HID driver.\n");
-
-	log_init(NAME);
-
-	return usb_driver_main(&usb_hid_driver);
-}
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/mouse/mousedev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,443 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak, 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 drvusbhid
- * @{
- */
-/**
- * @file
- * USB Mouse driver API.
- */
-
-#include <usb/debug.h>
-#include <usb/classes/classes.h>
-#include <usb/hid/hid.h>
-#include <usb/hid/request.h>
-#include <usb/hid/usages/core.h>
-#include <errno.h>
-#include <async.h>
-#include <str_error.h>
-#include <ipc/mouseev.h>
-#include <io/console.h>
-
-#include <ipc/kbdev.h>
-#include <io/keycode.h>
-
-#include "mousedev.h"
-#include "../usbhid.h"
-
-#define NAME "mouse"
-
-static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
-
-static ddf_dev_ops_t ops = { .default_handler = default_connection_handler };
-
-
-const usb_endpoint_description_t usb_hid_mouse_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
-};
-
-const char *HID_MOUSE_FUN_NAME = "mouse";
-const char *HID_MOUSE_CATEGORY = "mouse";
-
-/** Default idle rate for mouses. */
-static const uint8_t IDLE_RATE = 0;
-
-
-static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[] = {
-	0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
-	0x09, 0x02,                    // USAGE (Mouse)
-	0xa1, 0x01,                    // COLLECTION (Application)
-	0x09, 0x01,                    //   USAGE (Pointer)
-	0xa1, 0x00,                    //   COLLECTION (Physical)
-	0x95, 0x03,                    //     REPORT_COUNT (3)
-	0x75, 0x01,                    //     REPORT_SIZE (1)
-	0x05, 0x09,                    //     USAGE_PAGE (Button)
-	0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
-	0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
-	0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
-	0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
-	0x81, 0x02,                    //     INPUT (Data,Var,Abs)
-	0x95, 0x01,                    //     REPORT_COUNT (1)
-	0x75, 0x05,                    //     REPORT_SIZE (5)
-	0x81, 0x01,                    //     INPUT (Cnst)
-	0x75, 0x08,                    //     REPORT_SIZE (8)
-	0x95, 0x02,                    //     REPORT_COUNT (2)
-	0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
-	0x09, 0x30,                    //     USAGE (X)
-	0x09, 0x31,                    //     USAGE (Y)
-	0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
-	0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
-	0x81, 0x06,                    //     INPUT (Data,Var,Rel)
-	0xc0,                          //   END_COLLECTION
-	0xc0                           // END_COLLECTION
-};
-
-
-
-/** Default handler for IPC methods not handled by DDF.
- *
- * @param fun Device function handling the call.
- * @param icallid Call id.
- * @param icall Call data.
- */
-static void default_connection_handler(ddf_fun_t *fun,
-    ipc_callid_t icallid, ipc_call_t *icall)
-{
-	usb_mouse_t *mouse_dev = ddf_fun_data_get(fun);
-
-	if (mouse_dev == NULL) {
-		usb_log_debug("%s: Missing parameters.\n", __FUNCTION__);
-		async_answer_0(icallid, EINVAL);
-		return;
-	}
-
-	usb_log_debug("%s: fun->name: %s\n", __FUNCTION__, ddf_fun_get_name(fun));
-	usb_log_debug("%s: mouse_sess: %p\n",
-	    __FUNCTION__, mouse_dev->mouse_sess);
-
-	async_sess_t *sess =
-	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
-	if (sess != NULL) {
-		if (mouse_dev->mouse_sess == NULL) {
-			mouse_dev->mouse_sess = sess;
-			usb_log_debug("Console session to %s set ok (%p).\n",
-			    ddf_fun_get_name(fun), sess);
-			async_answer_0(icallid, EOK);
-		} else {
-			usb_log_error("Console session to %s already set.\n",
-			    ddf_fun_get_name(fun));
-			async_answer_0(icallid, ELIMIT);
-			async_hangup(sess);
-		}
-	} else {
-		usb_log_debug("%s: Invalid function.\n", __FUNCTION__);
-		async_answer_0(icallid, EINVAL);
-	}
-}
-
-static int get_mouse_axis_move_value(uint8_t rid, usb_hid_report_t *report,
-    int32_t usage)
-{
-	int result = 0;
-
-	usb_hid_report_path_t *path = usb_hid_report_path();
-	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_GENERIC_DESKTOP,
-	    usage);
-
-	usb_hid_report_path_set_report_id(path, rid);
-
-	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    report, NULL, path, USB_HID_PATH_COMPARE_END,
-	    USB_HID_REPORT_TYPE_INPUT);
-
-	if (field != NULL) {
-		result = field->value;
-	}
-
-	usb_hid_report_path_free(path);
-
-	return result;
-}
-
-static bool usb_mouse_process_report(usb_hid_dev_t *hid_dev,
-    usb_mouse_t *mouse_dev)
-{
-	assert(mouse_dev != NULL);
-
-	if (mouse_dev->mouse_sess == NULL) {
-		usb_log_warning(NAME " No console session.\n");
-		return true;
-	}
-
-	const int shift_x = get_mouse_axis_move_value(hid_dev->report_id,
-	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_X);
-	const int shift_y = get_mouse_axis_move_value(hid_dev->report_id,
-	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_Y);
-	const int wheel = get_mouse_axis_move_value(hid_dev->report_id,
-	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
-
-	if (shift_x || shift_y || wheel) {
-		async_exch_t *exch =
-		    async_exchange_begin(mouse_dev->mouse_sess);
-		if (exch != NULL) {
-			async_msg_3(exch, MOUSEEV_MOVE_EVENT,
-			    shift_x, shift_y, wheel);
-			async_exchange_end(exch);
-		}
-	}
-
-	/* Buttons */
-	usb_hid_report_path_t *path = usb_hid_report_path();
-	if (path == NULL) {
-		usb_log_warning("Failed to create USB HID report path.\n");
-		return true;
-	}
-	int ret =
-	   usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0);
-	if (ret != EOK) {
-		usb_hid_report_path_free(path);
-		usb_log_warning("Failed to add buttons to report path.\n");
-		return true;
-	}
-	usb_hid_report_path_set_report_id(path, hid_dev->report_id);
-
-	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
-	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, USB_HID_REPORT_TYPE_INPUT);
-
-	while (field != NULL) {
-		usb_log_debug2(NAME " VALUE(%X) USAGE(%X)\n", field->value,
-		    field->usage);
-		assert(field->usage > field->usage_minimum);
-		const unsigned index = field->usage - field->usage_minimum;
-		assert(index < mouse_dev->buttons_count);
-
-		if (mouse_dev->buttons[index] != field->value) {
-			async_exch_t *exch =
-			    async_exchange_begin(mouse_dev->mouse_sess);
-			if (exch != NULL) {
-				async_req_2_0(exch, MOUSEEV_BUTTON_EVENT,
-				    field->usage, (field->value != 0) ? 1 : 0);
-				async_exchange_end(exch);
-				mouse_dev->buttons[index] = field->value;
-			}
-		}
-
-		field = usb_hid_report_get_sibling(
-		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
-		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
-		    USB_HID_REPORT_TYPE_INPUT);
-	}
-
-	usb_hid_report_path_free(path);
-
-	return true;
-}
-
-#define FUN_UNBIND_DESTROY(fun) \
-if (fun) { \
-	if (ddf_fun_unbind((fun)) == EOK) { \
-		ddf_fun_destroy((fun)); \
-	} else { \
-		usb_log_error("Could not unbind function `%s', it " \
-		    "will not be destroyed.\n", ddf_fun_get_name(fun)); \
-	} \
-} else (void) 0
-
-/** Get highest index of a button mentioned in given report.
- *
- * @param report HID report.
- * @param report_id Report id we are interested in.
- * @return Highest button mentioned in the report.
- * @retval 1 No button was mentioned.
- *
- */
-static size_t usb_mouse_get_highest_button(usb_hid_report_t *report, uint8_t report_id)
-{
-	size_t highest_button = 0;
-
-	usb_hid_report_path_t *path = usb_hid_report_path();
-	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0);
-	usb_hid_report_path_set_report_id(path, report_id);
-
-	usb_hid_report_field_t *field = NULL;
-
-	/* Break from within. */
-	while (1) {
-		field = usb_hid_report_get_sibling(
-		    report, field, path,
-		    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
-		    USB_HID_REPORT_TYPE_INPUT);
-		/* No more buttons? */
-		if (field == NULL) {
-			break;
-		}
-
-		size_t current_button = field->usage - field->usage_minimum;
-		if (current_button > highest_button) {
-			highest_button = current_button;
-		}
-	}
-
-	usb_hid_report_path_free(path);
-
-	return highest_button;
-}
-
-static int mouse_dev_init(usb_mouse_t *mouse_dev, usb_hid_dev_t *hid_dev)
-{
-	// FIXME: This may not be optimal since stupid hardware vendor may
-	// use buttons 1, 2, 3 and 6000 and we would allocate array of
-	// 6001*4B and use only 4 items in it.
-	// Since I doubt that hardware producers would do that, I think
-	// that the current solution is good enough.
-	/* Adding 1 because we will be accessing buttons[highest]. */
-	mouse_dev->buttons_count = 1 + usb_mouse_get_highest_button(
-	    &hid_dev->report, hid_dev->report_id);
-	mouse_dev->buttons = calloc(mouse_dev->buttons_count, sizeof(int32_t));
-
-	if (mouse_dev->buttons == NULL) {
-		usb_log_error(NAME ": out of memory, giving up on device!\n");
-		free(mouse_dev);
-		return ENOMEM;
-	}
-
-	// TODO: how to know if the device supports the request???
-	usbhid_req_set_idle(usb_device_get_default_pipe(hid_dev->usb_dev),
-	    usb_device_get_iface_number(hid_dev->usb_dev), IDLE_RATE);
-	return EOK;
-}
-
-int usb_mouse_init(usb_hid_dev_t *hid_dev, void **data)
-{
-	usb_log_debug("Initializing HID/Mouse structure...\n");
-
-	if (hid_dev == NULL) {
-		usb_log_error("Failed to init mouse structure: no structure"
-		    " given.\n");
-		return EINVAL;
-	}
-
-	/* Create the exposed function. */
-	usb_log_debug("Creating DDF function %s...\n", HID_MOUSE_FUN_NAME);
-	ddf_fun_t *fun = usb_device_ddf_fun_create(hid_dev->usb_dev,
-	    fun_exposed, HID_MOUSE_FUN_NAME);
-	if (fun == NULL) {
-		usb_log_error("Could not create DDF function node `%s'.\n",
-		    HID_MOUSE_FUN_NAME);
-		return ENOMEM;
-	}
-
-	usb_mouse_t *mouse_dev = ddf_fun_data_alloc(fun, sizeof(usb_mouse_t));
-	if (mouse_dev == NULL) {
-		usb_log_error("Failed to alloc HID mouse device structure.\n");
-		ddf_fun_destroy(fun);
-		return ENOMEM;
-	}
-
-	int ret = mouse_dev_init(mouse_dev, hid_dev);
-	if (ret != EOK) {
-		usb_log_error("Failed to init HID mouse device structure.\n");
-		return ret;
-	}
-
-	ddf_fun_set_ops(fun, &ops);
-
-	ret = ddf_fun_bind(fun);
-	if (ret != EOK) {
-		usb_log_error("Could not bind DDF function `%s': %s.\n",
-		    ddf_fun_get_name(fun), str_error(ret));
-		ddf_fun_destroy(fun);
-		return ret;
-	}
-
-	usb_log_debug("Adding DDF function `%s' to category %s...\n",
-	    ddf_fun_get_name(fun), HID_MOUSE_CATEGORY);
-	ret = ddf_fun_add_to_category(fun, HID_MOUSE_CATEGORY);
-	if (ret != EOK) {
-		usb_log_error(
-		    "Could not add DDF function to category %s: %s.\n",
-		    HID_MOUSE_CATEGORY, str_error(ret));
-		FUN_UNBIND_DESTROY(fun);
-		return ret;
-	}
-	mouse_dev->mouse_fun = fun;
-
-	/* Save the Mouse device structure into the HID device structure. */
-	*data = mouse_dev;
-
-	return EOK;
-}
-
-bool usb_mouse_polling_callback(usb_hid_dev_t *hid_dev, void *data)
-{
-	if (hid_dev == NULL || data == NULL) {
-		usb_log_error(
-		    "Missing argument to the mouse polling callback.\n");
-		return false;
-	}
-
-	usb_mouse_t *mouse_dev = data;
-
-	return usb_mouse_process_report(hid_dev, mouse_dev);
-}
-
-void usb_mouse_deinit(usb_hid_dev_t *hid_dev, void *data)
-{
-	if (data == NULL)
-		return;
-
-	usb_mouse_t *mouse_dev = data;
-
-	/* Hangup session to the console */
-	if (mouse_dev->mouse_sess != NULL) {
-		const int ret = async_hangup(mouse_dev->mouse_sess);
-		if (ret != EOK)
-			usb_log_warning("Failed to hang up mouse session: "
-			    "%p, %s.\n", mouse_dev->mouse_sess, str_error(ret));
-	}
-
-	free(mouse_dev->buttons);
-	FUN_UNBIND_DESTROY(mouse_dev->mouse_fun);
-}
-
-int usb_mouse_set_boot_protocol(usb_hid_dev_t *hid_dev)
-{
-	int rc = usb_hid_parse_report_descriptor(
-	    &hid_dev->report, USB_MOUSE_BOOT_REPORT_DESCRIPTOR,
-	    sizeof(USB_MOUSE_BOOT_REPORT_DESCRIPTOR));
-
-	if (rc != EOK) {
-		usb_log_error("Failed to parse boot report descriptor: %s\n",
-		    str_error(rc));
-		return rc;
-	}
-
-	rc = usbhid_req_set_protocol(
-	    usb_device_get_default_pipe(hid_dev->usb_dev),
-	    usb_device_get_iface_number(hid_dev->usb_dev),
-	    USB_HID_PROTOCOL_BOOT);
-
-	if (rc != EOK) {
-		usb_log_warning("Failed to set boot protocol to the device: "
-		    "%s\n", str_error(rc));
-		return rc;
-	}
-
-	return EOK;
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/mouse/mousedev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,70 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * USB Mouse driver API.
- */
-
-#ifndef USB_HID_MOUSEDEV_H_
-#define USB_HID_MOUSEDEV_H_
-
-#include <usb/dev/driver.h>
-#include <async.h>
-#include "../usbhid.h"
-
-/** Container for USB mouse device. */
-typedef struct {
-	/** IPC session to consumer. */
-	async_sess_t *mouse_sess;
-	
-	/** Mouse buttons statuses. */
-	int32_t *buttons;
-	size_t buttons_count;
-	
-	/** DDF mouse function */
-	ddf_fun_t *mouse_fun;
-} usb_mouse_t;
-
-extern const usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description;
-
-extern const char *HID_MOUSE_FUN_NAME;
-extern const char *HID_MOUSE_CATEGORY;
-
-extern int usb_mouse_init(usb_hid_dev_t *, void **);
-extern bool usb_mouse_polling_callback(usb_hid_dev_t *, void *);
-extern void usb_mouse_deinit(usb_hid_dev_t *, void *);
-extern int usb_mouse_set_boot_protocol(usb_hid_dev_t *);
-
-#endif // USB_HID_MOUSEDEV_H_
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/multimedia/keymap.c
===================================================================
--- uspace/drv/bus/usb/usbhid/multimedia/keymap.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,94 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * UUSB multimedia key to keycode mapping.
- */
-
-#include <io/keycode.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <usb/debug.h>
-#include "keymap.h"
-
-/**
- * Mapping between USB HID multimedia usages (from HID Usage Tables) and 
- * corresponding HelenOS key codes.
- *
- * Currently only Usages used by Logitech UltraX keyboard are present. All other
- * should result in 0.
- */
-static int usb_hid_keymap_consumer[0x29c] = {
-	[0xb5] = 0,       /* Scan Next Track */
-	[0xb6] = 0,       /* Scan Previous Track */
-	[0xb7] = 0,       /* Stop */
-	[0xb8] = 0,       /* Eject */
-	[0xcd] = 0/*KC_F2*/,   /* Play/Pause */
-	[0xe2] = 0/*KC_F3*/,   /* Mute */
-	[0xe9] = 0/*KC_F5*/,   /* Volume Increment */
-	[0xea] = 0/*KC_F4*/,   /* Volume Decrement */
-	[0x183] = 0/*KC_F1*/,      /* AL Consumer Control Configuration */
-	[0x18a] = 0,      /* AL Email Reader */
-	[0x192] = 0,      /* AL Calculator */
-	[0x221] = 0,      /* AC Search */
-	[0x223] = 0/*KC_F6*/,      /* AC Home */
-	[0x224] = 0,      /* AC Back */
-	[0x225] = 0,      /* AC Forward */
-	[0x226] = 0,      /* AC Stop */
-	[0x227] = 0,  /* AC Refresh */
-	[0x22a] = 0   /* AC Bookmarks */
-};
-
-/**
- * Translates USB HID Usages from the Consumer Page into HelenOS keycodes.
- *
- * @param usage USB HID Consumer Page Usage number.
- * 
- * @retval HelenOS key code corresponding to the given USB Consumer Page Usage.
- */
-unsigned int usb_multimedia_map_usage(int usage)
-{
-	unsigned int key;
-	int *map = usb_hid_keymap_consumer;
-	size_t map_length = sizeof(usb_hid_keymap_consumer) / sizeof(int);
-
-	if ((usage < 0) || ((size_t)usage >= map_length))
-		return -1;
-
-	/*! @todo What if the usage is not in the table? */
-	key = map[usage];
-	
-	return key;
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/multimedia/keymap.h
===================================================================
--- uspace/drv/bus/usb/usbhid/multimedia/keymap.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * USB multimedia key to keycode mapping.
- */
-
-#ifndef USB_HID_MULTIMEDIA_KEYMAP_H_
-#define USB_HID_MULTIMEDIA_KEYMAP_H_
-
-unsigned int usb_multimedia_map_usage(int usage);
-
-#endif /* USB_HID_MULTIMEDIA_KEYMAP_H_ */
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/multimedia/multimedia.c
===================================================================
--- uspace/drv/bus/usb/usbhid/multimedia/multimedia.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,290 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/**
- * @file
- * USB Keyboard multimedia keys subdriver.
- */
-
-
-#include "multimedia.h"
-#include "../usbhid.h"
-#include "keymap.h"
-
-#include <usb/hid/hidparser.h>
-#include <usb/debug.h>
-#include <usb/hid/usages/core.h>
-#include <usb/hid/usages/consumer.h>
-
-#include <errno.h>
-#include <async.h>
-#include <str_error.h>
-
-#include <ipc/kbdev.h>
-#include <io/console.h>
-
-#define NAME  "multimedia-keys"
-
-
-/**
- * Logitech UltraX device type.
- */
-typedef struct usb_multimedia_t {
-	/** Previously pressed keys (not translated to key codes). */
-	//int32_t *keys_old;
-	/** Currently pressed keys (not translated to key codes). */
-	//int32_t *keys;
-	/** Count of stored keys (i.e. number of keys in the report). */
-	//size_t key_count;
-	/** IPC session to the console device (for sending key events). */
-	async_sess_t *console_sess;
-} usb_multimedia_t;
-
-
-
-/**
- * Default handler for IPC methods not handled by DDF.
- *
- * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
- * assumes the caller is the console and thus it stores IPC session to it for
- * later use by the driver to notify about key events.
- *
- * @param fun Device function handling the call.
- * @param icallid Call id.
- * @param icall Call data.
- */
-static void default_connection_handler(ddf_fun_t *fun,
-    ipc_callid_t icallid, ipc_call_t *icall)
-{
-	usb_log_debug(NAME " default_connection_handler()\n");
-
-	usb_multimedia_t *multim_dev = ddf_fun_data_get(fun);
-
-	async_sess_t *sess =
-	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
-	if (sess != NULL) {
-		if (multim_dev->console_sess == NULL) {
-			multim_dev->console_sess = sess;
-			usb_log_debug(NAME " Saved session to console: %p\n",
-			    sess);
-			async_answer_0(icallid, EOK);
-		} else
-			async_answer_0(icallid, ELIMIT);
-	} else
-		async_answer_0(icallid, EINVAL);
-}
-
-static ddf_dev_ops_t multimedia_ops = {
-	.default_handler = default_connection_handler
-};
-
-/**
- * Processes key events.
- *
- * @note This function was copied from AT keyboard driver and modified to suit
- *       USB keyboard.
- *
- * @note Lock keys are not sent to the console, as they are completely handled
- *       in the driver. It may, however, be required later that the driver
- *       sends also these keys to application (otherwise it cannot use those
- *       keys at all).
- *
- * @param hid_dev
- * @param multim_dev
- * @param type Type of the event (press / release). Recognized values:
- *             KEY_PRESS, KEY_RELEASE
- * @param key Key code of the key according to HID Usage Tables.
- */
-static void usb_multimedia_push_ev(
-    usb_multimedia_t *multim_dev, int type, unsigned int key)
-{
-	assert(multim_dev != NULL);
-
-	const kbd_event_t ev = {
-		.type = type,
-		.key = key,
-		.mods = 0,
-		.c = 0,
-	};
-
-	usb_log_debug2(NAME " Sending key %d to the console\n", ev.key);
-	if (multim_dev->console_sess == NULL) {
-		usb_log_warning(
-		    "Connection to console not ready, key discarded.\n");
-		return;
-	}
-
-	async_exch_t *exch = async_exchange_begin(multim_dev->console_sess);
-	if (exch != NULL) {
-		async_msg_4(exch, KBDEV_EVENT, ev.type, ev.key, ev.mods, ev.c);
-		async_exchange_end(exch);
-	} else {
-		usb_log_warning("Failed to send multimedia key.\n");
-	}
-}
-
-int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
-{
-	if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
-		return EINVAL;
-	}
-
-	usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
-
-	/* Create the exposed function. */
-	ddf_fun_t *fun = usb_device_ddf_fun_create(
-	    hid_dev->usb_dev, fun_exposed, NAME);
-	if (fun == NULL) {
-		usb_log_error("Could not create DDF function node.\n");
-		return ENOMEM;
-	}
-
-	ddf_fun_set_ops(fun, &multimedia_ops);
-
-	usb_multimedia_t *multim_dev =
-	    ddf_fun_data_alloc(fun, sizeof(usb_multimedia_t));
-	if (multim_dev == NULL) {
-		ddf_fun_destroy(fun);
-		return ENOMEM;
-	}
-
-	multim_dev->console_sess = NULL;
-
-	//todo Autorepeat?
-
-	int rc = ddf_fun_bind(fun);
-	if (rc != EOK) {
-		usb_log_error("Could not bind DDF function: %s.\n",
-		    str_error(rc));
-		ddf_fun_destroy(fun);
-		return rc;
-	}
-
-	usb_log_debug(NAME " function created (handle: %" PRIun ").\n",
-	    ddf_fun_get_handle(fun));
-
-	rc = ddf_fun_add_to_category(fun, "keyboard");
-	if (rc != EOK) {
-		usb_log_error(
-		    "Could not add DDF function to category 'keyboard': %s.\n",
-		    str_error(rc));
-		if (ddf_fun_unbind(fun) != EOK) {
-			usb_log_error("Failed to unbind %s, won't destroy.\n",
-			    ddf_fun_get_name(fun));
-		} else {
-			ddf_fun_destroy(fun);
-		}
-		return rc;
-	}
-
-	/* Save the KBD device structure into the HID device structure. */
-	*data = fun;
-
-	usb_log_debug(NAME " HID/multimedia structure initialized.\n");
-	return EOK;
-}
-
-void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data)
-{
-	ddf_fun_t *fun = data;
-
-	usb_multimedia_t *multim_dev = ddf_fun_data_get(fun);
-
-	/* Hangup session to the console */
-	if (multim_dev->console_sess)
-		async_hangup(multim_dev->console_sess);
-	if (ddf_fun_unbind(fun) != EOK) {
-		usb_log_error("Failed to unbind %s, won't destroy.\n",
-		    ddf_fun_get_name(fun));
-	} else {
-		usb_log_debug2("%s unbound.\n", ddf_fun_get_name(fun));
-		/* This frees multim_dev too as it was stored in
-		 * fun->data */
-		ddf_fun_destroy(fun);
-	}
-}
-
-bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data)
-{
-	// TODO: checks
-	ddf_fun_t *fun = data;
-	if (hid_dev == NULL) {
-		return false;
-	}
-
-	usb_multimedia_t *multim_dev = ddf_fun_data_get(fun);
-
-	usb_hid_report_path_t *path = usb_hid_report_path();
-	if (path == NULL)
-		return true; /* This might be a temporary failure. */
-
-	int ret =
-	    usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
-	if (ret != EOK) {
-		usb_hid_report_path_free(path);
-		return true; /* This might be a temporary failure. */
-	}
-
-	usb_hid_report_path_set_report_id(path, hid_dev->report_id);
-
-	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
-	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
-	    USB_HID_REPORT_TYPE_INPUT);
-
-	//FIXME Is this iterating OK if done multiple times?
-	//FIXME The parsing is not OK. (what's wrong?)
-	while (field != NULL) {
-		if (field->value != 0) {
-			usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n",
-			    field->value, field->usage);
-			const unsigned key =
-			    usb_multimedia_map_usage(field->usage);
-			const char *key_str =
-			    usbhid_multimedia_usage_to_str(field->usage);
-			usb_log_info("Pressed key: %s\n", key_str);
-			usb_multimedia_push_ev(multim_dev, KEY_PRESS, key);
-		}
-
-		field = usb_hid_report_get_sibling(
-		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
-		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
-		    USB_HID_REPORT_TYPE_INPUT);
-	}
-
-	usb_hid_report_path_free(path);
-
-	return true;
-}
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/multimedia/multimedia.h
===================================================================
--- uspace/drv/bus/usb/usbhid/multimedia/multimedia.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,50 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * USB Keyboard multimedia keys subdriver.
- */
-
-#ifndef USB_HID_MULTIMEDIA_H_
-#define USB_HID_MULTIMEDIA_H_
-
-#include <usb/dev/driver.h>
-#include "../usbhid.h"
-
-extern int usb_multimedia_init(usb_hid_dev_t *, void **);
-extern void usb_multimedia_deinit(usb_hid_dev_t *, void *);
-extern bool usb_multimedia_polling_callback(usb_hid_dev_t *, void *);
-
-#endif // USB_HID_MULTIMEDIA_H_
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/subdrivers.c
===================================================================
--- uspace/drv/bus/usb/usbhid/subdrivers.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,129 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * USB HID subdriver mappings.
- */
-
-#include "subdrivers.h"
-#include <usb/hid/usages/core.h>
-#include <usb/hid/hidpath.h>
-#include "kbd/kbddev.h"
-#include "mouse/mousedev.h"
-#include "multimedia/multimedia.h"
-#include "blink1/blink1.h"
-#include "generic/hiddev.h"
-
-static const usb_hid_subdriver_usage_t path_kbd[] = {
-	{
-		USB_HIDUT_PAGE_GENERIC_DESKTOP,
-		USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD
-	},
-	{0, 0}
-};
-
-static const usb_hid_subdriver_usage_t path_mouse[] = {
-	{
-		USB_HIDUT_PAGE_GENERIC_DESKTOP,
-		USB_HIDUT_USAGE_GENERIC_DESKTOP_MOUSE
-	},
-	{0, 0}
-};
-
-static const usb_hid_subdriver_usage_t path_multim_key[] = {
-	{
-		USB_HIDUT_PAGE_CONSUMER,
-		USB_HIDUT_USAGE_CONSUMER_CONSUMER_CONTROL
-	},
-	{0, 0}
-};
-
-const usb_hid_subdriver_mapping_t usb_hid_subdrivers[] = {
-	{
-		path_kbd,
-		0,
-		USB_HID_PATH_COMPARE_BEGIN,
-		-1,
-		-1,
-		{
-			.init = usb_kbd_init,
-			.deinit = usb_kbd_deinit,
-			.poll = usb_kbd_polling_callback,
-			.poll_end = NULL
-		},
-	},
-	{
-		path_multim_key,
-		1,
-		USB_HID_PATH_COMPARE_BEGIN,
-		-1,
-		-1,
-		{
-			.init = usb_multimedia_init,
-			.deinit = usb_multimedia_deinit,
-			.poll = usb_multimedia_polling_callback,
-			.poll_end = NULL
-		}
-	},
-	{
-		path_mouse,
-		0,
-		USB_HID_PATH_COMPARE_BEGIN,
-		-1,
-		-1,
-		{
-			.init = usb_mouse_init,
-			.deinit = usb_mouse_deinit,
-			.poll = usb_mouse_polling_callback,
-			.poll_end = NULL
-		}
-	},
-	{
-		NULL,
-		0,
-		USB_HID_PATH_COMPARE_BEGIN,
-		0x27b8,
-		0x01ed,
-		{
-			.init = usb_blink1_init,
-			.deinit = usb_blink1_deinit,
-			.poll = NULL,
-			.poll_end = NULL
-		}
-	}
-};
-
-const size_t USB_HID_MAX_SUBDRIVERS =
-    sizeof(usb_hid_subdrivers) / sizeof(usb_hid_subdrivers[0]);
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/subdrivers.h
===================================================================
--- uspace/drv/bus/usb/usbhid/subdrivers.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,87 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * USB HID subdriver mappings.
- */
-
-#ifndef USB_HID_SUBDRIVERS_H_
-#define USB_HID_SUBDRIVERS_H_
-
-#include "usbhid.h"
-#include "kbd/kbddev.h"
-
-typedef struct usb_hid_subdriver_usage {
-	int usage_page;
-	int usage;
-} usb_hid_subdriver_usage_t;
-
-/** Structure representing the mapping between device requirements and the
- *  subdriver supposed to handle this device.
- *
- * By filling in this structure and adding it to the usb_hid_subdrivers array,
- * a new subdriver mapping will be created and used by the HID driver when it
- * searches for appropriate subdrivers for a device.
- *
- */
-typedef struct usb_hid_subdriver_mapping {
-	/** Usage path that the device's input reports must contain.
-	 *
-	 * It is an array of pairs <usage_page, usage>, terminated by a <0, 0>
-	 * pair. If you do not wish to specify the device in this way, set this
-	 * to NULL.
-	 */
-	const usb_hid_subdriver_usage_t *usage_path;
-	
-	/** Report ID for which the path should apply. */
-	int report_id;
-	
-	/** Compare type for the usage path. */
-	int compare;
-	
-	/** Vendor ID (set to -1 if not specified). */
-	int vendor_id;
-	
-	/** Product ID (set to -1 if not specified). */
-	int product_id;
-	
-	/** Subdriver for controlling this device. */
-	const usb_hid_subdriver_t subdriver;
-} usb_hid_subdriver_mapping_t;
-
-extern const usb_hid_subdriver_mapping_t usb_hid_subdrivers[];
-extern const size_t USB_HID_MAX_SUBDRIVERS;
-
-#endif /* USB_HID_SUBDRIVERS_H_ */
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/usbhid.c
===================================================================
--- uspace/drv/bus/usb/usbhid/usbhid.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,548 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/**
- * @file
- * USB HID driver API.
- */
-
-#include <usb/debug.h>
-#include <usb/classes/classes.h>
-#include <usb/hid/hid.h>
-#include <usb/hid/hidparser.h>
-#include <usb/hid/hidreport.h>
-#include <usb/hid/request.h>
-
-#include <errno.h>
-#include <macros.h>
-#include <str_error.h>
-
-#include "usbhid.h"
-
-#include "kbd/kbddev.h"
-#include "generic/hiddev.h"
-#include "mouse/mousedev.h"
-#include "subdrivers.h"
-
-/* Array of endpoints expected on the device, NULL terminated. */
-const usb_endpoint_description_t *usb_hid_endpoints[] = {
-	&usb_hid_kbd_poll_endpoint_description,
-	&usb_hid_mouse_poll_endpoint_description,
-	&usb_hid_generic_poll_endpoint_description,
-	NULL
-};
-
-static int usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev)
-{
-	assert(hid_dev != NULL);
-	assert(hid_dev->subdriver_count == 0);
-
-	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
-	if (hid_dev->subdrivers == NULL) {
-		return ENOMEM;
-	}
-	hid_dev->subdriver_count = 1;
-	// TODO 0 should be keyboard, but find a better way
-	hid_dev->subdrivers[0] = usb_hid_subdrivers[0].subdriver;
-
-	return EOK;
-}
-
-static int usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev)
-{
-	assert(hid_dev != NULL);
-	assert(hid_dev->subdriver_count == 0);
-
-	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
-	if (hid_dev->subdrivers == NULL) {
-		return ENOMEM;
-	}
-	hid_dev->subdriver_count = 1;
-	// TODO 2 should be mouse, but find a better way
-	hid_dev->subdrivers[0] = usb_hid_subdrivers[2].subdriver;
-
-	return EOK;
-}
-
-static int usb_hid_set_generic_hid_subdriver(usb_hid_dev_t *hid_dev)
-{
-	assert(hid_dev != NULL);
-	assert(hid_dev->subdriver_count == 0);
-
-	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
-	if (hid_dev->subdrivers == NULL) {
-		return ENOMEM;
-	}
-	hid_dev->subdriver_count = 1;
-
-	/* Set generic hid subdriver routines */
-	hid_dev->subdrivers[0].init = usb_generic_hid_init;
-	hid_dev->subdrivers[0].poll = usb_generic_hid_polling_callback;
-	hid_dev->subdrivers[0].poll_end = NULL;
-	hid_dev->subdrivers[0].deinit = usb_generic_hid_deinit;
-
-	return EOK;
-}
-
-static bool usb_hid_ids_match(const usb_hid_dev_t *hid_dev,
-    const usb_hid_subdriver_mapping_t *mapping)
-{
-	assert(hid_dev);
-	assert(hid_dev->usb_dev);
-	assert(mapping);
-	const usb_standard_device_descriptor_t *d =
-	    &usb_device_descriptors(hid_dev->usb_dev)->device;
-
-	return (d->vendor_id == mapping->vendor_id)
-	    && (d->product_id == mapping->product_id);
-}
-
-static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev,
-    const usb_hid_subdriver_mapping_t *mapping)
-{
-	assert(hid_dev != NULL);
-	assert(mapping != NULL);
-
-	usb_hid_report_path_t *usage_path = usb_hid_report_path();
-	if (usage_path == NULL) {
-		usb_log_debug("Failed to create usage path.\n");
-		return false;
-	}
-
-	for (int i = 0; mapping->usage_path[i].usage != 0
-	    || mapping->usage_path[i].usage_page != 0; ++i) {
-		if (usb_hid_report_path_append_item(usage_path,
-		    mapping->usage_path[i].usage_page,
-		    mapping->usage_path[i].usage) != EOK) {
-			usb_log_debug("Failed to append to usage path.\n");
-			usb_hid_report_path_free(usage_path);
-			return false;
-		}
-	}
-
-	usb_log_debug("Compare flags: %d\n", mapping->compare);
-
-	bool matches = false;
-	uint8_t report_id = mapping->report_id;
-
-	do {
-		usb_log_debug("Trying report id %u\n", report_id);
-		if (report_id != 0) {
-			usb_hid_report_path_set_report_id(usage_path,
-				report_id);
-		}
-
-		const usb_hid_report_field_t *field =
-		    usb_hid_report_get_sibling(
-		        &hid_dev->report, NULL, usage_path, mapping->compare,
-		        USB_HID_REPORT_TYPE_INPUT);
-
-		usb_log_debug("Field: %p\n", field);
-
-		if (field != NULL) {
-			matches = true;
-			break;
-		}
-
-		report_id = usb_hid_get_next_report_id(
-		    &hid_dev->report, report_id, USB_HID_REPORT_TYPE_INPUT);
-	} while (!matches && report_id != 0);
-
-	usb_hid_report_path_free(usage_path);
-
-	return matches;
-}
-
-static int usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev,
-    const usb_hid_subdriver_t **subdrivers, unsigned count)
-{
-	assert(hid_dev);
-	assert(subdrivers);
-
-	if (count == 0) {
-		hid_dev->subdriver_count = 0;
-		hid_dev->subdrivers = NULL;
-		return EOK;
-	}
-
-	/* +1 for generic hid subdriver */
-	hid_dev->subdrivers = calloc((count + 1), sizeof(usb_hid_subdriver_t));
-	if (hid_dev->subdrivers == NULL) {
-		return ENOMEM;
-	}
-
-	for (unsigned i = 0; i < count; ++i) {
-		hid_dev->subdrivers[i] = *subdrivers[i];
-	}
-
-	/* Add one generic HID subdriver per device */
-	hid_dev->subdrivers[count].init = usb_generic_hid_init;
-	hid_dev->subdrivers[count].poll = usb_generic_hid_polling_callback;
-	hid_dev->subdrivers[count].deinit = usb_generic_hid_deinit;
-	hid_dev->subdrivers[count].poll_end = NULL;
-
-	hid_dev->subdriver_count = count + 1;
-
-	return EOK;
-}
-
-static int usb_hid_find_subdrivers(usb_hid_dev_t *hid_dev)
-{
-	assert(hid_dev != NULL);
-
-	const usb_hid_subdriver_t *subdrivers[USB_HID_MAX_SUBDRIVERS];
-	unsigned count = 0;
-
-	for (unsigned i = 0; i < USB_HID_MAX_SUBDRIVERS; ++i) {
-		const usb_hid_subdriver_mapping_t *mapping =
-		    &usb_hid_subdrivers[i];
-		/* Check the vendor & product ID. */
-		if (mapping->vendor_id >= 0 && mapping->product_id < 0) {
-			usb_log_warning("Mapping[%d]: Missing Product ID for "
-			    "Vendor ID %d\n", i, mapping->vendor_id);
-		}
-		if (mapping->product_id >= 0 && mapping->vendor_id < 0) {
-			usb_log_warning("Mapping[%d]: Missing Vendor ID for "
-			    "Product ID %d\n", i, mapping->product_id);
-		}
-
-		bool matched = false;
-
-		/* Check ID match. */
-		if (mapping->vendor_id >= 0 && mapping->product_id >= 0) {
-			usb_log_debug("Comparing device against vendor ID %u"
-			    " and product ID %u.\n", mapping->vendor_id,
-			    mapping->product_id);
-			if (usb_hid_ids_match(hid_dev, mapping)) {
-				usb_log_debug("IDs matched.\n");
-				matched = true;
-			}
-		}
-
-		/* Check usage match. */
-		if (mapping->usage_path != NULL) {
-			usb_log_debug("Comparing device against usage path.\n");
-			if (usb_hid_path_matches(hid_dev, mapping)) {
-				/* Does not matter if IDs were matched. */
-				matched = true;
-			}
-		}
-
-		if (matched) {
-			usb_log_debug("Subdriver matched.\n");
-			subdrivers[count++] = &mapping->subdriver;
-		}
-	}
-
-	/* We have all subdrivers determined, save them into the hid device */
-	return usb_hid_save_subdrivers(hid_dev, subdrivers, count);
-}
-
-static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
-{
-	assert(hid_dev);
-	assert(dev);
-
-	static const struct {
-		const usb_endpoint_description_t *desc;
-		const char* description;
-	} endpoints[] = {
-		{&usb_hid_kbd_poll_endpoint_description, "Keyboard endpoint"},
-		{&usb_hid_mouse_poll_endpoint_description, "Mouse endpoint"},
-		{&usb_hid_generic_poll_endpoint_description, "Generic HID endpoint"},
-	};
-
-	for (unsigned i = 0; i < ARRAY_SIZE(endpoints); ++i) {
-		usb_endpoint_mapping_t *epm =
-		    usb_device_get_mapped_ep_desc(dev, endpoints[i].desc);
-		if (epm && epm->present) {
-			usb_log_debug("Found: %s.\n", endpoints[i].description);
-			hid_dev->poll_pipe_mapping = epm;
-			return EOK;
-		}
-	}
-	return ENOTSUP;
-}
-
-static int usb_hid_init_report(usb_hid_dev_t *hid_dev)
-{
-	assert(hid_dev != NULL);
-
-	uint8_t report_id = 0;
-	size_t max_size = 0;
-
-	do {
-		usb_log_debug("Getting size of the report.\n");
-		const size_t size =
-		    usb_hid_report_byte_size(&hid_dev->report, report_id,
-		        USB_HID_REPORT_TYPE_INPUT);
-		usb_log_debug("Report ID: %u, size: %zu\n", report_id, size);
-		max_size = (size > max_size) ? size : max_size;
-		usb_log_debug("Getting next report ID\n");
-		report_id = usb_hid_get_next_report_id(&hid_dev->report,
-		    report_id, USB_HID_REPORT_TYPE_INPUT);
-	} while (report_id != 0);
-
-	usb_log_debug("Max size of input report: %zu\n", max_size);
-
-	assert(hid_dev->input_report == NULL);
-
-	hid_dev->input_report = calloc(1, max_size);
-	if (hid_dev->input_report == NULL) {
-		return ENOMEM;
-	}
-	hid_dev->max_input_report_size = max_size;
-
-	return EOK;
-}
-
-/*
- * This functions initializes required structures from the device's descriptors
- * and starts new fibril for polling the keyboard for events and another one for
- * handling auto-repeat of keys.
- *
- * During initialization, the keyboard is switched into boot protocol, the idle
- * rate is set to 0 (infinity), resulting in the keyboard only reporting event
- * when a key is pressed or released. Finally, the LED lights are turned on 
- * according to the default setup of lock keys.
- *
- * @note By default, the keyboards is initialized with Num Lock turned on and 
- *       other locks turned off.
- *
- * @param hid_dev Device to initialize, non-NULL.
- * @param dev USB device, non-NULL.
- * @return Error code.
- */
-int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
-{
-	assert(hid_dev);
-	assert(dev);
-
-	usb_log_debug("Initializing HID structure...\n");
-
-	usb_hid_report_init(&hid_dev->report);
-
-	/* The USB device should already be initialized, save it in structure */
-	hid_dev->usb_dev = dev;
-	hid_dev->poll_pipe_mapping = NULL;
-
-	int rc = usb_hid_check_pipes(hid_dev, dev);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	/* Get the report descriptor and parse it. */
-	rc = usb_hid_process_report_descriptor(
-	    hid_dev->usb_dev, &hid_dev->report, &hid_dev->report_desc,
-	    &hid_dev->report_desc_size);
-
-	/* If report parsing went well, find subdrivers. */
-	if (rc == EOK) {
-		usb_hid_find_subdrivers(hid_dev);
-	} else {
-		usb_log_error("Failed to parse report descriptor: fallback.\n");
-		hid_dev->subdrivers = NULL;
-		hid_dev->subdriver_count = 0;
-	}
-
-	usb_log_debug("Subdriver count(before trying boot protocol): %d\n",
-	    hid_dev->subdriver_count);
-
-	/* No subdrivers, fall back to the boot protocol if available. */
-	if (hid_dev->subdriver_count == 0) {
-		assert(hid_dev->subdrivers == NULL);
-		usb_log_info("No subdrivers found to handle device, trying "
-		    "boot protocol.\n");
-
-		switch (hid_dev->poll_pipe_mapping->interface->interface_protocol) {
-		case USB_HID_PROTOCOL_KEYBOARD:
-			usb_log_info("Falling back to kbd boot protocol.\n");
-			rc = usb_kbd_set_boot_protocol(hid_dev);
-			if (rc == EOK) {
-				usb_hid_set_boot_kbd_subdriver(hid_dev);
-			}
-			break;
-		case USB_HID_PROTOCOL_MOUSE:
-			usb_log_info("Falling back to mouse boot protocol.\n");
-			rc = usb_mouse_set_boot_protocol(hid_dev);
-			if (rc == EOK) {
-				usb_hid_set_boot_mouse_subdriver(hid_dev);
-			}
-			break;
-		default:
-			usb_log_info("Falling back to generic HID driver.\n");
-			usb_hid_set_generic_hid_subdriver(hid_dev);
-		}
-	}
-
-	usb_log_debug("Subdriver count(after trying boot protocol): %d\n",
-	    hid_dev->subdriver_count);
-
-	/* Still no subdrivers? */
-	if (hid_dev->subdriver_count == 0) {
-		assert(hid_dev->subdrivers == NULL);
-		usb_log_error(
-		    "No subdriver for handling this device could be found.\n");
-		return ENOTSUP;
-	}
-
-	/* Initialize subdrivers */
-	bool ok = false;
-	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
-		if (hid_dev->subdrivers[i].init != NULL) {
-			usb_log_debug("Initializing subdriver %d.\n",i);
-			const int pret = hid_dev->subdrivers[i].init(hid_dev,
-			    &hid_dev->subdrivers[i].data);
-			if (pret != EOK) {
-				usb_log_warning("Failed to initialize"
-				    " HID subdriver structure: %s.\n",
-				    str_error(pret));
-				rc = pret;
-			} else {
-				/* At least one subdriver initialized. */
-				ok = true;
-			}
-		} else {
-			/* Does not need initialization. */
-			ok = true;
-		}
-	}
-
-	if (ok) {
-		/* Save max input report size and
-		 * allocate space for the report */
-		rc = usb_hid_init_report(hid_dev);
-		if (rc != EOK) {
-			usb_log_error("Failed to initialize input report buffer"
-			    ".\n");
-		}
-	}
-
-	return rc;
-}
-
-bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
-    size_t buffer_size, void *arg)
-{
-	if (dev == NULL || arg == NULL || buffer == NULL) {
-		usb_log_error("Missing arguments to polling callback.\n");
-		return false;
-	}
-	usb_hid_dev_t *hid_dev = arg;
-
-	assert(hid_dev->input_report != NULL);
-
-	usb_log_debug("New data [%zu/%zu]: %s\n", buffer_size,
-	    hid_dev->max_input_report_size,
-	    usb_debug_str_buffer(buffer, buffer_size, 0));
-
-	if (hid_dev->max_input_report_size >= buffer_size) {
-		/*! @todo This should probably be atomic. */
-		memcpy(hid_dev->input_report, buffer, buffer_size);
-		hid_dev->input_report_size = buffer_size;
-		usb_hid_new_report(hid_dev);
-	}
-
-	/* Parse the input report */
-	const int rc = usb_hid_parse_report(
-	    &hid_dev->report, buffer, buffer_size, &hid_dev->report_id);
-	if (rc != EOK) {
-		usb_log_warning("Failure in usb_hid_parse_report():"
-		    "%s\n", str_error(rc));
-	}
-
-	bool cont = false;
-	/* Continue if at least one of the subdrivers want to continue */
-	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
-		if (hid_dev->subdrivers[i].poll != NULL) {
-			cont = cont || hid_dev->subdrivers[i].poll(
-			    hid_dev, hid_dev->subdrivers[i].data);
-		}
-	}
-
-	return cont;
-}
-
-void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, void *arg)
-{
-	assert(dev);
-	assert(arg);
-
-	usb_hid_dev_t *hid_dev = arg;
-
-	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
-		if (hid_dev->subdrivers[i].poll_end != NULL) {
-			hid_dev->subdrivers[i].poll_end(
-			    hid_dev, hid_dev->subdrivers[i].data, reason);
-		}
-	}
-
-	hid_dev->running = false;
-}
-
-void usb_hid_new_report(usb_hid_dev_t *hid_dev)
-{
-	++hid_dev->report_nr;
-}
-
-int usb_hid_report_number(const usb_hid_dev_t *hid_dev)
-{
-	return hid_dev->report_nr;
-}
-
-void usb_hid_deinit(usb_hid_dev_t *hid_dev)
-{
-	assert(hid_dev);
-	assert(hid_dev->subdrivers != NULL || hid_dev->subdriver_count == 0);
-
-
-	usb_log_debug("Subdrivers: %p, subdriver count: %d\n", 
-	    hid_dev->subdrivers, hid_dev->subdriver_count);
-
-	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
-		if (hid_dev->subdrivers[i].deinit != NULL) {
-			hid_dev->subdrivers[i].deinit(hid_dev,
-			    hid_dev->subdrivers[i].data);
-		}
-	}
-
-	/* Free allocated structures */
-	free(hid_dev->subdrivers);
-	free(hid_dev->report_desc);
-
-	/* Destroy the parser */
-	usb_hid_report_deinit(&hid_dev->report);
-
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/usbhid.h
===================================================================
--- uspace/drv/bus/usb/usbhid/usbhid.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,153 +1,0 @@
-/*
- * Copyright (c) 2011 Lubos Slovak
- * 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 drvusbhid
- * @{
- */
-/** @file
- * USB HID driver API.
- */
-
-#ifndef USB_HID_USBHID_H_
-#define USB_HID_USBHID_H_
-
-#include <stdint.h>
-
-#include <usb/hid/hidparser.h>
-#include <ddf/driver.h>
-#include <usb/dev/pipes.h>
-#include <usb/dev/driver.h>
-#include <usb/hid/hid.h>
-#include <stdbool.h>
-
-typedef struct usb_hid_dev usb_hid_dev_t;
-typedef struct usb_hid_subdriver usb_hid_subdriver_t;
-
-/** Subdriver initialization callback.
- *
- * @param dev Backing USB HID device.
- * @param data Custom subdriver data (pointer where to store them).
- * @return Error code.
- */
-typedef int (*usb_hid_driver_init_t)(usb_hid_dev_t *dev, void **data);
-
-/** Subdriver deinitialization callback.
- *
- * @param dev Backing USB HID device.
- * @param data Custom subdriver data.
- */
-typedef void (*usb_hid_driver_deinit_t)(usb_hid_dev_t *dev, void *data);
-
-/** Subdriver callback on data from device.
- *
- * @param dev Backing USB HID device.
- * @param data Custom subdriver data.
- * @return Whether to continue polling (typically true always).
- */
-typedef bool (*usb_hid_driver_poll_t)(usb_hid_dev_t *dev, void *data);
-
-/** Subdriver callback after communication with the device ceased.
- *
- * @param dev Backing USB HID device.
- * @param data Custom subdriver data.
- * @param ended_due_to_errors Whether communication ended due to errors in
- *	communication (true) or deliberately by driver (false).
- */
-typedef void (*usb_hid_driver_poll_ended_t)(usb_hid_dev_t *dev, void *data,
-    bool ended_due_to_errors);
-
-struct usb_hid_subdriver {
-	/** Function to be called when initializing HID device. */
-	usb_hid_driver_init_t init;
-	/** Function to be called when destroying the HID device structure. */
-	usb_hid_driver_deinit_t deinit;
-	/** Function to be called when data arrives from the device. */
-	usb_hid_driver_poll_t poll;
-	/** Function to be called when polling ends. */
-	usb_hid_driver_poll_ended_t poll_end;
-	/** Arbitrary data needed by the subdriver. */
-	void *data;
-};
-
-
-/**
- * Structure for holding general HID device data.
- */
-struct usb_hid_dev {
-	/** Structure holding generic USB device information. */
-	usb_device_t *usb_dev;
-
-	/** Endpont mapping of the polling pipe. */
-	usb_endpoint_mapping_t *poll_pipe_mapping;
-
-	/** Subdrivers. */
-	usb_hid_subdriver_t *subdrivers;
-
-	/** Number of subdrivers. */
-	unsigned subdriver_count;
-
-	/** Report descriptor. */
-	uint8_t *report_desc;
-
-	/** Report descriptor size. */
-	size_t report_desc_size;
-
-	/** HID Report parser. */
-	usb_hid_report_t report;
-
-	uint8_t report_id;
-
-	uint8_t *input_report;
-
-	size_t input_report_size;
-	size_t max_input_report_size;
-
-	int report_nr;
-	volatile bool running;
-};
-
-extern const usb_endpoint_description_t *usb_hid_endpoints[];
-
-int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev);
-
-void usb_hid_deinit(usb_hid_dev_t *hid_dev);
-
-bool usb_hid_polling_callback(usb_device_t *dev,
-    uint8_t *buffer, size_t buffer_size, void *arg);
-
-void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, void *arg);
-
-void usb_hid_new_report(usb_hid_dev_t *hid_dev);
-
-int usb_hid_report_number(const usb_hid_dev_t *hid_dev);
-
-#endif /* USB_HID_USBHID_H_ */
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbhid/usbhid.ma
===================================================================
--- uspace/drv/bus/usb/usbhid/usbhid.ma	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,3 +1,0 @@
-1000 usb&interface&class=HID&subclass=0x01&protocol=0x01
-1000 usb&interface&class=HID&subclass=0x01&protocol=0x02
-100 usb&interface&class=HID
Index: pace/drv/bus/usb/usbmast/Makefile
===================================================================
--- uspace/drv/bus/usb/usbmast/Makefile	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,41 +1,0 @@
-#
-# 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 = usbdev usb drv scsi
-
-BINARY = usbmast
-
-SOURCES = \
-	bo_trans.c \
-	cmdw.c \
-	main.c \
-	scsi_ms.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: pace/drv/bus/usb/usbmast/bo_trans.c
===================================================================
--- uspace/drv/bus/usb/usbmast/bo_trans.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,272 +1,0 @@
-/*
- * 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 drvusbmast
- * @{
- */
-/**
- * @file
- * USB mass storage bulk-only transport.
- */
-
-#include <stdbool.h>
-#include <errno.h>
-#include <str_error.h>
-#include <usb/debug.h>
-#include <usb/dev/request.h>
-
-#include "bo_trans.h"
-#include "cmdw.h"
-#include "usbmast.h"
-
-
-#define MASTLOG(format, ...) \
-	usb_log_debug2("USB cl08: " format, ##__VA_ARGS__)
-
-/** Send command via bulk-only transport.
- *
- * @param mfun		Mass storage function
- * @param tag		Command block wrapper tag (automatically compared
- *			with answer)
- * @param cmd		SCSI command
- *
- * @return		Error code
- */
-int usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, scsi_cmd_t *cmd)
-{
-	int rc;
-
-	if (cmd->data_in && cmd->data_out)
-		return EINVAL;
-
-	usb_pipe_t *bulk_in_pipe = mfun->mdev->bulk_in_pipe;
-	usb_pipe_t *bulk_out_pipe = mfun->mdev->bulk_out_pipe;
-
-	usb_pipe_t *dpipe = bulk_out_pipe;
-	usb_direction_t ddir = USB_DIRECTION_OUT;
-	size_t dbuf_size = cmd->data_out_size;
-
-	if (cmd->data_in) {
-		ddir = USB_DIRECTION_IN;
-		dbuf_size = cmd->data_in_size;
-		dpipe = bulk_in_pipe;
-	}
-
-	/* Prepare CBW - command block wrapper */
-	usb_massstor_cbw_t cbw;
-	usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, mfun->lun,
-	    cmd->cdb_size, cmd->cdb);
-
-	/* Send the CBW. */
-	MASTLOG("Sending CBW.\n");
-	rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
-	MASTLOG("CBW '%s' sent: %s.\n",
-	    usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
-	    str_error(rc));
-	if (rc != EOK) {
-		usb_log_error("Bulk out write failed: %s\n", str_error(rc));
-		return EIO;
-	}
-
-	MASTLOG("Transferring data.\n");
-	if (cmd->data_in) {
-		size_t act_size;
-		/* Recieve data from the device. */
-		rc = usb_pipe_read(dpipe, cmd->data_in, cmd->data_in_size,
-		    &act_size);
-		MASTLOG("Received %zu bytes (%s): %s.\n", act_size,
-		    usb_debug_str_buffer(cmd->data_in, act_size, 0),
-		    str_error(rc));
-	}
-	if (cmd->data_out) {
-		/* Send data to the device. */
-		rc = usb_pipe_write(dpipe, cmd->data_out, cmd->data_out_size);
-		MASTLOG("Sent %zu bytes (%s): %s.\n", cmd->data_out_size,
-		    usb_debug_str_buffer(cmd->data_out, cmd->data_out_size, 0),
-		    str_error(rc));
-	}
-
-	if (rc == ESTALL) {
-		/* Clear stall condition and continue below to read CSW. */
-		usb_pipe_clear_halt(
-		    usb_device_get_default_pipe(mfun->mdev->usb_dev), dpipe);
-        } else if (rc != EOK) {
-		usb_log_error("Failed to transfer data: %s", str_error(rc));
-		return EIO;
-	}
-
-	/* Read CSW. */
-	usb_massstor_csw_t csw;
-	size_t csw_size;
-	MASTLOG("Reading CSW.\n");
-	rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
-	MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
-	    usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
-	    str_error(rc));
-	if (rc != EOK) {
-		usb_log_error("Failed to read CSW: %s", str_error(rc));
-		return EIO;
-	}
-
-	if (csw_size != sizeof(csw)) {
-		usb_log_error("Received CSW of incorrect size.");
-		return EIO;
-	}
-
-	if (csw.dCSWTag != tag) {
-		usb_log_error("Received CSW with incorrect tag. (expected: %"
-		    PRIX32" received: %"PRIx32, tag, csw.dCSWTag);
-		return EIO;
-	}
-
-	/*
-	 * Determine the actual return value from the CSW.
-	 */
-	switch (csw.dCSWStatus) {
-	case cbs_passed:
-		cmd->status = CMDS_GOOD;
-		break;
-	case cbs_failed:
-		cmd->status = CMDS_FAILED;
-		usb_log_error("CBS Failed.\n");
-		break;
-	case cbs_phase_error:
-		usb_log_error("CBS phase error.\n");
-		rc = EIO;
-		break;
-	default:
-		usb_log_error("CBS other error.\n");
-		rc = EIO;
-		break;
-	}
-
-	const size_t residue = uint32_usb2host(csw.dCSWDataResidue);
-	if (residue > dbuf_size) {
-		usb_log_error("Residue > buffer size (%zu > %zu).\n",
-		    residue, dbuf_size);
-		return EIO;
-	}
-
-	/*
-	 * When the device has less data to send than requested (or cannot
-	 * receive moredata), it can either stall the pipe or send garbage
-	 * (ignore data) and indicate that via the residue field in CSW.
-	 * That means dbuf_size - residue is the authoritative size of data
-	 * received (sent).
-	 */
-
-	if (cmd->data_in)
-		cmd->rcvd_size = dbuf_size - residue;
-
-	return rc;
-}
-
-/** Perform bulk-only mass storage reset.
- *
- * @param mfun		Mass storage function
- * @return		Error code
- */
-int usb_massstor_reset(usbmast_dev_t *mdev)
-{
-	return usb_control_request_set(
-	    usb_device_get_default_pipe(mdev->usb_dev),
-	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
-	    0xFF, 0, usb_device_get_iface_number(mdev->usb_dev), NULL, 0);
-}
-
-/** Perform complete reset recovery of bulk-only mass storage.
- *
- * Notice that no error is reported because if this fails, the error
- * would reappear on next transaction somehow.
- *
- * @param mfun		Mass storage function
- */
-void usb_massstor_reset_recovery(usbmast_dev_t *mdev)
-{
-	/* We would ignore errors here because if this fails
-	 * we are doomed anyway and any following transaction would fail.
-	 */
-	usb_massstor_reset(mdev);
-	usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
-	    mdev->bulk_in_pipe);
-	usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
-	    mdev->bulk_out_pipe);
-}
-
-/** Get max LUN of a mass storage device.
- *
- * @see usb_masstor_get_lun_count
- *
- * @warning Error from this command does not necessarily indicate malfunction
- * of the device. Device does not need to support this request.
- * You shall rather use usb_masstor_get_lun_count.
- *
- * @param mfun		Mass storage function
- * @return		Error code of maximum LUN (index, not count)
- */
-int usb_massstor_get_max_lun(usbmast_dev_t *mdev)
-{
-	uint8_t max_lun;
-	size_t data_recv_len;
-	int rc = usb_control_request_get(
-	    usb_device_get_default_pipe(mdev->usb_dev),
-	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
-	    0xFE, 0, usb_device_get_iface_number(mdev->usb_dev), &max_lun, 1,
-	    &data_recv_len);
-	if (rc != EOK) {
-		return rc;
-	}
-	if (data_recv_len != 1) {
-		return EEMPTY;
-	}
-	return (int) max_lun;
-}
-
-/** Get number of LUNs supported by mass storage device.
- *
- * @warning This function hides any error during the request
- * (typically that shall not be a problem).
- *
- * @param mfun		Mass storage function
- * @return		Number of LUNs
- */
-size_t usb_masstor_get_lun_count(usbmast_dev_t *mdev)
-{
-	int max_lun = usb_massstor_get_max_lun(mdev);
-	if (max_lun < 0) {
-		max_lun = 1;
-	} else {
-		max_lun++;
-	}
-
-	return (size_t) max_lun;
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbmast/bo_trans.h
===================================================================
--- uspace/drv/bus/usb/usbmast/bo_trans.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,98 +1,0 @@
-/*
- * 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 drvusbmast
- * @{
- */
-/** @file
- * USB mass storage bulk-only transport.
- */
-
-#ifndef BO_TRANS_H_
-#define BO_TRANS_H_
-
-#include <scsi/spc.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <usb/usb.h>
-#include <usb/dev/pipes.h>
-#include <usb/dev/driver.h>
-#include "usbmast.h"
-
-typedef enum cmd_status {
-	CMDS_GOOD,
-	CMDS_FAILED
-} cmd_status_t;
-
-/** SCSI command.
- *
- * Contains (a subset of) the input and output arguments of SCSI
- * Execute Command procedure call (see SAM-4 chapter 5.1)
- */
-typedef struct {
-	/*
-	 * Related to IN fields
-	 */
-
-	/** Command Descriptor Block */
-	const void *cdb;
-	/** CDB size in bytes */
-	size_t cdb_size;
-
-	/** Outgoing data */
-	const void *data_out;
-	/** Size of outgoing data in bytes */
-	size_t data_out_size;
-
-	/*
-	 * Related to OUT fields
-	 */
-
-	/** Buffer for incoming data */
-	void *data_in;
-	/** Size of input buffer in bytes */
-	size_t data_in_size;
-
-	/** Number of bytes actually received */
-	size_t rcvd_size;
-
-	/** Status */
-	cmd_status_t status;
-} scsi_cmd_t;
-
-extern int usb_massstor_cmd(usbmast_fun_t *, uint32_t, scsi_cmd_t *);
-extern int usb_massstor_reset(usbmast_dev_t *);
-extern void usb_massstor_reset_recovery(usbmast_dev_t *);
-extern int usb_massstor_get_max_lun(usbmast_dev_t *);
-extern size_t usb_masstor_get_lun_count(usbmast_dev_t *);
-
-#endif
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbmast/cmdw.c
===================================================================
--- uspace/drv/bus/usb/usbmast/cmdw.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,66 +1,0 @@
-/*
- * 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 drvusbmast
- * @{
- */
-/** @file
- * USB mass storage commands.
- */
-
-#include <byteorder.h>
-#include <mem.h>
-#include <stdint.h>
-#include <usb/usb.h>
-#include "cmdw.h"
-
-void usb_massstor_cbw_prepare(usb_massstor_cbw_t *cbw,
-    uint32_t tag, uint32_t transfer_length, usb_direction_t dir,
-    uint8_t lun, uint8_t cmd_len, const uint8_t *cmd)
-{
-	cbw->dCBWSignature = uint32_host2usb(0x43425355);
-	cbw->dCBWTag = tag;
-	cbw->dCBWDataTransferLength = transfer_length;
-
-	cbw->bmCBWFlags = 0;
-	if (dir == USB_DIRECTION_IN) {
-		cbw->bmCBWFlags |= (1 << 7);
-	}
-
-	/* Only lowest 4 bits. */
-	cbw->bCBWLUN = lun & 0x0F;
-
-	/* Only lowest 5 bits. */
-	cbw->bCBWBLength = cmd_len & 0x1F;
-
-	memcpy(cbw->CBWCB, cmd, cbw->bCBWBLength);
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbmast/cmdw.h
===================================================================
--- uspace/drv/bus/usb/usbmast/cmdw.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,72 +1,0 @@
-/*
- * 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 drvusbmast
- * @{
- */
-/** @file
- * USB mass storage commands.
- */
-
-#ifndef CMDW_H_
-#define CMDW_H_
-
-#include <stdint.h>
-#include <usb/usb.h>
-
-typedef struct {
-	uint32_t dCBWSignature;
-	uint32_t dCBWTag;
-	uint32_t dCBWDataTransferLength;
-	uint8_t bmCBWFlags;
-	uint8_t bCBWLUN;
-	uint8_t bCBWBLength;
-	uint8_t CBWCB[16];
-} __attribute__((packed)) usb_massstor_cbw_t;
-
-typedef struct {
-	uint32_t dCSWSignature;
-	uint32_t dCSWTag;
-	uint32_t dCSWDataResidue;
-	uint8_t dCSWStatus;
-} __attribute__((packed)) usb_massstor_csw_t;
-
-enum cmd_block_status {
-	cbs_passed	= 0x00,
-	cbs_failed	= 0x01,
-	cbs_phase_error = 0x02
-};
-
-extern void usb_massstor_cbw_prepare(usb_massstor_cbw_t *, uint32_t, uint32_t,
-    usb_direction_t, uint8_t, uint8_t, const uint8_t *);
-
-#endif
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbmast/main.c
===================================================================
--- uspace/drv/bus/usb/usbmast/main.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,412 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * 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.
- */
-
-/** @addtogroup drvusbmast
- * @{
- */
-/**
- * @file
- * Main routines of USB mass storage driver.
- */
-
-#include <as.h>
-#include <async.h>
-#include <bd_srv.h>
-#include <macros.h>
-#include <usb/dev/driver.h>
-#include <usb/debug.h>
-#include <usb/classes/classes.h>
-#include <usb/classes/massstor.h>
-#include <errno.h>
-#include <io/logctl.h>
-#include <str_error.h>
-#include "cmdw.h"
-#include "bo_trans.h"
-#include "scsi_ms.h"
-#include "usbmast.h"
-
-#define NAME "usbmast"
-
-static const usb_endpoint_description_t bulk_in_ep = {
-	.transfer_type = USB_TRANSFER_BULK,
-	.direction = USB_DIRECTION_IN,
-	.interface_class = USB_CLASS_MASS_STORAGE,
-	.interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
-	.interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
-	.flags = 0
-};
-static const usb_endpoint_description_t bulk_out_ep = {
-	.transfer_type = USB_TRANSFER_BULK,
-	.direction = USB_DIRECTION_OUT,
-	.interface_class = USB_CLASS_MASS_STORAGE,
-	.interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
-	.interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
-	.flags = 0
-};
-
-static const usb_endpoint_description_t *mast_endpoints[] = {
-	&bulk_in_ep,
-	&bulk_out_ep,
-	NULL
-};
-
-static int usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun);
-static void usbmast_bd_connection(ipc_callid_t iid, ipc_call_t *icall,
-    void *arg);
-
-static int usbmast_bd_open(bd_srvs_t *, bd_srv_t *);
-static int usbmast_bd_close(bd_srv_t *);
-static int usbmast_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
-static int usbmast_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);
-static int usbmast_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
-static int usbmast_bd_get_block_size(bd_srv_t *, size_t *);
-static int usbmast_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
-
-static bd_ops_t usbmast_bd_ops = {
-	.open = usbmast_bd_open,
-	.close = usbmast_bd_close,
-	.read_blocks = usbmast_bd_read_blocks,
-	.sync_cache = usbmast_bd_sync_cache,
-	.write_blocks = usbmast_bd_write_blocks,
-	.get_block_size = usbmast_bd_get_block_size,
-	.get_num_blocks = usbmast_bd_get_num_blocks
-};
-
-static usbmast_fun_t *bd_srv_usbmast(bd_srv_t *bd)
-{
-	return (usbmast_fun_t *) bd->srvs->sarg;
-}
-
-/** Callback when a device is removed from the system.
- *
- * @param dev Representation of USB device.
- * @return Error code.
- */
-static int usbmast_device_gone(usb_device_t *dev)
-{
-	usbmast_dev_t *mdev = usb_device_data_get(dev);
-	assert(mdev);
-
-	for (size_t i = 0; i < mdev->lun_count; ++i) {
-		const int rc = ddf_fun_unbind(mdev->luns[i]);
-		if (rc != EOK) {
-			usb_log_error("Failed to unbind LUN function %zu: "
-			    "%s\n", i, str_error(rc));
-			return rc;
-		}
-		ddf_fun_destroy(mdev->luns[i]);
-		mdev->luns[i] = NULL;
-	}
-	free(mdev->luns);
-	return EOK;
-}
-
-/** Callback when a device is about to be removed.
- *
- * @param dev Representation of USB device.
- * @return Error code.
- */
-static int usbmast_device_remove(usb_device_t *dev)
-{
-	//TODO: flush buffers, or whatever.
-	//TODO: remove device
-	return ENOTSUP;
-}
-
-/** Callback when new device is attached and recognized as a mass storage.
- *
- * @param dev Representation of USB device.
- * @return Error code.
- */
-static int usbmast_device_add(usb_device_t *dev)
-{
-	int rc;
-	usbmast_dev_t *mdev = NULL;
-	unsigned i;
-
-	usb_endpoint_mapping_t *epm_in =
-	    usb_device_get_mapped_ep_desc(dev, &bulk_in_ep);
-	usb_endpoint_mapping_t *epm_out =
-	    usb_device_get_mapped_ep_desc(dev, &bulk_out_ep);
-	if (!epm_in || !epm_out || !epm_in->present || !epm_out->present) {
-		usb_log_error("Required EPs were not mapped.\n");
-		return ENOENT;
-	}
-
-	/* Allocate softstate */
-	mdev = usb_device_data_alloc(dev, sizeof(usbmast_dev_t));
-	if (mdev == NULL) {
-		usb_log_error("Failed allocating softstate.\n");
-		return ENOMEM;
-	}
-
-	mdev->usb_dev = dev;
-
-	usb_log_info("Initializing mass storage `%s'.\n",
-	    usb_device_get_name(dev));
-	usb_log_debug("Bulk in endpoint: %d [%zuB].\n",
-	    epm_in->pipe.endpoint_no, epm_in->pipe.max_packet_size);
-	usb_log_debug("Bulk out endpoint: %d [%zuB].\n",
-	    epm_out->pipe.endpoint_no, epm_out->pipe.max_packet_size);
-
-	usb_log_debug("Get LUN count...\n");
-	mdev->lun_count = usb_masstor_get_lun_count(mdev);
-	mdev->luns = calloc(mdev->lun_count, sizeof(ddf_fun_t*));
-	if (mdev->luns == NULL) {
-		rc = ENOMEM;
-		usb_log_error("Failed allocating luns table.\n");
-		goto error;
-	}
-
-	mdev->bulk_in_pipe = &epm_in->pipe;
-	mdev->bulk_out_pipe = &epm_out->pipe;
-	for (i = 0; i < mdev->lun_count; i++) {
-		rc = usbmast_fun_create(mdev, i);
-		if (rc != EOK)
-			goto error;
-	}
-
-	return EOK;
-error:
-	/* Destroy functions */
-	for (size_t i = 0; i < mdev->lun_count; ++i) {
-		if (mdev->luns[i] == NULL)
-			continue;
-		const int rc = ddf_fun_unbind(mdev->luns[i]);
-		if (rc != EOK) {
-			usb_log_warning("Failed to unbind LUN function %zu: "
-			    "%s.\n", i, str_error(rc));
-		}
-		ddf_fun_destroy(mdev->luns[i]);
-	}
-	free(mdev->luns);
-	return rc;
-}
-
-/** Create mass storage function.
- *
- * Called once for each LUN.
- *
- * @param mdev		Mass storage device
- * @param lun		LUN
- * @return		EOK on success or negative error code.
- */
-static int usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun)
-{
-	int rc;
-	char *fun_name = NULL;
-	ddf_fun_t *fun = NULL;
-	usbmast_fun_t *mfun = NULL;
-
-	if (asprintf(&fun_name, "l%u", lun) < 0) {
-		usb_log_error("Out of memory.\n");
-		rc = ENOMEM;
-		goto error;
-	}
-
-	fun = usb_device_ddf_fun_create(mdev->usb_dev, fun_exposed, fun_name);
-	if (fun == NULL) {
-		usb_log_error("Failed to create DDF function %s.\n", fun_name);
-		rc = ENOMEM;
-		goto error;
-	}
-
-	/* Allocate soft state */
-	mfun = ddf_fun_data_alloc(fun, sizeof(usbmast_fun_t));
-	if (mfun == NULL) {
-		usb_log_error("Failed allocating softstate.\n");
-		rc = ENOMEM;
-		goto error;
-	}
-
-	mfun->ddf_fun = fun;
-	mfun->mdev = mdev;
-	mfun->lun = lun;
-
-	bd_srvs_init(&mfun->bds);
-	mfun->bds.ops = &usbmast_bd_ops;
-	mfun->bds.sarg = mfun;
-
-	/* Set up a connection handler. */
-	ddf_fun_set_conn_handler(fun, usbmast_bd_connection);
-
-	usb_log_debug("Inquire...\n");
-	usbmast_inquiry_data_t inquiry;
-	rc = usbmast_inquiry(mfun, &inquiry);
-	if (rc != EOK) {
-		usb_log_warning("Failed to inquire device `%s': %s.\n",
-		    usb_device_get_name(mdev->usb_dev), str_error(rc));
-		rc = EIO;
-		goto error;
-	}
-
-	usb_log_info("Mass storage `%s' LUN %u: " \
-	    "%s by %s rev. %s is %s (%s).\n",
-	    usb_device_get_name(mdev->usb_dev),
-	    lun,
-	    inquiry.product,
-	    inquiry.vendor,
-	    inquiry.revision,
-	    usbmast_scsi_dev_type_str(inquiry.device_type),
-	    inquiry.removable ? "removable" : "non-removable");
-
-	uint32_t nblocks, block_size;
-
-	rc = usbmast_read_capacity(mfun, &nblocks, &block_size);
-	if (rc != EOK) {
-		usb_log_warning("Failed to read capacity, device `%s': %s.\n",
-		    usb_device_get_name(mdev->usb_dev), str_error(rc));
-		rc = EIO;
-		goto error;
-	}
-
-	usb_log_info("Read Capacity: nblocks=%" PRIu32 ", "
-	    "block_size=%" PRIu32 "\n", nblocks, block_size);
-
-	mfun->nblocks = nblocks;
-	mfun->block_size = block_size;
-
-	rc = ddf_fun_bind(fun);
-	if (rc != EOK) {
-		usb_log_error("Failed to bind DDF function %s: %s.\n",
-		    fun_name, str_error(rc));
-		goto error;
-	}
-
-	ddf_fun_add_to_category(fun, "disk");
-
-	free(fun_name);
-	mdev->luns[lun] = fun;
-
-	return EOK;
-
-	/* Error cleanup */
-error:
-	if (fun != NULL)
-		ddf_fun_destroy(fun);
-	if (fun_name != NULL)
-		free(fun_name);
-	return rc;
-}
-
-/** Blockdev client connection handler. */
-static void usbmast_bd_connection(ipc_callid_t iid, ipc_call_t *icall,
-    void *arg)
-{
-	usbmast_fun_t *mfun;
-
-	mfun = (usbmast_fun_t *) ddf_fun_data_get((ddf_fun_t *)arg);
-	bd_conn(iid, icall, &mfun->bds);
-}
-
-/** Open device. */
-static int usbmast_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
-{
-	return EOK;
-}
-
-/** Close device. */
-static int usbmast_bd_close(bd_srv_t *bd)
-{
-	return EOK;
-}
-
-/** Read blocks from the device. */
-static int usbmast_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, void *buf,
-    size_t size)
-{
-	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
-
-	if (size < cnt * mfun->block_size)
-		return EINVAL;
-
-	return usbmast_read(mfun, ba, cnt, buf);
-}
-
-/** Synchronize blocks to nonvolatile storage. */
-static int usbmast_bd_sync_cache(bd_srv_t *bd, uint64_t ba, size_t cnt)
-{
-	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
-
-	return usbmast_sync_cache(mfun, ba, cnt);
-}
-
-/** Write blocks to the device. */
-static int usbmast_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
-    const void *buf, size_t size)
-{
-	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
-
-	if (size < cnt * mfun->block_size)
-		return EINVAL;
-
-	return usbmast_write(mfun, ba, cnt, buf);
-}
-
-/** Get device block size. */
-static int usbmast_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
-{
-	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
-	*rsize = mfun->block_size;
-	return EOK;
-}
-
-/** Get number of blocks on device. */
-static int usbmast_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
-{
-	usbmast_fun_t *mfun = bd_srv_usbmast(bd);
-	*rnb = mfun->nblocks;
-	return EOK;
-}
-
-
-/** USB mass storage driver ops. */
-static const usb_driver_ops_t usbmast_driver_ops = {
-	.device_add = usbmast_device_add,
-	.device_rem = usbmast_device_remove,
-	.device_gone = usbmast_device_gone,
-};
-
-/** USB mass storage driver. */
-static const usb_driver_t usbmast_driver = {
-	.name = NAME,
-	.ops = &usbmast_driver_ops,
-	.endpoints = mast_endpoints
-};
-
-int main(int argc, char *argv[])
-{
-	log_init(NAME);
-	logctl_set_log_level(NAME, LVL_NOTE);
-	return usb_driver_main(&usbmast_driver);
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbmast/scsi_ms.c
===================================================================
--- uspace/drv/bus/usb/usbmast/scsi_ms.c	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,468 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * 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.
- */
-
-/** @addtogroup drvusbmast
- * @{
- */
-/**
- * @file
- * SCSI functions for USB mass storage driver.
- */
-
-#include <bitops.h>
-#include <byteorder.h>
-#include <inttypes.h>
-#include <macros.h>
-#include <usb/dev/driver.h>
-#include <usb/debug.h>
-#include <errno.h>
-#include <str_error.h>
-#include <str.h>
-#include <scsi/sbc.h>
-#include <scsi/spc.h>
-#include "cmdw.h"
-#include "bo_trans.h"
-#include "scsi_ms.h"
-#include "usbmast.h"
-
-/** Get string representation for SCSI peripheral device type.
- *
- * @param type		SCSI peripheral device type code.
- * @return		String representation.
- */
-const char *usbmast_scsi_dev_type_str(unsigned type)
-{
-	return scsi_get_dev_type_str(type);
-}
-
-static void usbmast_dump_sense(scsi_sense_data_t *sense_buf)
-{
-	const unsigned sense_key = sense_buf->flags_key & 0x0f;
-	printf("Got sense data. Sense key: 0x%x (%s), ASC 0x%02x, "
-	    "ASCQ 0x%02x.\n", sense_key,
-	    scsi_get_sense_key_str(sense_key),
-	    sense_buf->additional_code,
-	    sense_buf->additional_cqual);
-}
-
-static int usb_massstor_unit_ready(usbmast_fun_t *mfun)
-{
-	scsi_cmd_t cmd;
-	scsi_cdb_test_unit_ready_t cdb;
-	int rc;
-
-	memset(&cdb, 0, sizeof(cdb));
-	cdb.op_code = SCSI_CMD_TEST_UNIT_READY;
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.cdb = &cdb;
-	cmd.cdb_size = sizeof(cdb);
-
-	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
-
-        if (rc != EOK) {
-		usb_log_error("Test Unit Ready failed on device %s: %s.",
-		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
-		return rc;
-	}
-	/* Ignore command error here. If there's something wrong
-	 * with the device the following commands will fail too.
-	 */
-	if (cmd.status != CMDS_GOOD)
-		usb_log_warning("Test Unit Ready command failed on device %s.",
-		   usb_device_get_name(mfun->mdev->usb_dev));
-
-	return EOK;
-}
-
-/** Run SCSI command.
- *
- * Run command and repeat in case of unit attention.
- * XXX This is too simplified.
- */
-static int usbmast_run_cmd(usbmast_fun_t *mfun, scsi_cmd_t *cmd)
-{
-	uint8_t sense_key;
-	scsi_sense_data_t sense_buf;
-	int rc;
-
-	do {
-		rc = usb_massstor_unit_ready(mfun);
-		if (rc != EOK) {
-			usb_log_error("Inquiry transport failed, device %s: %s.\n",
-			   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
-			return rc;
-		}
-
-		rc = usb_massstor_cmd(mfun, 0xDEADBEEF, cmd);
-		if (rc != EOK) {
-			usb_log_error("Inquiry transport failed, device %s: %s.\n",
-			   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
-			return rc;
-		}
-
-		if (cmd->status == CMDS_GOOD)
-			return EOK;
-
-		usb_log_error("SCSI command failed, device %s.\n",
-		    usb_device_get_name(mfun->mdev->usb_dev));
-
-		rc = usbmast_request_sense(mfun, &sense_buf, sizeof(sense_buf));
-		if (rc != EOK) {
-			usb_log_error("Failed to read sense data.\n");
-			return EIO;
-		}
-
-		/* Dump sense data to log */
-		usbmast_dump_sense(&sense_buf);
-
-		/* Get sense key */
-		sense_key = sense_buf.flags_key & 0x0f;
-
-		if (sense_key == SCSI_SK_UNIT_ATTENTION) {
-			printf("Got unit attention. Re-trying command.\n");
-		}
-
-	} while (sense_key == SCSI_SK_UNIT_ATTENTION);
-
-	/* Command status is not good, nevertheless transport succeeded. */
-	return EOK;
-}
-
-/** Perform SCSI Inquiry command on USB mass storage device.
- *
- * @param mfun		Mass storage function
- * @param inquiry_result Where to store parsed inquiry result
- * @return		Error code
- */
-int usbmast_inquiry(usbmast_fun_t *mfun, usbmast_inquiry_data_t *inq_res)
-{
-	scsi_std_inquiry_data_t inq_data;
-	scsi_cmd_t cmd;
-	scsi_cdb_inquiry_t cdb;
-	int rc;
-
-	memset(&cdb, 0, sizeof(cdb));
-	cdb.op_code = SCSI_CMD_INQUIRY;
-	cdb.alloc_len = host2uint16_t_be(sizeof(inq_data));
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.cdb = &cdb;
-	cmd.cdb_size = sizeof(cdb);
-	cmd.data_in = &inq_data;
-	cmd.data_in_size = sizeof(inq_data);
-
-	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
-
-	if (rc != EOK) {
-		usb_log_error("Inquiry transport failed, device %s: %s.\n",
-		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
-		return rc;
-	}
-
-	if (cmd.status != CMDS_GOOD) {
-		usb_log_error("Inquiry command failed, device %s.\n",
-		   usb_device_get_name(mfun->mdev->usb_dev));
-		return EIO;
-	}
-
-	if (cmd.rcvd_size < SCSI_STD_INQUIRY_DATA_MIN_SIZE) {
-		usb_log_error("SCSI Inquiry response too short (%zu).\n",
-		    cmd.rcvd_size);
-		return EIO;
-	}
-
-	/*
-	 * Parse inquiry data and fill in the result structure.
-	 */
-
-	memset(inq_res, 0, sizeof(*inq_res));
-
-	inq_res->device_type = BIT_RANGE_EXTRACT(uint8_t,
-	    inq_data.pqual_devtype, SCSI_PQDT_DEV_TYPE_h, SCSI_PQDT_DEV_TYPE_l);
-
-	inq_res->removable = BIT_RANGE_EXTRACT(uint8_t,
-	    inq_data.rmb, SCSI_RMB_RMB, SCSI_RMB_RMB);
-
-	spascii_to_str(inq_res->vendor, SCSI_INQ_VENDOR_STR_BUFSIZE,
-	    inq_data.vendor, sizeof(inq_data.vendor));
-
-	spascii_to_str(inq_res->product, SCSI_INQ_PRODUCT_STR_BUFSIZE,
-	    inq_data.product, sizeof(inq_data.product));
-
-	spascii_to_str(inq_res->revision, SCSI_INQ_REVISION_STR_BUFSIZE,
-	    inq_data.revision, sizeof(inq_data.revision));
-
-	return EOK;
-}
-
-/** Perform SCSI Request Sense command on USB mass storage device.
- *
- * @param mfun		Mass storage function
- * @param buf		Destination buffer
- * @param size		Size of @a buf
- *
- * @return		Error code.
- */
-int usbmast_request_sense(usbmast_fun_t *mfun, void *buf, size_t size)
-{
-	scsi_cmd_t cmd;
-	scsi_cdb_request_sense_t cdb;
-	int rc;
-
-	memset(&cdb, 0, sizeof(cdb));
-	cdb.op_code = SCSI_CMD_REQUEST_SENSE;
-	cdb.alloc_len = min(size, SCSI_SENSE_DATA_MAX_SIZE);
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.cdb = &cdb;
-	cmd.cdb_size = sizeof(cdb);
-	cmd.data_in = buf;
-	cmd.data_in_size = size;
-
-	rc = usb_massstor_cmd(mfun, 0xDEADBEEF, &cmd);
-
-        if (rc != EOK || cmd.status != CMDS_GOOD) {
-		usb_log_error("Request Sense failed, device %s: %s.\n",
-		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
-		return rc;
-	}
-
-	if (cmd.rcvd_size < SCSI_SENSE_DATA_MIN_SIZE) {
-		/* The missing bytes should be considered to be zeroes. */
-		memset((uint8_t *)buf + cmd.rcvd_size, 0,
-		    SCSI_SENSE_DATA_MIN_SIZE - cmd.rcvd_size);
-	}
-
-	return EOK;
-}
-
-/** Perform SCSI Read Capacity command on USB mass storage device.
- *
- * @param mfun		Mass storage function
- * @param nblocks	Output, number of blocks
- * @param block_size	Output, block size in bytes
- *
- * @return		Error code.
- */
-int usbmast_read_capacity(usbmast_fun_t *mfun, uint32_t *nblocks,
-    uint32_t *block_size)
-{
-	scsi_cmd_t cmd;
-	scsi_cdb_read_capacity_10_t cdb;
-	scsi_read_capacity_10_data_t data;
-	int rc;
-
-	memset(&cdb, 0, sizeof(cdb));
-	cdb.op_code = SCSI_CMD_READ_CAPACITY_10;
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.cdb = &cdb;
-	cmd.cdb_size = sizeof(cdb);
-	cmd.data_in = &data;
-	cmd.data_in_size = sizeof(data);
-
-	rc = usbmast_run_cmd(mfun, &cmd);
-
-        if (rc != EOK) {
-		usb_log_error("Read Capacity (10) transport failed, device %s: %s.\n",
-		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
-		return rc;
-	}
-
-	if (cmd.status != CMDS_GOOD) {
-		usb_log_error("Read Capacity (10) command failed, device %s.\n",
-		   usb_device_get_name(mfun->mdev->usb_dev));
-		return EIO;
-	}
-
-	if (cmd.rcvd_size < sizeof(data)) {
-		usb_log_error("SCSI Read Capacity response too short (%zu).\n",
-		    cmd.rcvd_size);
-		return EIO;
-	}
-
-	*nblocks = uint32_t_be2host(data.last_lba) + 1;
-	*block_size = uint32_t_be2host(data.block_size);
-
-	return EOK;
-}
-
-/** Perform SCSI Read command on USB mass storage device.
- *
- * @param mfun		Mass storage function
- * @param ba		Address of first block
- * @param nblocks	Number of blocks to read
- *
- * @return		Error code
- */
-int usbmast_read(usbmast_fun_t *mfun, uint64_t ba, size_t nblocks, void *buf)
-{
-	scsi_cmd_t cmd;
-	scsi_cdb_read_10_t cdb;
-	int rc;
-
-	if (ba > UINT32_MAX)
-		return ELIMIT;
-
-	if (nblocks > UINT16_MAX)
-		return ELIMIT;
-
-	memset(&cdb, 0, sizeof(cdb));
-	cdb.op_code = SCSI_CMD_READ_10;
-	cdb.lba = host2uint32_t_be(ba);
-	cdb.xfer_len = host2uint16_t_be(nblocks);
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.cdb = &cdb;
-	cmd.cdb_size = sizeof(cdb);
-	cmd.data_in = buf;
-	cmd.data_in_size = nblocks * mfun->block_size;
-
-	rc = usbmast_run_cmd(mfun, &cmd);
-
-        if (rc != EOK) {
-		usb_log_error("Read (10) transport failed, device %s: %s.\n",
-		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
-		return rc;
-	}
-
-	if (cmd.status != CMDS_GOOD) {
-		usb_log_error("Read (10) command failed, device %s.\n",
-		   usb_device_get_name(mfun->mdev->usb_dev));
-		return EIO;
-	}
-
-	if (cmd.rcvd_size < nblocks * mfun->block_size) {
-		usb_log_error("SCSI Read response too short (%zu).\n",
-		    cmd.rcvd_size);
-		return EIO;
-	}
-
-	return EOK;
-}
-
-/** Perform SCSI Write command on USB mass storage device.
- *
- * @param mfun		Mass storage function
- * @param ba		Address of first block
- * @param nblocks	Number of blocks to read
- * @param data		Data to write
- *
- * @return		Error code
- */
-int usbmast_write(usbmast_fun_t *mfun, uint64_t ba, size_t nblocks,
-    const void *data)
-{
-	scsi_cmd_t cmd;
-	scsi_cdb_write_10_t cdb;
-	int rc;
-
-	if (ba > UINT32_MAX)
-		return ELIMIT;
-
-	if (nblocks > UINT16_MAX)
-		return ELIMIT;
-
-	memset(&cdb, 0, sizeof(cdb));
-	cdb.op_code = SCSI_CMD_WRITE_10;
-	cdb.lba = host2uint32_t_be(ba);
-	cdb.xfer_len = host2uint16_t_be(nblocks);
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.cdb = &cdb;
-	cmd.cdb_size = sizeof(cdb);
-	cmd.data_out = data;
-	cmd.data_out_size = nblocks * mfun->block_size;
-
-	rc = usbmast_run_cmd(mfun, &cmd);
-
-        if (rc != EOK) {
-		usb_log_error("Write (10) transport failed, device %s: %s.\n",
-		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
-		return rc;
-	}
-
-	if (cmd.status != CMDS_GOOD) {
-		usb_log_error("Write (10) command failed, device %s.\n",
-		   usb_device_get_name(mfun->mdev->usb_dev));
-		return EIO;
-	}
-
-	return EOK;
-}
-
-/** Perform SCSI Synchronize Cache command on USB mass storage device.
- *
- * @param mfun		Mass storage function
- * @param ba		Address of first block
- * @param nblocks	Number of blocks to read
- * @param data		Data to write
- *
- * @return		Error code
- */
-int usbmast_sync_cache(usbmast_fun_t *mfun, uint64_t ba, size_t nblocks)
-{
-	if (ba > UINT32_MAX)
-		return ELIMIT;
-
-	if (nblocks > UINT16_MAX)
-		return ELIMIT;
-
-	const scsi_cdb_sync_cache_10_t cdb = {
-		.op_code = SCSI_CMD_SYNC_CACHE_10,
-		.lba = host2uint32_t_be(ba),
-		.numlb = host2uint16_t_be(nblocks),
-	};
-
-	scsi_cmd_t cmd = {
-		.cdb = &cdb,
-		.cdb_size = sizeof(cdb),
-	};
-
-	const int rc = usbmast_run_cmd(mfun, &cmd);
-
-        if (rc != EOK) {
-		usb_log_error("Synchronize Cache (10) transport failed, device %s: %s.\n",
-		   usb_device_get_name(mfun->mdev->usb_dev), str_error(rc));
-		return rc;
-	}
-
-	if (cmd.status != CMDS_GOOD) {
-		usb_log_error("Synchronize Cache (10) command failed, device %s.\n",
-		   usb_device_get_name(mfun->mdev->usb_dev));
-		return EIO;
-	}
-
-	return EOK;
-}
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbmast/scsi_ms.h
===================================================================
--- uspace/drv/bus/usb/usbmast/scsi_ms.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,74 +1,0 @@
-/*
- * 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 drvusbmast
- * @{
- */
-/** @file
- * SCSI functions for USB mass storage.
- */
-
-#ifndef USB_USBMAST_SCSI_MS_H_
-#define USB_USBMAST_SCSI_MS_H_
-
-#include <scsi/spc.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <usb/usb.h>
-#include <usb/dev/driver.h>
-
-/** Result of SCSI Inquiry command.
- * This is already parsed structure, not the original buffer returned by
- * the device.
- */
-typedef struct {
-	/** SCSI peripheral device type */
-	unsigned device_type;
-	/** Whether the device is removable */
-	bool removable;
-	/** Vendor ID string */
-	char vendor[SCSI_INQ_VENDOR_STR_BUFSIZE];
-	/** Product ID string */
-	char product[SCSI_INQ_PRODUCT_STR_BUFSIZE];
-	/** Revision string */
-	char revision[SCSI_INQ_REVISION_STR_BUFSIZE];
-} usbmast_inquiry_data_t;
-
-extern int usbmast_inquiry(usbmast_fun_t *, usbmast_inquiry_data_t *);
-extern int usbmast_request_sense(usbmast_fun_t *, void *, size_t);
-extern int usbmast_read_capacity(usbmast_fun_t *, uint32_t *, uint32_t *);
-extern int usbmast_read(usbmast_fun_t *, uint64_t, size_t, void *);
-extern int usbmast_write(usbmast_fun_t *, uint64_t, size_t, const void *);
-extern int usbmast_sync_cache(usbmast_fun_t *, uint64_t, size_t);
-extern const char *usbmast_scsi_dev_type_str(unsigned);
-
-#endif
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbmast/usbmast.h
===================================================================
--- uspace/drv/bus/usb/usbmast/usbmast.h	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,82 +1,0 @@
-/*
- * 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.
- */
-
-/** @addtogroup drvusbmast
- * @{
- */
-/** @file
- * USB mass storage commands.
- */
-
-#ifndef USBMAST_H_
-#define USBMAST_H_
-
-#include <bd_srv.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <usb/usb.h>
-
-/** Mass storage device. */
-typedef struct usbmast_dev {
-	/** USB device */
-	usb_device_t *usb_dev;
-	/** Number of LUNs */
-	unsigned lun_count;
-	/** LUN functions */
-	ddf_fun_t **luns;
-	/** Data read pipe */
-	usb_pipe_t *bulk_in_pipe;
-	/** Data write pipe */
-	usb_pipe_t *bulk_out_pipe;
-} usbmast_dev_t;
-
-
-/** Mass storage function.
- *
- * Serves as soft state for function/LUN.
- */
-typedef struct {
-	/** Mass storage device the function belongs to */
-	usbmast_dev_t *mdev;
-	/** DDF function */
-	ddf_fun_t *ddf_fun;
-	/** LUN */
-	unsigned lun;
-	/** Total number of blocks */
-	uint64_t nblocks;
-	/** Block size in bytes */
-	size_t block_size;
-	/** Block device service structure */
-	bd_srvs_t bds;
-} usbmast_fun_t;
-
-#endif
-
-/**
- * @}
- */
Index: pace/drv/bus/usb/usbmast/usbmast.ma
===================================================================
--- uspace/drv/bus/usb/usbmast/usbmast.ma	(revision 6da15db79d9aaf490ef2139ceb05b2fe75ceb1e7)
+++ 	(revision )
@@ -1,1 +1,0 @@
-50 usb&interface&class=mass-storage&subclass=0x06&protocol=0x50
Index: uspace/drv/hid/usbhid/Makefile
===================================================================
--- uspace/drv/hid/usbhid/Makefile	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/Makefile	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2010-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 = usbhid usbdev usb drv
+
+EXTRA_CFLAGS += -I.
+
+BINARY = usbhid
+
+SUBDRIVER_SOURCES = \
+	kbd/conv.c \
+	kbd/kbddev.c \
+	kbd/kbdrepeat.c \
+	mouse/mousedev.c \
+	multimedia/multimedia.c \
+	multimedia/keymap.c \
+	blink1/blink1.c
+
+SOURCES = \
+	main.c \
+	usbhid.c \
+	subdrivers.c \
+	generic/hiddev.c \
+	$(SUBDRIVER_SOURCES)
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/hid/usbhid/blink1/blink1.c
===================================================================
--- uspace/drv/hid/usbhid/blink1/blink1.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/blink1/blink1.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2014 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB blink(1) subdriver.
+ */
+
+#include <errno.h>
+#include <str_error.h>
+#include <usb/debug.h>
+#include <ops/led_dev.h>
+#include <usb/hid/request.h>
+#include "blink1.h"
+
+const char *HID_BLINK1_FUN_NAME = "blink1";
+const char *HID_BLINK1_CATEGORY = "led";
+
+#define BLINK1_REPORT_ID  0x0001
+
+#define BLINK1_COMMAND_SET  0x006e
+
+typedef struct {
+	uint8_t id;
+	uint8_t command;
+	uint8_t arg0;
+	uint8_t arg1;
+	uint8_t arg2;
+	uint8_t arg3;
+	uint8_t arg4;
+	uint8_t arg5;
+} blink1_report_t;
+
+static int usb_blink1_color_set(ddf_fun_t *fun, pixel_t pixel)
+{
+	usb_blink1_t *blink1_dev = (usb_blink1_t *) ddf_fun_data_get(fun);
+	if (blink1_dev == NULL) {
+		usb_log_debug("Missing parameters.\n");
+		return EINVAL;
+	}
+	
+	blink1_report_t report;
+	
+	report.id = BLINK1_REPORT_ID;
+	report.command = BLINK1_COMMAND_SET;
+	report.arg0 = RED(pixel);
+	report.arg1 = GREEN(pixel);
+	report.arg2 = BLUE(pixel);
+	report.arg3 = 0;
+	report.arg4 = 0;
+	report.arg5 = 0;
+	
+	return usbhid_req_set_report(
+	    usb_device_get_default_pipe(blink1_dev->hid_dev->usb_dev),
+	    usb_device_get_iface_number(blink1_dev->hid_dev->usb_dev),
+	    USB_HID_REPORT_TYPE_FEATURE, (uint8_t *) &report, sizeof(report));
+}
+
+static led_dev_ops_t usb_blink1_iface = {
+	.color_set = usb_blink1_color_set
+};
+
+static ddf_dev_ops_t blink1_ops = {
+	.interfaces[LED_DEV_IFACE] = &usb_blink1_iface
+};
+
+int usb_blink1_init(usb_hid_dev_t *hid_dev, void **data)
+{
+	if (hid_dev == NULL) {
+		usb_log_error("Failed to init blink(1) structure: no structure "
+		    "given.\n");
+		return EINVAL;
+	}
+	
+	/* Create the exposed function. */
+	ddf_fun_t *fun = usb_device_ddf_fun_create(hid_dev->usb_dev,
+	    fun_exposed, HID_BLINK1_FUN_NAME);
+	if (fun == NULL) {
+		usb_log_error("Could not create DDF function node `%s'.\n",
+		    HID_BLINK1_FUN_NAME);
+		return ENOMEM;
+	}
+	
+	usb_blink1_t *blink1_dev = (usb_blink1_t *)
+	    ddf_fun_data_alloc(fun, sizeof(usb_blink1_t));
+	if (blink1_dev == NULL) {
+		usb_log_error("Error while creating USB/HID blink(1) device "
+		    "structure.\n");
+		ddf_fun_destroy(fun);
+		return ENOMEM;
+	}
+	
+	ddf_fun_set_ops(fun, &blink1_ops);
+	
+	int rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function `%s': %s.\n",
+		    ddf_fun_get_name(fun), str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	rc = ddf_fun_add_to_category(fun, HID_BLINK1_CATEGORY);
+	if (rc != EOK) {
+		usb_log_error("Could not add DDF function to category %s: %s.\n",
+		    HID_BLINK1_CATEGORY, str_error(rc));
+		
+		rc = ddf_fun_unbind(fun);
+		if (rc != EOK) {
+			usb_log_error("Could not unbind function `%s', it "
+			    "will not be destroyed.\n", ddf_fun_get_name(fun));
+			return rc;
+		}
+		
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+	
+	blink1_dev->fun = fun;
+	blink1_dev->hid_dev = hid_dev;
+	*data = blink1_dev;
+	
+	return EOK;
+}
+
+void usb_blink1_deinit(usb_hid_dev_t *hid_dev, void *data)
+{
+	if (data == NULL)
+		return;
+	
+	usb_blink1_t *blink1_dev = (usb_blink1_t *) data;
+	
+	int rc = ddf_fun_unbind(blink1_dev->fun);
+	if (rc != EOK) {
+		usb_log_error("Could not unbind function `%s', it "
+		    "will not be destroyed.\n", ddf_fun_get_name(blink1_dev->fun));
+		return;
+	}
+	
+	ddf_fun_destroy(blink1_dev->fun);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/blink1/blink1.h
===================================================================
--- uspace/drv/hid/usbhid/blink1/blink1.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/blink1/blink1.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup drvusbhid
+ * @{
+ */
+/** @file
+ * USB blink(1) subdriver.
+ */
+
+#ifndef USB_HID_BLINK1_H_
+#define USB_HID_BLINK1_H_
+
+#include <usb/dev/driver.h>
+#include "../usbhid.h"
+
+/** Container for USB blink(1) device. */
+typedef struct {
+	/** DDF blink(1) function */
+	ddf_fun_t *fun;
+	
+	/** USB HID device */
+	usb_hid_dev_t *hid_dev;
+} usb_blink1_t;
+
+extern const char *HID_BLINK1_FUN_NAME;
+extern const char *HID_BLINK1_CATEGORY;
+
+extern int usb_blink1_init(usb_hid_dev_t *, void **);
+extern void usb_blink1_deinit(usb_hid_dev_t *, void *);
+
+#endif // USB_HID_BLINK1_H_
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/generic/hiddev.c
===================================================================
--- uspace/drv/hid/usbhid/generic/hiddev.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/generic/hiddev.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID driver API.
+ */
+
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <errno.h>
+#include <str_error.h>
+#include <stdbool.h>
+
+#include <usbhid_iface.h>
+
+#include "hiddev.h"
+#include "usbhid.h"
+
+const usb_endpoint_description_t usb_hid_generic_poll_endpoint_description = {
+	.transfer_type = USB_TRANSFER_INTERRUPT,
+	.direction = USB_DIRECTION_IN,
+	.interface_class = USB_CLASS_HID,
+	.interface_subclass = -1,
+	.interface_protocol = -1,
+	.flags = 0
+};
+
+const char *HID_GENERIC_FUN_NAME = "hid";
+const char *HID_GENERIC_CATEGORY = "hid";
+
+
+static size_t usb_generic_hid_get_event_length(ddf_fun_t *fun);
+static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer,
+    size_t size, size_t *act_size, int *event_nr, unsigned int flags);
+static int usb_generic_hid_client_connected(ddf_fun_t *fun);
+static size_t usb_generic_get_report_descriptor_length(ddf_fun_t *fun);
+static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc,
+    size_t size, size_t *actual_size);
+
+static usbhid_iface_t usb_generic_iface = {
+	.get_event = usb_generic_hid_get_event,
+	.get_event_length = usb_generic_hid_get_event_length,
+	.get_report_descriptor_length = usb_generic_get_report_descriptor_length,
+	.get_report_descriptor = usb_generic_get_report_descriptor
+};
+
+static ddf_dev_ops_t usb_generic_hid_ops = {
+	.interfaces[USBHID_DEV_IFACE] = &usb_generic_iface,
+	.open = usb_generic_hid_client_connected
+};
+
+/** Return hid_dev_t * for generic HID function node.
+ *
+ * For the generic HID subdriver the 'hid' function has usb_hid_gen_fun_t
+ * as soft state. Through that we can get to the usb_hid_dev_t.
+ */
+static usb_hid_dev_t *fun_hid_dev(ddf_fun_t *fun)
+{
+	return ((usb_hid_gen_fun_t *)ddf_fun_data_get(fun))->hid_dev;
+}
+
+static size_t usb_generic_hid_get_event_length(ddf_fun_t *fun)
+{
+	usb_log_debug2("Generic HID: Get event length (fun: %p, "
+	    "fun->driver_data: %p.\n", fun, ddf_fun_data_get(fun));
+
+	const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
+
+	usb_log_debug2("hid_dev: %p, Max input report size (%zu).\n",
+	    hid_dev, hid_dev->max_input_report_size);
+
+	return hid_dev->max_input_report_size;
+}
+
+static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer,
+    size_t size, size_t *act_size, int *event_nr, unsigned int flags)
+{
+	usb_log_debug2("Generic HID: Get event.\n");
+
+	if (buffer == NULL || act_size == NULL || event_nr == NULL) {
+		usb_log_debug("No function");
+		return EINVAL;
+	}
+
+	const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
+
+	if (hid_dev->input_report_size > size) {
+		usb_log_debug("input_report_size > size (%zu, %zu)\n",
+		    hid_dev->input_report_size, size);
+		return EINVAL;	// TODO: other error code
+	}
+
+	/*! @todo This should probably be somehow atomic. */
+	memcpy(buffer, hid_dev->input_report,
+	    hid_dev->input_report_size);
+	*act_size = hid_dev->input_report_size;
+	*event_nr = usb_hid_report_number(hid_dev);
+
+	usb_log_debug2("OK\n");
+
+	return EOK;
+}
+
+static size_t usb_generic_get_report_descriptor_length(ddf_fun_t *fun)
+{
+	usb_log_debug("Generic HID: Get report descriptor length.\n");
+
+	const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
+
+	usb_log_debug2("hid_dev->report_desc_size = %zu\n",
+	    hid_dev->report_desc_size);
+
+	return hid_dev->report_desc_size;
+}
+
+static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc,
+    size_t size, size_t *actual_size)
+{
+	usb_log_debug2("Generic HID: Get report descriptor.\n");
+
+	const usb_hid_dev_t *hid_dev = fun_hid_dev(fun);
+
+	if (hid_dev->report_desc_size > size) {
+		return EINVAL;
+	}
+
+	memcpy(desc, hid_dev->report_desc, hid_dev->report_desc_size);
+	*actual_size = hid_dev->report_desc_size;
+
+	return EOK;
+}
+
+static int usb_generic_hid_client_connected(ddf_fun_t *fun)
+{
+	usb_log_debug("Generic HID: Client connected.\n");
+	return EOK;
+}
+
+void usb_generic_hid_deinit(usb_hid_dev_t *hid_dev, void *data)
+{
+	ddf_fun_t *fun = data;
+	if (fun == NULL)
+		return;
+
+	if (ddf_fun_unbind(fun) != EOK) {
+		usb_log_error("Failed to unbind generic hid fun.\n");
+		return;
+	}
+	usb_log_debug2("%s unbound.\n", ddf_fun_get_name(fun));
+	ddf_fun_destroy(fun);
+}
+
+int usb_generic_hid_init(usb_hid_dev_t *hid_dev, void **data)
+{
+	usb_hid_gen_fun_t *hid_fun;
+
+	if (hid_dev == NULL) {
+		return EINVAL;
+	}
+
+	/* Create the exposed function. */
+	usb_log_debug("Creating DDF function %s...\n", HID_GENERIC_FUN_NAME);
+	ddf_fun_t *fun = usb_device_ddf_fun_create(hid_dev->usb_dev,
+	    fun_exposed, HID_GENERIC_FUN_NAME);
+	if (fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+
+	/* Create softstate */
+	hid_fun = ddf_fun_data_alloc(fun, sizeof(usb_hid_gen_fun_t));
+	hid_fun->hid_dev = hid_dev;
+	ddf_fun_set_ops(fun, &usb_generic_hid_ops);
+
+	int rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	usb_log_debug("HID function created. Handle: %" PRIun "\n",
+	    ddf_fun_get_handle(fun));
+	*data = fun;
+
+	return EOK;
+}
+
+bool usb_generic_hid_polling_callback(usb_hid_dev_t *hid_dev, void *data)
+{
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/generic/hiddev.h
===================================================================
--- uspace/drv/hid/usbhid/generic/hiddev.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/generic/hiddev.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID driver API.
+ */
+
+#ifndef USB_HID_HIDDDEV_H_
+#define USB_HID_HIDDDEV_H_
+
+#include <usb/dev/driver.h>
+#include "../usbhid.h"
+
+extern const usb_endpoint_description_t
+    usb_hid_generic_poll_endpoint_description;
+
+extern const char *HID_GENERIC_FUN_NAME;
+extern const char *HID_GENERIC_CATEGORY;
+
+/** The USB HID generic 'hid' function softstate */
+typedef struct {
+	usb_hid_dev_t *hid_dev;
+} usb_hid_gen_fun_t;
+
+extern int usb_generic_hid_init(usb_hid_dev_t *, void **);
+extern void usb_generic_hid_deinit(usb_hid_dev_t *, void *);
+extern bool usb_generic_hid_polling_callback(usb_hid_dev_t *, void *);
+
+#endif // USB_HID_HIDDDEV_H_
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/kbd/conv.c
===================================================================
--- uspace/drv/hid/usbhid/kbd/conv.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/kbd/conv.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB scancode parser.
+ */
+
+#include <io/keycode.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <usb/debug.h>
+#include "conv.h"
+
+/**
+ * Mapping between USB HID key codes (from HID Usage Tables) and corresponding
+ * HelenOS key codes.
+ */
+static int scanmap_simple[255] = {
+	[0x04] = KC_A,
+	[0x05] = KC_B,
+	[0x06] = KC_C,
+	[0x07] = KC_D,
+	[0x08] = KC_E,
+	[0x09] = KC_F,
+	[0x0a] = KC_G,
+	[0x0b] = KC_H,
+	[0x0c] = KC_I,
+	[0x0d] = KC_J,
+	[0x0e] = KC_K,
+	[0x0f] = KC_L,
+	[0x10] = KC_M,
+	[0x11] = KC_N,
+	[0x12] = KC_O,
+	[0x13] = KC_P,
+	[0x14] = KC_Q,
+	[0x15] = KC_R,
+	[0x16] = KC_S,
+	[0x17] = KC_T,
+	[0x18] = KC_U,
+	[0x19] = KC_V,
+	[0x1a] = KC_W,
+	[0x1b] = KC_X,
+	[0x1c] = KC_Y,
+	[0x1d] = KC_Z,
+
+	[0x1e] = KC_1,
+	[0x1f] = KC_2,
+	[0x20] = KC_3,
+	[0x21] = KC_4,
+	[0x22] = KC_5,
+	[0x23] = KC_6,
+	[0x24] = KC_7,
+	[0x25] = KC_8,
+	[0x26] = KC_9,
+	[0x27] = KC_0,
+
+	[0x28] = KC_ENTER,
+	[0x29] = KC_ESCAPE,
+	[0x2a] = KC_BACKSPACE,
+	[0x2b] = KC_TAB,
+	[0x2c] = KC_SPACE,
+
+	[0x2d] = KC_MINUS,
+	[0x2e] = KC_EQUALS,
+	[0x2f] = KC_LBRACKET,
+	[0x30] = KC_RBRACKET,
+	[0x31] = KC_BACKSLASH,
+	[0x32] = KC_HASH,
+	[0x33] = KC_SEMICOLON,
+	[0x34] = KC_QUOTE,
+	[0x35] = KC_BACKTICK,
+	[0x36] = KC_COMMA,
+	[0x37] = KC_PERIOD,
+	[0x38] = KC_SLASH,
+
+	[0x39] = KC_CAPS_LOCK,
+
+	[0x3a] = KC_F1,
+	[0x3b] = KC_F2,
+	[0x3c] = KC_F3,
+	[0x3d] = KC_F4,
+	[0x3e] = KC_F5,
+	[0x3f] = KC_F6,
+	[0x40] = KC_F7,
+	[0x41] = KC_F8,
+	[0x42] = KC_F9,
+	[0x43] = KC_F10,
+	[0x44] = KC_F11,
+	[0x45] = KC_F12,
+
+	[0x46] = KC_PRTSCR,
+	[0x47] = KC_SCROLL_LOCK,
+	[0x48] = KC_PAUSE,
+	[0x49] = KC_INSERT,
+	[0x4a] = KC_HOME,
+	[0x4b] = KC_PAGE_UP,
+	[0x4c] = KC_DELETE,
+	[0x4d] = KC_END,
+	[0x4e] = KC_PAGE_DOWN,
+	[0x4f] = KC_RIGHT,
+	[0x50] = KC_LEFT,
+	[0x51] = KC_DOWN,
+	[0x52] = KC_UP,
+
+	[0x53] = KC_NUM_LOCK,
+	[0x54] = KC_NSLASH,
+	[0x55] = KC_NTIMES,
+	[0x56] = KC_NMINUS,
+	[0x57] = KC_NPLUS,
+	[0x58] = KC_NENTER,
+	[0x59] = KC_N1,
+	[0x5a] = KC_N2,
+	[0x5b] = KC_N3,
+	[0x5c] = KC_N4,
+	[0x5d] = KC_N5,
+	[0x5e] = KC_N6,
+	[0x5f] = KC_N7,
+	[0x60] = KC_N8,
+	[0x61] = KC_N9,
+	[0x62] = KC_N0,
+	[0x63] = KC_NPERIOD,
+
+	[0x64] = KC_BACKSLASH,
+
+	[0x9a] = KC_SYSREQ,
+
+	[0xe0] = KC_LCTRL,
+	[0xe1] = KC_LSHIFT,
+	[0xe2] = KC_LALT,
+	[0xe4] = KC_RCTRL,
+	[0xe5] = KC_RSHIFT,
+	[0xe6] = KC_RALT,
+};
+
+/**
+ * Translate USB HID key codes (from HID Usage Tables) to generic key codes
+ * recognized by HelenOS.
+ *
+ * @param scancode USB HID key code (from HID Usage Tables).
+ *
+ * @retval HelenOS key code corresponding to the given USB HID key code.
+ */
+unsigned int usbhid_parse_scancode(int scancode)
+{
+	unsigned int key;
+	int *map = scanmap_simple;
+	size_t map_length = sizeof(scanmap_simple) / sizeof(int);
+
+	if ((scancode < 0) || ((size_t) scancode >= map_length))
+		return -1;
+
+	key = map[scancode];
+
+	return key;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/kbd/conv.h
===================================================================
--- uspace/drv/hid/usbhid/kbd/conv.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/kbd/conv.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB scancode parser.
+ */
+
+#ifndef USB_HID_CONV_H_
+#define USB_HID_CONV_H_
+
+unsigned int usbhid_parse_scancode(int scancode);
+
+#endif /* USB_HID_CONV_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/kbd/kbddev.c
===================================================================
--- uspace/drv/hid/usbhid/kbd/kbddev.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/kbd/kbddev.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,805 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID keyboard device structure and API.
+ */
+
+#include <errno.h>
+#include <str_error.h>
+#include <stdio.h>
+
+#include <io/keycode.h>
+#include <io/console.h>
+#include <abi/ipc/methods.h>
+#include <ipc/kbdev.h>
+#include <async.h>
+#include <fibril.h>
+#include <fibril_synch.h>
+
+#include <ddf/log.h>
+
+#include <usb/usb.h>
+#include <usb/dev/dp.h>
+#include <usb/dev/request.h>
+#include <usb/hid/hid.h>
+#include <usb/dev/pipes.h>
+#include <usb/debug.h>
+#include <usb/hid/hidparser.h>
+#include <usb/classes/classes.h>
+#include <usb/hid/usages/core.h>
+#include <usb/hid/request.h>
+#include <usb/hid/hidreport.h>
+#include <usb/hid/usages/led.h>
+
+#include <usb/dev/driver.h>
+
+#include "kbddev.h"
+
+#include "conv.h"
+#include "kbdrepeat.h"
+
+#include "../usbhid.h"
+
+static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+static ddf_dev_ops_t kbdops = { .default_handler = default_connection_handler };
+
+
+static const unsigned DEFAULT_ACTIVE_MODS = KM_NUM_LOCK;
+
+static const uint8_t ERROR_ROLLOVER = 1;
+
+/** Default idle rate for keyboards. */
+static const uint8_t IDLE_RATE = 0;
+
+/** Delay before a pressed key starts auto-repeating. */
+static const unsigned int DEFAULT_DELAY_BEFORE_FIRST_REPEAT = 500 * 1000;
+
+/** Delay between two repeats of a pressed key when auto-repeating. */
+static const unsigned int DEFAULT_REPEAT_DELAY = 50 * 1000;
+
+
+/** Keyboard polling endpoint description for boot protocol class. */
+const usb_endpoint_description_t usb_hid_kbd_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_KEYBOARD,
+	.flags = 0
+};
+
+const char *HID_KBD_FUN_NAME = "keyboard";
+const char *HID_KBD_CATEGORY_NAME = "keyboard";
+
+static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev);
+
+static const uint8_t USB_KBD_BOOT_REPORT_DESCRIPTOR[] = {
+	0x05, 0x01,  /* Usage Page (Generic Desktop), */
+	0x09, 0x06,  /* Usage (Keyboard), */
+	0xA1, 0x01,  /* Collection (Application), */
+	0x75, 0x01,  /*   Report Size (1), */
+	0x95, 0x08,  /*   Report Count (8), */
+	0x05, 0x07,  /*   Usage Page (Key Codes); */
+	0x19, 0xE0,  /*   Usage Minimum (224), */
+	0x29, 0xE7,  /*   Usage Maximum (231), */
+	0x15, 0x00,  /*   Logical Minimum (0), */
+	0x25, 0x01,  /*   Logical Maximum (1), */
+	0x81, 0x02,  /*   Input (Data, Variable, Absolute),  ; Modifier byte */
+	0x95, 0x01,  /*   Report Count (1), */
+	0x75, 0x08,  /*   Report Size (8), */
+	0x81, 0x01,  /*   Input (Constant),                  ; Reserved byte */
+	0x95, 0x05,  /*   Report Count (5), */
+	0x75, 0x01,  /*   Report Size (1), */
+	0x05, 0x08,  /*   Usage Page (Page# for LEDs), */
+	0x19, 0x01,  /*   Usage Minimum (1), */
+	0x29, 0x05,  /*   Usage Maxmimum (5), */
+	0x91, 0x02,  /*   Output (Data, Variable, Absolute),  ; LED report */
+	0x95, 0x01,  /*   Report Count (1), */
+	0x75, 0x03,  /*   Report Size (3), */
+	0x91, 0x01,  /*   Output (Constant),            ; LED report padding */
+	0x95, 0x06,  /*   Report Count (6), */
+	0x75, 0x08,  /*   Report Size (8), */
+	0x15, 0x00,  /*   Logical Minimum (0), */
+	0x25, 0xff,  /*   Logical Maximum (255), */
+	0x05, 0x07,  /*   Usage Page (Key Codes), */
+	0x19, 0x00,  /*   Usage Minimum (0), */
+	0x29, 0xff,  /*   Usage Maximum (255), */
+	0x81, 0x00,  /*   Input (Data, Array),   ; Key arrays (6 bytes) */
+	0xC0         /* End Collection */
+};
+
+typedef enum usb_kbd_flags {
+	USB_KBD_STATUS_UNINITIALIZED = 0,
+	USB_KBD_STATUS_INITIALIZED = 1,
+	USB_KBD_STATUS_TO_DESTROY = -1
+} usb_kbd_flags;
+
+/* IPC method handler                                                         */
+
+/**
+ * Default handler for IPC methods not handled by DDF.
+ *
+ * Currently recognizes only two methods (IPC_M_CONNECT_TO_ME and KBDEV_SET_IND)
+ * IPC_M_CONNECT_TO_ME assumes the caller is the console and  stores IPC
+ * session to it for later use by the driver to notify about key events.
+ * KBDEV_SET_IND sets LED keyboard indicators.
+ *
+ * @param fun Device function handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+static void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	const sysarg_t method = IPC_GET_IMETHOD(*icall);
+	usb_kbd_t *kbd_dev = ddf_fun_data_get(fun);
+
+	switch (method) {
+	case KBDEV_SET_IND:
+		kbd_dev->mods = IPC_GET_ARG1(*icall);
+		usb_kbd_set_led(kbd_dev->hid_dev, kbd_dev);
+		async_answer_0(icallid, EOK);
+		break;
+	/* This might be ugly but async_callback_receive_start makes no
+	 * difference for incorrect call and malloc failure. */
+	case IPC_M_CONNECT_TO_ME: {
+		async_sess_t *sess =
+		    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
+		/* Probably ENOMEM error, try again. */
+		if (sess == NULL) {
+			usb_log_warning(
+			    "Failed to create start console session.\n");
+			async_answer_0(icallid, EAGAIN);
+			break;
+		}
+		if (kbd_dev->client_sess == NULL) {
+			kbd_dev->client_sess = sess;
+			usb_log_debug("%s: OK\n", __FUNCTION__);
+			async_answer_0(icallid, EOK);
+		} else {
+			usb_log_error("%s: console session already set\n",
+			   __FUNCTION__);
+			async_answer_0(icallid, ELIMIT);
+		}
+		break;
+	}
+	default:
+			usb_log_error("%s: Unknown method: %d.\n",
+			    __FUNCTION__, (int) method);
+			async_answer_0(icallid, EINVAL);
+			break;
+	}
+
+}
+
+/* Key processing functions                                                   */
+
+/**
+ * Handles turning of LED lights on and off.
+ *
+ * As with most other keyboards, the LED indicators in USB keyboards are
+ * driven by software. When state of some modifier changes, the input server
+ * will call us and tell us to update the LED state and what the new state
+ * should be.
+ *
+ * This functions sets the LED lights according to current settings of modifiers
+ * kept in the keyboard device structure.
+ *
+ * @param kbd_dev Keyboard device structure.
+ */
+static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev)
+{
+	if (kbd_dev->output_size == 0) {
+		return;
+	}
+
+	/* Reset the LED data. */
+	memset(kbd_dev->led_data, 0, kbd_dev->led_output_size * sizeof(int32_t));
+	usb_log_debug("Creating output report:\n");
+
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+	    &hid_dev->report, NULL, kbd_dev->led_path,
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+	    USB_HID_REPORT_TYPE_OUTPUT);
+
+	while (field != NULL) {
+
+		if ((field->usage == USB_HID_LED_NUM_LOCK)
+		    && (kbd_dev->mods & KM_NUM_LOCK)){
+			field->value = 1;
+		}
+
+		if ((field->usage == USB_HID_LED_CAPS_LOCK)
+		    && (kbd_dev->mods & KM_CAPS_LOCK)){
+			field->value = 1;
+		}
+
+		if ((field->usage == USB_HID_LED_SCROLL_LOCK)
+		    && (kbd_dev->mods & KM_SCROLL_LOCK)){
+			field->value = 1;
+		}
+
+		field = usb_hid_report_get_sibling(
+		    &hid_dev->report, field, kbd_dev->led_path,
+		USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+		    USB_HID_REPORT_TYPE_OUTPUT);
+	}
+
+	// TODO: what about the Report ID?
+	int rc = usb_hid_report_output_translate(&hid_dev->report, 0,
+	    kbd_dev->output_buffer, kbd_dev->output_size);
+
+	if (rc != EOK) {
+		usb_log_warning("Could not translate LED output to output"
+		    "report.\n");
+		return;
+	}
+
+	usb_log_debug("Output report buffer: %s\n",
+	    usb_debug_str_buffer(kbd_dev->output_buffer, kbd_dev->output_size,
+	        0));
+
+	rc = usbhid_req_set_report(
+	    usb_device_get_default_pipe(hid_dev->usb_dev),
+	    usb_device_get_iface_number(hid_dev->usb_dev),
+	    USB_HID_REPORT_TYPE_OUTPUT,
+	    kbd_dev->output_buffer, kbd_dev->output_size);
+	if (rc != EOK) {
+		usb_log_warning("Failed to set kbd indicators.\n");
+	}
+}
+
+/** Send key event.
+ *
+ * @param kbd_dev Keyboard device structure.
+ * @param type Type of the event (press / release). Recognized values:
+ *             KEY_PRESS, KEY_RELEASE
+ * @param key Key code
+ */
+void usb_kbd_push_ev(usb_kbd_t *kbd_dev, int type, unsigned key)
+{
+	usb_log_debug2("Sending kbdev event %d/%d to the console\n", type, key);
+	if (kbd_dev->client_sess == NULL) {
+		usb_log_warning(
+		    "Connection to console not ready, key discarded.\n");
+		return;
+	}
+
+	async_exch_t *exch = async_exchange_begin(kbd_dev->client_sess);
+	if (exch != NULL) {
+		async_msg_2(exch, KBDEV_EVENT, type, key);
+		async_exchange_end(exch);
+	} else {
+		usb_log_warning("Failed to send key to console.\n");
+	}
+}
+
+static inline int usb_kbd_is_lock(unsigned int key_code)
+{
+	return (key_code == KC_NUM_LOCK
+	    || key_code == KC_SCROLL_LOCK
+	    || key_code == KC_CAPS_LOCK);
+}
+
+static size_t find_in_array_int32(int32_t val, int32_t *arr, size_t arr_size)
+{
+	for (size_t i = 0; i < arr_size; i++) {
+		if (arr[i] == val) {
+			return i;
+		}
+	}
+
+	return (size_t) -1;
+}
+
+/**
+ * Checks if some keys were pressed or released and generates key events.
+ *
+ * An event is created only when key is pressed or released. Besides handling
+ * the events (usb_kbd_push_ev()), the auto-repeat fibril is notified about
+ * key presses and releases (see usb_kbd_repeat_start() and 
+ * usb_kbd_repeat_stop()).
+ *
+ * @param kbd_dev Keyboard device structure.
+ * @param key_codes Parsed keyboard report - codes of currently pressed keys 
+ *                  according to HID Usage Tables.
+ * @param count Number of key codes in report (size of the report).
+ *
+ * @sa usb_kbd_push_ev(), usb_kbd_repeat_start(), usb_kbd_repeat_stop()
+ */
+static void usb_kbd_check_key_changes(usb_hid_dev_t *hid_dev,
+    usb_kbd_t *kbd_dev)
+{
+
+	/*
+	 * First of all, check if the kbd have reported phantom state.
+	 *
+	 * As there is no way to distinguish keys from modifiers, we do not have
+	 * a way to check that 'all keys report Error Rollover'. We thus check
+	 * if there is at least one such error and in such case we ignore the
+	 * whole input report.
+	 */
+	size_t i = find_in_array_int32(ERROR_ROLLOVER, kbd_dev->keys,
+	    kbd_dev->key_count);
+	if (i != (size_t) -1) {
+		usb_log_error("Detected phantom state.\n");
+		return;
+	}
+
+	/*
+	 * Key releases
+	 */
+	for (i = 0; i < kbd_dev->key_count; i++) {
+		const int32_t old_key = kbd_dev->keys_old[i];
+		/* Find the old key among currently pressed keys. */
+		const size_t pos = find_in_array_int32(old_key, kbd_dev->keys,
+		    kbd_dev->key_count);
+		/* If the key was not found, we need to signal release. */
+		if (pos == (size_t) -1) {
+			const unsigned key = usbhid_parse_scancode(old_key);
+			if (!usb_kbd_is_lock(key)) {
+				usb_kbd_repeat_stop(kbd_dev, key);
+			}
+			usb_kbd_push_ev(kbd_dev, KEY_RELEASE, key);
+			usb_log_debug2("Key released: %u "
+			    "(USB code %" PRIu32 ")\n", key, old_key);
+		}
+	}
+
+	/*
+	 * Key presses
+	 */
+	for (i = 0; i < kbd_dev->key_count; ++i) {
+		const int32_t new_key = kbd_dev->keys[i];
+		/* Find the new key among already pressed keys. */
+		const size_t pos = find_in_array_int32(new_key,
+		    kbd_dev->keys_old, kbd_dev->key_count);
+		/* If the key was not found, we need to signal press. */
+		if (pos == (size_t) -1) {
+			unsigned key = usbhid_parse_scancode(kbd_dev->keys[i]);
+			if (!usb_kbd_is_lock(key)) {
+				usb_kbd_repeat_start(kbd_dev, key);
+			}
+			usb_kbd_push_ev(kbd_dev, KEY_PRESS, key);
+			usb_log_debug2("Key pressed: %u "
+			    "(USB code %" PRIu32 ")\n", key, new_key);
+		}
+	}
+
+	memcpy(kbd_dev->keys_old, kbd_dev->keys, kbd_dev->key_count * 4);
+
+	// TODO Get rid of this
+	char key_buffer[512];
+	ddf_dump_buffer(key_buffer, 512,
+	    kbd_dev->keys_old, 4, kbd_dev->key_count, 0);
+	usb_log_debug2("Stored keys %s.\n", key_buffer);
+}
+
+/* General kbd functions                                                      */
+
+/**
+ * Processes data received from the device in form of report.
+ *
+ * This function uses the HID report parser to translate the data received from
+ * the device into generic USB HID key codes and into generic modifiers bitmap.
+ * The parser then calls the given callback (usb_kbd_process_keycodes()).
+ *
+ * @note Currently, only the boot protocol is supported.
+ *
+ * @param kbd_dev Keyboard device structure (must be initialized).
+ * @param buffer Data from the keyboard (i.e. the report).
+ * @param actual_size Size of the data from keyboard (report size) in bytes.
+ *
+ * @sa usb_kbd_process_keycodes(), usb_hid_boot_keyboard_input_report(),
+ *     usb_hid_parse_report().
+ */
+static void usb_kbd_process_data(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev)
+{
+	assert(hid_dev != NULL);
+	assert(kbd_dev != NULL);
+
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	if (path == NULL) {
+		usb_log_error("Failed to create hid/kbd report path.\n");
+		return;
+	}
+
+	int ret =
+	   usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	if (ret != EOK) {
+		usb_log_error("Failed to append to hid/kbd report path.\n");
+		return;
+	}
+
+	usb_hid_report_path_set_report_id(path, hid_dev->report_id);
+
+	/* Fill in the currently pressed keys. */
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+	    &hid_dev->report, NULL, path,
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+	    USB_HID_REPORT_TYPE_INPUT);
+	unsigned i = 0;
+
+	while (field != NULL) {
+		usb_log_debug2("FIELD (%p) - VALUE(%d) USAGE(%u)\n",
+		    field, field->value, field->usage);
+
+		assert(i < kbd_dev->key_count);
+
+		/* Save the key usage. */
+		if (field->value != 0) {
+			kbd_dev->keys[i] = field->usage;
+		}
+		else {
+			kbd_dev->keys[i] = 0;
+		}
+		usb_log_debug2("Saved %u. key usage %d\n", i, kbd_dev->keys[i]);
+
+		++i;
+		field = usb_hid_report_get_sibling(
+		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
+		        | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+		    USB_HID_REPORT_TYPE_INPUT);
+	}
+
+	usb_hid_report_path_free(path);
+
+	usb_kbd_check_key_changes(hid_dev, kbd_dev);
+}
+
+/* HID/KBD structure manipulation                                             */
+
+static int kbd_dev_init(usb_kbd_t *kbd_dev, usb_hid_dev_t *hid_dev)
+{
+	assert(kbd_dev);
+	assert(hid_dev);
+
+	/* Default values */
+	fibril_mutex_initialize(&kbd_dev->repeat_mtx);
+	kbd_dev->initialized = USB_KBD_STATUS_UNINITIALIZED;
+
+	/* Store link to HID device */
+	kbd_dev->hid_dev = hid_dev;
+
+	/* Modifiers and locks */
+	kbd_dev->mods = DEFAULT_ACTIVE_MODS;
+
+	/* Autorepeat */
+	kbd_dev->repeat.delay_before = DEFAULT_DELAY_BEFORE_FIRST_REPEAT;
+	kbd_dev->repeat.delay_between = DEFAULT_REPEAT_DELAY;
+
+	// TODO: make more general
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	if (path == NULL) {
+		usb_log_error("Failed to create kbd report path.\n");
+		usb_kbd_destroy(kbd_dev);
+		return ENOMEM;
+	}
+
+	int ret =
+	    usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	if (ret != EOK) {
+		usb_log_error("Failed to append item to kbd report path.\n");
+		usb_hid_report_path_free(path);
+		usb_kbd_destroy(kbd_dev);
+		return ret;
+	}
+
+	usb_hid_report_path_set_report_id(path, 0);
+
+	kbd_dev->key_count =
+	    usb_hid_report_size(&hid_dev->report, 0, USB_HID_REPORT_TYPE_INPUT);
+
+	usb_hid_report_path_free(path);
+
+	usb_log_debug("Size of the input report: %zu\n", kbd_dev->key_count);
+
+	kbd_dev->keys = calloc(kbd_dev->key_count, sizeof(int32_t));
+	if (kbd_dev->keys == NULL) {
+		usb_log_error("Failed to allocate key buffer.\n");
+		usb_kbd_destroy(kbd_dev);
+		return ENOMEM;
+	}
+
+	kbd_dev->keys_old = calloc(kbd_dev->key_count, sizeof(int32_t));
+	if (kbd_dev->keys_old == NULL) {
+		usb_log_error("Failed to allocate old_key buffer.\n");
+		usb_kbd_destroy(kbd_dev);
+		return ENOMEM;
+	}
+
+	/* Output report */
+	kbd_dev->output_size = 0;
+	kbd_dev->output_buffer = usb_hid_report_output(&hid_dev->report,
+	    &kbd_dev->output_size, 0);
+	if (kbd_dev->output_buffer == NULL) {
+		usb_log_error("Error creating output report buffer.\n");
+		usb_kbd_destroy(kbd_dev);
+		return ENOMEM;
+	}
+
+	usb_log_debug("Output buffer size: %zu\n", kbd_dev->output_size);
+
+	kbd_dev->led_path = usb_hid_report_path();
+	if (kbd_dev->led_path == NULL) {
+		usb_log_error("Failed to create kbd led report path.\n");
+		usb_kbd_destroy(kbd_dev);
+		return ENOMEM;
+	}
+
+	ret = usb_hid_report_path_append_item(
+	    kbd_dev->led_path, USB_HIDUT_PAGE_LED, 0);
+	if (ret != EOK) {
+		usb_log_error("Failed to append to kbd/led report path.\n");
+		usb_kbd_destroy(kbd_dev);
+		return ret;
+	}
+
+	kbd_dev->led_output_size = usb_hid_report_size(
+	    &hid_dev->report, 0, USB_HID_REPORT_TYPE_OUTPUT);
+
+	usb_log_debug("Output report size (in items): %zu\n",
+	    kbd_dev->led_output_size);
+
+	kbd_dev->led_data = calloc(kbd_dev->led_output_size, sizeof(int32_t));
+	if (kbd_dev->led_data == NULL) {
+		usb_log_error("Error creating buffer for LED output report.\n");
+		usb_kbd_destroy(kbd_dev);
+		return ENOMEM;
+	}
+
+	/* Set LEDs according to initial setup.
+	 * Set Idle rate */
+	usb_kbd_set_led(hid_dev, kbd_dev);
+
+	usbhid_req_set_idle(usb_device_get_default_pipe(hid_dev->usb_dev),
+	    usb_device_get_iface_number(hid_dev->usb_dev), IDLE_RATE);
+
+
+	kbd_dev->initialized = USB_KBD_STATUS_INITIALIZED;
+	usb_log_debug("HID/KBD device structure initialized.\n");
+
+	return EOK;
+}
+
+
+/* API functions                                                              */
+
+/**
+ * Initialization of the USB/HID keyboard structure.
+ *
+ * This functions initializes required structures from the device's descriptors.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and
+ *       other locks turned off.
+ *
+ * @param kbd_dev Keyboard device structure to be initialized.
+ * @param dev DDF device structure of the keyboard.
+ *
+ * @retval EOK if successful.
+ * @retval EINVAL if some parameter is not given.
+ * @return Other value inherited from function usbhid_dev_init().
+ */
+int usb_kbd_init(usb_hid_dev_t *hid_dev, void **data)
+{
+	usb_log_debug("Initializing HID/KBD structure...\n");
+
+	if (hid_dev == NULL) {
+		usb_log_error(
+		    "Failed to init keyboard structure: no structure given.\n");
+		return EINVAL;
+	}
+
+	/* Create the exposed function. */
+	usb_log_debug("Creating DDF function %s...\n", HID_KBD_FUN_NAME);
+	ddf_fun_t *fun = usb_device_ddf_fun_create(hid_dev->usb_dev,
+	    fun_exposed, HID_KBD_FUN_NAME);
+	if (fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+
+	usb_kbd_t *kbd_dev = ddf_fun_data_alloc(fun, sizeof(usb_kbd_t));
+	if (kbd_dev == NULL) {
+		usb_log_error("Failed to allocate KBD device structure.\n");
+		ddf_fun_destroy(fun);
+		return ENOMEM;
+	}
+
+	int ret = kbd_dev_init(kbd_dev, hid_dev);
+	if (ret != EOK) {
+		usb_log_error("Failed to initialize KBD device  structure.\n");
+		ddf_fun_destroy(fun);
+		return ret;
+	}
+
+	/* Store the initialized HID device and HID ops
+	 * to the DDF function. */
+	ddf_fun_set_ops(fun, &kbdops);
+
+	ret = ddf_fun_bind(fun);
+	if (ret != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(ret));
+		usb_kbd_destroy(kbd_dev);
+		ddf_fun_destroy(fun);
+		return ret;
+	}
+
+	usb_log_debug("%s function created. Handle: %" PRIun "\n",
+	    HID_KBD_FUN_NAME, ddf_fun_get_handle(fun));
+
+	usb_log_debug("Adding DDF function to category %s...\n",
+	    HID_KBD_CATEGORY_NAME);
+	ret = ddf_fun_add_to_category(fun, HID_KBD_CATEGORY_NAME);
+	if (ret != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to category %s: %s.\n",
+		    HID_KBD_CATEGORY_NAME, str_error(ret));
+		usb_kbd_destroy(kbd_dev);
+		if (ddf_fun_unbind(fun) == EOK) {
+			ddf_fun_destroy(fun);
+		} else {
+			usb_log_error(
+			    "Failed to unbind `%s', will not destroy.\n",
+			    ddf_fun_get_name(fun));
+		}
+		return ret;
+	}
+
+	/* Create new fibril for auto-repeat. */
+	fid_t fid = fibril_create(usb_kbd_repeat_fibril, kbd_dev);
+	if (fid == 0) {
+		usb_log_error("Failed to start fibril for KBD auto-repeat");
+		usb_kbd_destroy(kbd_dev);
+		return ENOMEM;
+	}
+	fibril_add_ready(fid);
+	kbd_dev->fun = fun;
+	/* Save the KBD device structure into the HID device structure. */
+	*data = kbd_dev;
+
+	return EOK;
+}
+
+bool usb_kbd_polling_callback(usb_hid_dev_t *hid_dev, void *data)
+{
+	if (hid_dev == NULL || data == NULL) {
+		/* This means something serious */
+		return false;
+	}
+
+	usb_kbd_t *kbd_dev = data;
+	// TODO: add return value from this function
+	usb_kbd_process_data(hid_dev, kbd_dev);
+
+	return true;
+}
+
+int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev)
+{
+	return (kbd_dev->initialized == USB_KBD_STATUS_INITIALIZED);
+}
+
+int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev)
+{
+	return (kbd_dev->initialized == USB_KBD_STATUS_TO_DESTROY);
+}
+
+/**
+ * Properly destroys the USB/HID keyboard structure.
+ *
+ * @param kbd_dev Pointer to the structure to be destroyed.
+ */
+void usb_kbd_destroy(usb_kbd_t *kbd_dev)
+{
+	if (kbd_dev == NULL) {
+		return;
+	}
+
+	/* Hangup session to the console. */
+	if (kbd_dev->client_sess)
+		async_hangup(kbd_dev->client_sess);
+
+	//assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
+	// FIXME - the fibril_mutex_is_locked may not cause
+	// fibril scheduling
+	while (fibril_mutex_is_locked(&kbd_dev->repeat_mtx)) {}
+
+	/* Free all buffers. */
+	free(kbd_dev->keys);
+	free(kbd_dev->keys_old);
+	free(kbd_dev->led_data);
+
+	usb_hid_report_path_free(kbd_dev->led_path);
+	usb_hid_report_output_free(kbd_dev->output_buffer);
+
+	if (kbd_dev->fun) {
+		if (ddf_fun_unbind(kbd_dev->fun) != EOK) {
+			usb_log_warning("Failed to unbind %s.\n",
+			    ddf_fun_get_name(kbd_dev->fun));
+		} else {
+			usb_log_debug2("%s unbound.\n",
+			    ddf_fun_get_name(kbd_dev->fun));
+			ddf_fun_destroy(kbd_dev->fun);
+		}
+	}
+}
+
+void usb_kbd_deinit(usb_hid_dev_t *hid_dev, void *data)
+{
+	if (data != NULL) {
+		usb_kbd_t *kbd_dev = data;
+		if (usb_kbd_is_initialized(kbd_dev)) {
+			kbd_dev->initialized = USB_KBD_STATUS_TO_DESTROY;
+			/* Wait for autorepeat */
+			async_usleep(CHECK_DELAY);
+		}
+		usb_kbd_destroy(kbd_dev);
+	}
+}
+
+int usb_kbd_set_boot_protocol(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev);
+	int rc = usb_hid_parse_report_descriptor(
+	    &hid_dev->report, USB_KBD_BOOT_REPORT_DESCRIPTOR,
+	    sizeof(USB_KBD_BOOT_REPORT_DESCRIPTOR));
+
+	if (rc != EOK) {
+		usb_log_error("Failed to parse boot report descriptor: %s\n",
+		    str_error(rc));
+		return rc;
+	}
+
+	rc = usbhid_req_set_protocol(
+	    usb_device_get_default_pipe(hid_dev->usb_dev),
+	    usb_device_get_iface_number(hid_dev->usb_dev),
+	    USB_HID_PROTOCOL_BOOT);
+
+	if (rc != EOK) {
+		usb_log_warning("Failed to set boot protocol to the device: "
+		    "%s\n", str_error(rc));
+		return rc;
+	}
+
+	return EOK;
+}
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/kbd/kbddev.h
===================================================================
--- uspace/drv/hid/usbhid/kbd/kbddev.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/kbd/kbddev.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID keyboard device structure and API.
+ */
+
+#ifndef USB_HID_KBDDEV_H_
+#define USB_HID_KBDDEV_H_
+
+#include <stdint.h>
+#include <async.h>
+#include <fibril_synch.h>
+#include <usb/hid/hid.h>
+#include <usb/hid/hidparser.h>
+#include <ddf/driver.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/driver.h>
+#include "../usbhid.h"
+#include "kbdrepeat.h"
+
+/**
+ * USB/HID keyboard device type.
+ *
+ * Holds a reference to generic USB/HID device structure and keyboard-specific
+ * data, such as currently pressed keys, modifiers and lock keys.
+ *
+ * Also holds a IPC session to the console (since there is now no other way to 
+ * communicate with it).
+ *
+ * @note Storing active lock keys in this structure results in their setting
+ *       being device-specific.
+ */
+typedef struct usb_kbd_t {
+	/** Link to HID device structure */
+	usb_hid_dev_t *hid_dev;
+	
+	/** Previously pressed keys (not translated to key codes). */
+	int32_t *keys_old;
+	/** Currently pressed keys (not translated to key codes). */
+	int32_t *keys;
+	/** Count of stored keys (i.e. number of keys in the report). */
+	size_t key_count;
+	/** Currently pressed modifiers (bitmap). */
+	uint8_t modifiers;
+	
+	/** Currently active modifiers including locks. Sent to the console. */
+	unsigned int mods;
+	
+	/** Currently active lock keys. */
+	unsigned int lock_keys;
+	
+	/** IPC session to client (for sending key events). */
+	async_sess_t *client_sess;
+	
+	/** Information for auto-repeat of keys. */
+	usb_kbd_repeat_t repeat;
+	
+	/** Mutex for accessing the information about auto-repeat. */
+	fibril_mutex_t repeat_mtx;
+	
+	uint8_t *output_buffer;
+	
+	size_t output_size;
+	
+	size_t led_output_size;
+	
+	usb_hid_report_path_t *led_path;
+	
+	int32_t *led_data;
+	
+	/** State of the structure (for checking before use). 
+	 *
+	 * 0 - not initialized
+	 * 1 - initialized
+	 * -1 - ready for destroying
+	 */
+	int initialized;
+	
+	/** DDF function */
+	ddf_fun_t *fun;
+} usb_kbd_t;
+
+extern const usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description;
+
+extern const char *HID_KBD_FUN_NAME;
+extern const char *HID_KBD_CATEGORY;
+
+extern int usb_kbd_init(usb_hid_dev_t *, void **);
+extern bool usb_kbd_polling_callback(usb_hid_dev_t *, void *);
+extern int usb_kbd_is_initialized(const usb_kbd_t *);
+extern int usb_kbd_is_ready_to_destroy(const usb_kbd_t *);
+extern void usb_kbd_destroy(usb_kbd_t *);
+extern void usb_kbd_push_ev(usb_kbd_t *, int, unsigned int);
+extern void usb_kbd_deinit(usb_hid_dev_t *, void *);
+extern int usb_kbd_set_boot_protocol(usb_hid_dev_t *);
+
+#endif /* USB_HID_KBDDEV_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/kbd/kbdrepeat.c
===================================================================
--- uspace/drv/hid/usbhid/kbd/kbdrepeat.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/kbd/kbdrepeat.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID keyboard autorepeat facilities
+ */
+
+#include <fibril_synch.h>
+#include <io/keycode.h>
+#include <io/console.h>
+#include <errno.h>
+
+#include <usb/debug.h>
+
+#include "kbdrepeat.h"
+#include "kbddev.h"
+
+/**
+ * Main loop handling the auto-repeat of keys.
+ *
+ * This functions periodically checks if there is some key to be auto-repeated.
+ *
+ * If a new key is to be repeated, it uses the delay before first repeat stored
+ * in the keyboard structure to wait until the key has to start repeating.
+ *
+ * If the same key is still pressed, it uses the delay between repeats stored
+ * in the keyboard structure to wait until the key should be repeated.
+ *
+ * If the currently repeated key is not pressed any more (
+ * usb_kbd_repeat_stop() was called), it stops repeating it and starts
+ * checking again.
+ *
+ * @note For accessing the keyboard device auto-repeat information a fibril
+ *       mutex (repeat_mtx) from the @a kbd structure is used.
+ *
+ * @param kbd Keyboard device structure.
+ */
+static void usb_kbd_repeat_loop(usb_kbd_t *kbd)
+{
+	unsigned int delay = 0;
+
+	usb_log_debug("Starting autorepeat loop.\n");
+
+	while (true) {
+		/* Check if the kbd structure is usable. */
+		if (!usb_kbd_is_initialized(kbd)) {
+			usb_log_warning("kbd not ready, exiting autorepeat.\n");
+			return;
+		}
+
+		fibril_mutex_lock(&kbd->repeat_mtx);
+
+		if (kbd->repeat.key_new > 0) {
+			if (kbd->repeat.key_new == kbd->repeat.key_repeated) {
+				usb_log_debug2("Repeating key: %u.\n",
+				    kbd->repeat.key_repeated);
+				usb_kbd_push_ev(kbd, KEY_PRESS,
+				    kbd->repeat.key_repeated);
+				delay = kbd->repeat.delay_between;
+			} else {
+				usb_log_debug2("New key to repeat: %u.\n",
+				    kbd->repeat.key_new);
+				kbd->repeat.key_repeated = kbd->repeat.key_new;
+				delay = kbd->repeat.delay_before;
+			}
+		} else {
+			if (kbd->repeat.key_repeated > 0) {
+				usb_log_debug2("Stopping to repeat key: %u.\n",
+				    kbd->repeat.key_repeated);
+				kbd->repeat.key_repeated = 0;
+			}
+			delay = CHECK_DELAY;
+		}
+		fibril_mutex_unlock(&kbd->repeat_mtx);
+		async_usleep(delay);
+	}
+}
+
+/**
+ * Main routine to be executed by a fibril for handling auto-repeat.
+ *
+ * Starts the loop for checking changes in auto-repeat.
+ *
+ * @param arg User-specified argument. Expects pointer to the keyboard device
+ *            structure representing the keyboard.
+ *
+ * @retval EOK if the routine has finished.
+ * @retval EINVAL if no argument is supplied.
+ */
+int usb_kbd_repeat_fibril(void *arg)
+{
+	usb_log_debug("Autorepeat fibril spawned.\n");
+
+	if (arg == NULL) {
+		usb_log_error("No device!\n");
+		return EINVAL;
+	}
+
+	usb_kbd_t *kbd = arg;
+
+	usb_kbd_repeat_loop(kbd);
+
+	return EOK;
+}
+
+/**
+ * Start repeating particular key.
+ *
+ * @note Only one key is repeated at any time, so calling this function 
+ *       effectively cancels auto-repeat of the current repeated key (if any)
+ *       and 'schedules' another key for auto-repeat.
+ *
+ * @param kbd Keyboard device structure.
+ * @param key Key to start repeating.
+ */
+void usb_kbd_repeat_start(usb_kbd_t *kbd, unsigned int key)
+{
+	fibril_mutex_lock(&kbd->repeat_mtx);
+	kbd->repeat.key_new = key;
+	fibril_mutex_unlock(&kbd->repeat_mtx);
+}
+
+/**
+ * Stop repeating particular key.
+ *
+ * @note Only one key is repeated at any time, but this function may be called
+ *       even with key that is not currently repeated (in that case nothing
+ *       happens).
+ *
+ * @param kbd Keyboard device structure.
+ * @param key Key to stop repeating.
+ */
+void usb_kbd_repeat_stop(usb_kbd_t *kbd, unsigned int key)
+{
+	fibril_mutex_lock(&kbd->repeat_mtx);
+	if (key == kbd->repeat.key_new) {
+		kbd->repeat.key_new = 0;
+	}
+	fibril_mutex_unlock(&kbd->repeat_mtx);
+}
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/kbd/kbdrepeat.h
===================================================================
--- uspace/drv/hid/usbhid/kbd/kbdrepeat.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/kbd/kbdrepeat.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID keyboard autorepeat facilities
+ */
+
+#ifndef USB_HID_KBDREPEAT_H_
+#define USB_HID_KBDREPEAT_H_
+
+/** Delay between auto-repeat state checks when no key is being repeated. */
+#define CHECK_DELAY 10000
+
+struct usb_kbd_t;
+
+
+/**
+ * Structure for keeping information needed for auto-repeat of keys.
+ */
+typedef struct {
+	/** Last pressed key. */
+	unsigned int key_new;
+	/** Key to be repeated. */
+	unsigned int key_repeated;
+	/** Delay before first repeat in microseconds. */
+	unsigned int delay_before;
+	/** Delay between repeats in microseconds. */
+	unsigned int delay_between;
+} usb_kbd_repeat_t;
+
+
+
+int usb_kbd_repeat_fibril(void *arg);
+
+void usb_kbd_repeat_start(struct usb_kbd_t *kbd, unsigned int key);
+
+void usb_kbd_repeat_stop(struct usb_kbd_t *kbd, unsigned int key);
+
+#endif /* USB_HID_KBDREPEAT_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/main.c
===================================================================
--- uspace/drv/hid/usbhid/main.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/main.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB HID driver.
+ */
+
+#include <ddf/driver.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/dev/driver.h>
+#include <usb/dev/poll.h>
+
+#include "usbhid.h"
+
+#define NAME "usbhid"
+
+/**
+ * Callback for passing a new device to the driver.
+ *
+ * @note Currently, only boot-protocol keyboards are supported by this driver.
+ *
+ * @param dev Structure representing the new device.
+ * @return Error code.
+ */
+static int usb_hid_device_add(usb_device_t *dev)
+{
+	usb_log_debug("%s\n", __FUNCTION__);
+
+	if (dev == NULL) {
+		usb_log_error("Wrong parameter given for add_device().\n");
+		return EINVAL;
+	}
+
+	if (usb_device_get_iface_number(dev) < 0) {
+		usb_log_error("Failed to add HID device: endpoints not found."
+		    "\n");
+		return ENOTSUP;
+	}
+	usb_hid_dev_t *hid_dev =
+	    usb_device_data_alloc(dev, sizeof(usb_hid_dev_t));
+	if (hid_dev == NULL) {
+		usb_log_error("Failed to create USB/HID device structure.\n");
+		return ENOMEM;
+	}
+
+	int rc = usb_hid_init(hid_dev, dev);
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize USB/HID device.\n");
+		usb_hid_deinit(hid_dev);
+		return rc;
+	}
+
+	usb_log_debug("USB/HID device structure initialized.\n");
+
+	/* Start automated polling function.
+	 * This will create a separate fibril that will query the device
+	 * for the data continuously. */
+	rc = usb_device_auto_poll_desc(dev,
+	   /* Index of the polling pipe. */
+	   hid_dev->poll_pipe_mapping->description,
+	   /* Callback when data arrives. */
+	   usb_hid_polling_callback,
+	   /* How much data to request. */
+	   hid_dev->poll_pipe_mapping->pipe.max_packet_size,
+	   /* Delay */
+	   -1,
+	   /* Callback when the polling ends. */
+	   usb_hid_polling_ended_callback,
+	   /* Custom argument. */
+	   hid_dev);
+
+	if (rc != EOK) {
+		usb_log_error("Failed to start polling fibril for `%s'.\n",
+		    usb_device_get_name(dev));
+		usb_hid_deinit(hid_dev);
+		return rc;
+	}
+	hid_dev->running = true;
+
+	usb_log_info("HID device `%s' ready.\n", usb_device_get_name(dev));
+
+	return EOK;
+}
+
+/**
+ * Callback for a device about to be removed from the driver.
+ *
+ * @param dev Structure representing the device.
+ * @return Error code.
+ */
+static int usb_hid_device_rem(usb_device_t *dev)
+{
+	// TODO: Stop device polling
+	// TODO: Call deinit (stops autorepeat too)
+	return ENOTSUP;
+}
+
+/**
+ * Callback for removing a device from the driver.
+ *
+ * @param dev Structure representing the device.
+ * @return Error code.
+ */
+static int usb_hid_device_gone(usb_device_t *dev)
+{
+	assert(dev);
+	usb_hid_dev_t *hid_dev = usb_device_data_get(dev);
+	assert(hid_dev);
+	unsigned tries = 100;
+	/* Wait for fail. */
+	while (hid_dev->running && tries--) {
+		async_usleep(100000);
+	}
+	if (hid_dev->running) {
+		usb_log_error("Can't remove hid, still running.\n");
+		return EBUSY;
+	}
+
+	usb_hid_deinit(hid_dev);
+	usb_log_debug2("%s destruction complete.\n", usb_device_get_name(dev));
+	return EOK;
+}
+
+/** USB generic driver callbacks */
+static const usb_driver_ops_t usb_hid_driver_ops = {
+	.device_add = usb_hid_device_add,
+	.device_rem = usb_hid_device_rem,
+	.device_gone = usb_hid_device_gone,
+};
+
+/** The driver itself. */
+static const usb_driver_t usb_hid_driver = {
+        .name = NAME,
+        .ops = &usb_hid_driver_ops,
+        .endpoints = usb_hid_endpoints
+};
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS USB HID driver.\n");
+
+	log_init(NAME);
+
+	return usb_driver_main(&usb_hid_driver);
+}
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/mouse/mousedev.c
===================================================================
--- uspace/drv/hid/usbhid/mouse/mousedev.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/mouse/mousedev.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak, 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB Mouse driver API.
+ */
+
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/hid/hid.h>
+#include <usb/hid/request.h>
+#include <usb/hid/usages/core.h>
+#include <errno.h>
+#include <async.h>
+#include <str_error.h>
+#include <ipc/mouseev.h>
+#include <io/console.h>
+
+#include <ipc/kbdev.h>
+#include <io/keycode.h>
+
+#include "mousedev.h"
+#include "../usbhid.h"
+
+#define NAME "mouse"
+
+static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
+
+static ddf_dev_ops_t ops = { .default_handler = default_connection_handler };
+
+
+const usb_endpoint_description_t usb_hid_mouse_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
+};
+
+const char *HID_MOUSE_FUN_NAME = "mouse";
+const char *HID_MOUSE_CATEGORY = "mouse";
+
+/** Default idle rate for mouses. */
+static const uint8_t IDLE_RATE = 0;
+
+
+static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[] = {
+	0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
+	0x09, 0x02,                    // USAGE (Mouse)
+	0xa1, 0x01,                    // COLLECTION (Application)
+	0x09, 0x01,                    //   USAGE (Pointer)
+	0xa1, 0x00,                    //   COLLECTION (Physical)
+	0x95, 0x03,                    //     REPORT_COUNT (3)
+	0x75, 0x01,                    //     REPORT_SIZE (1)
+	0x05, 0x09,                    //     USAGE_PAGE (Button)
+	0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
+	0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
+	0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
+	0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
+	0x81, 0x02,                    //     INPUT (Data,Var,Abs)
+	0x95, 0x01,                    //     REPORT_COUNT (1)
+	0x75, 0x05,                    //     REPORT_SIZE (5)
+	0x81, 0x01,                    //     INPUT (Cnst)
+	0x75, 0x08,                    //     REPORT_SIZE (8)
+	0x95, 0x02,                    //     REPORT_COUNT (2)
+	0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
+	0x09, 0x30,                    //     USAGE (X)
+	0x09, 0x31,                    //     USAGE (Y)
+	0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
+	0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
+	0x81, 0x06,                    //     INPUT (Data,Var,Rel)
+	0xc0,                          //   END_COLLECTION
+	0xc0                           // END_COLLECTION
+};
+
+
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param fun Device function handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+static void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	usb_mouse_t *mouse_dev = ddf_fun_data_get(fun);
+
+	if (mouse_dev == NULL) {
+		usb_log_debug("%s: Missing parameters.\n", __FUNCTION__);
+		async_answer_0(icallid, EINVAL);
+		return;
+	}
+
+	usb_log_debug("%s: fun->name: %s\n", __FUNCTION__, ddf_fun_get_name(fun));
+	usb_log_debug("%s: mouse_sess: %p\n",
+	    __FUNCTION__, mouse_dev->mouse_sess);
+
+	async_sess_t *sess =
+	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
+	if (sess != NULL) {
+		if (mouse_dev->mouse_sess == NULL) {
+			mouse_dev->mouse_sess = sess;
+			usb_log_debug("Console session to %s set ok (%p).\n",
+			    ddf_fun_get_name(fun), sess);
+			async_answer_0(icallid, EOK);
+		} else {
+			usb_log_error("Console session to %s already set.\n",
+			    ddf_fun_get_name(fun));
+			async_answer_0(icallid, ELIMIT);
+			async_hangup(sess);
+		}
+	} else {
+		usb_log_debug("%s: Invalid function.\n", __FUNCTION__);
+		async_answer_0(icallid, EINVAL);
+	}
+}
+
+static int get_mouse_axis_move_value(uint8_t rid, usb_hid_report_t *report,
+    int32_t usage)
+{
+	int result = 0;
+
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_GENERIC_DESKTOP,
+	    usage);
+
+	usb_hid_report_path_set_report_id(path, rid);
+
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+	    report, NULL, path, USB_HID_PATH_COMPARE_END,
+	    USB_HID_REPORT_TYPE_INPUT);
+
+	if (field != NULL) {
+		result = field->value;
+	}
+
+	usb_hid_report_path_free(path);
+
+	return result;
+}
+
+static bool usb_mouse_process_report(usb_hid_dev_t *hid_dev,
+    usb_mouse_t *mouse_dev)
+{
+	assert(mouse_dev != NULL);
+
+	if (mouse_dev->mouse_sess == NULL) {
+		usb_log_warning(NAME " No console session.\n");
+		return true;
+	}
+
+	const int shift_x = get_mouse_axis_move_value(hid_dev->report_id,
+	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_X);
+	const int shift_y = get_mouse_axis_move_value(hid_dev->report_id,
+	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_Y);
+	const int wheel = get_mouse_axis_move_value(hid_dev->report_id,
+	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
+
+	if (shift_x || shift_y || wheel) {
+		async_exch_t *exch =
+		    async_exchange_begin(mouse_dev->mouse_sess);
+		if (exch != NULL) {
+			async_msg_3(exch, MOUSEEV_MOVE_EVENT,
+			    shift_x, shift_y, wheel);
+			async_exchange_end(exch);
+		}
+	}
+
+	/* Buttons */
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	if (path == NULL) {
+		usb_log_warning("Failed to create USB HID report path.\n");
+		return true;
+	}
+	int ret =
+	   usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0);
+	if (ret != EOK) {
+		usb_hid_report_path_free(path);
+		usb_log_warning("Failed to add buttons to report path.\n");
+		return true;
+	}
+	usb_hid_report_path_set_report_id(path, hid_dev->report_id);
+
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+	    &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
+	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, USB_HID_REPORT_TYPE_INPUT);
+
+	while (field != NULL) {
+		usb_log_debug2(NAME " VALUE(%X) USAGE(%X)\n", field->value,
+		    field->usage);
+		assert(field->usage > field->usage_minimum);
+		const unsigned index = field->usage - field->usage_minimum;
+		assert(index < mouse_dev->buttons_count);
+
+		if (mouse_dev->buttons[index] != field->value) {
+			async_exch_t *exch =
+			    async_exchange_begin(mouse_dev->mouse_sess);
+			if (exch != NULL) {
+				async_req_2_0(exch, MOUSEEV_BUTTON_EVENT,
+				    field->usage, (field->value != 0) ? 1 : 0);
+				async_exchange_end(exch);
+				mouse_dev->buttons[index] = field->value;
+			}
+		}
+
+		field = usb_hid_report_get_sibling(
+		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
+		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+		    USB_HID_REPORT_TYPE_INPUT);
+	}
+
+	usb_hid_report_path_free(path);
+
+	return true;
+}
+
+#define FUN_UNBIND_DESTROY(fun) \
+if (fun) { \
+	if (ddf_fun_unbind((fun)) == EOK) { \
+		ddf_fun_destroy((fun)); \
+	} else { \
+		usb_log_error("Could not unbind function `%s', it " \
+		    "will not be destroyed.\n", ddf_fun_get_name(fun)); \
+	} \
+} else (void) 0
+
+/** Get highest index of a button mentioned in given report.
+ *
+ * @param report HID report.
+ * @param report_id Report id we are interested in.
+ * @return Highest button mentioned in the report.
+ * @retval 1 No button was mentioned.
+ *
+ */
+static size_t usb_mouse_get_highest_button(usb_hid_report_t *report, uint8_t report_id)
+{
+	size_t highest_button = 0;
+
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0);
+	usb_hid_report_path_set_report_id(path, report_id);
+
+	usb_hid_report_field_t *field = NULL;
+
+	/* Break from within. */
+	while (1) {
+		field = usb_hid_report_get_sibling(
+		    report, field, path,
+		    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+		    USB_HID_REPORT_TYPE_INPUT);
+		/* No more buttons? */
+		if (field == NULL) {
+			break;
+		}
+
+		size_t current_button = field->usage - field->usage_minimum;
+		if (current_button > highest_button) {
+			highest_button = current_button;
+		}
+	}
+
+	usb_hid_report_path_free(path);
+
+	return highest_button;
+}
+
+static int mouse_dev_init(usb_mouse_t *mouse_dev, usb_hid_dev_t *hid_dev)
+{
+	// FIXME: This may not be optimal since stupid hardware vendor may
+	// use buttons 1, 2, 3 and 6000 and we would allocate array of
+	// 6001*4B and use only 4 items in it.
+	// Since I doubt that hardware producers would do that, I think
+	// that the current solution is good enough.
+	/* Adding 1 because we will be accessing buttons[highest]. */
+	mouse_dev->buttons_count = 1 + usb_mouse_get_highest_button(
+	    &hid_dev->report, hid_dev->report_id);
+	mouse_dev->buttons = calloc(mouse_dev->buttons_count, sizeof(int32_t));
+
+	if (mouse_dev->buttons == NULL) {
+		usb_log_error(NAME ": out of memory, giving up on device!\n");
+		free(mouse_dev);
+		return ENOMEM;
+	}
+
+	// TODO: how to know if the device supports the request???
+	usbhid_req_set_idle(usb_device_get_default_pipe(hid_dev->usb_dev),
+	    usb_device_get_iface_number(hid_dev->usb_dev), IDLE_RATE);
+	return EOK;
+}
+
+int usb_mouse_init(usb_hid_dev_t *hid_dev, void **data)
+{
+	usb_log_debug("Initializing HID/Mouse structure...\n");
+
+	if (hid_dev == NULL) {
+		usb_log_error("Failed to init mouse structure: no structure"
+		    " given.\n");
+		return EINVAL;
+	}
+
+	/* Create the exposed function. */
+	usb_log_debug("Creating DDF function %s...\n", HID_MOUSE_FUN_NAME);
+	ddf_fun_t *fun = usb_device_ddf_fun_create(hid_dev->usb_dev,
+	    fun_exposed, HID_MOUSE_FUN_NAME);
+	if (fun == NULL) {
+		usb_log_error("Could not create DDF function node `%s'.\n",
+		    HID_MOUSE_FUN_NAME);
+		return ENOMEM;
+	}
+
+	usb_mouse_t *mouse_dev = ddf_fun_data_alloc(fun, sizeof(usb_mouse_t));
+	if (mouse_dev == NULL) {
+		usb_log_error("Failed to alloc HID mouse device structure.\n");
+		ddf_fun_destroy(fun);
+		return ENOMEM;
+	}
+
+	int ret = mouse_dev_init(mouse_dev, hid_dev);
+	if (ret != EOK) {
+		usb_log_error("Failed to init HID mouse device structure.\n");
+		return ret;
+	}
+
+	ddf_fun_set_ops(fun, &ops);
+
+	ret = ddf_fun_bind(fun);
+	if (ret != EOK) {
+		usb_log_error("Could not bind DDF function `%s': %s.\n",
+		    ddf_fun_get_name(fun), str_error(ret));
+		ddf_fun_destroy(fun);
+		return ret;
+	}
+
+	usb_log_debug("Adding DDF function `%s' to category %s...\n",
+	    ddf_fun_get_name(fun), HID_MOUSE_CATEGORY);
+	ret = ddf_fun_add_to_category(fun, HID_MOUSE_CATEGORY);
+	if (ret != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to category %s: %s.\n",
+		    HID_MOUSE_CATEGORY, str_error(ret));
+		FUN_UNBIND_DESTROY(fun);
+		return ret;
+	}
+	mouse_dev->mouse_fun = fun;
+
+	/* Save the Mouse device structure into the HID device structure. */
+	*data = mouse_dev;
+
+	return EOK;
+}
+
+bool usb_mouse_polling_callback(usb_hid_dev_t *hid_dev, void *data)
+{
+	if (hid_dev == NULL || data == NULL) {
+		usb_log_error(
+		    "Missing argument to the mouse polling callback.\n");
+		return false;
+	}
+
+	usb_mouse_t *mouse_dev = data;
+
+	return usb_mouse_process_report(hid_dev, mouse_dev);
+}
+
+void usb_mouse_deinit(usb_hid_dev_t *hid_dev, void *data)
+{
+	if (data == NULL)
+		return;
+
+	usb_mouse_t *mouse_dev = data;
+
+	/* Hangup session to the console */
+	if (mouse_dev->mouse_sess != NULL) {
+		const int ret = async_hangup(mouse_dev->mouse_sess);
+		if (ret != EOK)
+			usb_log_warning("Failed to hang up mouse session: "
+			    "%p, %s.\n", mouse_dev->mouse_sess, str_error(ret));
+	}
+
+	free(mouse_dev->buttons);
+	FUN_UNBIND_DESTROY(mouse_dev->mouse_fun);
+}
+
+int usb_mouse_set_boot_protocol(usb_hid_dev_t *hid_dev)
+{
+	int rc = usb_hid_parse_report_descriptor(
+	    &hid_dev->report, USB_MOUSE_BOOT_REPORT_DESCRIPTOR,
+	    sizeof(USB_MOUSE_BOOT_REPORT_DESCRIPTOR));
+
+	if (rc != EOK) {
+		usb_log_error("Failed to parse boot report descriptor: %s\n",
+		    str_error(rc));
+		return rc;
+	}
+
+	rc = usbhid_req_set_protocol(
+	    usb_device_get_default_pipe(hid_dev->usb_dev),
+	    usb_device_get_iface_number(hid_dev->usb_dev),
+	    USB_HID_PROTOCOL_BOOT);
+
+	if (rc != EOK) {
+		usb_log_warning("Failed to set boot protocol to the device: "
+		    "%s\n", str_error(rc));
+		return rc;
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/mouse/mousedev.h
===================================================================
--- uspace/drv/hid/usbhid/mouse/mousedev.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/mouse/mousedev.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB Mouse driver API.
+ */
+
+#ifndef USB_HID_MOUSEDEV_H_
+#define USB_HID_MOUSEDEV_H_
+
+#include <usb/dev/driver.h>
+#include <async.h>
+#include "../usbhid.h"
+
+/** Container for USB mouse device. */
+typedef struct {
+	/** IPC session to consumer. */
+	async_sess_t *mouse_sess;
+	
+	/** Mouse buttons statuses. */
+	int32_t *buttons;
+	size_t buttons_count;
+	
+	/** DDF mouse function */
+	ddf_fun_t *mouse_fun;
+} usb_mouse_t;
+
+extern const usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description;
+
+extern const char *HID_MOUSE_FUN_NAME;
+extern const char *HID_MOUSE_CATEGORY;
+
+extern int usb_mouse_init(usb_hid_dev_t *, void **);
+extern bool usb_mouse_polling_callback(usb_hid_dev_t *, void *);
+extern void usb_mouse_deinit(usb_hid_dev_t *, void *);
+extern int usb_mouse_set_boot_protocol(usb_hid_dev_t *);
+
+#endif // USB_HID_MOUSEDEV_H_
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/multimedia/keymap.c
===================================================================
--- uspace/drv/hid/usbhid/multimedia/keymap.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/multimedia/keymap.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * UUSB multimedia key to keycode mapping.
+ */
+
+#include <io/keycode.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <usb/debug.h>
+#include "keymap.h"
+
+/**
+ * Mapping between USB HID multimedia usages (from HID Usage Tables) and 
+ * corresponding HelenOS key codes.
+ *
+ * Currently only Usages used by Logitech UltraX keyboard are present. All other
+ * should result in 0.
+ */
+static int usb_hid_keymap_consumer[0x29c] = {
+	[0xb5] = 0,       /* Scan Next Track */
+	[0xb6] = 0,       /* Scan Previous Track */
+	[0xb7] = 0,       /* Stop */
+	[0xb8] = 0,       /* Eject */
+	[0xcd] = 0/*KC_F2*/,   /* Play/Pause */
+	[0xe2] = 0/*KC_F3*/,   /* Mute */
+	[0xe9] = 0/*KC_F5*/,   /* Volume Increment */
+	[0xea] = 0/*KC_F4*/,   /* Volume Decrement */
+	[0x183] = 0/*KC_F1*/,      /* AL Consumer Control Configuration */
+	[0x18a] = 0,      /* AL Email Reader */
+	[0x192] = 0,      /* AL Calculator */
+	[0x221] = 0,      /* AC Search */
+	[0x223] = 0/*KC_F6*/,      /* AC Home */
+	[0x224] = 0,      /* AC Back */
+	[0x225] = 0,      /* AC Forward */
+	[0x226] = 0,      /* AC Stop */
+	[0x227] = 0,  /* AC Refresh */
+	[0x22a] = 0   /* AC Bookmarks */
+};
+
+/**
+ * Translates USB HID Usages from the Consumer Page into HelenOS keycodes.
+ *
+ * @param usage USB HID Consumer Page Usage number.
+ * 
+ * @retval HelenOS key code corresponding to the given USB Consumer Page Usage.
+ */
+unsigned int usb_multimedia_map_usage(int usage)
+{
+	unsigned int key;
+	int *map = usb_hid_keymap_consumer;
+	size_t map_length = sizeof(usb_hid_keymap_consumer) / sizeof(int);
+
+	if ((usage < 0) || ((size_t)usage >= map_length))
+		return -1;
+
+	/*! @todo What if the usage is not in the table? */
+	key = map[usage];
+	
+	return key;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/multimedia/keymap.h
===================================================================
--- uspace/drv/hid/usbhid/multimedia/keymap.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/multimedia/keymap.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB multimedia key to keycode mapping.
+ */
+
+#ifndef USB_HID_MULTIMEDIA_KEYMAP_H_
+#define USB_HID_MULTIMEDIA_KEYMAP_H_
+
+unsigned int usb_multimedia_map_usage(int usage);
+
+#endif /* USB_HID_MULTIMEDIA_KEYMAP_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/multimedia/multimedia.c
===================================================================
--- uspace/drv/hid/usbhid/multimedia/multimedia.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/multimedia/multimedia.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB Keyboard multimedia keys subdriver.
+ */
+
+
+#include "multimedia.h"
+#include "../usbhid.h"
+#include "keymap.h"
+
+#include <usb/hid/hidparser.h>
+#include <usb/debug.h>
+#include <usb/hid/usages/core.h>
+#include <usb/hid/usages/consumer.h>
+
+#include <errno.h>
+#include <async.h>
+#include <str_error.h>
+
+#include <ipc/kbdev.h>
+#include <io/console.h>
+
+#define NAME  "multimedia-keys"
+
+
+/**
+ * Logitech UltraX device type.
+ */
+typedef struct usb_multimedia_t {
+	/** Previously pressed keys (not translated to key codes). */
+	//int32_t *keys_old;
+	/** Currently pressed keys (not translated to key codes). */
+	//int32_t *keys;
+	/** Count of stored keys (i.e. number of keys in the report). */
+	//size_t key_count;
+	/** IPC session to the console device (for sending key events). */
+	async_sess_t *console_sess;
+} usb_multimedia_t;
+
+
+
+/**
+ * Default handler for IPC methods not handled by DDF.
+ *
+ * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
+ * assumes the caller is the console and thus it stores IPC session to it for
+ * later use by the driver to notify about key events.
+ *
+ * @param fun Device function handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+static void default_connection_handler(ddf_fun_t *fun,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	usb_log_debug(NAME " default_connection_handler()\n");
+
+	usb_multimedia_t *multim_dev = ddf_fun_data_get(fun);
+
+	async_sess_t *sess =
+	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
+	if (sess != NULL) {
+		if (multim_dev->console_sess == NULL) {
+			multim_dev->console_sess = sess;
+			usb_log_debug(NAME " Saved session to console: %p\n",
+			    sess);
+			async_answer_0(icallid, EOK);
+		} else
+			async_answer_0(icallid, ELIMIT);
+	} else
+		async_answer_0(icallid, EINVAL);
+}
+
+static ddf_dev_ops_t multimedia_ops = {
+	.default_handler = default_connection_handler
+};
+
+/**
+ * Processes key events.
+ *
+ * @note This function was copied from AT keyboard driver and modified to suit
+ *       USB keyboard.
+ *
+ * @note Lock keys are not sent to the console, as they are completely handled
+ *       in the driver. It may, however, be required later that the driver
+ *       sends also these keys to application (otherwise it cannot use those
+ *       keys at all).
+ *
+ * @param hid_dev
+ * @param multim_dev
+ * @param type Type of the event (press / release). Recognized values:
+ *             KEY_PRESS, KEY_RELEASE
+ * @param key Key code of the key according to HID Usage Tables.
+ */
+static void usb_multimedia_push_ev(
+    usb_multimedia_t *multim_dev, int type, unsigned int key)
+{
+	assert(multim_dev != NULL);
+
+	const kbd_event_t ev = {
+		.type = type,
+		.key = key,
+		.mods = 0,
+		.c = 0,
+	};
+
+	usb_log_debug2(NAME " Sending key %d to the console\n", ev.key);
+	if (multim_dev->console_sess == NULL) {
+		usb_log_warning(
+		    "Connection to console not ready, key discarded.\n");
+		return;
+	}
+
+	async_exch_t *exch = async_exchange_begin(multim_dev->console_sess);
+	if (exch != NULL) {
+		async_msg_4(exch, KBDEV_EVENT, ev.type, ev.key, ev.mods, ev.c);
+		async_exchange_end(exch);
+	} else {
+		usb_log_warning("Failed to send multimedia key.\n");
+	}
+}
+
+int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
+{
+	if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
+		return EINVAL;
+	}
+
+	usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
+
+	/* Create the exposed function. */
+	ddf_fun_t *fun = usb_device_ddf_fun_create(
+	    hid_dev->usb_dev, fun_exposed, NAME);
+	if (fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+
+	ddf_fun_set_ops(fun, &multimedia_ops);
+
+	usb_multimedia_t *multim_dev =
+	    ddf_fun_data_alloc(fun, sizeof(usb_multimedia_t));
+	if (multim_dev == NULL) {
+		ddf_fun_destroy(fun);
+		return ENOMEM;
+	}
+
+	multim_dev->console_sess = NULL;
+
+	//todo Autorepeat?
+
+	int rc = ddf_fun_bind(fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	usb_log_debug(NAME " function created (handle: %" PRIun ").\n",
+	    ddf_fun_get_handle(fun));
+
+	rc = ddf_fun_add_to_category(fun, "keyboard");
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to category 'keyboard': %s.\n",
+		    str_error(rc));
+		if (ddf_fun_unbind(fun) != EOK) {
+			usb_log_error("Failed to unbind %s, won't destroy.\n",
+			    ddf_fun_get_name(fun));
+		} else {
+			ddf_fun_destroy(fun);
+		}
+		return rc;
+	}
+
+	/* Save the KBD device structure into the HID device structure. */
+	*data = fun;
+
+	usb_log_debug(NAME " HID/multimedia structure initialized.\n");
+	return EOK;
+}
+
+void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data)
+{
+	ddf_fun_t *fun = data;
+
+	usb_multimedia_t *multim_dev = ddf_fun_data_get(fun);
+
+	/* Hangup session to the console */
+	if (multim_dev->console_sess)
+		async_hangup(multim_dev->console_sess);
+	if (ddf_fun_unbind(fun) != EOK) {
+		usb_log_error("Failed to unbind %s, won't destroy.\n",
+		    ddf_fun_get_name(fun));
+	} else {
+		usb_log_debug2("%s unbound.\n", ddf_fun_get_name(fun));
+		/* This frees multim_dev too as it was stored in
+		 * fun->data */
+		ddf_fun_destroy(fun);
+	}
+}
+
+bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data)
+{
+	// TODO: checks
+	ddf_fun_t *fun = data;
+	if (hid_dev == NULL) {
+		return false;
+	}
+
+	usb_multimedia_t *multim_dev = ddf_fun_data_get(fun);
+
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	if (path == NULL)
+		return true; /* This might be a temporary failure. */
+
+	int ret =
+	    usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
+	if (ret != EOK) {
+		usb_hid_report_path_free(path);
+		return true; /* This might be a temporary failure. */
+	}
+
+	usb_hid_report_path_set_report_id(path, hid_dev->report_id);
+
+	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
+	    &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
+	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+	    USB_HID_REPORT_TYPE_INPUT);
+
+	//FIXME Is this iterating OK if done multiple times?
+	//FIXME The parsing is not OK. (what's wrong?)
+	while (field != NULL) {
+		if (field->value != 0) {
+			usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n",
+			    field->value, field->usage);
+			const unsigned key =
+			    usb_multimedia_map_usage(field->usage);
+			const char *key_str =
+			    usbhid_multimedia_usage_to_str(field->usage);
+			usb_log_info("Pressed key: %s\n", key_str);
+			usb_multimedia_push_ev(multim_dev, KEY_PRESS, key);
+		}
+
+		field = usb_hid_report_get_sibling(
+		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
+		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+		    USB_HID_REPORT_TYPE_INPUT);
+	}
+
+	usb_hid_report_path_free(path);
+
+	return true;
+}
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/multimedia/multimedia.h
===================================================================
--- uspace/drv/hid/usbhid/multimedia/multimedia.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/multimedia/multimedia.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB Keyboard multimedia keys subdriver.
+ */
+
+#ifndef USB_HID_MULTIMEDIA_H_
+#define USB_HID_MULTIMEDIA_H_
+
+#include <usb/dev/driver.h>
+#include "../usbhid.h"
+
+extern int usb_multimedia_init(usb_hid_dev_t *, void **);
+extern void usb_multimedia_deinit(usb_hid_dev_t *, void *);
+extern bool usb_multimedia_polling_callback(usb_hid_dev_t *, void *);
+
+#endif // USB_HID_MULTIMEDIA_H_
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/subdrivers.c
===================================================================
--- uspace/drv/hid/usbhid/subdrivers.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/subdrivers.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID subdriver mappings.
+ */
+
+#include "subdrivers.h"
+#include <usb/hid/usages/core.h>
+#include <usb/hid/hidpath.h>
+#include "kbd/kbddev.h"
+#include "mouse/mousedev.h"
+#include "multimedia/multimedia.h"
+#include "blink1/blink1.h"
+#include "generic/hiddev.h"
+
+static const usb_hid_subdriver_usage_t path_kbd[] = {
+	{
+		USB_HIDUT_PAGE_GENERIC_DESKTOP,
+		USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD
+	},
+	{0, 0}
+};
+
+static const usb_hid_subdriver_usage_t path_mouse[] = {
+	{
+		USB_HIDUT_PAGE_GENERIC_DESKTOP,
+		USB_HIDUT_USAGE_GENERIC_DESKTOP_MOUSE
+	},
+	{0, 0}
+};
+
+static const usb_hid_subdriver_usage_t path_multim_key[] = {
+	{
+		USB_HIDUT_PAGE_CONSUMER,
+		USB_HIDUT_USAGE_CONSUMER_CONSUMER_CONTROL
+	},
+	{0, 0}
+};
+
+const usb_hid_subdriver_mapping_t usb_hid_subdrivers[] = {
+	{
+		path_kbd,
+		0,
+		USB_HID_PATH_COMPARE_BEGIN,
+		-1,
+		-1,
+		{
+			.init = usb_kbd_init,
+			.deinit = usb_kbd_deinit,
+			.poll = usb_kbd_polling_callback,
+			.poll_end = NULL
+		},
+	},
+	{
+		path_multim_key,
+		1,
+		USB_HID_PATH_COMPARE_BEGIN,
+		-1,
+		-1,
+		{
+			.init = usb_multimedia_init,
+			.deinit = usb_multimedia_deinit,
+			.poll = usb_multimedia_polling_callback,
+			.poll_end = NULL
+		}
+	},
+	{
+		path_mouse,
+		0,
+		USB_HID_PATH_COMPARE_BEGIN,
+		-1,
+		-1,
+		{
+			.init = usb_mouse_init,
+			.deinit = usb_mouse_deinit,
+			.poll = usb_mouse_polling_callback,
+			.poll_end = NULL
+		}
+	},
+	{
+		NULL,
+		0,
+		USB_HID_PATH_COMPARE_BEGIN,
+		0x27b8,
+		0x01ed,
+		{
+			.init = usb_blink1_init,
+			.deinit = usb_blink1_deinit,
+			.poll = NULL,
+			.poll_end = NULL
+		}
+	}
+};
+
+const size_t USB_HID_MAX_SUBDRIVERS =
+    sizeof(usb_hid_subdrivers) / sizeof(usb_hid_subdrivers[0]);
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/subdrivers.h
===================================================================
--- uspace/drv/hid/usbhid/subdrivers.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/subdrivers.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID subdriver mappings.
+ */
+
+#ifndef USB_HID_SUBDRIVERS_H_
+#define USB_HID_SUBDRIVERS_H_
+
+#include "usbhid.h"
+#include "kbd/kbddev.h"
+
+typedef struct usb_hid_subdriver_usage {
+	int usage_page;
+	int usage;
+} usb_hid_subdriver_usage_t;
+
+/** Structure representing the mapping between device requirements and the
+ *  subdriver supposed to handle this device.
+ *
+ * By filling in this structure and adding it to the usb_hid_subdrivers array,
+ * a new subdriver mapping will be created and used by the HID driver when it
+ * searches for appropriate subdrivers for a device.
+ *
+ */
+typedef struct usb_hid_subdriver_mapping {
+	/** Usage path that the device's input reports must contain.
+	 *
+	 * It is an array of pairs <usage_page, usage>, terminated by a <0, 0>
+	 * pair. If you do not wish to specify the device in this way, set this
+	 * to NULL.
+	 */
+	const usb_hid_subdriver_usage_t *usage_path;
+	
+	/** Report ID for which the path should apply. */
+	int report_id;
+	
+	/** Compare type for the usage path. */
+	int compare;
+	
+	/** Vendor ID (set to -1 if not specified). */
+	int vendor_id;
+	
+	/** Product ID (set to -1 if not specified). */
+	int product_id;
+	
+	/** Subdriver for controlling this device. */
+	const usb_hid_subdriver_t subdriver;
+} usb_hid_subdriver_mapping_t;
+
+extern const usb_hid_subdriver_mapping_t usb_hid_subdrivers[];
+extern const size_t USB_HID_MAX_SUBDRIVERS;
+
+#endif /* USB_HID_SUBDRIVERS_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/usbhid.c
===================================================================
--- uspace/drv/hid/usbhid/usbhid.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/usbhid.c	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * USB HID driver API.
+ */
+
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/hid/hid.h>
+#include <usb/hid/hidparser.h>
+#include <usb/hid/hidreport.h>
+#include <usb/hid/request.h>
+
+#include <errno.h>
+#include <macros.h>
+#include <str_error.h>
+
+#include "usbhid.h"
+
+#include "kbd/kbddev.h"
+#include "generic/hiddev.h"
+#include "mouse/mousedev.h"
+#include "subdrivers.h"
+
+/* Array of endpoints expected on the device, NULL terminated. */
+const usb_endpoint_description_t *usb_hid_endpoints[] = {
+	&usb_hid_kbd_poll_endpoint_description,
+	&usb_hid_mouse_poll_endpoint_description,
+	&usb_hid_generic_poll_endpoint_description,
+	NULL
+};
+
+static int usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL);
+	assert(hid_dev->subdriver_count == 0);
+
+	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+	hid_dev->subdriver_count = 1;
+	// TODO 0 should be keyboard, but find a better way
+	hid_dev->subdrivers[0] = usb_hid_subdrivers[0].subdriver;
+
+	return EOK;
+}
+
+static int usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL);
+	assert(hid_dev->subdriver_count == 0);
+
+	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+	hid_dev->subdriver_count = 1;
+	// TODO 2 should be mouse, but find a better way
+	hid_dev->subdrivers[0] = usb_hid_subdrivers[2].subdriver;
+
+	return EOK;
+}
+
+static int usb_hid_set_generic_hid_subdriver(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL);
+	assert(hid_dev->subdriver_count == 0);
+
+	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+	hid_dev->subdriver_count = 1;
+
+	/* Set generic hid subdriver routines */
+	hid_dev->subdrivers[0].init = usb_generic_hid_init;
+	hid_dev->subdrivers[0].poll = usb_generic_hid_polling_callback;
+	hid_dev->subdrivers[0].poll_end = NULL;
+	hid_dev->subdrivers[0].deinit = usb_generic_hid_deinit;
+
+	return EOK;
+}
+
+static bool usb_hid_ids_match(const usb_hid_dev_t *hid_dev,
+    const usb_hid_subdriver_mapping_t *mapping)
+{
+	assert(hid_dev);
+	assert(hid_dev->usb_dev);
+	assert(mapping);
+	const usb_standard_device_descriptor_t *d =
+	    &usb_device_descriptors(hid_dev->usb_dev)->device;
+
+	return (d->vendor_id == mapping->vendor_id)
+	    && (d->product_id == mapping->product_id);
+}
+
+static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev,
+    const usb_hid_subdriver_mapping_t *mapping)
+{
+	assert(hid_dev != NULL);
+	assert(mapping != NULL);
+
+	usb_hid_report_path_t *usage_path = usb_hid_report_path();
+	if (usage_path == NULL) {
+		usb_log_debug("Failed to create usage path.\n");
+		return false;
+	}
+
+	for (int i = 0; mapping->usage_path[i].usage != 0
+	    || mapping->usage_path[i].usage_page != 0; ++i) {
+		if (usb_hid_report_path_append_item(usage_path,
+		    mapping->usage_path[i].usage_page,
+		    mapping->usage_path[i].usage) != EOK) {
+			usb_log_debug("Failed to append to usage path.\n");
+			usb_hid_report_path_free(usage_path);
+			return false;
+		}
+	}
+
+	usb_log_debug("Compare flags: %d\n", mapping->compare);
+
+	bool matches = false;
+	uint8_t report_id = mapping->report_id;
+
+	do {
+		usb_log_debug("Trying report id %u\n", report_id);
+		if (report_id != 0) {
+			usb_hid_report_path_set_report_id(usage_path,
+				report_id);
+		}
+
+		const usb_hid_report_field_t *field =
+		    usb_hid_report_get_sibling(
+		        &hid_dev->report, NULL, usage_path, mapping->compare,
+		        USB_HID_REPORT_TYPE_INPUT);
+
+		usb_log_debug("Field: %p\n", field);
+
+		if (field != NULL) {
+			matches = true;
+			break;
+		}
+
+		report_id = usb_hid_get_next_report_id(
+		    &hid_dev->report, report_id, USB_HID_REPORT_TYPE_INPUT);
+	} while (!matches && report_id != 0);
+
+	usb_hid_report_path_free(usage_path);
+
+	return matches;
+}
+
+static int usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev,
+    const usb_hid_subdriver_t **subdrivers, unsigned count)
+{
+	assert(hid_dev);
+	assert(subdrivers);
+
+	if (count == 0) {
+		hid_dev->subdriver_count = 0;
+		hid_dev->subdrivers = NULL;
+		return EOK;
+	}
+
+	/* +1 for generic hid subdriver */
+	hid_dev->subdrivers = calloc((count + 1), sizeof(usb_hid_subdriver_t));
+	if (hid_dev->subdrivers == NULL) {
+		return ENOMEM;
+	}
+
+	for (unsigned i = 0; i < count; ++i) {
+		hid_dev->subdrivers[i] = *subdrivers[i];
+	}
+
+	/* Add one generic HID subdriver per device */
+	hid_dev->subdrivers[count].init = usb_generic_hid_init;
+	hid_dev->subdrivers[count].poll = usb_generic_hid_polling_callback;
+	hid_dev->subdrivers[count].deinit = usb_generic_hid_deinit;
+	hid_dev->subdrivers[count].poll_end = NULL;
+
+	hid_dev->subdriver_count = count + 1;
+
+	return EOK;
+}
+
+static int usb_hid_find_subdrivers(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL);
+
+	const usb_hid_subdriver_t *subdrivers[USB_HID_MAX_SUBDRIVERS];
+	unsigned count = 0;
+
+	for (unsigned i = 0; i < USB_HID_MAX_SUBDRIVERS; ++i) {
+		const usb_hid_subdriver_mapping_t *mapping =
+		    &usb_hid_subdrivers[i];
+		/* Check the vendor & product ID. */
+		if (mapping->vendor_id >= 0 && mapping->product_id < 0) {
+			usb_log_warning("Mapping[%d]: Missing Product ID for "
+			    "Vendor ID %d\n", i, mapping->vendor_id);
+		}
+		if (mapping->product_id >= 0 && mapping->vendor_id < 0) {
+			usb_log_warning("Mapping[%d]: Missing Vendor ID for "
+			    "Product ID %d\n", i, mapping->product_id);
+		}
+
+		bool matched = false;
+
+		/* Check ID match. */
+		if (mapping->vendor_id >= 0 && mapping->product_id >= 0) {
+			usb_log_debug("Comparing device against vendor ID %u"
+			    " and product ID %u.\n", mapping->vendor_id,
+			    mapping->product_id);
+			if (usb_hid_ids_match(hid_dev, mapping)) {
+				usb_log_debug("IDs matched.\n");
+				matched = true;
+			}
+		}
+
+		/* Check usage match. */
+		if (mapping->usage_path != NULL) {
+			usb_log_debug("Comparing device against usage path.\n");
+			if (usb_hid_path_matches(hid_dev, mapping)) {
+				/* Does not matter if IDs were matched. */
+				matched = true;
+			}
+		}
+
+		if (matched) {
+			usb_log_debug("Subdriver matched.\n");
+			subdrivers[count++] = &mapping->subdriver;
+		}
+	}
+
+	/* We have all subdrivers determined, save them into the hid device */
+	return usb_hid_save_subdrivers(hid_dev, subdrivers, count);
+}
+
+static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
+{
+	assert(hid_dev);
+	assert(dev);
+
+	static const struct {
+		const usb_endpoint_description_t *desc;
+		const char* description;
+	} endpoints[] = {
+		{&usb_hid_kbd_poll_endpoint_description, "Keyboard endpoint"},
+		{&usb_hid_mouse_poll_endpoint_description, "Mouse endpoint"},
+		{&usb_hid_generic_poll_endpoint_description, "Generic HID endpoint"},
+	};
+
+	for (unsigned i = 0; i < ARRAY_SIZE(endpoints); ++i) {
+		usb_endpoint_mapping_t *epm =
+		    usb_device_get_mapped_ep_desc(dev, endpoints[i].desc);
+		if (epm && epm->present) {
+			usb_log_debug("Found: %s.\n", endpoints[i].description);
+			hid_dev->poll_pipe_mapping = epm;
+			return EOK;
+		}
+	}
+	return ENOTSUP;
+}
+
+static int usb_hid_init_report(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev != NULL);
+
+	uint8_t report_id = 0;
+	size_t max_size = 0;
+
+	do {
+		usb_log_debug("Getting size of the report.\n");
+		const size_t size =
+		    usb_hid_report_byte_size(&hid_dev->report, report_id,
+		        USB_HID_REPORT_TYPE_INPUT);
+		usb_log_debug("Report ID: %u, size: %zu\n", report_id, size);
+		max_size = (size > max_size) ? size : max_size;
+		usb_log_debug("Getting next report ID\n");
+		report_id = usb_hid_get_next_report_id(&hid_dev->report,
+		    report_id, USB_HID_REPORT_TYPE_INPUT);
+	} while (report_id != 0);
+
+	usb_log_debug("Max size of input report: %zu\n", max_size);
+
+	assert(hid_dev->input_report == NULL);
+
+	hid_dev->input_report = calloc(1, max_size);
+	if (hid_dev->input_report == NULL) {
+		return ENOMEM;
+	}
+	hid_dev->max_input_report_size = max_size;
+
+	return EOK;
+}
+
+/*
+ * This functions initializes required structures from the device's descriptors
+ * and starts new fibril for polling the keyboard for events and another one for
+ * handling auto-repeat of keys.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on 
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and 
+ *       other locks turned off.
+ *
+ * @param hid_dev Device to initialize, non-NULL.
+ * @param dev USB device, non-NULL.
+ * @return Error code.
+ */
+int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
+{
+	assert(hid_dev);
+	assert(dev);
+
+	usb_log_debug("Initializing HID structure...\n");
+
+	usb_hid_report_init(&hid_dev->report);
+
+	/* The USB device should already be initialized, save it in structure */
+	hid_dev->usb_dev = dev;
+	hid_dev->poll_pipe_mapping = NULL;
+
+	int rc = usb_hid_check_pipes(hid_dev, dev);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Get the report descriptor and parse it. */
+	rc = usb_hid_process_report_descriptor(
+	    hid_dev->usb_dev, &hid_dev->report, &hid_dev->report_desc,
+	    &hid_dev->report_desc_size);
+
+	/* If report parsing went well, find subdrivers. */
+	if (rc == EOK) {
+		usb_hid_find_subdrivers(hid_dev);
+	} else {
+		usb_log_error("Failed to parse report descriptor: fallback.\n");
+		hid_dev->subdrivers = NULL;
+		hid_dev->subdriver_count = 0;
+	}
+
+	usb_log_debug("Subdriver count(before trying boot protocol): %d\n",
+	    hid_dev->subdriver_count);
+
+	/* No subdrivers, fall back to the boot protocol if available. */
+	if (hid_dev->subdriver_count == 0) {
+		assert(hid_dev->subdrivers == NULL);
+		usb_log_info("No subdrivers found to handle device, trying "
+		    "boot protocol.\n");
+
+		switch (hid_dev->poll_pipe_mapping->interface->interface_protocol) {
+		case USB_HID_PROTOCOL_KEYBOARD:
+			usb_log_info("Falling back to kbd boot protocol.\n");
+			rc = usb_kbd_set_boot_protocol(hid_dev);
+			if (rc == EOK) {
+				usb_hid_set_boot_kbd_subdriver(hid_dev);
+			}
+			break;
+		case USB_HID_PROTOCOL_MOUSE:
+			usb_log_info("Falling back to mouse boot protocol.\n");
+			rc = usb_mouse_set_boot_protocol(hid_dev);
+			if (rc == EOK) {
+				usb_hid_set_boot_mouse_subdriver(hid_dev);
+			}
+			break;
+		default:
+			usb_log_info("Falling back to generic HID driver.\n");
+			usb_hid_set_generic_hid_subdriver(hid_dev);
+		}
+	}
+
+	usb_log_debug("Subdriver count(after trying boot protocol): %d\n",
+	    hid_dev->subdriver_count);
+
+	/* Still no subdrivers? */
+	if (hid_dev->subdriver_count == 0) {
+		assert(hid_dev->subdrivers == NULL);
+		usb_log_error(
+		    "No subdriver for handling this device could be found.\n");
+		return ENOTSUP;
+	}
+
+	/* Initialize subdrivers */
+	bool ok = false;
+	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
+		if (hid_dev->subdrivers[i].init != NULL) {
+			usb_log_debug("Initializing subdriver %d.\n",i);
+			const int pret = hid_dev->subdrivers[i].init(hid_dev,
+			    &hid_dev->subdrivers[i].data);
+			if (pret != EOK) {
+				usb_log_warning("Failed to initialize"
+				    " HID subdriver structure: %s.\n",
+				    str_error(pret));
+				rc = pret;
+			} else {
+				/* At least one subdriver initialized. */
+				ok = true;
+			}
+		} else {
+			/* Does not need initialization. */
+			ok = true;
+		}
+	}
+
+	if (ok) {
+		/* Save max input report size and
+		 * allocate space for the report */
+		rc = usb_hid_init_report(hid_dev);
+		if (rc != EOK) {
+			usb_log_error("Failed to initialize input report buffer"
+			    ".\n");
+		}
+	}
+
+	return rc;
+}
+
+bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
+    size_t buffer_size, void *arg)
+{
+	if (dev == NULL || arg == NULL || buffer == NULL) {
+		usb_log_error("Missing arguments to polling callback.\n");
+		return false;
+	}
+	usb_hid_dev_t *hid_dev = arg;
+
+	assert(hid_dev->input_report != NULL);
+
+	usb_log_debug("New data [%zu/%zu]: %s\n", buffer_size,
+	    hid_dev->max_input_report_size,
+	    usb_debug_str_buffer(buffer, buffer_size, 0));
+
+	if (hid_dev->max_input_report_size >= buffer_size) {
+		/*! @todo This should probably be atomic. */
+		memcpy(hid_dev->input_report, buffer, buffer_size);
+		hid_dev->input_report_size = buffer_size;
+		usb_hid_new_report(hid_dev);
+	}
+
+	/* Parse the input report */
+	const int rc = usb_hid_parse_report(
+	    &hid_dev->report, buffer, buffer_size, &hid_dev->report_id);
+	if (rc != EOK) {
+		usb_log_warning("Failure in usb_hid_parse_report():"
+		    "%s\n", str_error(rc));
+	}
+
+	bool cont = false;
+	/* Continue if at least one of the subdrivers want to continue */
+	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
+		if (hid_dev->subdrivers[i].poll != NULL) {
+			cont = cont || hid_dev->subdrivers[i].poll(
+			    hid_dev, hid_dev->subdrivers[i].data);
+		}
+	}
+
+	return cont;
+}
+
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, void *arg)
+{
+	assert(dev);
+	assert(arg);
+
+	usb_hid_dev_t *hid_dev = arg;
+
+	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
+		if (hid_dev->subdrivers[i].poll_end != NULL) {
+			hid_dev->subdrivers[i].poll_end(
+			    hid_dev, hid_dev->subdrivers[i].data, reason);
+		}
+	}
+
+	hid_dev->running = false;
+}
+
+void usb_hid_new_report(usb_hid_dev_t *hid_dev)
+{
+	++hid_dev->report_nr;
+}
+
+int usb_hid_report_number(const usb_hid_dev_t *hid_dev)
+{
+	return hid_dev->report_nr;
+}
+
+void usb_hid_deinit(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev);
+	assert(hid_dev->subdrivers != NULL || hid_dev->subdriver_count == 0);
+
+
+	usb_log_debug("Subdrivers: %p, subdriver count: %d\n", 
+	    hid_dev->subdrivers, hid_dev->subdriver_count);
+
+	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
+		if (hid_dev->subdrivers[i].deinit != NULL) {
+			hid_dev->subdrivers[i].deinit(hid_dev,
+			    hid_dev->subdrivers[i].data);
+		}
+	}
+
+	/* Free allocated structures */
+	free(hid_dev->subdrivers);
+	free(hid_dev->report_desc);
+
+	/* Destroy the parser */
+	usb_hid_report_deinit(&hid_dev->report);
+
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/usbhid.h
===================================================================
--- uspace/drv/hid/usbhid/usbhid.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/usbhid.h	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * USB HID driver API.
+ */
+
+#ifndef USB_HID_USBHID_H_
+#define USB_HID_USBHID_H_
+
+#include <stdint.h>
+
+#include <usb/hid/hidparser.h>
+#include <ddf/driver.h>
+#include <usb/dev/pipes.h>
+#include <usb/dev/driver.h>
+#include <usb/hid/hid.h>
+#include <stdbool.h>
+
+typedef struct usb_hid_dev usb_hid_dev_t;
+typedef struct usb_hid_subdriver usb_hid_subdriver_t;
+
+/** Subdriver initialization callback.
+ *
+ * @param dev Backing USB HID device.
+ * @param data Custom subdriver data (pointer where to store them).
+ * @return Error code.
+ */
+typedef int (*usb_hid_driver_init_t)(usb_hid_dev_t *dev, void **data);
+
+/** Subdriver deinitialization callback.
+ *
+ * @param dev Backing USB HID device.
+ * @param data Custom subdriver data.
+ */
+typedef void (*usb_hid_driver_deinit_t)(usb_hid_dev_t *dev, void *data);
+
+/** Subdriver callback on data from device.
+ *
+ * @param dev Backing USB HID device.
+ * @param data Custom subdriver data.
+ * @return Whether to continue polling (typically true always).
+ */
+typedef bool (*usb_hid_driver_poll_t)(usb_hid_dev_t *dev, void *data);
+
+/** Subdriver callback after communication with the device ceased.
+ *
+ * @param dev Backing USB HID device.
+ * @param data Custom subdriver data.
+ * @param ended_due_to_errors Whether communication ended due to errors in
+ *	communication (true) or deliberately by driver (false).
+ */
+typedef void (*usb_hid_driver_poll_ended_t)(usb_hid_dev_t *dev, void *data,
+    bool ended_due_to_errors);
+
+struct usb_hid_subdriver {
+	/** Function to be called when initializing HID device. */
+	usb_hid_driver_init_t init;
+	/** Function to be called when destroying the HID device structure. */
+	usb_hid_driver_deinit_t deinit;
+	/** Function to be called when data arrives from the device. */
+	usb_hid_driver_poll_t poll;
+	/** Function to be called when polling ends. */
+	usb_hid_driver_poll_ended_t poll_end;
+	/** Arbitrary data needed by the subdriver. */
+	void *data;
+};
+
+
+/**
+ * Structure for holding general HID device data.
+ */
+struct usb_hid_dev {
+	/** Structure holding generic USB device information. */
+	usb_device_t *usb_dev;
+
+	/** Endpont mapping of the polling pipe. */
+	usb_endpoint_mapping_t *poll_pipe_mapping;
+
+	/** Subdrivers. */
+	usb_hid_subdriver_t *subdrivers;
+
+	/** Number of subdrivers. */
+	unsigned subdriver_count;
+
+	/** Report descriptor. */
+	uint8_t *report_desc;
+
+	/** Report descriptor size. */
+	size_t report_desc_size;
+
+	/** HID Report parser. */
+	usb_hid_report_t report;
+
+	uint8_t report_id;
+
+	uint8_t *input_report;
+
+	size_t input_report_size;
+	size_t max_input_report_size;
+
+	int report_nr;
+	volatile bool running;
+};
+
+extern const usb_endpoint_description_t *usb_hid_endpoints[];
+
+int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev);
+
+void usb_hid_deinit(usb_hid_dev_t *hid_dev);
+
+bool usb_hid_polling_callback(usb_device_t *dev,
+    uint8_t *buffer, size_t buffer_size, void *arg);
+
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, void *arg);
+
+void usb_hid_new_report(usb_hid_dev_t *hid_dev);
+
+int usb_hid_report_number(const usb_hid_dev_t *hid_dev);
+
+#endif /* USB_HID_USBHID_H_ */
+
+/**
+ * @}
+ */
Index: uspace/drv/hid/usbhid/usbhid.ma
===================================================================
--- uspace/drv/hid/usbhid/usbhid.ma	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
+++ uspace/drv/hid/usbhid/usbhid.ma	(revision 53b9f2c3825e0a362ac71ad50183265aa5d20115)
@@ -0,0 +1,3 @@
+1000 usb&interface&class=HID&subclass=0x01&protocol=0x01
+1000 usb&interface&class=HID&subclass=0x01&protocol=0x02
+100 usb&interface&class=HID
