Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision bb41b8510c8359a9d0db89675e425ca4f828efff)
+++ uspace/lib/c/Makefile	(revision d8e61b0dff1803e2d084988ff419e8d7e75fddae)
@@ -65,4 +65,5 @@
 	generic/str.c \
 	generic/str_error.c \
+	generic/l18n/langs.c \
 	generic/fibril.c \
 	generic/fibril_synch.c \
Index: uspace/lib/c/generic/l18n/langs.c
===================================================================
--- uspace/lib/c/generic/l18n/langs.c	(revision d8e61b0dff1803e2d084988ff419e8d7e75fddae)
+++ uspace/lib/c/generic/l18n/langs.c	(revision d8e61b0dff1803e2d084988ff419e8d7e75fddae)
@@ -0,0 +1,76 @@
+/*
+ * 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 libc
+ * @{
+ */
+/** @file
+ * Language and locale ids.
+ */
+
+#include <l18n/langs.h>
+#include <stdio.h>
+#include <fibril.h>
+
+#define UNKNOWN_LOCALE_LEN 64
+
+static fibril_local char unknown_locale[UNKNOWN_LOCALE_LEN];
+
+/** Get string representation of a given locale.
+ *
+ * @param locale The locale.
+ * @return Name of the locale.
+ */
+const char *str_l18_win_locale(l18_win_locales_t locale)
+{
+	/*
+	 * Static array with names might be better but it would be
+	 * way too big.
+	 */
+	switch (locale) {
+		case L18N_WIN_LOCALE_AFRIKAANS:
+			return "Afrikaans";
+		case L18N_WIN_LOCALE_CZECH:
+			return "Czech";
+		case L18N_WIN_LOCALE_ENGLISH_UNITED_STATES:
+			return "English (US)";
+		case L18N_WIN_LOCALE_SLOVAK:
+			return "Slovak";
+		case L18N_WIN_LOCALE_SPANISH_TRADITIONAL:
+			return "Spanish (traditional)";
+		case L18N_WIN_LOCALE_ZULU:
+			return "Zulu";
+	}
+
+	snprintf(unknown_locale, UNKNOWN_LOCALE_LEN, "Unknown locale 0x%04d",
+	    (int) locale);
+	return unknown_locale;
+}
+
+/** @}
+ */
Index: uspace/lib/c/include/l18n/langs.h
===================================================================
--- uspace/lib/c/include/l18n/langs.h	(revision bb41b8510c8359a9d0db89675e425ca4f828efff)
+++ uspace/lib/c/include/l18n/langs.h	(revision d8e61b0dff1803e2d084988ff419e8d7e75fddae)
@@ -57,4 +57,6 @@
 } l18_win_locales_t;
 
+const char *str_l18_win_locale(l18_win_locales_t);
+
 #endif
 
Index: uspace/lib/usb/include/usb/dp.h
===================================================================
--- uspace/lib/usb/include/usb/dp.h	(revision bb41b8510c8359a9d0db89675e425ca4f828efff)
+++ uspace/lib/usb/include/usb/dp.h	(revision d8e61b0dff1803e2d084988ff419e8d7e75fddae)
@@ -77,4 +77,7 @@
     usb_dp_parser_data_t *, uint8_t *, uint8_t *);
 
