Index: .bzrignore
===================================================================
--- .bzrignore	(revision 540e2d2d349d99aec0ff607211896ef70e96f23d)
+++ .bzrignore	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -88,4 +88,5 @@
 ./uspace/drv/usbhub/usbhub
 ./uspace/drv/usbhid/usbhid
+./uspace/drv/usbmid/usbmid
 ./uspace/drv/vhc/vhc
 ./uspace/srv/bd/ata_bd/ata_bd
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision 540e2d2d349d99aec0ff607211896ef70e96f23d)
+++ boot/arch/amd64/Makefile.inc	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -47,4 +47,5 @@
 	usbhub \
 	usbhid \
+	usbmid \
 	vhc
 
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 540e2d2d349d99aec0ff607211896ef70e96f23d)
+++ uspace/Makefile	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -121,4 +121,5 @@
 		drv/usbhid \
 		drv/usbhub \
+		drv/usbmid \
 		drv/vhc
 endif
@@ -136,4 +137,5 @@
 		drv/usbhid \
 		drv/usbhub \
+		drv/usbmid \
 		drv/vhc
 endif
Index: uspace/doc/doxygroups.h
===================================================================
--- uspace/doc/doxygroups.h	(revision 540e2d2d349d99aec0ff607211896ef70e96f23d)
+++ uspace/doc/doxygroups.h	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -220,4 +220,17 @@
 
 	/**
+	 * @defgroup drvusbmid USB multi interface device driver
+	 * @ingroup usb
+	 * @brief USB multi interface device driver
+	 * @details
+	 * This driver serves as a mini hub (or bus) driver for devices
+	 * that have the class defined at interface level (those devices
+	 * usually have several interfaces).
+	 *
+	 * The term multi interface device driver (MID) was borrowed
+	 * Solaris operating system.
+	 */
+
+	/**
 	 * @defgroup drvusbhub USB hub driver
 	 * @ingroup usb
Index: uspace/drv/usbmid/Makefile
===================================================================
--- uspace/drv/usbmid/Makefile	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
+++ uspace/drv/usbmid/Makefile	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2011 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBUSB_PREFIX)/include
+BINARY = usbmid
+
+SOURCES = \
+	dump.c \
+	explore.c \
+	main.c \
+	usbmid.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbmid/dump.c
===================================================================
--- uspace/drv/usbmid/dump.c	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
+++ uspace/drv/usbmid/dump.c	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -0,0 +1,120 @@
+/*
+ * 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 drvusbmid
+ * @{
+ */
+/**
+ * @file
+ * Dumping and debugging functions.
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <stdlib.h>
+#include <usb/pipes.h>
+#include <usb/dp.h>
+#include <usb/classes/classes.h>
+#include "usbmid.h"
+
+/** Dump found descriptor.
+ *
+ * @param data Descriptor data.
+ * @param depth Nesting depth.
+ */
+static void dump_tree_descriptor(uint8_t *data, size_t depth)
+{
+	if (data == NULL) {
+		return;
+	}
+	int type = (int) *(data + 1);
+	if (type == USB_DESCTYPE_INTERFACE) {
+		usb_standard_interface_descriptor_t *descriptor
+		    = (usb_standard_interface_descriptor_t *) data;
+		usb_log_info("Found interface: %s (0x%02x/0x%02x/0x%02x).\n",
+		    usb_str_class(descriptor->interface_class),
+		    (int) descriptor->interface_class,
+		    (int) descriptor->interface_subclass,
+		    (int) descriptor->interface_protocol);
+	}
+}
+
+/** Dump tree of descriptors.
+ *
+ * @param parser Descriptor parser.
+ * @param data Descriptor parser data.
+ * @param root Pointer to current root.
+ * @param depth Nesting depth.
+ */
+static void dump_tree_internal(usb_dp_parser_t *parser, usb_dp_parser_data_t *data,
+    uint8_t *root, size_t depth)
+{
+	if (root == NULL) {
+		return;
+	}
+	dump_tree_descriptor(root, depth);
+	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	do {
+		dump_tree_internal(parser, data, child, depth + 1);
+		child = usb_dp_get_sibling_descriptor(parser, data, root, child);
+	} while (child != NULL);
+}
+
+/** Dump descriptor tree.
+ *
+ * @param parser Descriptor parser.
+ * @param data Descriptor parser data.
+ */
+static void dump_tree(usb_dp_parser_t *parser, usb_dp_parser_data_t *data)
+{
+	uint8_t *ptr = data->data;
+	dump_tree_internal(parser, data, ptr, 0);
+}
+
+/** Dump given descriptors.
+ *
+ * @param descriptors Descriptors buffer (typically full config descriptor).
+ * @param length Size of @p descriptors buffer in bytes.
+ */
+void usbmid_dump_descriptors(uint8_t *descriptors, size_t length)
+{
+	usb_dp_parser_data_t data = {
+		.data = descriptors,
+		.size = length,
+		.arg = NULL
+	};
+
+	usb_dp_parser_t parser = {
+		.nesting = usb_dp_standard_descriptor_nesting
+	};
+
+	dump_tree(&parser, &data);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmid/explore.c
===================================================================
--- uspace/drv/usbmid/explore.c	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
+++ uspace/drv/usbmid/explore.c	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -0,0 +1,236 @@
+/*
+ * 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 drvusbmid
+ * @{
+ */
+/**
+ * @file
+ * Exploration of available interfaces in the USB device.
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <stdlib.h>
+#include <usb/classes/classes.h>
+#include <usb/request.h>
+#include <usb/dp.h>
+#include "usbmid.h"
+
+/** Allocate and retrieve full configuration descriptor.
+ *
+ * @param[in] dev USB device.
+ * @param[in] config_index Configuration index.
+ * @param[out] size Pointer where to store size of the allocated buffer.
+ * @return Allocated full configuration descriptor.
+ * @retval NULL Error occured.
+ */
+static void *get_configuration_descriptor(usbmid_device_t *dev,
+    size_t config_index, size_t *size)
+{
+	usb_standard_configuration_descriptor_t config_descriptor;
+	int rc = usb_request_get_bare_configuration_descriptor(&dev->ctrl_pipe,
+	    config_index, &config_descriptor);
+	if (rc != EOK) {
+		usb_log_error("Failed getting configuration descriptor: %s.\n",
+		    str_error(rc));
+		return NULL;
+	}
+
+	void *full_config_descriptor = malloc(config_descriptor.total_length);
+	if (full_config_descriptor == NULL) {
+		usb_log_fatal("Out of memory (wanted: %zuB).\n",
+		    (size_t) config_descriptor.total_length);
+		return NULL;
+	}
+
+	size_t full_config_descriptor_size;
+	rc = usb_request_get_full_configuration_descriptor(&dev->ctrl_pipe,
+	    config_index,
+	    full_config_descriptor, config_descriptor.total_length,
+	    &full_config_descriptor_size);
+	if (rc != EOK) {
+		usb_log_error("Failed getting configuration descriptor: %s.\n",
+		    str_error(rc));
+		free(full_config_descriptor);
+		return NULL;
+	}
+
+	if (full_config_descriptor_size != config_descriptor.total_length) {
+		usb_log_error("Failed getting full configuration descriptor.\n");
+		free(full_config_descriptor);
+		return NULL;
+	}
+
+	if (size != NULL) {
+		*size = full_config_descriptor_size;
+	}
+
+	return full_config_descriptor;
+}
+
+/** Find starting indexes of all interface descriptors in a configuration.
+ *
+ * @param config_descriptor Full configuration descriptor.
+ * @param config_descriptor_size Size of @p config_descriptor in bytes.
+ * @param interface_positions Array where to store indexes of interfaces.
+ * @param interface_count Size of @p interface_positions array.
+ * @return Number of found interfaces.
+ * @retval (size_t)-1 Error occured.
+ */
+static size_t find_interface_descriptors(uint8_t *config_descriptor,
+    size_t config_descriptor_size,
+    size_t *interface_positions, size_t interface_count)
+{
+	if (interface_count == 0) {
+		return (size_t) -1;
+	}
+
+	usb_dp_parser_data_t data = {
+		.data = config_descriptor,
+		.size = config_descriptor_size,
+		.arg = NULL
+	};
+
+	usb_dp_parser_t parser = {
+		.nesting = usb_dp_standard_descriptor_nesting
+	};
+
+	uint8_t *interface = usb_dp_get_nested_descriptor(&parser, &data,
+	    data.data);
+	if (interface == NULL) {
+		return (size_t) -1;
+	}
+	if (interface[1] != USB_DESCTYPE_INTERFACE) {
+		return (size_t) -1;
+	}
+
+	size_t found_interfaces = 0;
+	interface_positions[found_interfaces] = interface - config_descriptor;
+	found_interfaces++;
+
+	while (interface != NULL) {
+		interface = usb_dp_get_sibling_descriptor(&parser, &data,
+		    data.data, interface);
+		if ((interface != NULL)
+		    && (found_interfaces < interface_count)
+		    && (interface[1] == USB_DESCTYPE_INTERFACE)) {
+			interface_positions[found_interfaces]
+			    = interface - config_descriptor;
+			found_interfaces++;
+		}
+	}
+
+	return found_interfaces;
+}
+
+/** Explore MID device.
+ *
+ * We expect that @p dev is initialized and session on control pipe is
+ * started.
+ *
+ * @param dev Device to be explored.
+ * @return Whether to accept this device from devman.
+ */
+bool usbmid_explore_device(usbmid_device_t *dev)
+{
+	usb_standard_device_descriptor_t device_descriptor;
+	int rc = usb_request_get_device_descriptor(&dev->ctrl_pipe,
+	    &device_descriptor);
+	if (rc != EOK) {
+		usb_log_error("Getting device descriptor failed: %s.\n",
+		    str_error(rc));
+		return false;
+	}
+
+	if (device_descriptor.device_class != USB_CLASS_USE_INTERFACE) {
+		usb_log_warning(
+		    "Device class: %d (%s), but expected class 0.\n",
+		    device_descriptor.device_class,
+		    usb_str_class(device_descriptor.device_class));
+		usb_log_error("Not multi interface device, refusing.\n");
+		return false;
+	}
+
+	size_t config_descriptor_size;
+	uint8_t *config_descriptor_raw = get_configuration_descriptor(dev, 0,
+	    &config_descriptor_size);
+	if (config_descriptor_raw == NULL) {
+		return false;
+	}
+
+	usb_standard_configuration_descriptor_t *config_descriptor
+	    = (usb_standard_configuration_descriptor_t *) config_descriptor_raw;
+
+	size_t *interface_descriptors
+	    = malloc(sizeof(size_t) * config_descriptor->interface_count);
+	if (interface_descriptors == NULL) {
+		usb_log_error("Out of memory (wanted %zuB).\n",
+		    sizeof(size_t) * config_descriptor->interface_count);
+		free(config_descriptor_raw);
+		return false;
+	}
+	size_t interface_descriptors_count
+	    = find_interface_descriptors(
+	    config_descriptor_raw, config_descriptor_size,
+	    interface_descriptors, config_descriptor->interface_count);
+
+	if (interface_descriptors_count == (size_t) -1) {
+		usb_log_error("Problem parsing configuration descriptor.\n");
+		free(config_descriptor_raw);
+		free(interface_descriptors);
+		return false;
+	}
+
+	usbmid_dump_descriptors(config_descriptor_raw, config_descriptor_size);
+
+	size_t i;
+	for (i = 0; i < interface_descriptors_count; i++) {
+		usb_standard_interface_descriptor_t *interface
+		    = (usb_standard_interface_descriptor_t *)
+		    (config_descriptor_raw + interface_descriptors[i]);
+		usb_log_debug("Interface descriptor at index %zu (type %d).\n",
+		    interface_descriptors[i], (int) interface->descriptor_type);
+		usb_log_info("Creating child for interface %d (%s).\n",
+		    (int) interface->interface_number,
+		    usb_str_class(interface->interface_class));
+		rc = usbmid_spawn_interface_child(dev, &device_descriptor,
+		    interface);
+		if (rc != EOK) {
+			usb_log_error("Failed to create interface child: %s.\n",
+			    str_error(rc));
+		}
+	}
+
+	free(config_descriptor_raw);
+
+	return true;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmid/main.c
===================================================================
--- uspace/drv/usbmid/main.c	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
+++ uspace/drv/usbmid/main.c	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -0,0 +1,108 @@
+/*
+ * 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 drvusbmid
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB multi interface device driver.
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <usb/debug.h>
+#include <usb/classes/classes.h>
+#include <usb/request.h>
+#include <usb/descriptor.h>
+#include <usb/pipes.h>
+
+#include "usbmid.h"
+
+static int usbmid_add_device(device_t *gen_dev)
+{
+	usbmid_device_t *dev = usbmid_device_create(gen_dev);
+	if (dev == NULL) {
+		usb_log_error("Initialization of new USB MID device failed.\n");
+		return ENOMEM;
+	}
+
+	usb_log_info("Taking care of new MID: addr %d (HC %zu)\n",
+	    dev->wire.address, dev->wire.hc_handle);
+
+	int rc;
+
+	rc = usb_endpoint_pipe_start_session(&dev->ctrl_pipe);
+	if (rc != EOK) {
+		usb_log_error("Failed to start session on control pipe: %s.\n",
+		    str_error(rc));
+		goto error_leave;
+	}
+
+	bool accept = usbmid_explore_device(dev);
+
+	rc = usb_endpoint_pipe_end_session(&dev->ctrl_pipe);
+	if (rc != EOK) {
+		usb_log_warning("Failed to end session on control pipe: %s.\n",
+		    str_error(rc));
+	}
+
+	if (!accept) {
+		rc = ENOTSUP;
+		goto error_leave;
+	}
+
+	gen_dev->driver_data = dev;
+
+	return EOK;
+
+
+error_leave:
+	free(dev);
+	return rc;
+}
+
+static driver_ops_t mid_driver_ops = {
+	.add_device = usbmid_add_device,
+};
+
+static driver_t mid_driver = {
+	.name = NAME,
+	.driver_ops = &mid_driver_ops
+};
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": USB multi interface device driver.\n");
+
+	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
+	return driver_main(&mid_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmid/usbmid.c
===================================================================
--- uspace/drv/usbmid/usbmid.c	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
+++ uspace/drv/usbmid/usbmid.c	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -0,0 +1,173 @@
+/*
+ * 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 drvusbmid
+ * @{
+ */
+/**
+ * @file
+ * Helper functions.
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <stdlib.h>
+#include <usb_iface.h>
+#include <usb/pipes.h>
+#include <usb/classes/classes.h>
+#include <usb/recognise.h>
+#include "usbmid.h"
+
+/** Callback for DDF USB interface. */
+static int iface_get_hc_handle(device_t *dev, devman_handle_t *handle)
+{
+	device_t *parent = dev->parent;
+
+	usb_log_debug("iface_get_hc_handle(dev=%zu)\n", (size_t) dev->handle);
+
+	if (parent && parent->ops && parent->ops->interfaces[USB_DEV_IFACE]) {
+		usb_iface_t *usb_iface
+		    = (usb_iface_t *) parent->ops->interfaces[USB_DEV_IFACE];
+		assert(usb_iface != NULL);
+		if (usb_iface->get_hc_handle) {
+			int rc = usb_iface->get_hc_handle(parent, handle);
+			return rc;
+		}
+		return ENOTSUP;
+	} else {
+		return usb_hc_find(dev->handle, handle);
+	}
+}
+
+static usb_iface_t usb_iface = {
+	.get_hc_handle = iface_get_hc_handle
+};
+
+static device_ops_t device_ops = {
+	.interfaces[USB_DEV_IFACE] = &usb_iface
+};
+
+/** Create new USB multi interface device.
+ *
+ * @param dev Backing generic DDF device.
+ * @return New USB MID device.
+ * @retval NULL Error occured.
+ */
+usbmid_device_t *usbmid_device_create(device_t *dev)
+{
+	usbmid_device_t *mid = malloc(sizeof(usbmid_device_t));
+	if (mid == NULL) {
+		return NULL;
+	}
+
+	int rc;
+	rc = usb_device_connection_initialize_from_device(&mid->wire, dev);
+	if (rc != EOK) {
+		free(mid);
+		return NULL;
+	}
+
+	rc = usb_endpoint_pipe_initialize_default_control(&mid->ctrl_pipe,
+	    &mid->wire);
+	if (rc != EOK) {
+		free(mid);
+		return NULL;
+	}
+
+	mid->dev = dev;
+	dev->ops = &device_ops;
+
+	return mid;
+}
+
+
+/** Spawn new child device from one interface.
+ *
+ * @param parent Parent MID device.
+ * @param device_descriptor Device descriptor.
+ * @param interface_descriptor Interface descriptor.
+ * @return Error code.
+ */
+int usbmid_spawn_interface_child(usbmid_device_t *parent,
+    const usb_standard_device_descriptor_t *device_descriptor,
+    const usb_standard_interface_descriptor_t *interface_descriptor)
+{
+	device_t *child = NULL;
+	char *child_name = NULL;
+	int rc;
+
+	/* Create the device. */
+	child = create_device();
+	if (child == NULL) {
+		rc = ENOMEM;
+		goto error_leave;
+	}
+
+	/*
+	 * Name is class name followed by interface number.
+	 * The interface number shall provide uniqueness while the
+	 * class name something humanly understandable.
+	 */
+	rc = asprintf(&child_name, "%s%d",
+	    usb_str_class(interface_descriptor->interface_class),
+	    (int) interface_descriptor->interface_number);
+	if (rc < 0) {
+		goto error_leave;
+	}
+	child->parent = parent->dev;
+	child->name = child_name;
+	child->ops = &device_ops;
+
+	rc = usb_device_create_match_ids_from_interface(interface_descriptor,
+	    &child->match_ids);
+	if (rc != EOK) {
+		goto error_leave;
+	}
+
+	rc = child_device_register(child, parent->dev);
+	if (rc != EOK) {
+		goto error_leave;
+	}
+
+	return EOK;
+
+error_leave:
+	if (child != NULL) {
+		child->name = NULL;
+		/* This takes care of match_id deallocation as well. */
+		delete_device(child);
+	}
+	if (child_name != NULL) {
+		free(child_name);
+	}
+
+	return rc;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbmid/usbmid.h
===================================================================
--- uspace/drv/usbmid/usbmid.h	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
+++ uspace/drv/usbmid/usbmid.h	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -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 drvusbmid
+ * @{
+ */
+/** @file
+ * Common definitions.
+ */
+
+#ifndef USBMID_H_
+#define USBMID_H_
+
+#include <driver.h>
+#include <usb/usb.h>
+#include <usb/pipes.h>
+#include <usb/debug.h>
+
+#define NAME "usbmid"
+
+typedef struct {
+	/** Device container. */
+	device_t *dev;
+
+	/** Representation of USB wire. */
+	usb_device_connection_t wire;
+	/** Default control pipe. */
+	usb_endpoint_pipe_t ctrl_pipe;
+} usbmid_device_t;
+
+usbmid_device_t *usbmid_device_create(device_t *);
+bool usbmid_explore_device(usbmid_device_t *);
+int usbmid_spawn_interface_child(usbmid_device_t *,
+    const usb_standard_device_descriptor_t *,
+    const usb_standard_interface_descriptor_t *);
+void usbmid_dump_descriptors(uint8_t *, size_t);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/usbmid/usbmid.ma
===================================================================
--- uspace/drv/usbmid/usbmid.ma	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
+++ uspace/drv/usbmid/usbmid.ma	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -0,0 +1,1 @@
+100 usb&mid
Index: uspace/lib/usb/src/recognise.c
===================================================================
--- uspace/lib/usb/src/recognise.c	(revision 540e2d2d349d99aec0ff607211896ef70e96f23d)
+++ uspace/lib/usb/src/recognise.c	(revision 3ae93a822febda099a86ca24250d39ee29ddb5f0)
@@ -231,9 +231,14 @@
 	/*
 	 * If the device class points to interface we skip adding
-	 * class directly.
+	 * class directly but we add a multi interface device.
 	 */
 	if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) {
 		rc = usb_add_match_id(matches, 50, "usb&class=%s",
 		    usb_str_class(device_descriptor->device_class));
+		if (rc != EOK) {
+			return rc;
+		}
+	} else {
+		rc = usb_add_match_id(matches, 50, "usb&mid");
 		if (rc != EOK) {
 			return rc;
