Index: uspace/app/usbinfo/dump.c
===================================================================
--- uspace/app/usbinfo/dump.c	(revision e7b95417778edab3ef17565af850cd0937a29834)
+++ uspace/app/usbinfo/dump.c	(revision 0c05496f204beecce9084ee85523c0e663429449)
@@ -69,4 +69,17 @@
 }
 
+void dump_match_ids(match_id_list_t *matches)
+{
+	printf("Match ids:\n");
+	link_t *link;
+	for (link = matches->ids.next;
+	    link != &matches->ids;
+	    link = link->next) {
+		match_id_t *match = list_get_instance(link, match_id_t, link);
+
+		printf(INDENT "%d %s\n", match->score, match->id);
+	}
+}
+
 void dump_standard_device_descriptor(usb_standard_device_descriptor_t *d)
 {
Index: uspace/app/usbinfo/main.c
===================================================================
--- uspace/app/usbinfo/main.c	(revision e7b95417778edab3ef17565af850cd0937a29834)
+++ uspace/app/usbinfo/main.c	(revision 0c05496f204beecce9084ee85523c0e663429449)
@@ -112,4 +112,18 @@
 
 	/*
+	 * Dump information about possible match ids.
+	 */
+	match_id_list_t match_id_list;
+	init_match_ids(&match_id_list);
+	rc = usb_drv_create_device_match_ids(hc_phone, &match_id_list, address);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to fetch match ids of the device: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	dump_match_ids(&match_id_list);
+
+	/*
 	 * Get device descriptor and dump it.
 	 */
Index: uspace/app/usbinfo/usbinfo.h
===================================================================
--- uspace/app/usbinfo/usbinfo.h	(revision e7b95417778edab3ef17565af850cd0937a29834)
+++ uspace/app/usbinfo/usbinfo.h	(revision 0c05496f204beecce9084ee85523c0e663429449)
@@ -39,4 +39,5 @@
 #include <usb/descriptor.h>
 #include <usb/debug.h>
+#include <ipc/devman.h>
 
 
@@ -44,4 +45,5 @@
 
 void dump_buffer(const char *, const uint8_t *, size_t);
+void dump_match_ids(match_id_list_t *matches);
 void dump_standard_device_descriptor(usb_standard_device_descriptor_t *);
 void dump_standard_configuration_descriptor(int, 
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision e7b95417778edab3ef17565af850cd0937a29834)
+++ uspace/lib/usb/Makefile	(revision 0c05496f204beecce9084ee85523c0e663429449)
@@ -34,4 +34,5 @@
 SOURCES = \
 	src/addrkeep.c \
+	src/class.c \
 	src/debug.c \
 	src/drvpsync.c \
@@ -40,4 +41,5 @@
 	src/hidparser.c \
 	src/localdrv.c \
+	src/recognise.c \
 	src/remotedrv.c \
 	src/usb.c \
Index: uspace/lib/usb/include/usb/classes/classes.h
===================================================================
--- uspace/lib/usb/include/usb/classes/classes.h	(revision e7b95417778edab3ef17565af850cd0937a29834)
+++ uspace/lib/usb/include/usb/classes/classes.h	(revision 0c05496f204beecce9084ee85523c0e663429449)
@@ -60,4 +60,5 @@
 } usb_class_t;
 
+const char *usb_str_class(usb_class_t);
 
 #endif
Index: uspace/lib/usb/include/usb/usbdrv.h
===================================================================
--- uspace/lib/usb/include/usb/usbdrv.h	(revision e7b95417778edab3ef17565af850cd0937a29834)
+++ uspace/lib/usb/include/usb/usbdrv.h	(revision 0c05496f204beecce9084ee85523c0e663429449)
@@ -94,4 +94,8 @@
 int usb_drv_async_wait_for(usb_handle_t);
 
+int usb_drv_create_device_match_ids(int, match_id_list_t *, usb_address_t);
+int usb_drv_register_child_in_devman(int, device_t *, usb_address_t,
+    devman_handle_t *);
+
 
 #endif