+void usb_dp_walk_simple(uint8_t *, size_t, usb_dp_descriptor_nesting_t *,
+    void (*)(uint8_t *, size_t, void *), void *);
+
 #endif
 /**
Index: uspace/lib/usb/include/usb/pipes.h
===================================================================
--- uspace/lib/usb/include/usb/pipes.h	(revision bb41b8510c8359a9d0db89675e425ca4f828efff)
+++ uspace/lib/usb/include/usb/pipes.h	(revision d8e61b0dff1803e2d084988ff419e8d7e75fddae)
@@ -123,4 +123,5 @@
 
 int usb_device_get_assigned_interface(ddf_dev_t *);
+usb_address_t usb_device_get_assigned_address(devman_handle_t);
 
 int usb_endpoint_pipe_initialize(usb_endpoint_pipe_t *,
Index: uspace/lib/usb/src/dp.c
===================================================================
--- uspace/lib/usb/src/dp.c	(revision bb41b8510c8359a9d0db89675e425ca4f828efff)
+++ uspace/lib/usb/src/dp.c	(revision d8e61b0dff1803e2d084988ff419e8d7e75fddae)
@@ -258,4 +258,68 @@
 }
 
+/** Browser of the descriptor tree.
+ *
+ * @see usb_dp_walk_simple
+ *
+ * @param parser Descriptor parser.
+ * @param data Data for descriptor parser.
+ * @param root Pointer to current root of the tree.
+ * @param depth Current nesting depth.
+ * @param callback Callback for each found descriptor.
+ * @param arg Custom (user) argument.
+ */
+static void usb_dp_browse_simple_internal(usb_dp_parser_t *parser,
+    usb_dp_parser_data_t *data, uint8_t *root, size_t depth,
+    void (*callback)(uint8_t *, size_t, void *), void *arg)
+{
+	if (root == NULL) {
+		return;
+	}
+	callback(root, depth, arg);
+	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	do {
+		usb_dp_browse_simple_internal(parser, data, child, depth + 1,
+		    callback, arg);
+		child = usb_dp_get_sibling_descriptor(parser, data,
+		    root, child);
+	} while (child != NULL);
+}
+
+/** Browse flatten descriptor tree.
+ *
+ * The callback is called with following arguments: pointer to the start
+ * of the descriptor (somewhere inside @p descriptors), depth of the nesting
+ * (starting from 0 for the first descriptor) and the custom argument.
+ * Note that the size of the descriptor is not passed because it can
+ * be read from the first byte of the descriptor.
+ *
+ * @param descriptors Descriptor data.
+ * @param descriptors_size Size of descriptor data (in bytes).
+ * @param descriptor_nesting Possible descriptor nesting.
+ * @param callback Callback for each found descriptor.
+ * @param arg Custom (user) argument.
+ */
+void usb_dp_walk_simple(uint8_t *descriptors, size_t descriptors_size,
+    usb_dp_descriptor_nesting_t *descriptor_nesting,
+    void (*callback)(uint8_t *, size_t, void *), void *arg)
+{
+	if ((descriptors == NULL) || (descriptors_size == 0)
+	    || (descriptor_nesting == NULL) || (callback == NULL)) {
+		return;
+	}
+
+	usb_dp_parser_data_t data = {
+		.data = descriptors,
+		.size = descriptors_size,
+		.arg = NULL
+	};
+
+	usb_dp_parser_t parser = {
+		.nesting = descriptor_nesting
+	};
+
+	usb_dp_browse_simple_internal(&parser, &data, descriptors,
+	    0, callback, arg);
+}
 
 /** @}
Index: uspace/lib/usb/src/pipes.c
===================================================================
--- uspace/lib/usb/src/pipes.c	(revision bb41b8510c8359a9d0db89675e425ca4f828efff)
+++ uspace/lib/usb/src/pipes.c	(revision d8e61b0dff1803e2d084988ff419e8d7e75fddae)
@@ -52,5 +52,4 @@
 	sysarg_t address;
 
-
 	/*
 	 * We are sending special value as a handle - zero - to get
@@ -94,4 +93,32 @@
 
 	return (int) iface_no;
+}
+
+/** Tell USB address assigned to given device.
+ *
+ * @param dev_handle Devman handle of the USB device in question.
+ * @return USB address or negative error code.
+ */
+usb_address_t usb_device_get_assigned_address(devman_handle_t dev_handle)
+{
+	int parent_phone = devman_parent_device_connect(dev_handle,
+	    IPC_FLAG_BLOCKING);
+	if (parent_phone < 0) {
+		return parent_phone;
+	}
+
+	sysarg_t address;
+
+	int rc = async_req_2_1(parent_phone, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_ADDRESS,
+	    dev_handle, &address);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	async_hangup(parent_phone);
+
+	return (usb_address_t) address;
 }
 
