Index: uspace/lib/usb/src/debug.c
===================================================================
--- uspace/lib/usb/src/debug.c	(revision 947d78839aee48678e3102bf15a647260383d50d)
+++ uspace/lib/usb/src/debug.c	(revision 947d78839aee48678e3102bf15a647260383d50d)
@@ -0,0 +1,160 @@
+/*
+ * 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 Debugging support.
+ */
+#include <adt/list.h>
+#include <fibril_synch.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <usb/debug.h>
+
+/** Debugging tag. */
+typedef struct {
+	/** Linked list member. */
+	link_t link;
+	/** Tag name.
+	 * We always have a private copy of the name.
+	 */
+	char *tag;
+	/** Enabled level of debugging. */
+	int level;
+} usb_debug_tag_t;
+
+/** Get instance of usb_debug_tag_t from link_t. */
+#define USB_DEBUG_TAG_INSTANCE(iterator) \
+	list_get_instance(iterator, usb_debug_tag_t, link)
+
+/** List of all known tags. */
+static LIST_INITIALIZE(tag_list);
+/** Mutex guard for the list of all tags. */
+static FIBRIL_MUTEX_INITIALIZE(tag_list_guard);
+
+/** Find or create new tag with given name.
+ *
+ * @param tagname Tag name.
+ * @return Debug tag structure.
+ * @retval NULL Out of memory.
+ */
+static usb_debug_tag_t *get_tag(const char *tagname)
+{
+	link_t *link;
+	for (link = tag_list.next; \
+	    link != &tag_list; \
+	    link = link->next) {
+		usb_debug_tag_t *tag = USB_DEBUG_TAG_INSTANCE(link);
+		if (str_cmp(tag->tag, tagname) == 0) {
+			return tag;
+		}
+	}
+
+	/*
+	 * Tag not found, we will create a new one.
+	 */
+	usb_debug_tag_t *new_tag = malloc(sizeof(usb_debug_tag_t));
+	int rc = asprintf(&new_tag->tag, "%s", tagname);
+	if (rc < 0) {
+		free(new_tag);
+		return NULL;
+	}
+	list_initialize(&new_tag->link);
+	new_tag->level = 1;
+
+	/*
+	 * Append it to the end of known tags.
+	 */
+	list_append(&new_tag->link, &tag_list);
+
+	return new_tag;
+}
+
+/** Print debugging information.
+ * If the tag is used for the first time, its structures are automatically
+ * created and initial verbosity level is set to 1.
+ *
+ * @param tagname Tag name.
+ * @param level Level (verbosity) of the message.
+ * @param format Formatting string for printf().
+ */
+void usb_dprintf(const char *tagname, int level, const char *format, ...)
+{
+	fibril_mutex_lock(&tag_list_guard);
+	usb_debug_tag_t *tag = get_tag(tagname);
+	if (tag == NULL) {
+		printf("USB debug: FATAL ERROR - failed to create tag.\n");
+		goto leave;
+	}
+
+	if (tag->level < level) {
+		goto leave;
+	}
+
+	va_list args;
+	va_start(args, format);
+
+	printf("[%s:%d]: ", tagname, level);
+	vprintf(format, args);
+
+	va_end(args);
+
+leave:
+	fibril_mutex_unlock(&tag_list_guard);
+}
+
+/** Enable debugging prints for given tag.
+ *
+ * Setting level to <i>n</i> will cause that only printing messages
+ * with level lower or equal to <i>n</i> will be printed.
+ *
+ * @param tagname Tag name.
+ * @param level Enabled level.
+ */
+void usb_dprintf_enable(const char *tagname, int level)
+{
+	fibril_mutex_lock(&tag_list_guard);
+	usb_debug_tag_t *tag = get_tag(tagname);
+	if (tag == NULL) {
+		printf("USB debug: FATAL ERROR - failed to create tag.\n");
+		goto leave;
+	}
+
+	tag->level = level;
+
+leave:
+	fibril_mutex_unlock(&tag_list_guard);
+}
+
+
+/**
+ * @}
+ */