Index: uspace/lib/usb/src/class.c
===================================================================
--- uspace/lib/usb/src/class.c	(revision 0c05496f204beecce9084ee85523c0e663429449)
+++ uspace/lib/usb/src/class.c	(revision 0c05496f204beecce9084ee85523c0e663429449)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2010 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Class related functions.
+ */
+#include <usb/classes/classes.h>
+#include <errno.h>
+
+/** Tell string representation of USB class.
+ *
+ * @param cls Class code.
+ * @return String representation.
+ */
+const char *usb_str_class(usb_class_t cls)
+{
+	switch (cls) {
+		case USB_CLASS_USE_INTERFACE:
+			return "use-interface";
+		case USB_CLASS_AUDIO:
+			return "audio";
+		case USB_CLASS_COMMUNICATIONS_CDC_CONTROL:
+			return "communications";
+		case USB_CLASS_HID:
+			return "HID";
+		case USB_CLASS_PHYSICAL:
+			return "physical";
+		case USB_CLASS_IMAGE:
+			return "image";
+		case USB_CLASS_PRINTER:
+			return "printer";
+		case USB_CLASS_MASS_STORAGE:
+			return "mass-storage";
+		case USB_CLASS_HUB:
+			return "hub";
+		case USB_CLASS_CDC_DATA:
+			return "CDC";
+		case USB_CLASS_SMART_CARD:
+			return "smart-card";
+		case USB_CLASS_CONTENT_SECURITY:
+			return "security";
+		case USB_CLASS_VIDEO:
+			return "video";
+		case USB_CLASS_PERSONAL_HEALTHCARE:
+			return "healthcare";
+		case USB_CLASS_DIAGNOSTIC:
+			return "diagnostic";
+		case USB_CLASS_WIRELESS_CONTROLLER:
+			return "wireless";
+		case USB_CLASS_MISCELLANEOUS:
+			return "misc";
+		case USB_CLASS_APPLICATION_SPECIFIC:
+			return "application";
+		case USB_CLASS_VENDOR_SPECIFIC:
+			return "vendor";
+		default:
+			return "unknown";
+	}
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/recognise.c
===================================================================
--- uspace/lib/usb/src/recognise.c	(revision 0c05496f204beecce9084ee85523c0e663429449)
+++ uspace/lib/usb/src/recognise.c	(revision 0c05496f204beecce9084ee85523c0e663429449)
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2010 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Functions for recognising kind of attached devices.
+ */
+#include <usb/usbdrv.h>
+#include <usb/classes/classes.h>
+#include <stdio.h>
+#include <errno.h>
+
+
+#define BCD_INT(a) (((unsigned int)(a)) / 256)
+#define BCD_FRAC(a) (((unsigned int)(a)) % 256)
+
+#define BCD_FMT "%x.%x"
+#define BCD_ARGS(a) BCD_INT((a)), BCD_FRAC((a))
+
+/* FIXME: make this dynamic */
+#define MATCH_STRING_MAX 256
+
+/** Add formatted match id.
+ *
+ * @param matches List of match ids where to add to.
+ * @param score Score of the match.
+ * @param format Printf-like format
+ * @return Error code.
+ */
+static int usb_add_match_id(match_id_list_t *matches, int score,
+    const char *format, ...)
+{
+	char *match_str = NULL;
+	match_id_t *match_id = NULL;
+	int rc;
+	
+	match_str = malloc(MATCH_STRING_MAX + 1);
+	if (match_str == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	/*
+	 * FIXME: replace with dynamic allocation of exact size
+	 */
+	va_list args;
+	va_start(args, format	);
+	vsnprintf(match_str, MATCH_STRING_MAX, format, args);
+	match_str[MATCH_STRING_MAX] = 0;
+	va_end(args);
+
+	match_id = create_match_id();
+	if (match_id == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	match_id->id = match_str;
+	match_id->score = score;
+	add_match_id(matches, match_id);
+
+	return EOK;
+	
+failure:
+	if (match_str != NULL) {
+		free(match_str);
+	}
+	if (match_id != NULL) {
+		match_id->id = NULL;
+		delete_match_id(match_id);
+	}
+	
+	return rc;
+}
+
+/** Create match ids describing attached device.
+ *
+ * @warning The list of match ids @p matches may change even when
+ * function exits with error.
+ *
+ * @param hc Open phone to host controller.
+ * @param matches Initialized list of match ids.
+ * @param address USB address of the attached device.
+ * @return Error code.
+ */
+int usb_drv_create_device_match_ids(int hc, match_id_list_t *matches,
+    usb_address_t address)
+{
+	int rc;
+	usb_standard_device_descriptor_t device_descriptor;
+
+	rc = usb_drv_req_get_device_descriptor(hc, address,
+	    &device_descriptor);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/*
+	 * Unless the vendor id is 0, the pair idVendor-idProduct
+	 * quite uniquely describes the device.
+	 */
+	if (device_descriptor.vendor_id != 0) {
+		/* First, with release number. */
+		rc = usb_add_match_id(matches, 100,
+		    "usb&vendor=%d&product=%d&release=" BCD_FMT,
+		    (int) device_descriptor.vendor_id,
+		    (int) device_descriptor.product_id,
+		    BCD_ARGS(device_descriptor.device_version));
+		if (rc != EOK) {
+			return rc;
+		}
+		
+		/* Next, without release number. */
+		rc = usb_add_match_id(matches, 90, "usb&vendor=%d&product=%d",
+		    (int) device_descriptor.vendor_id,
+		    (int) device_descriptor.product_id);
+		if (rc != EOK) {
+			return rc;
+		}
+
+	}	
+
+	/*
+	 * If the device class does not point to interface,
+	 * it is added immediatelly, otherwise full configuration
+	 * descriptor must be obtained and parsed.
+	 */
+	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 {
+		/* TODO */
+	}
+
+	/*
+	 * As a fallback, provide the simplest match id possible.
+	 */
+	rc = usb_add_match_id(matches, 1, "usb&fallback");
+	if (rc != EOK) {
+		return rc;
+	}
+
+	return EOK;
+}
+
+
+/** Probe for device kind and register it in devman.
+ *
+ * @param hc Open phone to the host controller.
+ * @param parent Parent device.
+ * @param address Address of the (unknown) attached device.
+ * @return Error code.
+ */
+int usb_drv_register_child_in_devman(int hc, device_t *parent,
+    usb_address_t address, devman_handle_t *child_handle)
+{
+	device_t *child = NULL;
+	char *child_name = NULL;
+	int rc;
+
+	child = create_device();
+	if (child == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	/*
+	 * TODO: some better child naming
+	 */
+	rc = asprintf(&child_name, "usb%p", child);
+	if (rc < 0) {
+		goto failure;
+	}
+	child->name = child_name;
+	
+	rc = usb_drv_create_device_match_ids(hc, &child->match_ids, address);
+	if (rc != EOK) {
+		goto failure;
+	}
+
+	rc = child_device_register(child, parent);
+	if (rc != EOK) {
+		goto failure;
+	}
+
+	if (child_handle != NULL) {
+		*child_handle = child->handle;
+	}
+	
+	return EOK;
+
+failure:
+	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;
+
+}
+
+
+/**
+ * @}
+ */
