Index: .bzrignore
===================================================================
--- .bzrignore	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ .bzrignore	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -62,72 +62,20 @@
 ./uspace/app/trace/trace
 ./uspace/app/usb/usb
+./uspace/app/usbinfo/usbinfo
 ./uspace/app/virtusbkbd/vuk
-./uspace/dist/app/bdsh
-./uspace/dist/app/edit
-./uspace/dist/app/getterm
-./uspace/dist/app/klog
-./uspace/dist/app/mkfat
-./uspace/dist/app/netecho
-./uspace/dist/app/netstart
-./uspace/dist/app/nettest1
-./uspace/dist/app/nettest2
-./uspace/dist/app/ping
-./uspace/dist/app/redir
-./uspace/dist/app/sbi
-./uspace/dist/app/stats
-./uspace/dist/app/taskdump
-./uspace/dist/app/tasks
-./uspace/dist/app/tester
-./uspace/dist/app/test_serial
-./uspace/dist/app/tetris
-./uspace/dist/app/top
-./uspace/dist/app/trace
-./uspace/dist/app/usb
-./uspace/dist/app/vuk
+./uspace/dist/app/*
 ./uspace/dist/cfg/net/general
 ./uspace/dist/cfg/net/lo
 ./uspace/dist/cfg/net/ne2k
-./uspace/dist/drv/isa/
-./uspace/dist/drv/ns8250/
-./uspace/dist/drv/pciintel/
-./uspace/dist/drv/root/
-./uspace/dist/drv/rootia32/
-./uspace/dist/drv/uhci/
-./uspace/dist/drv/usbhub/
-./uspace/dist/drv/usbkbd/
-./uspace/dist/drv/vhc/
-./uspace/dist/srv/arp
-./uspace/dist/srv/ata_bd
-./uspace/dist/srv/char_ms
-./uspace/dist/srv/clip
-./uspace/dist/srv/console
-./uspace/dist/srv/devfs
-./uspace/dist/srv/devman
-./uspace/dist/srv/dp8390
-./uspace/dist/srv/eth
-./uspace/dist/srv/fat
-./uspace/dist/srv/fb
-./uspace/dist/srv/file_bd
-./uspace/dist/srv/g_part
-./uspace/dist/srv/i8042
-./uspace/dist/srv/icmp
-./uspace/dist/srv/ip
-./uspace/dist/srv/kbd
-./uspace/dist/srv/lo
-./uspace/dist/srv/mbr_part
-./uspace/dist/srv/net
-./uspace/dist/srv/netstart
-./uspace/dist/srv/nildummy
-./uspace/dist/srv/pci
-./uspace/dist/srv/taskmon
-./uspace/dist/srv/tcp
-./uspace/dist/srv/tmpfs
-./uspace/dist/srv/udp
-./uspace/dist/srv/vhcd
+./uspace/dist/drv/*
+./uspace/dist/srv/*
 ./uspace/drv/root/root
 ./uspace/drv/isa/isa
 ./uspace/drv/ns8250/ns8250
 ./uspace/drv/pciintel/pciintel
-./uspace/drv/rootia32/rootia32
+./uspace/drv/rootpc/rootpc
+./uspace/drv/rootvirt/rootvirt
+./uspace/drv/test1/test1
+./uspace/drv/test2/test2
 ./uspace/drv/uhci/uhci
 ./uspace/drv/usbhub/usbhub
Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ HelenOS.config	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -545,2 +545,6 @@
 % Line debugging information
 ! [CONFIG_STRIP_BINARIES!=y] CONFIG_LINE_DEBUG (n/y)
+
+% Launch (devman) test drivers
+! [CONFIG_DEBUG=y] CONFIG_TEST_DRIVERS (n/y)
+
Index: Makefile
===================================================================
--- Makefile	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -41,5 +41,5 @@
 CONFIG_HEADER = config.h
 
-.PHONY: all precheck cscope autotool config_default config distclean clean
+.PHONY: all precheck cscope autotool config_auto config_default config distclean clean
 
 all: $(COMMON_MAKEFILE) $(COMMON_HEADER) $(CONFIG_MAKEFILE) $(CONFIG_HEADER)
@@ -66,5 +66,9 @@
 
 config_default: $(CONFIG_RULES)
-	$(CONFIG) $< default
+ifeq ($(HANDS_OFF),y)
+	$(CONFIG) $< hands-off $(PROFILE)
+else
+	$(CONFIG) $< default $(PROFILE)
+endif
 
 config: $(CONFIG_RULES)
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ boot/Makefile.common	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -111,5 +111,7 @@
 RD_DRVS = \
 	root \
-	vhc
+	rootvirt \
+	test1 \
+	test2
 
 RD_DRV_CFG = 
@@ -142,7 +144,8 @@
 	$(USPACE_PATH)/app/ping/ping \
 	$(USPACE_PATH)/app/stats/stats \
-	$(USPACE_PATH)/app/virtusbkbd/vuk \
 	$(USPACE_PATH)/app/tasks/tasks \
-	$(USPACE_PATH)/app/top/top
+	$(USPACE_PATH)/app/top/top \
+	$(USPACE_PATH)/app/usbinfo/usbinfo \
+	$(USPACE_PATH)/app/virtusbkbd/vuk
 
 ifneq ($(CONFIG_BAREBONE),y)
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ boot/arch/amd64/Makefile.inc	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -37,5 +37,5 @@
 
 RD_DRVS += \
-	rootia32 \
+	rootpc \
 	pciintel \
 	isa \
@@ -43,5 +43,6 @@
 	uhci \
 	usbhub \
-	usbkbd
+	usbkbd \
+	vhc
 	
 RD_DRV_CFG += \
Index: kernel/generic/include/ipc/ipc.h
===================================================================
--- kernel/generic/include/ipc/ipc.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ kernel/generic/include/ipc/ipc.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -43,10 +43,6 @@
 #define IPC_CALL_LEN  6
 
-/** Maximum active async calls per thread */
-#ifdef CONFIG_DEBUG
-	#define IPC_MAX_ASYNC_CALLS  16
-#else
-	#define IPC_MAX_ASYNC_CALLS  4000
-#endif
+/** Maximum active async calls per phone */
+#define IPC_MAX_ASYNC_CALLS  4
 
 /* Flags for calls */
Index: kernel/generic/include/proc/task.h
===================================================================
--- kernel/generic/include/proc/task.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ kernel/generic/include/proc/task.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -93,9 +93,4 @@
 	phone_t phones[IPC_MAX_PHONES];
 	stats_ipc_t ipc_info;   /**< IPC statistics */
-	/**
-	 * Active asynchronous messages. It is used for limiting uspace to
-	 * certain extent.
-	 */
-	atomic_t active_calls;
 	/** List of synchronous answerboxes. */
 	link_t sync_box_head;
Index: kernel/generic/src/ipc/ipc.c
===================================================================
--- kernel/generic/src/ipc/ipc.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ kernel/generic/src/ipc/ipc.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -655,12 +655,4 @@
 		    (call->flags & IPC_CALL_NOTIF));
 		
-		/*
-		 * Record the receipt of this call in the current task's counter
-		 * of active calls. IPC_M_PHONE_HUNGUP calls do not contribute
-		 * to this counter so do not record answers to them either.
-		 */
-		if (!(call->flags & IPC_CALL_DISCARD_ANSWER))
-			atomic_dec(&TASK->active_calls);
-		
 		ipc_call_free(call);
 	}
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ kernel/generic/src/ipc/sysipc.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -644,15 +644,15 @@
 }
 
-/** Check that the task did not exceed the allowed limit of asynchronous calls.
- *
+/** Check that the task did not exceed the allowed limit of asynchronous calls
+ * made over a phone.
+ *
+ * @param phone Phone to check the limit against. 
  * @return 0 if limit not reached or -1 if limit exceeded.
  *
  */
-static int check_call_limit(void)
-{
-	if (atomic_preinc(&TASK->active_calls) > IPC_MAX_ASYNC_CALLS) {
-		atomic_dec(&TASK->active_calls);
+static int check_call_limit(phone_t *phone)
+{
+	if (atomic_get(&phone->active_calls) >= IPC_MAX_ASYNC_CALLS)
 		return -1;
-	}
 	
 	return 0;
@@ -680,10 +680,10 @@
     unative_t arg1, unative_t arg2, unative_t arg3, unative_t arg4)
 {
-	if (check_call_limit())
-		return IPC_CALLRET_TEMPORARY;
-	
 	phone_t *phone;
 	if (phone_get(phoneid, &phone) != EOK)
 		return IPC_CALLRET_FATAL;
+
+	if (check_call_limit(phone))
+		return IPC_CALLRET_TEMPORARY;
 	
 	call_t *call = ipc_call_alloc(0);
@@ -720,10 +720,10 @@
 unative_t sys_ipc_call_async_slow(unative_t phoneid, ipc_data_t *data)
 {
-	if (check_call_limit())
-		return IPC_CALLRET_TEMPORARY;
-	
 	phone_t *phone;
 	if (phone_get(phoneid, &phone) != EOK)
 		return IPC_CALLRET_FATAL;
+
+	if (check_call_limit(phone))
+		return IPC_CALLRET_TEMPORARY;
 
 	call_t *call = ipc_call_alloc(0);
@@ -1046,11 +1046,4 @@
 			ipc_call_free(call);
 			goto restart;
-		} else {
-			/*
-			 * Decrement the counter of active calls only if the
-			 * call is not an answer to IPC_M_PHONE_HUNGUP,
-			 * which doesn't contribute to the counter.
-			 */
-			atomic_dec(&TASK->active_calls);
 		}
 		
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ kernel/generic/src/proc/task.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -151,5 +151,4 @@
 	atomic_set(&task->refcount, 0);
 	atomic_set(&task->lifecount, 0);
-	atomic_set(&task->active_calls, 0);
 	
 	irq_spinlock_initialize(&task->lock, "task_t_lock");
@@ -478,6 +477,6 @@
 #ifdef __32_BITS__
 	if (*additional)
-		printf("%-8" PRIu64 " %9" PRIua " %7" PRIua, task->taskid,
-		    atomic_get(&task->refcount), atomic_get(&task->active_calls));
+		printf("%-8" PRIu64 " %9" PRIua, task->taskid,
+		    atomic_get(&task->refcount));
 	else
 		printf("%-8" PRIu64 " %-14s %-5" PRIu32 " %10p %10p"
@@ -490,7 +489,6 @@
 	if (*additional)
 		printf("%-8" PRIu64 " %9" PRIu64 "%c %9" PRIu64 "%c "
-		    "%9" PRIua " %7" PRIua,
-		    task->taskid, ucycles, usuffix, kcycles, ksuffix,
-		    atomic_get(&task->refcount), atomic_get(&task->active_calls));
+		    "%9" PRIua, task->taskid, ucycles, usuffix, kcycles,
+		    ksuffix, atomic_get(&task->refcount));
 	else
 		printf("%-8" PRIu64 " %-14s %-5" PRIu32 " %18p %18p\n",
Index: tools/config.py
===================================================================
--- tools/config.py	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ tools/config.py	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -47,5 +47,5 @@
 
 def read_config(fname, config):
-	"Read saved values from last configuration run"
+	"Read saved values from last configuration run or a preset file"
 	
 	inf = open(fname, 'r')
@@ -218,9 +218,9 @@
 # and verify that all variables have a value (previously specified or inferred).
 #
-# @param config	Configuration to work on
-# @param rules	Rules
-#
-# @return	True if configuration is complete and valid, False
-#		otherwise.
+# @param config Configuration to work on
+# @param rules  Rules
+#
+# @return True if configuration is complete and valid, False
+#         otherwise.
 #
 def infer_verify_choices(config, rules):
@@ -229,5 +229,5 @@
 	for rule in rules:
 		varname, vartype, name, choices, cond = rule
-
+		
 		if cond and (not check_condition(cond, config, rules)):
 			continue
@@ -237,12 +237,18 @@
 		else:
 			value = config[varname]
-
-		if not rule_value_is_valid(rule, value):
+		
+		if not validate_rule_value(rule, value):
 			value = None
-
-		default = rule_get_default(rule)
-		if default != None:
+		
+		default = get_default_rule(rule)
+
+		#
+		# If we don't have a value but we do have
+		# a default, use it.
+		#
+		if value == None and default != None:
+			value = default
 			config[varname] = default
-
+		
 		if not varname in config:
 			return False
@@ -251,9 +257,9 @@
 
 ## Get default value from a rule.
-def rule_get_default(rule):
+def get_default_rule(rule):
 	varname, vartype, name, choices, cond = rule
-
+	
 	default = None
-
+	
 	if vartype == 'choice':
 		# If there is just one option, use it
@@ -270,19 +276,19 @@
 	else:
 		raise RuntimeError("Unknown variable type: %s" % vartype)
-
+	
 	return default
 
 ## Get option from a rule.
 #
-# @param rule	Rule for a variable
-# @param value	Current value of the variable
+# @param rule  Rule for a variable
+# @param value Current value of the variable
 #
 # @return Option (string) to ask or None which means not to ask.
 #
-def rule_get_option(rule, value):
+def get_rule_option(rule, value):
 	varname, vartype, name, choices, cond = rule
-
+	
 	option = None
-
+	
 	if vartype == 'choice':
 		# If there is just one option, don't ask
@@ -302,20 +308,20 @@
 	else:
 		raise RuntimeError("Unknown variable type: %s" % vartype)
-
+	
 	return option
 
 ## Check if variable value is valid.
 #
-# @param rule	Rule for the variable
-# @param value	Value of the variable
-#
-# @return	True if valid, False if not valid.
-#
-def rule_value_is_valid(rule, value):
+# @param rule  Rule for the variable
+# @param value Value of the variable
+#
+# @return True if valid, False if not valid.
+#
+def validate_rule_value(rule, value):
 	varname, vartype, name, choices, cond = rule
 	
 	if value == None:
 		return True
-
+	
 	if vartype == 'choice':
 		if not value in [choice[0] for choice in choices]:
@@ -335,5 +341,5 @@
 	else:
 		raise RuntimeError("Unknown variable type: %s" % vartype)
-
+	
 	return True
 
@@ -413,7 +419,7 @@
 	return list
 
-## Choose a profile and load configuration presets.
-#
-def load_presets(root, fname, screen, config):
+## Ask user to choose a configuration profile.
+#
+def choose_profile(root, fname, screen, config):
 	options = []
 	opt2path = {}
@@ -436,10 +442,10 @@
 					subprofile = True
 					options.append("%s (%s)" % (name, subname))
-					opt2path[cnt] = (canon, subcanon)
+					opt2path[cnt] = [name, subname]
 					cnt += 1
 			
 			if not subprofile:
 				options.append(name)
-				opt2path[cnt] = (canon, None)
+				opt2path[cnt] = [name]
 				cnt += 1
 	
@@ -449,9 +455,36 @@
 		return None
 	
-	read_config(opt2path[value][0], config)
-	if opt2path[value][1] != None:
-		read_config(opt2path[value][1], config)
+	return opt2path[value]
+
+## Read presets from a configuration profile.
+#
+# @param profile Profile to load from (a list of string components)
+# @param config  Output configuration
+#
+def read_presets(profile, config):
+	path = os.path.join(PRESETS_DIR, profile[0], MAKEFILE)
+	read_config(path, config)
+	
+	if len(profile) > 1:
+		path = os.path.join(PRESETS_DIR, profile[0], profile[1], MAKEFILE)
+		read_config(path, config)
+
+## Parse profile name (relative OS path) into a list of components.
+#
+# @param profile_name Relative path (using OS separator)
+# @return             List of components
+#
+def parse_profile_name(profile_name):
+	profile = []
+	
+	head, tail = os.path.split(profile_name)
+	if head != '':
+		profile.append(head)
+	
+	profile.append(tail)
+	return profile
 
 def main():
+	profile = None
 	config = {}
 	rules = []
@@ -460,13 +493,33 @@
 	parse_rules(RULES_FILE, rules)
 	
-	# Read configuration from previous run
-	if os.path.exists(MAKEFILE):
+	# Input configuration file can be specified on command line
+	# otherwise configuration from previous run is used.
+	if len(sys.argv) >= 4:
+		profile = parse_profile_name(sys.argv[3])
+		read_presets(profile, config)
+	elif os.path.exists(MAKEFILE):
 		read_config(MAKEFILE, config)
 	
-	# Default mode: only check values and regenerate configuration files
+	# Default mode: check values and regenerate configuration files
 	if (len(sys.argv) >= 3) and (sys.argv[2] == 'default'):
 		if (infer_verify_choices(config, rules)):
 			create_output(MAKEFILE, MACROS, config, rules)
 			return 0
+	
+	# Hands-off mode: check values and regenerate configuration files,
+	# but no interactive fallback
+	if (len(sys.argv) >= 3) and (sys.argv[2] == 'hands-off'):
+		# We deliberately test sys.argv >= 4 because we do not want
+		# to read implicitly any possible previous run configuration
+		if len(sys.argv) < 4:
+			sys.stderr.write("Configuration error: No presets specified\n")
+			return 2
+		
+		if (infer_verify_choices(config, rules)):
+			create_output(MAKEFILE, MACROS, config, rules)
+			return 0
+		
+		sys.stderr.write("Configuration error: The presets are ambiguous\n")
+		return 1
 	
 	# Check mode: only check configuration
@@ -507,15 +560,22 @@
 					value = config[varname]
 				
-				if not rule_value_is_valid(rule, value):
+				if not validate_rule_value(rule, value):
 					value = None
-
-				default = rule_get_default(rule)
-				if default != None:
+				
+				default = get_default_rule(rule)
+
+				#
+				# If we don't have a value but we do have
+				# a default, use it.
+				#
+				if value == None and default != None:
 					value = default
 					config[varname] = default
-
-				option = rule_get_option(rule, value)
+				
+				option = get_rule_option(rule, value)
 				if option != None:
 					options.append(option)
+				else:
+					continue
 				
 				opt2row[cnt] = (varname, vartype, name, choices)
@@ -539,5 +599,7 @@
 			
 			if value == 0:
-				load_presets(PRESETS_DIR, MAKEFILE, screen, config)
+				profile = choose_profile(PRESETS_DIR, MAKEFILE, screen, config)
+				if profile != None:
+					read_presets(profile, config)
 				position = 1
 				continue
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -49,4 +49,5 @@
 	app/trace \
 	app/top \
+	app/usbinfo \
 	app/virtusbkbd \
 	app/netecho \
@@ -87,5 +88,7 @@
 	srv/net/net \
 	drv/root \
-	drv/vhc
+	drv/rootvirt \
+	drv/test1 \
+	drv/test2
 
 ## Networking
@@ -110,8 +113,5 @@
 
 ifeq ($(UARCH),amd64)
-endif
-
-ifeq ($(UARCH),ia32)
-	DIRS += drv/rootia32
+	DIRS += drv/rootpc
 	DIRS += drv/pciintel
 	DIRS += drv/isa
@@ -120,4 +120,16 @@
 	DIRS += drv/usbhub
 	DIRS += drv/usbkbd
+	DIRS += drv/vhc
+endif
+
+ifeq ($(UARCH),ia32)
+	DIRS += drv/rootpc
+	DIRS += drv/pciintel
+	DIRS += drv/isa
+	DIRS += drv/ns8250
+	DIRS += drv/uhci
+	DIRS += drv/usbhub
+	DIRS += drv/usbkbd
+	DIRS += drv/vhc
 endif
 
Index: uspace/app/netecho/print_error.c
===================================================================
--- uspace/app/netecho/print_error.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/app/netecho/print_error.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -164,5 +164,5 @@
 	case EDESTADDRREQ:
 		fprintf(output, "Destination address required (%d) error", error_code);
-	case TRY_AGAIN:
+	case EAGAIN:
 		fprintf(output, "Try again (%d) error", error_code);
 	default:
Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/app/tester/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -31,6 +31,10 @@
 BINARY = tester
 
+LIBS += $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS += -I$(LIBUSB_PREFIX)/include
+
 SOURCES = \
 	tester.c \
+	adt/usbaddrkeep.c \
 	thread/thread1.c \
 	print/print1.c \
Index: uspace/app/tester/adt/usbaddrkeep.c
===================================================================
--- uspace/app/tester/adt/usbaddrkeep.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/app/tester/adt/usbaddrkeep.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <usb/hcd.h>
+#include <errno.h>
+#include "../tester.h"
+
+#define MAX_ADDRESS 5
+
+
+const char *test_usbaddrkeep(void)
+{
+	int rc;
+	usb_address_keeping_t addresses;
+
+	TPRINTF("Initializing addresses keeping structure...\n");
+	usb_address_keeping_init(&addresses, MAX_ADDRESS);
+	
+	TPRINTF("Requesting address...\n");
+	usb_address_t addr = usb_address_keeping_request(&addresses);
+	TPRINTF("Address assigned: %d\n", (int) addr);
+	if (addr != 1) {
+		return "have not received expected address 1";
+	}
+
+	TPRINTF("Releasing not assigned address...\n");
+	rc = usb_address_keeping_release(&addresses, 2);
+	if (rc != ENOENT) {
+		return "have not received expected ENOENT";
+	}
+
+	TPRINTF("Releasing acquired address...\n");
+	rc = usb_address_keeping_release(&addresses, addr);
+	if (rc != EOK) {
+		return "have not received expected EOK";
+	}
+
+	return NULL;
+}
Index: uspace/app/tester/adt/usbaddrkeep.def
===================================================================
--- uspace/app/tester/adt/usbaddrkeep.def	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/app/tester/adt/usbaddrkeep.def	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,6 @@
+{
+	"usbaddrkeep",
+	"USB address keeping structure",
+	&test_usbaddrkeep,
+	true
+},
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/app/tester/tester.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -65,4 +65,5 @@
 #include "mm/malloc1.def"
 #include "hw/serial/serial1.def"
+#include "adt/usbaddrkeep.def"
 	{NULL, NULL, NULL, false}
 };
Index: uspace/app/tester/tester.h
===================================================================
--- uspace/app/tester/tester.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/app/tester/tester.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -82,4 +82,5 @@
 extern const char *test_malloc1(void);
 extern const char *test_serial1(void);
+extern const char *test_usbaddrkeep(void);
 
 extern test_t tests[];
Index: uspace/app/usbinfo/Makefile
===================================================================
--- uspace/app/usbinfo/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/app/usbinfo/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = usbinfo
+
+LIBS = $(LIBUSB_PREFIX)/libusb.a $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS = -I$(LIBUSB_PREFIX)/include -I$(LIBDRV_PREFIX)/include
+
+SOURCES = \
+	dump.c \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/usbinfo/dump.c
===================================================================
--- uspace/app/usbinfo/dump.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/app/usbinfo/dump.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,129 @@
+/*
+ * 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 usb
+ * @{
+ */
+/**
+ * @file
+ * @brief USB querying.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+
+#include "usbinfo.h"
+
+#define INDENT "  "
+#define BYTES_PER_LINE 12
+
+#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))
+
+void dump_buffer(const char *msg, const uint8_t *buffer, size_t length)
+{
+	printf("%s\n", msg);
+
+	size_t i;
+	for (i = 0; i < length; i++) {
+		printf("  0x%02X", buffer[i]);
+		if (((i > 0) && (((i+1) % BYTES_PER_LINE) == 0))
+		    || (i + 1 == length)) {
+			printf("\n");
+		}
+	}
+}
+
+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)
+{
+	printf("Standard device descriptor:\n");
+
+	printf(INDENT "bLength = %d\n", d->length);
+	printf(INDENT "bDescriptorType = 0x%02x\n", d->descriptor_type);
+	printf(INDENT "bcdUSB = %d (" BCD_FMT ")\n", d->usb_spec_version,
+	    BCD_ARGS(d->usb_spec_version));
+	printf(INDENT "bDeviceClass = 0x%02x\n", d->device_class);
+	printf(INDENT "bDeviceSubClass = 0x%02x\n", d->device_subclass);
+	printf(INDENT "bDeviceProtocol = 0x%02x\n", d->device_protocol);
+	printf(INDENT "bMaxPacketSize0 = %d\n", d->max_packet_size);
+	printf(INDENT "idVendor = %d\n", d->vendor_id);
+	printf(INDENT "idProduct = %d\n", d->product_id);
+	printf(INDENT "bcdDevice = %d\n", d->device_version);
+	printf(INDENT "iManufacturer = %d\n", d->str_manufacturer);
+	printf(INDENT "iProduct = %d\n", d->str_product);
+	printf(INDENT "iSerialNumber = %d\n", d->str_serial_number);
+	printf(INDENT "bNumConfigurations = %d\n", d->configuration_count);
+}
+
+void dump_standard_configuration_descriptor(
+    int index, usb_standard_configuration_descriptor_t *d)
+{
+	bool self_powered = d->attributes & 64;
+	bool remote_wakeup = d->attributes & 32;
+	
+	printf("Standard configuration descriptor #%d\n", index);
+	printf(INDENT "bLength = %d\n", d->length);
+	printf(INDENT "bDescriptorType = 0x%02x\n", d->descriptor_type);
+	printf(INDENT "wTotalLength = %d\n", d->total_length);
+	printf(INDENT "bNumInterfaces = %d\n", d->interface_count);
+	printf(INDENT "bConfigurationValue = %d\n", d->configuration_number);
+	printf(INDENT "iConfiguration = %d\n", d->str_configuration);
+	printf(INDENT "bmAttributes = %d [%s%s%s]\n", d->attributes,
+	    self_powered ? "self-powered" : "",
+	    (self_powered & remote_wakeup) ? ", " : "",
+	    remote_wakeup ? "remote-wakeup" : "");
+	printf(INDENT "MaxPower = %d (%dmA)\n", d->max_power,
+	    2 * d->max_power);
+	// printf(INDENT " = %d\n", d->);
+}
+
+
+/** @}
+ */
Index: uspace/app/usbinfo/main.c
===================================================================
--- uspace/app/usbinfo/main.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/app/usbinfo/main.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,188 @@
+/*
+ * 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 usb
+ * @{
+ */
+/**
+ * @file
+ * @brief USB querying.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <str_error.h>
+#include <bool.h>
+#include <devman.h>
+#include <usb/usbdrv.h>
+#include "usbinfo.h"
+
+#define DEFAULT_HOST_CONTROLLER_PATH "/virt/usbhc"
+
+static void print_usage(char *app_name)
+{
+	printf(NAME ": query USB devices for descriptors\n\n");
+	printf("Usage: %s /path/to/hc usb-address\n where\n", app_name);
+	printf("   /path/to/hc   Devman path to USB host controller " \
+	    "(use `-' for\n");
+	printf("                   default HC at `%s').\n",
+	    DEFAULT_HOST_CONTROLLER_PATH);
+	printf("   usb-address   USB address of device to be queried\n");
+	printf("\n");
+}
+
+static int connect_to_hc(const char *path)
+{
+	int rc;
+	devman_handle_t handle;
+
+	rc = devman_device_get_handle(path, &handle, 0);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	int phone = devman_device_connect(handle, 0);
+
+	return phone;
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc != 3) {
+		print_usage(argv[0]);
+		return EINVAL;
+	}
+
+	char *hc_path = argv[1];
+	long int address_long = strtol(argv[2], NULL, 0);
+
+	/*
+	 * Connect to given host controller driver.
+	 */
+	if (str_cmp(hc_path, "-") == 0) {
+		hc_path = (char *) DEFAULT_HOST_CONTROLLER_PATH;
+	}
+	int hc_phone = connect_to_hc(hc_path);
+	if (hc_phone < 0) {
+		fprintf(stderr,
+		    NAME ": unable to connect to HC at `%s': %s.\n",
+		    hc_path, str_error(hc_phone));
+		return hc_phone;
+	}
+
+	/*
+	 * Verify address is okay.
+	 */
+	usb_address_t address = (usb_address_t) address_long;
+	if ((address < 0) || (address >= USB11_ADDRESS_MAX)) {
+		fprintf(stderr, NAME ": USB address out of range.\n");
+		return ERANGE;
+	}
+
+	/*
+	 * Now, learn information about the device.
+	 */
+	int rc;
+
+	/*
+	 * 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.
+	 */
+	usb_standard_device_descriptor_t device_descriptor;
+	usb_dprintf(NAME, 1,
+	    "usb_drv_req_get_device_descriptor(%d, %d, %p)\n",
+	    hc_phone, (int) address, &device_descriptor);
+
+	rc = usb_drv_req_get_device_descriptor(hc_phone, address,
+	    &device_descriptor);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to fetch standard device descriptor: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	dump_standard_device_descriptor(&device_descriptor);
+
+	/*
+	 * Get first configuration descriptor and dump it.
+	 */
+	usb_standard_configuration_descriptor_t config_descriptor;
+	int config_index = 0;
+	usb_dprintf(NAME, 1,
+	    "usb_drv_req_get_bare_configuration_descriptor(%d, %d, %d, %p)\n",
+	    hc_phone, (int) address, config_index, &config_descriptor);
+
+	rc = usb_drv_req_get_bare_configuration_descriptor(hc_phone, address,
+	    config_index, &config_descriptor );
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to fetch standard configuration descriptor: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	dump_standard_configuration_descriptor(config_index,
+	    &config_descriptor);
+
+	void *full_config_descriptor = malloc(config_descriptor.total_length);
+	usb_dprintf(NAME, 1,
+	    "usb_drv_req_get_full_configuration_descriptor(%d, %d, %d, %p, %zu)\n",
+	    hc_phone, (int) address, config_index,
+	    full_config_descriptor, config_descriptor.total_length);
+
+	rc = usb_drv_req_get_full_configuration_descriptor(hc_phone, address,
+	    config_index,
+	    full_config_descriptor, config_descriptor.total_length, NULL);
+	if (rc != EOK) {
+		fprintf(stderr,
+		    NAME ": failed to fetch full configuration descriptor: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	dump_buffer("Full configuration descriptor:",
+	    full_config_descriptor, config_descriptor.total_length);
+
+	return EOK;
+}
+
+
+/** @}
+ */
Index: uspace/app/usbinfo/usbinfo.h
===================================================================
--- uspace/app/usbinfo/usbinfo.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/app/usbinfo/usbinfo.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,55 @@
+/*
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Common header for usbinfo application.
+ */
+#ifndef USBINFO_USBINFO_H_
+#define USBINFO_USBINFO_H_
+
+#include <usb/usb.h>
+#include <usb/descriptor.h>
+#include <usb/debug.h>
+#include <ipc/devman.h>
+
+
+#define NAME "usbinfo"
+
+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, 
+    usb_standard_configuration_descriptor_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/app/virtusbkbd/Makefile
===================================================================
--- uspace/app/virtusbkbd/Makefile	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/app/virtusbkbd/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -33,5 +33,5 @@
 
 LIBS = $(LIBUSB_PREFIX)/libusb.a $(LIBUSBVIRT_PREFIX)/libusbvirt.a
-EXTRA_CFLAGS = -I$(LIBUSB_PREFIX)/include -I$(LIBUSBVIRT_PREFIX)/include
+EXTRA_CFLAGS = -I$(LIBUSB_PREFIX)/include -I$(LIBUSBVIRT_PREFIX)/include -I$(LIBDRV_PREFIX)/include
 
 SOURCES = \
Index: uspace/app/virtusbkbd/virtusbkbd.c
===================================================================
--- uspace/app/virtusbkbd/virtusbkbd.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/app/virtusbkbd/virtusbkbd.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -55,5 +55,6 @@
 #include "stdreq.h"
 
-#define LOOPS 5
+/** Pause between individual key-presses in seconds. */
+#define KEY_PRESS_DELAY 2
 #define NAME "virt-usb-kbd"
 
@@ -83,7 +84,32 @@
 }
 
+/** Compares current and last status of pressed keys.
+ *
+ * @warning Has side-efect - changes status_last field.
+ *
+ * @param status_now Status now.
+ * @param status_last Last status.
+ * @param len Size of status.
+ * @return Whether they are the same.
+ */
+static bool keypress_check_with_last_request(uint8_t *status_now,
+    uint8_t *status_last, size_t len)
+{
+	bool same = true;
+	size_t i;
+	for (i = 0; i < len; i++) {
+		if (status_now[i] != status_last[i]) {
+			status_last[i] = status_now[i];
+			same = false;
+		}
+	}
+	return same;
+}
+
 static int on_request_for_data(struct usbvirt_device *dev,
     usb_endpoint_t endpoint, void *buffer, size_t size, size_t *actual_size)
 {
+	static uint8_t last_data[2 + KB_MAX_KEYS_AT_ONCE];
+
 	if (size < 2 + KB_MAX_KEYS_AT_ONCE) {
 		return EINVAL;
@@ -101,4 +127,10 @@
 	}
 	
+	if (keypress_check_with_last_request(data, last_data,
+	    2 + KB_MAX_KEYS_AT_ONCE)) {
+		*actual_size = 0;
+		return EOK;
+	}
+
 	memcpy(buffer, &data, *actual_size);
 	
@@ -153,4 +185,6 @@
 	.ops = &keyboard_ops,
 	.descriptors = &descriptors,
+	.lib_debug_level = 3,
+	.lib_debug_enabled_tags = USBVIRT_DEBUGTAG_ALL,
 	.name = "keyboard"
 };
@@ -178,5 +212,5 @@
 	printf("\n");
 	
-	fibril_sleep(1);
+	fibril_sleep(KEY_PRESS_DELAY);
 }
 
@@ -203,5 +237,5 @@
 int main(int argc, char * argv[])
 {
-	printf("Dump of report descriptor (%u bytes):\n", report_descriptor_size);
+	printf("Dump of report descriptor (%zu bytes):\n", report_descriptor_size);
 	size_t i;
 	for (i = 0; i < report_descriptor_size; i++) {
@@ -224,6 +258,8 @@
 	
 	printf("%s: Simulating keyboard events...\n", NAME);
-	kb_process_events(&status, keyboard_events, keyboard_events_count,
-	    on_keyboard_change);
+	while (1) {
+		kb_process_events(&status, keyboard_events, keyboard_events_count,
+			on_keyboard_change);
+	}
 	
 	printf("%s: Terminating...\n", NAME);
Index: uspace/drv/isa/isa.c
===================================================================
--- uspace/drv/isa/isa.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/isa/isa.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -282,5 +282,6 @@
 
 		printf(NAME ": added io range (addr=0x%x, size=0x%x) to "
-		    "device %s\n", addr, len, dev->name);
+		    "device %s\n", (unsigned int) addr, (unsigned int) len,
+		    dev->name);
 	}
 }
@@ -489,5 +490,6 @@
 static int isa_add_device(device_t *dev)
 {
-	printf(NAME ": isa_add_device, device handle = %d\n", dev->handle);
+	printf(NAME ": isa_add_device, device handle = %d\n",
+	    (int) dev->handle);
 
 	/* Add child devices. */
Index: uspace/drv/ns8250/ns8250.c
===================================================================
--- uspace/drv/ns8250/ns8250.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/ns8250/ns8250.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -274,5 +274,5 @@
 	
 	/* Gain control over port's registers. */
-	if (pio_enable((void *) data->io_addr, REG_COUNT,
+	if (pio_enable((void *)(uintptr_t) data->io_addr, REG_COUNT,
 	    (void **) &data->port)) {
 		printf(NAME ": error - cannot gain the port %#" PRIx32 " for device "
@@ -727,5 +727,5 @@
 {
 	printf(NAME ": ns8250_add_device %s (handle = %d)\n",
-	    dev->name, dev->handle);
+	    dev->name, (int) dev->handle);
 	
 	int res = ns8250_dev_initialize(dev);
Index: uspace/drv/pciintel/pci.c
===================================================================
--- uspace/drv/pciintel/pci.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/pciintel/pci.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -324,5 +324,5 @@
 		printf(NAME ": device %s : ", dev->name);
 		printf("address = %" PRIx64, range_addr);
-		printf(", size = %x\n", range_size);
+		printf(", size = %x\n", (unsigned int) range_size);
 	}
 	
@@ -489,5 +489,5 @@
 	    (uint32_t) hw_resources.resources[0].res.io_range.address;
 	
-	if (pio_enable((void *)bus_data->conf_io_addr, 8,
+	if (pio_enable((void *)(uintptr_t)bus_data->conf_io_addr, 8,
 	    &bus_data->conf_addr_port)) {
 		printf(NAME ": failed to enable configuration ports.\n");
Index: uspace/drv/root/root.c
===================================================================
--- uspace/drv/root/root.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/root/root.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2010 Vojtech Horky
  * All rights reserved.
  *
@@ -53,4 +54,12 @@
 #define NAME "root"
 
+#define PLATFORM_DEVICE_NAME "hw"
+#define PLATFORM_DEVICE_MATCH_ID STRING(UARCH)
+#define PLATFORM_DEVICE_MATCH_SCORE 100
+
+#define VIRTUAL_DEVICE_NAME "virt"
+#define VIRTUAL_DEVICE_MATCH_ID "rootvirt"
+#define VIRTUAL_DEVICE_MATCH_SCORE 100
+
 static int root_add_device(device_t *dev);
 
@@ -66,4 +75,22 @@
 };
 
+/** Create the device which represents the root of virtual device tree.
+ *
+ * @param parent Parent of the newly created device.
+ * @return Error code.
+ */
+static int add_virtual_root_child(device_t *parent)
+{
+	printf(NAME ": adding new child for virtual devices.\n");
+	printf(NAME ":   device node is `%s' (%d %s)\n", VIRTUAL_DEVICE_NAME,
+	    VIRTUAL_DEVICE_MATCH_SCORE, VIRTUAL_DEVICE_MATCH_ID);
+
+	int res = child_device_register_wrapper(parent, VIRTUAL_DEVICE_NAME,
+	    VIRTUAL_DEVICE_MATCH_ID, VIRTUAL_DEVICE_MATCH_SCORE,
+	    NULL);
+
+	return res;
+}
+
 /** Create the device which represents the root of HW device tree.
  *
@@ -74,102 +101,12 @@
 {
 	printf(NAME ": adding new child for platform device.\n");
+	printf(NAME ":   device node is `%s' (%d %s)\n", PLATFORM_DEVICE_NAME,
+	    PLATFORM_DEVICE_MATCH_SCORE, PLATFORM_DEVICE_MATCH_ID);
 	
-	int res = EOK;
-	device_t *platform = NULL;
-	match_id_t *match_id = NULL;
-	
-	/* Create new device. */
-	platform = create_device();
-	if (NULL == platform) {
-		res = ENOMEM;
-		goto failure;
-	}	
-	
-	platform->name = "hw";
-	printf(NAME ": the new device's name is %s.\n", platform->name);
-	
-	/* Initialize match id list. */
-	match_id = create_match_id();
-	if (NULL == match_id) {
-		res = ENOMEM;
-		goto failure;
-	}
-	
-	/* TODO - replace this with some better solution (sysinfo ?) */
-	match_id->id = STRING(UARCH);
-	match_id->score = 100;
-	add_match_id(&platform->match_ids, match_id);
-	
-	/* Register child device. */
-	res = child_device_register(platform, parent);
-	if (EOK != res)
-		goto failure;
-	
+	int res = child_device_register_wrapper(parent, PLATFORM_DEVICE_NAME,
+	    PLATFORM_DEVICE_MATCH_ID, PLATFORM_DEVICE_MATCH_SCORE,
+	    NULL);
+
 	return res;
-	
-failure:
-	if (NULL != match_id)
-		match_id->id = NULL;
-	
-	if (NULL != platform) {
-		platform->name = NULL;
-		delete_device(platform);
-	}
-	
-	return res;
-}
-
-/** Create virtual USB host controller device.
- * Note that the virtual HC is actually device and driver in one
- * task.
- *
- * @param parent Parent device.
- * @return Error code.
- */
-static int add_virtual_usb_host_controller(device_t *parent)
-{
-	printf(NAME ": adding virtual host contoller.\n");
-
-	int rc;
-	device_t *vhc = NULL;
-	match_id_t *match_id = NULL;
-
-	vhc = create_device();
-	if (vhc == NULL) {
-		rc = ENOMEM;
-		goto failure;
-	}
-
-	vhc->name = "vhc";
-	printf(NAME ": the new device's name is %s.\n", vhc->name);
-
-	/* Initialize match id list. */
-	match_id = create_match_id();
-	if (match_id == NULL) {
-		rc = ENOMEM;
-		goto failure;
-	}
-
-	match_id->id = "usb&hc=vhc";
-	match_id->score = 100;
-	add_match_id(&vhc->match_ids, match_id);
-
-	/* Register child device. */
-	rc = child_device_register(vhc, parent);
-	if (rc != EOK)
-		goto failure;
-
-	return EOK;
-
-failure:
-	if (match_id != NULL)
-		match_id->id = NULL;
-
-	if (vhc != NULL) {
-		vhc->name = NULL;
-		delete_device(vhc);
-	}
-
-	return rc;
 }
 
@@ -184,4 +121,11 @@
 	    dev->handle);
 	
+	/*
+	 * Register virtual devices root.
+	 * We ignore error occurrence because virtual devices shall not be
+	 * vital for the system.
+	 */
+	add_virtual_root_child(dev);
+
 	/* Register root device's children. */
 	int res = add_platform_child(dev);
@@ -189,10 +133,4 @@
 		printf(NAME ": failed to add child device for platform.\n");
 	
-	/* Register virtual USB host controller. */
-	int rc = add_virtual_usb_host_controller(dev);
-	if (EOK != rc) {
-		printf(NAME ": failed to add child device - virtual USB HC.\n");
-	}
-
 	return res;
 }
Index: pace/drv/rootia32/Makefile
===================================================================
--- uspace/drv/rootia32/Makefile	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ 	(revision )
@@ -1,37 +1,0 @@
-#
-# Copyright (c) 2010 Lenka Trochtova
-# 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
-EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
-BINARY = rootia32
-
-SOURCES = \
-	rootia32.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: pace/drv/rootia32/rootia32.c
===================================================================
--- uspace/drv/rootia32/rootia32.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ 	(revision )
@@ -1,204 +1,0 @@
-/*
- * Copyright (c) 2010 Lenka Trochtova
- * 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.
- */
-
-/**
- * @defgroup root_ia32 Root HW device driver for ia32 platform.
- * @brief HelenOS root HW device driver for ia32 platform.
- * @{
- */
-
-/** @file
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <errno.h>
-#include <bool.h>
-#include <fibril_synch.h>
-#include <stdlib.h>
-#include <str.h>
-#include <ctype.h>
-#include <macros.h>
-
-#include <driver.h>
-#include <devman.h>
-#include <ipc/devman.h>
-#include <ipc/dev_iface.h>
-#include <resource.h>
-#include <device/hw_res.h>
-
-#define NAME "rootia32"
-
-typedef struct rootia32_child_dev_data {
-	hw_resource_list_t hw_resources;
-} rootia32_child_dev_data_t;
-
-static int rootia32_add_device(device_t *dev);
-static void root_ia32_init(void);
-
-/** The root device driver's standard operations. */
-static driver_ops_t rootia32_ops = {
-	.add_device = &rootia32_add_device
-};
-
-/** The root device driver structure. */
-static driver_t rootia32_driver = {
-	.name = NAME,
-	.driver_ops = &rootia32_ops
-};
-
-static hw_resource_t pci_conf_regs = {
-	.type = IO_RANGE,
-	.res.io_range = {
-		.address = 0xCF8,
-		.size = 8,
-		.endianness = LITTLE_ENDIAN
-	}
-};
-
-static rootia32_child_dev_data_t pci_data = {
-	.hw_resources = {
-		1,
-		&pci_conf_regs
-	}
-};
-
-static hw_resource_list_t *rootia32_get_child_resources(device_t *dev)
-{
-	rootia32_child_dev_data_t *data;
-	
-	data = (rootia32_child_dev_data_t *) dev->driver_data;
-	if (NULL == data)
-		return NULL;
-	
-	return &data->hw_resources;
-}
-
-static bool rootia32_enable_child_interrupt(device_t *dev)
-{
-	/* TODO */
-	
-	return false;
-}
-
-static resource_iface_t child_res_iface = {
-	&rootia32_get_child_resources,
-	&rootia32_enable_child_interrupt
-};
-
-/* Initialized in root_ia32_init() function. */
-static device_ops_t rootia32_child_ops;
-
-static bool
-rootia32_add_child(device_t *parent, const char *name, const char *str_match_id,
-    rootia32_child_dev_data_t *drv_data)
-{
-	printf(NAME ": adding new child device '%s'.\n", name);
-	
-	device_t *child = NULL;
-	match_id_t *match_id = NULL;
-	
-	/* Create new device. */
-	child = create_device();
-	if (NULL == child)
-		goto failure;
-	
-	child->name = name;
-	child->driver_data = drv_data;
-	
-	/* Initialize match id list */
-	match_id = create_match_id();
-	if (NULL == match_id)
-		goto failure;
-	
-	match_id->id = str_match_id;
-	match_id->score = 100;
-	add_match_id(&child->match_ids, match_id);
-	
-	/* Set provided operations to the device. */
-	child->ops = &rootia32_child_ops;
-	
-	/* Register child device. */
-	if (EOK != child_device_register(child, parent))
-		goto failure;
-	
-	return true;
-	
-failure:
-	if (NULL != match_id)
-		match_id->id = NULL;
-	
-	if (NULL != child) {
-		child->name = NULL;
-		delete_device(child);
-	}
-	
-	printf(NAME ": failed to add child device '%s'.\n", name);
-	
-	return false;
-}
-
-static bool rootia32_add_children(device_t *dev)
-{
-	return rootia32_add_child(dev, "pci0", "intel_pci", &pci_data);
-}
-
-/** Get the root device.
- *
- * @param dev		The device which is root of the whole device tree (both
- *			of HW and pseudo devices).
- * @return		Zero on success, negative error number otherwise.
- */
-static int rootia32_add_device(device_t *dev)
-{
-	printf(NAME ": rootia32_add_device, device handle = %d\n", dev->handle);
-	
-	/* Register child devices. */
-	if (!rootia32_add_children(dev)) {
-		printf(NAME ": failed to add child devices for platform "
-		    "ia32.\n");
-	}
-	
-	return EOK;
-}
-
-static void root_ia32_init(void)
-{
-	rootia32_child_ops.interfaces[HW_RES_DEV_IFACE] = &child_res_iface;
-}
-
-int main(int argc, char *argv[])
-{
-	printf(NAME ": HelenOS rootia32 device driver\n");
-	root_ia32_init();
-	return driver_main(&rootia32_driver);
-}
-
-/**
- * @}
- */
Index: pace/drv/rootia32/rootia32.ma
===================================================================
--- uspace/drv/rootia32/rootia32.ma	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ 	(revision )
@@ -1,1 +1,0 @@
-10 ia32
Index: uspace/drv/rootpc/Makefile
===================================================================
--- uspace/drv/rootpc/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/rootpc/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Lenka Trochtova
+# 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
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = rootpc
+
+SOURCES = \
+	rootpc.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/rootpc/rootpc.c
===================================================================
--- uspace/drv/rootpc/rootpc.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/rootpc/rootpc.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2010 Lenka Trochtova
+ * 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.
+ */
+
+/**
+ * @defgroup root_pc Root HW device driver for ia32 and amd64 platform.
+ * @brief HelenOS root HW device driver for ia32 and amd64 platform.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <bool.h>
+#include <fibril_synch.h>
+#include <stdlib.h>
+#include <str.h>
+#include <ctype.h>
+#include <macros.h>
+
+#include <driver.h>
+#include <devman.h>
+#include <ipc/devman.h>
+#include <ipc/dev_iface.h>
+#include <resource.h>
+#include <device/hw_res.h>
+
+#define NAME "rootpc"
+
+typedef struct rootpc_child_dev_data {
+	hw_resource_list_t hw_resources;
+} rootpc_child_dev_data_t;
+
+static int rootpc_add_device(device_t *dev);
+static void root_pc_init(void);
+
+/** The root device driver's standard operations. */
+static driver_ops_t rootpc_ops = {
+	.add_device = &rootpc_add_device
+};
+
+/** The root device driver structure. */
+static driver_t rootpc_driver = {
+	.name = NAME,
+	.driver_ops = &rootpc_ops
+};
+
+static hw_resource_t pci_conf_regs = {
+	.type = IO_RANGE,
+	.res.io_range = {
+		.address = 0xCF8,
+		.size = 8,
+		.endianness = LITTLE_ENDIAN
+	}
+};
+
+static rootpc_child_dev_data_t pci_data = {
+	.hw_resources = {
+		1,
+		&pci_conf_regs
+	}
+};
+
+static hw_resource_list_t *rootpc_get_child_resources(device_t *dev)
+{
+	rootpc_child_dev_data_t *data;
+	
+	data = (rootpc_child_dev_data_t *) dev->driver_data;
+	if (NULL == data)
+		return NULL;
+	
+	return &data->hw_resources;
+}
+
+static bool rootpc_enable_child_interrupt(device_t *dev)
+{
+	/* TODO */
+	
+	return false;
+}
+
+static resource_iface_t child_res_iface = {
+	&rootpc_get_child_resources,
+	&rootpc_enable_child_interrupt
+};
+
+/* Initialized in root_pc_init() function. */
+static device_ops_t rootpc_child_ops;
+
+static bool
+rootpc_add_child(device_t *parent, const char *name, const char *str_match_id,
+    rootpc_child_dev_data_t *drv_data)
+{
+	printf(NAME ": adding new child device '%s'.\n", name);
+	
+	device_t *child = NULL;
+	match_id_t *match_id = NULL;
+	
+	/* Create new device. */
+	child = create_device();
+	if (NULL == child)
+		goto failure;
+	
+	child->name = name;
+	child->driver_data = drv_data;
+	
+	/* Initialize match id list */
+	match_id = create_match_id();
+	if (NULL == match_id)
+		goto failure;
+	
+	match_id->id = str_match_id;
+	match_id->score = 100;
+	add_match_id(&child->match_ids, match_id);
+	
+	/* Set provided operations to the device. */
+	child->ops = &rootpc_child_ops;
+	
+	/* Register child device. */
+	if (EOK != child_device_register(child, parent))
+		goto failure;
+	
+	return true;
+	
+failure:
+	if (NULL != match_id)
+		match_id->id = NULL;
+	
+	if (NULL != child) {
+		child->name = NULL;
+		delete_device(child);
+	}
+	
+	printf(NAME ": failed to add child device '%s'.\n", name);
+	
+	return false;
+}
+
+static bool rootpc_add_children(device_t *dev)
+{
+	return rootpc_add_child(dev, "pci0", "intel_pci", &pci_data);
+}
+
+/** Get the root device.
+ *
+ * @param dev		The device which is root of the whole device tree (both
+ *			of HW and pseudo devices).
+ * @return		Zero on success, negative error number otherwise.
+ */
+static int rootpc_add_device(device_t *dev)
+{
+	printf(NAME ": rootpc_add_device, device handle = %d\n",
+	    (int)dev->handle);
+	
+	/* Register child devices. */
+	if (!rootpc_add_children(dev)) {
+		printf(NAME ": failed to add child devices for platform "
+		    "ia32.\n");
+	}
+	
+	return EOK;
+}
+
+static void root_pc_init(void)
+{
+	rootpc_child_ops.interfaces[HW_RES_DEV_IFACE] = &child_res_iface;
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS rootpc device driver\n");
+	root_pc_init();
+	return driver_main(&rootpc_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/rootpc/rootpc.ma
===================================================================
--- uspace/drv/rootpc/rootpc.ma	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/rootpc/rootpc.ma	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,2 @@
+10 ia32
+10 amd64
Index: uspace/drv/rootvirt/Makefile
===================================================================
--- uspace/drv/rootvirt/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/rootvirt/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = rootvirt
+
+SOURCES = \
+	rootvirt.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/rootvirt/devices.def
===================================================================
--- uspace/drv/rootvirt/devices.def	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/rootvirt/devices.def	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,24 @@
+/*
+ * Add list of virtual devices you want to launch driver for here.
+ *
+ * Unless the list is empty, the last item shall be followed by a comma.
+ */
+#ifdef CONFIG_TEST_DRIVERS
+{
+	.name = "test1",
+	.match_id = "virtual&test1"
+},
+{
+	.name = "test2alpha",
+	.match_id = "virtual&test2"
+},
+{
+	.name = "test2bravo",
+	.match_id = "virtual&test2"
+},
+#endif
+/* Virtual USB host controller. */
+{
+	.name = "usbhc",
+	.match_id = "usb&hc=vhc"
+},
Index: uspace/drv/rootvirt/rootvirt.c
===================================================================
--- uspace/drv/rootvirt/rootvirt.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/rootvirt/rootvirt.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup rootvirt Root device driver for virtual devices.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <driver.h>
+
+#define NAME "rootvirt"
+
+/** Virtual device entry. */
+typedef struct {
+	/** Device name. */
+	const char *name;
+	/** Device match id. */
+	const char *match_id;
+} virtual_device_t;
+
+/** List of existing virtual devices. */
+virtual_device_t virtual_devices[] = {
+#include "devices.def"
+	/* Terminating item. */
+	{
+		.name = NULL,
+		.match_id = NULL
+	}
+};
+
+static int add_device(device_t *dev);
+
+static driver_ops_t rootvirt_ops = {
+	.add_device = &add_device
+};
+
+static driver_t rootvirt_driver = {
+	.name = NAME,
+	.driver_ops = &rootvirt_ops
+};
+
+/** Add child device.
+ *
+ * @param parent Parent device.
+ * @param virt_dev Virtual device to add.
+ * @return Error code.
+ */
+static int add_child(device_t *parent, virtual_device_t *virt_dev)
+{
+	printf(NAME ": registering child device `%s' (match \"%s\")\n",
+	    virt_dev->name, virt_dev->match_id);
+
+	int rc = child_device_register_wrapper(parent, virt_dev->name,
+	    virt_dev->match_id, 10, NULL);
+
+	if (rc == EOK) {
+		printf(NAME ": registered child device `%s'\n",
+		    virt_dev->name);
+	} else {
+		printf(NAME ": failed to register child device `%s': %s\n",
+		    virt_dev->name, str_error(rc));
+	}
+
+	return rc;
+}
+
+static int add_device(device_t *dev)
+{
+	static int instances = 0;
+
+	/*
+	 * Allow only single instance of root virtual device.
+	 */
+	instances++;
+	if (instances > 1) {
+		return ELIMIT;
+	}
+
+	printf(NAME ": add_device(name=\"%s\", handle=%d)\n",
+	    dev->name, (int)dev->handle);
+	
+	/*
+	 * Go through all virtual devices and try to add them.
+	 * We silently ignore failures.
+	 */
+	virtual_device_t *virt_dev = virtual_devices;
+	while (virt_dev->name != NULL) {
+		(void) add_child(dev, virt_dev);
+		virt_dev++;
+	}
+
+	return EOK;
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS virtual devices root driver\n");
+	return driver_main(&rootvirt_driver);
+}
+
+/**
+ * @}
+ */
+
Index: uspace/drv/rootvirt/rootvirt.ma
===================================================================
--- uspace/drv/rootvirt/rootvirt.ma	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/rootvirt/rootvirt.ma	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,1 @@
+10 rootvirt
Index: uspace/drv/test1/Makefile
===================================================================
--- uspace/drv/test1/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/test1/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = test1
+
+SOURCES = \
+	test1.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/test1/test1.c
===================================================================
--- uspace/drv/test1/test1.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/test1/test1.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+/** @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <driver.h>
+
+#define NAME "test1"
+
+static int add_device(device_t *dev);
+
+static driver_ops_t driver_ops = {
+	.add_device = &add_device
+};
+
+static driver_t the_driver = {
+	.name = NAME,
+	.driver_ops = &driver_ops
+};
+
+/** Register child and inform user about it.
+ *
+ * @param parent Parent device.
+ * @param message Message for the user.
+ * @param name Device name.
+ * @param match_id Device match id.
+ * @param score Device match score.
+ */
+static void register_child_verbose(device_t *parent, const char *message,
+    const char *name, const char *match_id, int match_score)
+{
+	printf(NAME ": registering child device `%s': %s.\n",
+	   name, message);
+
+	int rc = child_device_register_wrapper(parent, name,
+	    match_id, match_score, NULL);
+
+	if (rc == EOK) {
+		printf(NAME ": registered child device `%s'.\n", name);
+	} else {
+		printf(NAME ": failed to register child `%s' (%s).\n",
+		    name, str_error(rc));
+	}
+}
+
+/** Callback when new device is passed to this driver.
+ * This function is the body of the test: it shall register new child
+ * (named `clone') that shall be driven by the same task. When the clone
+ * is added, it registers another child (named `child') that is also driven
+ * by this task. The conditions ensure that we do not recurse indefinitely.
+ * When successful, the device tree shall contain following fragment:
+ *
+ * /virtual/test1
+ * /virtual/test1/clone
+ * /virtual/test1/clone/child
+ *
+ * and devman shall not deadlock.
+ *
+ *
+ * @param dev New device.
+ * @return Error code reporting success of the operation.
+ */
+static int add_device(device_t *dev)
+{
+	printf(NAME ": add_device(name=\"%s\", handle=%d)\n",
+	    dev->name, (int) dev->handle);
+
+	add_device_to_class(dev, "virtual");
+
+	if (dev->parent == NULL) {
+		register_child_verbose(dev, "cloning myself ;-)", "clone",
+		    "virtual&test1", 10);
+	} else if (str_cmp(dev->name, "clone") == 0) {
+		register_child_verbose(dev, "run by the same task", "child",
+		    "virtual&test1&child", 10);
+	}
+
+	printf(NAME ": device `%s' accepted.\n", dev->name);
+
+	return EOK;
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS test1 virtual device driver\n");
+	return driver_main(&the_driver);
+}
+
+
Index: uspace/drv/test1/test1.ma
===================================================================
--- uspace/drv/test1/test1.ma	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/test1/test1.ma	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,2 @@
+10 virtual&test1
+10 virtual&test1&child
Index: uspace/drv/test2/Makefile
===================================================================
--- uspace/drv/test2/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/test2/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include
+BINARY = test2
+
+SOURCES = \
+	test2.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/test2/test2.c
===================================================================
--- uspace/drv/test2/test2.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/test2/test2.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+/** @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <driver.h>
+
+#define NAME "test2"
+
+static int add_device(device_t *dev);
+
+static driver_ops_t driver_ops = {
+	.add_device = &add_device
+};
+
+static driver_t the_driver = {
+	.name = NAME,
+	.driver_ops = &driver_ops
+};
+
+/** Register child and inform user about it.
+ *
+ * @param parent Parent device.
+ * @param message Message for the user.
+ * @param name Device name.
+ * @param match_id Device match id.
+ * @param score Device match score.
+ */
+static void register_child_verbose(device_t *parent, const char *message,
+    const char *name, const char *match_id, int match_score)
+{
+	printf(NAME ": registering child device `%s': %s.\n",
+	   name, message);
+
+	int rc = child_device_register_wrapper(parent, name,
+	    match_id, match_score, NULL);
+
+	if (rc == EOK) {
+		printf(NAME ": registered child device `%s'.\n", name);
+	} else {
+		printf(NAME ": failed to register child `%s' (%s).\n",
+		    name, str_error(rc));
+	}
+}
+
+/** Add child devices after some sleep.
+ *
+ * @param arg Parent device structure (device_t *).
+ * @return Always EOK.
+ */
+static int postponed_birth(void *arg)
+{
+	device_t *dev = (device_t *) arg;
+
+	async_usleep(1000);
+
+	register_child_verbose(dev, "child driven by the same task",
+	    "child", "virtual&test2", 10);
+	register_child_verbose(dev, "child driven by test1",
+	    "test1", "virtual&test1", 10);
+
+	add_device_to_class(dev, "virtual");
+
+	return EOK;
+}
+
+
+static int add_device(device_t *dev)
+{
+	printf(NAME ": add_device(name=\"%s\", handle=%d)\n",
+	    dev->name, (int) dev->handle);
+
+	if (dev->parent == NULL) {
+		fid_t postpone = fibril_create(postponed_birth, dev);
+		fibril_add_ready(postpone);
+	} else {
+		register_child_verbose(dev, "child without available driver",
+		    "ERROR", "non-existent.match.id", 10);
+	}
+
+	return EOK;
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS test2 virtual device driver\n");
+	return driver_main(&the_driver);
+}
+
+
Index: uspace/drv/test2/test2.ma
===================================================================
--- uspace/drv/test2/test2.ma	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/test2/test2.ma	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,1 @@
+10 virtual&test2
Index: uspace/drv/uhci/main.c
===================================================================
--- uspace/drv/uhci/main.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/uhci/main.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -27,5 +27,7 @@
  */
 #include <usb/hcdhubd.h>
+#include <usb/debug.h>
 #include <errno.h>
+#include <driver.h>
 #include "uhci.h"
 
@@ -36,4 +38,5 @@
 static int uhci_add_device(device_t *device)
 {
+	usb_dprintf(NAME, 1, "uhci_add_device() called\n");
 	device->ops = &uhci_ops;
 
@@ -41,4 +44,5 @@
 	 * We need to announce the presence of our root hub.
 	 */
+	usb_dprintf(NAME, 2, "adding root hub\n");
 	usb_hcd_add_root_hub(device);
 
@@ -61,4 +65,5 @@
 	 */
 	sleep(5);
+	usb_dprintf_enable(NAME, 5);
 
 	return driver_main(&uhci_driver);
Index: uspace/drv/uhci/transfers.c
===================================================================
--- uspace/drv/uhci/transfers.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/uhci/transfers.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -36,5 +36,5 @@
     usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	printf(NAME ": transfer OUT [%d.%d (%s); %u]\n",
+	printf(NAME ": transfer OUT [%d.%d (%s); %zu]\n",
 	    target.address, target.endpoint,
 	    usb_str_transfer_type(transfer_type),
@@ -49,5 +49,5 @@
     usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	printf(NAME ": transfer SETUP [%d.%d (%s); %u]\n",
+	printf(NAME ": transfer SETUP [%d.%d (%s); %zu]\n",
 	    target.address, target.endpoint,
 	    usb_str_transfer_type(transfer_type),
@@ -62,5 +62,5 @@
     usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
-	printf(NAME ": transfer IN [%d.%d (%s); %u]\n",
+	printf(NAME ": transfer IN [%d.%d (%s); %zu]\n",
 	    target.address, target.endpoint,
 	    usb_str_transfer_type(transfer_type),
Index: uspace/drv/usbhub/main.c
===================================================================
--- uspace/drv/usbhub/main.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/usbhub/main.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -26,8 +26,15 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-#include <usb/usbdrv.h>
+
 #include <driver.h>
 #include <errno.h>
+#include <async.h>
+
+#include <usb/usbdrv.h>
 #include "usbhub.h"
+#include "usbhub_private.h"
+
+
+usb_general_list_t usb_hub_list;
 
 static driver_ops_t hub_driver_ops = {
@@ -40,6 +47,23 @@
 };
 
+int usb_hub_control_loop(void * noparam){
+	while(true){
+		usb_hub_check_hub_changes();
+		async_usleep(1000 * 1000);
+	}
+	return 0;
+}
+
+
 int main(int argc, char *argv[])
 {
+	usb_lst_init(&usb_hub_list);
+	fid_t fid = fibril_create(usb_hub_control_loop, NULL);
+	if (fid == 0) {
+		printf("%s: failed to start fibril for HUB devices\n", NAME);
+		return ENOMEM;
+	}
+	fibril_add_ready(fid);
+
 	return driver_main(&hub_driver);
 }
Index: uspace/drv/usbhub/port_status.h
===================================================================
--- uspace/drv/usbhub/port_status.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/usbhub/port_status.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * 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.
+ */
+
+#ifndef PORT_STATUS_H
+#define	PORT_STATUS_H
+
+#include <bool.h>
+#include <sys/types.h>
+#include <usb/devreq.h>
+#include "usbhub_private.h"
+
+/**
+ * structure holding port status and changes flags.
+ * should not be accessed directly, use supplied getter/setter methods.
+ *
+ * For more information refer to table 11-15 in
+ * "Universal Serial Bus Specification Revision 1.1"
+ *
+ */
+typedef uint32_t usb_port_status_t;
+
+/**
+ * set values in request to be it a port status request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_port_status_request(
+usb_device_request_setup_packet_t * request, uint16_t port
+){
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS;
+	request->request = USB_HUB_REQUEST_GET_STATUS;
+	request->value = 0;
+	request->length = 4;
+}
+
+
+/**
+ * create request for usb hub port status
+ * @param port
+ * @return
+ */
+static inline usb_device_request_setup_packet_t *
+usb_hub_create_port_status_request(uint16_t port){
+	usb_device_request_setup_packet_t * result =
+		usb_new(usb_device_request_setup_packet_t);
+	usb_hub_set_port_status_request(result,port);
+	return result;
+}
+
+
+/**
+ * set the device request to be a port enable request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_enable_port_request(
+usb_device_request_setup_packet_t * request, uint16_t port
+){
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
+	request->request = USB_HUB_REQUEST_SET_FEATURE;
+	request->value = USB_HUB_FEATURE_C_PORT_ENABLE;
+	request->length = 0;
+}
+
+/**
+ * enable specified port
+ * @param port
+ * @return
+ */
+static inline usb_device_request_setup_packet_t *
+usb_hub_create_enable_port_request(uint16_t port){
+	usb_device_request_setup_packet_t * result =
+		usb_new(usb_device_request_setup_packet_t);
+	usb_hub_set_enable_port_request(result,port);
+	return result;
+}
+
+/**
+ * set the device request to be a port disable request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_disable_port_request(
+usb_device_request_setup_packet_t * request, uint16_t port
+){
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
+	request->request = USB_HUB_REQUEST_SET_FEATURE;
+	request->value = USB_HUB_FEATURE_C_PORT_SUSPEND;
+	request->length = 0;
+}
+
+/**
+ * disable specified port
+ * @param port
+ * @return
+ */
+static inline usb_device_request_setup_packet_t *
+usb_hub_create_disable_port_request(uint16_t port){
+	usb_device_request_setup_packet_t * result =
+		usb_new(usb_device_request_setup_packet_t);
+	usb_hub_set_disable_port_request(result,port);
+	return result;
+}
+
+/**
+ * set the device request to be a port disable request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_reset_port_request(
+usb_device_request_setup_packet_t * request, uint16_t port
+){
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
+	request->request = USB_HUB_REQUEST_SET_FEATURE;
+	request->value = USB_HUB_FEATURE_PORT_RESET;
+	request->length = 0;
+}
+
+/**
+ * disable specified port
+ * @param port
+ * @return
+ */
+static inline usb_device_request_setup_packet_t *
+usb_hub_create_reset_port_request(uint16_t port){
+	usb_device_request_setup_packet_t * result =
+		usb_new(usb_device_request_setup_packet_t);
+	usb_hub_set_reset_port_request(result,port);
+	return result;
+}
+
+/**
+ * set the device request to be a port disable request
+ * @param request
+ * @param port
+ */
+static inline void usb_hub_set_power_port_request(
+usb_device_request_setup_packet_t * request, uint16_t port
+){
+	request->index = port;
+	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
+	request->request = USB_HUB_REQUEST_SET_FEATURE;
+	request->value = USB_HUB_FEATURE_PORT_POWER;
+	request->length = 0;
+}
+
+/** get i`th bit of port status */
+static inline bool usb_port_get_bit(usb_port_status_t * status, int idx)
+{
+	return (((*status)>>(idx))%2);
+}
+
+/** set i`th bit of port status */
+static inline void usb_port_set_bit(
+	usb_port_status_t * status, int idx, bool value)
+{
+	(*status) = value?
+		               ((*status)|(1<<(idx))):
+		               ((*status)&(~(1<<(idx))));
+}
+
+//device connnected on port
+static inline bool usb_port_dev_connected(usb_port_status_t * status){
+	return usb_port_get_bit(status,0);
+}
+
+static inline void usb_port_set_dev_connected(usb_port_status_t * status,bool connected){
+	usb_port_set_bit(status,0,connected);
+}
+
+//port enabled
+static inline bool usb_port_enabled(usb_port_status_t * status){
+	return usb_port_get_bit(status,1);
+}
+
+static inline void usb_port_set_enabled(usb_port_status_t * status,bool enabled){
+	usb_port_set_bit(status,1,enabled);
+}
+
+//port suspended
+static inline bool usb_port_suspended(usb_port_status_t * status){
+	return usb_port_get_bit(status,2);
+}
+
+static inline void usb_port_set_suspended(usb_port_status_t * status,bool suspended){
+	usb_port_set_bit(status,2,suspended);
+}
+
+//over currect
+static inline bool usb_port_over_current(usb_port_status_t * status){
+	return usb_port_get_bit(status,3);
+}
+
+static inline void usb_port_set_over_current(usb_port_status_t * status,bool value){
+	usb_port_set_bit(status,3,value);
+}
+
+//port reset
+static inline bool usb_port_reset(usb_port_status_t * status){
+	return usb_port_get_bit(status,4);
+}
+
+static inline void usb_port_set_reset(usb_port_status_t * status,bool value){
+	usb_port_set_bit(status,4,value);
+}
+
+//powered
+static inline bool usb_port_powered(usb_port_status_t * status){
+	return usb_port_get_bit(status,8);
+}
+
+static inline void usb_port_set_powered(usb_port_status_t * status,bool powered){
+	usb_port_set_bit(status,8,powered);
+}
+
+//low speed device attached
+static inline bool usb_port_low_speed(usb_port_status_t * status){
+	return usb_port_get_bit(status,9);
+}
+
+static inline void usb_port_set_low_speed(usb_port_status_t * status,bool low_speed){
+	usb_port_set_bit(status,9,low_speed);
+}
+
+
+//connect change
+static inline bool usb_port_connect_change(usb_port_status_t * status){
+	return usb_port_get_bit(status,16);
+}
+
+static inline void usb_port_set_connect_change(usb_port_status_t * status,bool change){
+	usb_port_set_bit(status,16,change);
+}
+
+//port enable change
+static inline bool usb_port_enabled_change(usb_port_status_t * status){
+	return usb_port_get_bit(status,17);
+}
+
+static inline void usb_port_set_enabled_change(usb_port_status_t * status,bool change){
+	usb_port_set_bit(status,17,change);
+}
+
+//suspend change
+static inline bool usb_port_suspend_change(usb_port_status_t * status){
+	return usb_port_get_bit(status,18);
+}
+
+static inline void usb_port_set_suspend_change(usb_port_status_t * status,bool change){
+	usb_port_set_bit(status,18,change);
+}
+
+//over current change
+static inline bool usb_port_overcurrent_change(usb_port_status_t * status){
+	return usb_port_get_bit(status,19);
+}
+
+static inline void usb_port_set_overcurrent_change(usb_port_status_t * status,bool change){
+	usb_port_set_bit(status,19,change);
+}
+
+//reset change
+static inline bool usb_port_reset_completed(usb_port_status_t * status){
+	return usb_port_get_bit(status,20);
+}
+
+static inline void usb_port_set_reset_completed(usb_port_status_t * status,bool completed){
+	usb_port_set_bit(status,20,completed);
+}
+
+
+
+#endif	/* PORT_STATUS_H */
+
Index: uspace/drv/usbhub/usbhub.h
===================================================================
--- uspace/drv/usbhub/usbhub.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/usbhub/usbhub.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -38,5 +38,47 @@
 #define NAME "usbhub"
 
-int usb_add_hub_device(device_t *);
+#include "usb/hcdhubd.h"
+
+/** basic information about device attached to hub */
+typedef struct{
+	usb_address_t address;
+	devman_handle_t devman_handle;
+}usb_hub_attached_device_t;
+
+/** Information about attached hub. */
+typedef struct {
+	/** Number of ports. */
+	int port_count;
+	/** attached device handles */
+	usb_hub_attached_device_t * attached_devs;
+	/** General usb device info. */
+	usb_hcd_attached_device_info_t * usb_device;
+	/** General device info*/
+	device_t * device;
+
+} usb_hub_info_t;
+
+/**
+ * function running the hub-controlling loop.
+ * @param noparam fundtion does not need any parameters
+ */
+int usb_hub_control_loop(void * noparam);
+
+/** Callback when new hub device is detected.
+ *
+ * @param dev New device.
+ * @return Error code.
+ */
+int usb_add_hub_device(device_t *dev);
+
+/**
+ * check changes on all registered hubs
+ */
+void usb_hub_check_hub_changes(void);
+
+
+//int usb_add_hub_device(device_t *);
+
+
 
 #endif
Index: uspace/drv/usbhub/usbhub.ma
===================================================================
--- uspace/drv/usbhub/usbhub.ma	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/usbhub/usbhub.ma	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -1,1 +1,2 @@
 10 usb&hub
+10 usb&class=hub
Index: uspace/drv/usbhub/usbhub_private.h
===================================================================
--- uspace/drv/usbhub/usbhub_private.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/drv/usbhub/usbhub_private.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * 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 usb
+ * @{
+ */
+/** @file
+ * @brief Hub driver.
+ */
+
+#ifndef USBHUB_PRIVATE_H
+#define	USBHUB_PRIVATE_H
+
+#include "usbhub.h"
+#include <adt/list.h>
+#include <bool.h>
+#include <driver.h>
+#include <usb/usb.h>
+#include <usb/classes/hub.h>
+#include <usb/devreq.h>
+
+//************
+//
+// convenience define for malloc
+//
+//************
+#define usb_new(type) (type*)malloc(sizeof(type))
+
+
+//************
+//
+// My private list implementation; I did not like the original helenos list
+//
+// This one does not depend on the structure of stored data
+//
+//************
+
+/** general list structure */
+
+
+typedef struct usb_general_list{
+	void * data;
+	struct usb_general_list * prev, * next;
+} usb_general_list_t;
+
+/** create head of usb general list */
+usb_general_list_t * usb_lst_create(void);
+
+/** initialize head of usb general list */
+void usb_lst_init(usb_general_list_t * lst);
+
+
+/** is the list empty? */
+static inline bool usb_lst_empty(usb_general_list_t * lst){
+	return lst?(lst->next==lst):true;
+}
+
+/** append data behind item */
+void usb_lst_append(usb_general_list_t * lst, void * data);
+
+/** prepend data beore item */
+void usb_lst_prepend(usb_general_list_t * lst, void * data);
+
+/** remove list item from list */
+void usb_lst_remove(usb_general_list_t * item);
+
+/** get data o specified type from list item */
+#define usb_lst_get_data(item, type)  (type *) (item->data)
+
+/** get usb_hub_info_t data from list item */
+static inline usb_hub_info_t * usb_hub_lst_get_data(usb_general_list_t * item) {
+	return usb_lst_get_data(item,usb_hub_info_t);
+}
+
+/**
+ * @brief create hub structure instance
+ *
+ * Set the address and port count information most importantly.
+ *
+ * @param device
+ * @param hc host controller phone
+ * @return
+ */
+usb_hub_info_t * usb_create_hub_info(device_t * device, int hc);
+
+/** list of hubs maanged by this driver */
+extern usb_general_list_t usb_hub_list;
+
+
+/**
+ * @brief perform complete control read transaction
+ *
+ * manages all three steps of transaction: setup, read and finalize
+ * @param phone
+ * @param target
+ * @param request request for data
+ * @param rcvd_buffer received data
+ * @param rcvd_size
+ * @param actual_size actual size of received data
+ * @return error code
+ */
+int usb_drv_sync_control_read(
+    int phone, usb_target_t target,
+    usb_device_request_setup_packet_t * request,
+    void * rcvd_buffer, size_t rcvd_size, size_t * actual_size
+);
+
+/**
+ * @brief perform complete control write transaction
+ *
+ * maanges all three steps of transaction: setup, write and finalize
+ * @param phone
+ * @param target
+ * @param request request to send data
+ * @param sent_buffer
+ * @param sent_size
+ * @return error code
+ */
+int usb_drv_sync_control_write(
+    int phone, usb_target_t target,
+    usb_device_request_setup_packet_t * request,
+    void * sent_buffer, size_t sent_size
+);
+
+
+/**
+ * set the device request to be a set address request
+ * @param request
+ * @param addr
+ * \TODO this will be obsolete see usb/dev_req.h
+ */
+static inline void usb_hub_set_set_address_request(
+usb_device_request_setup_packet_t * request, uint16_t addr
+){
+	request->index = 0;
+	request->request_type = 0;/// \TODO this is not very nice sollution, we ned constant
+	request->request = USB_DEVREQ_SET_ADDRESS;
+	request->value = addr;
+	request->length = 0;
+}
+
+/**
+ * set the device request to be a get hub descriptor request.
+ * @warning the size is allways set to USB_HUB_MAX_DESCRIPTOR_SIZE
+ * @param request
+ * @param addr
+ */
+static inline void usb_hub_set_descriptor_request(
+usb_device_request_setup_packet_t * request
+){
+	request->index = 0;
+	request->request_type = USB_HUB_REQ_TYPE_GET_DESCRIPTOR;
+	request->request = USB_HUB_REQUEST_GET_DESCRIPTOR;
+	request->value_high = USB_DESCTYPE_HUB;
+	request->value_low = 0;
+	request->length = USB_HUB_MAX_DESCRIPTOR_SIZE;
+}
+
+static inline int usb_hub_clear_port_feature(int hc, usb_address_t address,
+    int port_index,
+    usb_hub_class_feature_t feature) {
+	usb_target_t target = {
+		.address = address,
+		.endpoint = 0
+	};
+	usb_device_request_setup_packet_t clear_request = {
+		.request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE,
+		.request = USB_DEVREQ_CLEAR_FEATURE,
+		.length = 0,
+		.index = port_index
+	};
+	clear_request.value = feature;
+	return usb_drv_psync_control_write(hc, target, &clear_request,
+	    sizeof(clear_request), NULL, 0);
+}
+
+
+
+#endif	/* USBHUB_PRIVATE_H */
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhub/utils.c
===================================================================
--- uspace/drv/usbhub/utils.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/usbhub/utils.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -34,15 +34,17 @@
  */
 #include <driver.h>
-#include <usb/devreq.h>
+#include <bool.h>
+#include <errno.h>
+
 #include <usbhc_iface.h>
 #include <usb/usbdrv.h>
 #include <usb/descriptor.h>
-#include <driver.h>
-#include <bool.h>
-#include <errno.h>
+#include <usb/devreq.h>
 #include <usb/classes/hub.h>
+
 #include "usbhub.h"
-
-static void check_hub_changes(void);
+#include "usbhub_private.h"
+#include "port_status.h"
+
 
 size_t USB_HUB_MAX_DESCRIPTOR_SIZE = 71;
@@ -53,4 +55,6 @@
 //
 //*********************************************
+
+//hub descriptor utils
 
 void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor) {
@@ -84,7 +88,13 @@
 usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * serialized_descriptor) {
 	uint8_t * sdescriptor = (uint8_t*) serialized_descriptor;
-	if (sdescriptor[1] != USB_DESCTYPE_HUB) return NULL;
-	usb_hub_descriptor_t * result = (usb_hub_descriptor_t*) malloc(sizeof (usb_hub_descriptor_t));
-	//uint8_t size = sdescriptor[0];
+
+	if (sdescriptor[1] != USB_DESCTYPE_HUB) {
+		printf("[usb_hub] wrong descriptor %x\n",sdescriptor[1]);
+		return NULL;
+	}
+
+	usb_hub_descriptor_t * result = usb_new(usb_hub_descriptor_t);
+	
+
 	result->ports_count = sdescriptor[2];
 	/// @fixme handling of endianness??
@@ -94,5 +104,5 @@
 	size_t var_size = result->ports_count / 8 + ((result->ports_count % 8 > 0) ? 1 : 0);
 	result->devices_removable = (uint8_t*) malloc(var_size);
-
+	//printf("[usb_hub] getting removable devices data \n");
 	size_t i;
 	for (i = 0; i < var_size; ++i) {
@@ -102,26 +112,265 @@
 }
 
+//control transactions
+
+int usb_drv_sync_control_read(
+		int phone, usb_target_t target,
+		usb_device_request_setup_packet_t * request,
+		void * rcvd_buffer, size_t rcvd_size, size_t * actual_size
+		) {
+	usb_handle_t handle;
+	int opResult;
+	//setup
+	opResult = usb_drv_async_control_read_setup(phone, target,
+			request, sizeof (usb_device_request_setup_packet_t),
+			&handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	opResult = usb_drv_async_wait_for(handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	//read
+	opResult = usb_drv_async_control_read_data(phone, target,
+			rcvd_buffer, rcvd_size, actual_size,
+			&handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	opResult = usb_drv_async_wait_for(handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	//finalize
+	opResult = usb_drv_async_control_read_status(phone, target,
+			&handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	opResult = usb_drv_async_wait_for(handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	return EOK;
+}
+
+int usb_drv_sync_control_write(
+		int phone, usb_target_t target,
+		usb_device_request_setup_packet_t * request,
+		void * sent_buffer, size_t sent_size
+		) {
+	usb_handle_t handle;
+	int opResult;
+	//setup
+	opResult = usb_drv_async_control_write_setup(phone, target,
+			request, sizeof (usb_device_request_setup_packet_t),
+			&handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	opResult = usb_drv_async_wait_for(handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	//write
+	opResult = usb_drv_async_control_write_data(phone, target,
+			sent_buffer, sent_size,
+			&handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	opResult = usb_drv_async_wait_for(handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	//finalize
+	opResult = usb_drv_async_control_write_status(phone, target,
+			&handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	opResult = usb_drv_async_wait_for(handle);
+	if (opResult != EOK) {
+		return opResult;
+	}
+	return EOK;
+}
+
+//list implementation
+
+usb_general_list_t * usb_lst_create(void) {
+	usb_general_list_t* result = usb_new(usb_general_list_t);
+	usb_lst_init(result);
+	return result;
+}
+
+void usb_lst_init(usb_general_list_t * lst) {
+	lst->prev = lst;
+	lst->next = lst;
+	lst->data = NULL;
+}
+
+void usb_lst_prepend(usb_general_list_t* item, void* data) {
+	usb_general_list_t* appended = usb_new(usb_general_list_t);
+	appended->data = data;
+	appended->next = item;
+	appended->prev = item->prev;
+	item->prev->next = appended;
+	item->prev = appended;
+}
+
+void usb_lst_append(usb_general_list_t* item, void* data) {
+	usb_general_list_t* appended = usb_new(usb_general_list_t);
+	appended->data = data;
+	appended->next = item->next;
+	appended->prev = item;
+	item->next->prev = appended;
+	item->next = appended;
+}
+
+void usb_lst_remove(usb_general_list_t* item) {
+	item->next->prev = item->prev;
+	item->prev->next = item->next;
+}
+
+static void usb_hub_test_port_status(void) {
+	printf("[usb_hub] -------------port status test---------\n");
+	usb_port_status_t status = 0;
+
+	//printf("original status %d (should be 0)\n",(uint32_t)status);
+	usb_port_set_bit(&status, 1, 1);
+	//printf("%d =?= 2\n",(uint32_t)status);
+	if (status != 2) {
+		printf("[usb_port_status] test failed: wrong set of bit 1\n");
+		return;
+	}
+	usb_port_set_bit(&status, 3, 1);
+	if (status != 10) {
+		printf("[usb_port_status] test failed: wrong set of bit 3\n");
+		return;
+	}
+
+	usb_port_set_bit(&status, 15, 1);
+	if (status != 10 + (1 << 15)) {
+		printf("[usb_port_status] test failed: wrong set of bit 15\n");
+		return;
+	}
+	usb_port_set_bit(&status, 1, 0);
+	if (status != 8 + (1 << 15)) {
+		printf("[usb_port_status] test failed: wrong unset of bit 1\n");
+		return;
+	}
+	int i;
+	for (i = 0; i < 32; ++i) {
+		if (i == 3 || i == 15) {
+			if (!usb_port_get_bit(&status, i)) {
+				printf("[usb_port_status] test failed: wrong bit at %d\n", i);
+			}
+		} else {
+			if (usb_port_get_bit(&status, i)) {
+				printf("[usb_port_status] test failed: wrong bit at %d\n", i);
+			}
+		}
+	}
+
+	printf("test ok\n");
+
+
+	//printf("%d =?= 10\n",(uint32_t)status);
+
+	//printf("this should be 0: %d \n",usb_port_get_bit(&status,0));
+	//printf("this should be 1: %d \n",usb_port_get_bit(&status,1));
+	//printf("this should be 0: %d \n",usb_port_get_bit(&status,2));
+	//printf("this should be 1: %d \n",usb_port_get_bit(&status,3));
+	//printf("this should be 0: %d \n",usb_port_get_bit(&status,4));
+
+
+
+
+}
 
 //*********************************************
 //
-//  hub driver code
+//  hub driver code, initialization
 //
 //*********************************************
 
-usb_hcd_hub_info_t * usb_create_hub_info(device_t * device) {
-	usb_hcd_hub_info_t* result = (usb_hcd_hub_info_t*) malloc(sizeof (usb_hcd_hub_info_t));
+usb_hub_info_t * usb_create_hub_info(device_t * device, int hc) {
+	usb_hub_info_t* result = usb_new(usb_hub_info_t);
+	//result->device = device;
+	result->port_count = -1;
+	/// \TODO is this correct? is the device stored?
+	result->device = device;
+
+
+	//printf("[usb_hub] phone to hc = %d\n", hc);
+	if (hc < 0) {
+		return result;
+	}
+	//get some hub info
+	usb_address_t addr = usb_drv_get_my_address(hc, device);
+	printf("[usb_hub] addres of newly created hub = %d\n", addr);
+	/*if(addr<0){
+		//return result;
+		
+	}*/
+
+	result->usb_device = usb_new(usb_hcd_attached_device_info_t);
+	result->usb_device->address = addr;
+
+	// get hub descriptor
+	usb_target_t target;
+	target.address = addr;
+	target.endpoint = 0;
+	usb_device_request_setup_packet_t request;
+	//printf("[usb_hub] creating descriptor request\n");
+	usb_hub_set_descriptor_request(&request);
+
+	//printf("[usb_hub] creating serialized descriptor\n");
+	void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
+	usb_hub_descriptor_t * descriptor;
+	size_t received_size;
+	int opResult;
+	//printf("[usb_hub] starting control transaction\n");
+	opResult = usb_drv_sync_control_read(
+			hc, target, &request, serialized_descriptor,
+			USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
+	if (opResult != EOK) {
+		printf("[usb_hub] failed when receiving hub descriptor, badcode = %d\n",opResult);
+		///\TODO memory leak will occur here!
+		return result;
+	}
+	//printf("[usb_hub] deserializing descriptor\n");
+	descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
+	if(descriptor==NULL){
+		printf("[usb_hub] could not deserialize descriptor \n");
+		result->port_count = 1;///\TODO this code is only for debug!!!
+		return result;
+	}
+	//printf("[usb_hub] setting port count to %d\n",descriptor->ports_count);
+	result->port_count = descriptor->ports_count;
+	result->attached_devs = (usb_hub_attached_device_t*)
+	    malloc((result->port_count+1) * sizeof(usb_hub_attached_device_t));
+	int i;
+	for(i=0;i<result->port_count+1;++i){
+		result->attached_devs[i].devman_handle=0;
+		result->attached_devs[i].address=0;
+	}
+	//printf("[usb_hub] freeing data\n");
+	free(serialized_descriptor);
+	free(descriptor->devices_removable);
+	free(descriptor);
+
+	//finish
+
+	printf("[usb_hub] hub info created\n");
 
 	return result;
 }
 
-/** Callback when new hub device is detected.
- *
- * @param dev New device.
- * @return Error code.
- */
 int usb_add_hub_device(device_t *dev) {
 	printf(NAME ": add_hub_device(handle=%d)\n", (int) dev->handle);
-
-	check_hub_changes();
+	printf("[usb_hub] hub device\n");
 
 	/*
@@ -132,6 +381,80 @@
 
 	//create the hub structure
-	usb_hcd_hub_info_t * hub_info = usb_create_hub_info(dev);
-	(void)hub_info;
+	//get hc connection
+	/// \TODO correct params
+	int hc = usb_drv_hc_connect(dev, 0);
+
+	usb_hub_info_t * hub_info = usb_create_hub_info(dev, hc);
+	int port;
+	int opResult;
+	usb_device_request_setup_packet_t request;
+	usb_target_t target;
+	target.address = hub_info->usb_device->address;
+	target.endpoint = 0;
+
+	//get configuration descriptor
+	// this is not fully correct - there are more configurations
+	// and all should be checked
+	usb_standard_device_descriptor_t std_descriptor;
+	opResult = usb_drv_req_get_device_descriptor(hc, target.address,
+    &std_descriptor);
+	if(opResult!=EOK){
+		printf("[usb_hub] could not get device descriptor, %d\n",opResult);
+		return 1;///\TODO some proper error code needed
+	}
+	printf("[usb_hub] hub has %d configurations\n",std_descriptor.configuration_count);
+	if(std_descriptor.configuration_count<1){
+		printf("[usb_hub] THERE ARE NO CONFIGURATIONS AVAILABLE\n");
+	}
+	usb_standard_configuration_descriptor_t config_descriptor;
+	opResult = usb_drv_req_get_bare_configuration_descriptor(hc,
+        target.address, 0,
+        &config_descriptor);
+	if(opResult!=EOK){
+		printf("[usb_hub] could not get configuration descriptor, %d\n",opResult);
+		return 1;///\TODO some proper error code needed
+	}
+	//set configuration
+	request.request_type = 0;
+	request.request = USB_DEVREQ_SET_CONFIGURATION;
+	request.index=0;
+	request.length=0;
+	request.value_high=0;
+	request.value_low = config_descriptor.configuration_number;
+	opResult = usb_drv_sync_control_write(hc, target, &request, NULL, 0);
+	if (opResult != EOK) {
+		printf("[usb_hub]something went wrong when setting hub`s configuration, %d\n", opResult);
+	}
+
+
+	for (port = 1; port < hub_info->port_count+1; ++port) {
+		usb_hub_set_power_port_request(&request, port);
+		opResult = usb_drv_sync_control_write(hc, target, &request, NULL, 0);
+		printf("[usb_hub] powering port %d\n",port);
+		if (opResult != EOK) {
+			printf("[usb_hub]something went wrong when setting hub`s %dth port\n", port);
+		}
+	}
+	//ports powered, hub seems to be enabled
+	
+
+	ipc_hangup(hc);
+
+	//add the hub to list
+	usb_lst_append(&usb_hub_list, hub_info);
+	printf("[usb_hub] hub info added to list\n");
+	//(void)hub_info;
+	usb_hub_check_hub_changes();
+
+	/// \TODO start the check loop, if not already started...
+
+	//this is just a test for port status bitmap type
+	usb_hub_test_port_status();
+
+	printf("[usb_hub] hub dev added\n");
+	printf("\taddress %d, has %d ports \n",
+			hub_info->usb_device->address,
+			hub_info->port_count);
+	printf("\tused configuration %d\n",config_descriptor.configuration_number);
 
 	return EOK;
@@ -139,26 +462,242 @@
 }
 
+//*********************************************
+//
+//  hub driver code, main loop
+//
+//*********************************************
+
+/**
+ * reset the port with new device and reserve the default address
+ * @param hc
+ * @param port
+ * @param target
+ */
+static void usb_hub_init_add_device(int hc, uint16_t port, usb_target_t target) {
+	usb_device_request_setup_packet_t request;
+	int opResult;
+	printf("[usb_hub] some connection changed\n");
+	//get default address
+	opResult = usb_drv_reserve_default_address(hc);
+	if (opResult != EOK) {
+		printf("[usb_hub] cannot assign default address, it is probably used\n");
+		return;
+	}
+	//reset port
+	usb_hub_set_reset_port_request(&request, port);
+	opResult = usb_drv_sync_control_write(
+			hc, target,
+			&request,
+			NULL, 0
+			);
+	if (opResult != EOK) {
+		//continue;
+		printf("[usb_hub] something went wrong when reseting a port\n");
+	}
+}
+
+/**
+ * finalize adding new device after port reset
+ * @param hc
+ * @param port
+ * @param target
+ */
+static void usb_hub_finalize_add_device( usb_hub_info_t * hub,
+		int hc, uint16_t port, usb_target_t target) {
+
+	int opResult;
+	printf("[usb_hub] finalizing add device\n");
+	opResult = usb_hub_clear_port_feature(hc, target.address,
+	    port, USB_HUB_FEATURE_C_PORT_RESET);
+	if (opResult != EOK) {
+		goto release;
+	}
+
+	/* Request address at from host controller. */
+	usb_address_t new_device_address = usb_drv_request_address(hc);
+	if (new_device_address < 0) {
+		printf("[usb_hub] failed to get free USB address\n");
+		opResult = new_device_address;
+		goto release;
+	}
+	printf("[usb_hub] setting new address\n");
+	opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
+	    new_device_address);
+
+	if (opResult != EOK) {
+		printf("[usb_hub] could not set address for new device\n");
+		goto release;
+	}
+
+release:
+	printf("[usb_hub] releasing default address\n");
+	usb_drv_release_default_address(hc);
+	if (opResult != EOK) {
+		return;
+	}
+
+	devman_handle_t child_handle;
+	opResult = usb_drv_register_child_in_devman(hc, hub->device,
+            new_device_address, &child_handle);
+	if (opResult != EOK) {
+		printf("[usb_hub] could not start driver for new device \n");
+		return;
+	}
+	hub->attached_devs[port].devman_handle = child_handle;
+	hub->attached_devs[port].address = new_device_address;
+
+	opResult = usb_drv_bind_address(hc, new_device_address, child_handle);
+	if (opResult != EOK) {
+		printf("[usb_hub] could not assign address of device in hcd \n");
+		return;
+	}
+	printf("[usb_hub] new device address %d, handle %d\n",
+	    new_device_address, child_handle);
+	
+}
+
+/**
+ * unregister device address in hc, close the port
+ * @param hc
+ * @param port
+ * @param target
+ */
+static void usb_hub_removed_device(
+    usb_hub_info_t * hub, int hc, uint16_t port, usb_target_t target) {
+	//usb_device_request_setup_packet_t request;
+	int opResult;
+	//disable port
+	/*usb_hub_set_disable_port_request(&request, port);
+	opResult = usb_drv_sync_control_write(
+			hc, target,
+			&request,
+			NULL, 0
+			);
+	if (opResult != EOK) {
+		//continue;
+		printf("[usb_hub] something went wrong when disabling a port\n");
+	}*/
+	/// \TODO remove device
+
+	hub->attached_devs[port].devman_handle=0;
+	//close address
+	if(hub->attached_devs[port].address!=0){
+		opResult = usb_drv_release_address(hc,hub->attached_devs[port].address);
+		if(opResult != EOK) {
+			printf("[usb_hub] could not release address of removed device: %d\n",opResult);
+		}
+		hub->attached_devs[port].address = 0;
+	}else{
+		printf("[usb_hub] this is strange, disconnected device had no address\n");
+		//device was disconnected before it`s port was reset - return default address
+		usb_drv_release_default_address(hc);
+	}
+}
+
+/**
+ * process interrupts on given hub port
+ * @param hc
+ * @param port
+ * @param target
+ */
+static void usb_hub_process_interrupt(usb_hub_info_t * hub, int hc,
+        uint16_t port, usb_address_t address) {
+	printf("[usb_hub] interrupt at port %d\n", port);
+	//determine type of change
+	usb_target_t target;
+	target.address=address;
+	target.endpoint=0;
+	usb_port_status_t status;
+	size_t rcvd_size;
+	usb_device_request_setup_packet_t request;
+	int opResult;
+	usb_hub_set_port_status_request(&request, port);
+	//endpoint 0
+
+	opResult = usb_drv_sync_control_read(
+			hc, target,
+			&request,
+			&status, 4, &rcvd_size
+			);
+	if (opResult != EOK) {
+		printf("[usb_hub] ERROR: could not get port status\n");
+		return;
+	}
+	if (rcvd_size != sizeof (usb_port_status_t)) {
+		printf("[usb_hub] ERROR: received status has incorrect size\n");
+		return;
+	}
+	//something connected/disconnected
+	if (usb_port_connect_change(&status)) {
+		opResult = usb_hub_clear_port_feature(hc, target.address,
+		    port, USB_HUB_FEATURE_C_PORT_CONNECTION);
+		// TODO: check opResult
+		if (usb_port_dev_connected(&status)) {
+			printf("[usb_hub] some connection changed\n");
+			usb_hub_init_add_device(hc, port, target);
+		} else {
+			usb_hub_removed_device(hub, hc, port, target);
+		}
+	}
+	//port reset
+	if (usb_port_reset_completed(&status)) {
+		printf("[usb_hub] port reset complete\n");
+		if (usb_port_enabled(&status)) {
+			usb_hub_finalize_add_device(hub, hc, port, target);
+		} else {
+			printf("[usb_hub] ERROR: port reset, but port still not enabled\n");
+		}
+	}
+
+	usb_port_set_connect_change(&status, false);
+	usb_port_set_reset(&status, false);
+	usb_port_set_reset_completed(&status, false);
+	usb_port_set_dev_connected(&status, false);
+	if (status) {
+		printf("[usb_hub]there was some unsupported change on port %d\n",port);
+	}
+	/// \TODO handle other changes
+	/// \TODO debug log for various situations
+
+
+
+	/*
+	//configure device
+	usb_drv_reserve_default_address(hc);
+
+	usb_address_t new_device_address = usb_drv_request_address(hc);
+
+
+	usb_drv_release_default_address(hc);
+	 * */
+}
 
 /** Check changes on all known hubs.
  */
-static void check_hub_changes(void) {
+void usb_hub_check_hub_changes(void) {
 	/*
 	 * Iterate through all hubs.
 	 */
-	for (; false; ) {
+	usb_general_list_t * lst_item;
+	for (lst_item = usb_hub_list.next;
+			lst_item != &usb_hub_list;
+			lst_item = lst_item->next) {
+		usb_hub_info_t * hub_info = ((usb_hub_info_t*)lst_item->data);
 		/*
 		 * Check status change pipe of this hub.
 		 */
-		usb_target_t target = {
-			.address = 5,
-			.endpoint = 1
-		};
-
-		size_t port_count = 7;
+
+		usb_target_t target;
+		target.address = hub_info->usb_device->address;
+		target.endpoint = 1;/// \TODO get from endpoint descriptor
+		printf("[usb_hub] checking changes for hub at addr %d\n",
+		    target.address);
+
+		size_t port_count = hub_info->port_count;
 
 		/*
 		 * Connect to respective HC.
 		 */
-		int hc = usb_drv_hc_connect(NULL, 0);
+		int hc = usb_drv_hc_connect(hub_info->device, 0);
 		if (hc < 0) {
 			continue;
@@ -166,5 +705,5 @@
 
 		// FIXME: count properly
-		size_t byte_length = (port_count / 8) + 1;
+		size_t byte_length = ((port_count+1) / 8) + 1;
 
 		void *change_bitmap = malloc(byte_length);
@@ -174,11 +713,24 @@
 		/*
 		 * Send the request.
-		 * FIXME: check returned value for possible errors
-		 */
-		usb_drv_async_interrupt_in(hc, target,
+		 */
+		int opResult = usb_drv_async_interrupt_in(hc, target,
 				change_bitmap, byte_length, &actual_size,
 				&handle);
 
 		usb_drv_async_wait_for(handle);
+
+		if (opResult != EOK) {
+			printf("[usb_hub] something went wrong while getting status of hub\n");
+			continue;
+		}
+		unsigned int port;
+		for (port = 1; port < port_count+1; ++port) {
+			bool interrupt = (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
+			if (interrupt) {
+				usb_hub_process_interrupt(
+				        hub_info, hc, port, hub_info->usb_device->address);
+			}
+		}
+
 
 		/*
Index: uspace/drv/usbkbd/main.c
===================================================================
--- uspace/drv/usbkbd/main.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/usbkbd/main.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -28,75 +28,264 @@
 #include <usb/usbdrv.h>
 #include <driver.h>
+#include <ipc/driver.h>
 #include <errno.h>
+#include <fibril.h>
+#include <usb/classes/hid.h>
+#include <usb/classes/hidparser.h>
+#include <usb/devreq.h>
+#include <usb/descriptor.h>
 
 #define BUFFER_SIZE 32
-
-/* Call this periodically to check keyboard status changes. */
-static void poll_keyboard(device_t *dev)
+#define NAME "usbkbd"
+
+#define GUESSED_POLL_ENDPOINT 1
+
+/*
+ * Callbacks for parser
+ */
+static void usbkbd_process_keycodes(const uint16_t *key_codes, size_t count,
+                                    void *arg)
+{
+
+}
+
+/*
+ * Kbd functions
+ */
+static int usbkbd_parse_descriptors(usb_hid_dev_kbd_t *kbd_dev,
+                                    const uint8_t *data, size_t size)
+{
+//	const uint8_t *pos = data;
+	
+//	// get the configuration descriptor (should be first)
+//	if (*pos != sizeof(usb_standard_configuration_descriptor_t)
+//	    || *(pos + 1) != USB_DESCTYPE_CONFIGURATION) {
+//		fprintf(stderr, "Wrong format of configuration descriptor");
+//		return EINVAL;
+//	}
+	
+//	usb_standard_configuration_descriptor_t config_descriptor;
+//	memcpy(&config_descriptor, pos, 
+//	    sizeof(usb_standard_configuration_descriptor_t));
+//	pos += sizeof(usb_standard_configuration_descriptor_t);
+	
+//	// parse other descriptors
+//	while (pos - data < size) {
+//		//uint8_t desc_size = *pos;
+//		uint8_t desc_type = *(pos + 1);
+//		switch (desc_type) {
+//		case USB_DESCTYPE_INTERFACE:
+//			break;
+//		case USB_DESCTYPE_ENDPOINT:
+//			break;
+//		case USB_DESCTYPE_HID:
+//			break;
+//		case USB_DESCTYPE_HID_REPORT:
+//			break;
+//		case USB_DESCTYPE_HID_PHYSICAL:
+//			break;
+//		}
+//	}
+	
+	return EOK;
+}
+
+static int usbkbd_get_descriptors(usb_hid_dev_kbd_t *kbd_dev)
+{
+	// get the first configuration descriptor (TODO: or some other??)
+	usb_standard_configuration_descriptor_t config_desc;
+	
+	int rc = usb_drv_req_get_bare_configuration_descriptor(
+	    kbd_dev->device->parent_phone, kbd_dev->address, 0, &config_desc);
+	
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	// prepare space for all underlying descriptors
+	uint8_t *descriptors = (uint8_t *)malloc(config_desc.total_length);
+	if (descriptors == NULL) {
+		return ENOMEM;
+	}
+	
+	size_t transferred = 0;
+	// get full configuration descriptor
+	rc = usb_drv_req_get_full_configuration_descriptor(
+	    kbd_dev->device->parent_phone, kbd_dev->address, 0, descriptors,
+	    config_desc.total_length, &transferred);
+	
+	if (rc != EOK) {
+		return rc;
+	}
+	if (transferred != config_desc.total_length) {
+		return ELIMIT;
+	}
+	
+	rc = usbkbd_parse_descriptors(kbd_dev, descriptors, transferred);
+	free(descriptors);
+	
+	return rc;
+}
+
+static usb_hid_dev_kbd_t *usbkbd_init_device(device_t *dev)
+{
+	usb_hid_dev_kbd_t *kbd_dev = (usb_hid_dev_kbd_t *)malloc(
+			sizeof(usb_hid_dev_kbd_t));
+
+	if (kbd_dev == NULL) {
+		fprintf(stderr, NAME ": No memory!\n");
+		return NULL;
+	}
+
+	kbd_dev->device = dev;
+
+	// get phone to my HC and save it as my parent's phone
+	// TODO: maybe not a good idea if DDF will use parent_phone
+	kbd_dev->device->parent_phone = usb_drv_hc_connect(dev, 0);
+
+	kbd_dev->address = usb_drv_get_my_address(dev->parent_phone,
+	    dev);
+
+	// doesn't matter now that we have no address
+//	if (kbd_dev->address < 0) {
+//		fprintf(stderr, NAME ": No device address!\n");
+//		free(kbd_dev);
+//		return NULL;
+//	}
+
+	// default endpoint
+	kbd_dev->poll_endpoint = GUESSED_POLL_ENDPOINT;
+	
+	/*
+	 * will need all descriptors:
+	 * 1) choose one configuration from configuration descriptors 
+	 *    (set it to the device)
+	 * 2) set endpoints from endpoint descriptors
+	 */
+
+	// TODO: get descriptors
+	usbkbd_get_descriptors(kbd_dev);
+	// TODO: parse descriptors and save endpoints
+
+	return kbd_dev;
+}
+
+static void usbkbd_process_interrupt_in(usb_hid_dev_kbd_t *kbd_dev,
+                                        uint8_t *buffer, size_t actual_size)
+{
+	/*
+	 * here, the parser will be called, probably with some callbacks
+	 * now only take last 6 bytes and process, i.e. send to kbd
+	 */
+
+	usb_hid_report_in_callbacks_t *callbacks =
+	    (usb_hid_report_in_callbacks_t *)malloc(
+		sizeof(usb_hid_report_in_callbacks_t));
+	callbacks->keyboard = usbkbd_process_keycodes;
+
+	usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks, 
+	    NULL);
+}
+
+static void usbkbd_poll_keyboard(usb_hid_dev_kbd_t *kbd_dev)
 {
 	int rc;
 	usb_handle_t handle;
-	char buffer[BUFFER_SIZE];
+	uint8_t buffer[BUFFER_SIZE];
 	size_t actual_size;
-	usb_endpoint_t poll_endpoint = 1;
-
-	usb_address_t my_address = usb_drv_get_my_address(dev->parent_phone,
-	    dev);
-	if (my_address < 0) {
-		return;
-	}
+	//usb_endpoint_t poll_endpoint = 1;
+
+//	usb_address_t my_address = usb_drv_get_my_address(dev->parent_phone,
+//	    dev);
+//	if (my_address < 0) {
+//		return;
+//	}
 
 	usb_target_t poll_target = {
-		.address = my_address,
-		.endpoint = poll_endpoint
+		.address = kbd_dev->address,
+		.endpoint = kbd_dev->poll_endpoint
 	};
 
-	rc = usb_drv_async_interrupt_in(dev->parent_phone, poll_target,
-	    buffer, BUFFER_SIZE, &actual_size, &handle);
-	if (rc != EOK) {
-		return;
-	}
-
-	rc = usb_drv_async_wait_for(handle);
-	if (rc != EOK) {
-		return;
-	}
-
-	/*
-	 * If the keyboard answered with NAK, it returned no data.
-	 * This implies that no change happened since last query.
-	 */
-	if (actual_size == 0) {
-		return;
-	}
-
-	/*
-	 * Process pressed keys.
-	 */
-}
-
-static int add_kbd_device(device_t *dev)
+	while (true) {
+		async_usleep(1000 * 1000);
+		rc = usb_drv_async_interrupt_in(kbd_dev->device->parent_phone,
+		    poll_target, buffer, BUFFER_SIZE, &actual_size, &handle);
+
+		if (rc != EOK) {
+			continue;
+		}
+
+		rc = usb_drv_async_wait_for(handle);
+		if (rc != EOK) {
+			continue;
+		}
+
+		/*
+		 * If the keyboard answered with NAK, it returned no data.
+		 * This implies that no change happened since last query.
+		 */
+		if (actual_size == 0) {
+			continue;
+		}
+
+		/*
+		 * TODO: Process pressed keys.
+		 */
+		usbkbd_process_interrupt_in(kbd_dev, buffer, actual_size);
+	}
+
+	// not reached
+	assert(0);
+}
+
+static int usbkbd_fibril_device(void *arg)
+{
+	printf("!!! USB device fibril\n");
+
+	if (arg == NULL) {
+		printf("No device!\n");
+		return -1;
+	}
+
+	device_t *dev = (device_t *)arg;
+
+	// initialize device (get and process descriptors, get address, etc.)
+	usb_hid_dev_kbd_t *kbd_dev = usbkbd_init_device(dev);
+
+	usbkbd_poll_keyboard(kbd_dev);
+
+	return EOK;
+}
+
+static int usbkbd_add_device(device_t *dev)
 {
 	/* For now, fail immediately. */
-	return ENOTSUP;
+	//return ENOTSUP;
 
 	/*
 	 * When everything is okay, connect to "our" HC.
-	 */
-	int phone = usb_drv_hc_connect(dev, 0);
-	if (phone < 0) {
-		/*
-		 * Connecting to HC failed, roll-back and announce
-		 * failure.
-		 */
-		return phone;
-	}
-
-	dev->parent_phone = phone;
-
-	/*
-	 * Just for fun ;-).
-	 */
-	poll_keyboard(dev);
+	 *
+	 * Not supported yet, skip..
+	 */
+//	int phone = usb_drv_hc_connect(dev, 0);
+//	if (phone < 0) {
+//		/*
+//		 * Connecting to HC failed, roll-back and announce
+//		 * failure.
+//		 */
+//		return phone;
+//	}
+
+//	dev->parent_phone = phone;
+
+	/*
+	 * Create new fibril for handling this keyboard
+	 */
+	fid_t fid = fibril_create(usbkbd_fibril_device, dev);
+	if (fid == 0) {
+		printf("%s: failed to start fibril for HID device\n", NAME);
+		return ENOMEM;
+	}
+	fibril_add_ready(fid);
 
 	/*
@@ -107,9 +296,9 @@
 
 static driver_ops_t kbd_driver_ops = {
-	.add_device = add_kbd_device,
+	.add_device = usbkbd_add_device,
 };
 
 static driver_t kbd_driver = {
-	.name = "usbkbd",
+	.name = NAME,
 	.driver_ops = &kbd_driver_ops
 };
Index: uspace/drv/usbkbd/usbkbd.ma
===================================================================
--- uspace/drv/usbkbd/usbkbd.ma	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/usbkbd/usbkbd.ma	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -1,2 +1,4 @@
 10 usb&class=hid
+10 usb&class=HID
+10 usb&interface&class=HID
 10 usb&hid
Index: uspace/drv/vhc/Makefile
===================================================================
--- uspace/drv/vhc/Makefile	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -39,5 +39,4 @@
 
 SOURCES = \
-	addrmgm.c \
 	conndev.c \
 	connhost.c \
Index: pace/drv/vhc/addrmgm.c
===================================================================
--- uspace/drv/vhc/addrmgm.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ 	(revision )
@@ -1,199 +1,0 @@
-/*
- * 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 usb
- * @{
- */
-/** @file
- * @brief Address management.
- */
-
-#include <usb/usb.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <str_error.h>
-#include <fibril_synch.h>
-
-#include "vhcd.h"
-#include "conn.h"
-
-#define ADDRESS_COUNT 100
-#define DEFAULT_ADDRESS 0
-
-typedef struct {
-	usb_address_t address;
-	devman_handle_t devman_handle;
-	bool available;
-} address_info_t;
-
-static address_info_t dev_address[ADDRESS_COUNT];
-fibril_mutex_t address_guard;
-
-typedef struct {
-	fibril_mutex_t condvar_guard;
-	fibril_condvar_t condvar;
-	bool available;
-} reservable_address_info_t;
-
-static reservable_address_info_t default_address;
-
-void address_init(void)
-{
-	usb_address_t i;
-	for (i = 0; i < ADDRESS_COUNT; i++) {
-		dev_address[i].address = i + 1;
-		dev_address[i].available = true;
-		dev_address[i].devman_handle = 0;
-	}
-
-	fibril_mutex_initialize(&address_guard);
-	fibril_mutex_initialize(&default_address.condvar_guard);
-	fibril_condvar_initialize(&default_address.condvar);
-}
-
-int reserve_default_address(device_t *dev)
-{
-	fibril_mutex_lock(&default_address.condvar_guard);
-	while (!default_address.available) {
-		fibril_condvar_wait(&default_address.condvar,
-		    &default_address.condvar_guard);
-	}
-	fibril_mutex_unlock(&default_address.condvar_guard);
-
-	return EOK;
-}
-
-int release_default_address(device_t *dev)
-{
-	fibril_mutex_lock(&default_address.condvar_guard);
-	default_address.available = true;
-	fibril_condvar_signal(&default_address.condvar);
-	fibril_mutex_unlock(&default_address.condvar_guard);
-
-	return EOK;
-}
-
-int request_address(device_t *dev, usb_address_t *address)
-{
-	fibril_mutex_lock(&address_guard);
-	usb_address_t i;
-	bool found = false;
-	for (i = 0; i < ADDRESS_COUNT; i++) {
-		if (dev_address[i].available) {
-			dev_address[i].available = false;
-			*address = dev_address[i].address;
-			found = true;
-			break;
-		}
-	}
-	fibril_mutex_unlock(&address_guard);
-
-	if (!found) {
-		return ELIMIT;
-	} else {
-		return EOK;
-	}
-}
-
-int bind_address(device_t *dev, usb_address_t address, devman_handle_t handle)
-{
-	if (address == DEFAULT_ADDRESS) {
-		return EPERM;
-	}
-
-	int rc = EPERM;
-
-	fibril_mutex_lock(&address_guard);
-	usb_address_t i;
-	for (i = 0; i < ADDRESS_COUNT; i++) {
-		if (dev_address[i].address == address) {
-			if (dev_address[i].available) {
-				rc = ENOENT;
-				break;
-			}
-
-			dev_address[i].devman_handle = handle;
-			rc = EOK;
-			break;
-		}
-	}
-	fibril_mutex_unlock(&address_guard);
-
-	return rc;
-}
-
-int tell_address(device_t *dev, devman_handle_t handle, usb_address_t *address)
-{
-	int rc = ENOENT;
-
-	fibril_mutex_lock(&address_guard);
-	usb_address_t i;
-	for (i = 0; i < ADDRESS_COUNT; i++) {
-		if (dev_address[i].devman_handle == handle) {
-			*address = dev_address[i].address;
-			rc = EOK;
-			break;
-		}
-	}
-	fibril_mutex_unlock(&address_guard);
-
-	return rc;
-}
-
-int release_address(device_t *dev, usb_address_t address)
-{
-	if (address == DEFAULT_ADDRESS) {
-		return EPERM;
-	}
-
-	int rc = EPERM;
-
-	fibril_mutex_lock(&address_guard);
-	usb_address_t i;
-	for (i = 0; i < ADDRESS_COUNT; i++) {
-		if (dev_address[i].address == address) {
-			if (dev_address[i].available) {
-				rc = ENOENT;
-				break;
-			}
-
-			dev_address[i].available = true;
-			dev_address[i].devman_handle = 0;
-			rc = EOK;
-			break;
-		}
-	}
-	fibril_mutex_unlock(&address_guard);
-
-	return rc;
-}
-
-/**
- * @}
- */
Index: uspace/drv/vhc/conn.h
===================================================================
--- uspace/drv/vhc/conn.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/conn.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -48,11 +48,5 @@
 
 void address_init(void);
-int reserve_default_address(device_t *);
-int release_default_address(device_t *);
-int request_address(device_t *, usb_address_t *);
-int release_address(device_t *, usb_address_t);
-int bind_address(device_t *, usb_address_t, devman_handle_t);
 
-int tell_address(device_t *, devman_handle_t, usb_address_t *);
 
 void default_connection_handler(device_t *, ipc_callid_t, ipc_call_t *);
Index: uspace/drv/vhc/connhost.c
===================================================================
--- uspace/drv/vhc/connhost.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/connhost.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -36,4 +36,5 @@
 #include <errno.h>
 #include <usb/usb.h>
+#include <usb/hcd.h>
 
 #include "vhcd.h"
@@ -57,5 +58,5 @@
 		case USB_DIRECTION_IN:
 			transfer->in_callback(transfer->dev,
-			    size, outcome,
+			    outcome, size,
 			    transfer->arg);
 			break;
@@ -92,5 +93,5 @@
     usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	printf(NAME ": transfer OUT [%d.%d (%s); %u]\n",
+	dprintf(3, "transfer OUT [%d.%d (%s); %zu]",
 	    target.address, target.endpoint,
 	    usb_str_transfer_type(transfer_type),
@@ -112,5 +113,5 @@
     usbhc_iface_transfer_out_callback_t callback, void *arg)
 {
-	printf(NAME ": transfer SETUP [%d.%d (%s); %u]\n",
+	dprintf(3, "transfer SETUP [%d.%d (%s); %zu]",
 	    target.address, target.endpoint,
 	    usb_str_transfer_type(transfer_type),
@@ -132,5 +133,5 @@
     usbhc_iface_transfer_in_callback_t callback, void *arg)
 {
-	printf(NAME ": transfer IN [%d.%d (%s); %u]\n",
+	dprintf(3, "transfer IN [%d.%d (%s); %zu]",
 	    target.address, target.endpoint,
 	    usb_str_transfer_type(transfer_type),
@@ -218,4 +219,58 @@
 }
 
+static usb_address_keeping_t addresses;
+
+
+static int reserve_default_address(device_t *dev)
+{
+	usb_address_keeping_reserve_default(&addresses);
+	return EOK;
+}
+
+static int release_default_address(device_t *dev)
+{
+	usb_address_keeping_release_default(&addresses);
+	return EOK;
+}
+
+static int request_address(device_t *dev, usb_address_t *address)
+{
+	usb_address_t addr = usb_address_keeping_request(&addresses);
+	if (addr < 0) {
+		return (int)addr;
+	}
+
+	*address = addr;
+	return EOK;
+}
+
+static int release_address(device_t *dev, usb_address_t address)
+{
+	return usb_address_keeping_release(&addresses, address);
+}
+
+static int bind_address(device_t *dev, usb_address_t address,
+    devman_handle_t handle)
+{
+	usb_address_keeping_devman_bind(&addresses, address, handle);
+	return EOK;
+}
+
+static int tell_address(device_t *dev, devman_handle_t handle,
+    usb_address_t *address)
+{
+	usb_address_t addr = usb_address_keeping_find(&addresses, handle);
+	if (addr < 0) {
+		return addr;
+	}
+
+	*address = addr;
+	return EOK;
+}
+
+void address_init(void)
+{
+	usb_address_keeping_init(&addresses, 50);
+}
 
 usbhc_iface_t vhc_iface = {
Index: uspace/drv/vhc/debug.c
===================================================================
--- uspace/drv/vhc/debug.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/debug.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -35,31 +35,8 @@
 #include <stdio.h>
 #include <ipc/ipc.h>
+#include <usb/debug.h>
 
 #include "vhcd.h"
 
-/** Current debug level. */
-int debug_level = 0;
-
-/** Debugging printf.
- * This function is intended for single-line messages as it
- * automatically prints debugging prefix at the beginning of the
- * line.
- *
- * @see printf
- * @param level Debugging level.
- */
-void dprintf(int level, const char *format, ...)
-{
-	if (level > debug_level) {
-		return;
-	}
-	
-	printf("%s(%d): ", NAME, level);
-	va_list args;
-	va_start(args, format);
-	vprintf(format, args);
-	va_end(args);
-	printf("\n");
-}
 
 /** Debug print informing of invalid call.
Index: uspace/drv/vhc/devices.c
===================================================================
--- uspace/drv/vhc/devices.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/devices.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -147,5 +147,5 @@
 	if (virthub_dev.address == transaction->target.address) {
 		size_t tmp;
-		dprintf(3, "sending `%s' transaction to hub",
+		dprintf(1, "sending `%s' transaction to hub",
 		    usbvirt_str_transaction_type(transaction->type));
 		switch (transaction->type) {
Index: uspace/drv/vhc/hc.c
===================================================================
--- uspace/drv/vhc/hc.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/hc.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -50,7 +50,7 @@
 #include "hub.h"
 
-#define USLEEP_BASE (500 * 1000)
+#define USLEEP_BASE (0 * 5 * 1000)
 
-#define USLEEP_VAR 5000
+#define USLEEP_VAR 50
 
 #define SHORTENING_VAR 15
@@ -89,5 +89,5 @@
     usb_transaction_outcome_t outcome)
 {
-	dprintf(3, "processing transaction " TRANSACTION_FORMAT ", outcome: %s",
+	dprintf(3, "transaction " TRANSACTION_FORMAT " done, outcome: %s",
 	    TRANSACTION_PRINTF(*transaction),
 	    usb_str_transaction_outcome(outcome));
@@ -116,5 +116,5 @@
 		char ports[HUB_PORT_COUNT + 2];
 		hub_get_port_statuses(ports, HUB_PORT_COUNT + 1);
-		dprintf(3, "virtual hub: addr=%d ports=%s",
+		dprintf(4, "virtual hub: addr=%d ports=%s",
 		    virthub_dev.address, ports);
 		
@@ -124,4 +124,8 @@
 		list_remove(first_transaction_link);
 		
+
+		dprintf(0, "about to process " TRANSACTION_FORMAT " (vhub:%s)",
+		    TRANSACTION_PRINTF(*transaction), ports);
+
 		dprintf(3, "processing transaction " TRANSACTION_FORMAT "",
 		    TRANSACTION_PRINTF(*transaction));
@@ -153,5 +157,5 @@
 	transaction->callback_arg = arg;
 	
-	dprintf(1, "creating transaction " TRANSACTION_FORMAT,
+	dprintf(3, "creating transaction " TRANSACTION_FORMAT,
 	    TRANSACTION_PRINTF(*transaction));
 	
Index: uspace/drv/vhc/hcd.c
===================================================================
--- uspace/drv/vhc/hcd.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/hcd.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -79,6 +79,5 @@
 	 * Initialize our hub and announce its presence.
 	 */
-	hub_init();
-	usb_hcd_add_root_hub(dev);
+	hub_init(dev);
 
 	printf("%s: virtual USB host controller ready.\n", NAME);
@@ -111,5 +110,5 @@
 	printf("%s: virtual USB host controller driver.\n", NAME);
 
-	debug_level = 10;
+	usb_dprintf_enable(NAME, 0);
 
 	fid_t fid = fibril_create(hc_manager_fibril, NULL);
Index: uspace/drv/vhc/hub.c
===================================================================
--- uspace/drv/vhc/hub.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/hub.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -37,9 +37,12 @@
 #include <usbvirt/device.h>
 #include <errno.h>
+#include <str_error.h>
 #include <stdlib.h>
+#include <driver.h>
 
 #include "vhcd.h"
 #include "hub.h"
 #include "hubintern.h"
+#include "conn.h"
 
 
@@ -141,5 +144,5 @@
 	.ops = &hub_ops,
 	.descriptors = &descriptors,
-	.lib_debug_level = 4,
+	.lib_debug_level = 0,
 	.lib_debug_enabled_tags = USBVIRT_DEBUGTAG_ALL
 };
@@ -148,14 +151,39 @@
 hub_device_t hub_dev;
 
+static usb_address_t hub_set_address(usbvirt_device_t *hub)
+{
+	usb_address_t new_address;
+	int rc = vhc_iface.request_address(NULL, &new_address);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 0,
+		.request = USB_DEVREQ_SET_ADDRESS,
+		.index = 0,
+		.length = 0,
+	};
+	setup_packet.value = new_address;
+
+	hub->transaction_setup(hub, 0, &setup_packet, sizeof(setup_packet));
+	hub->transaction_in(hub, 0, NULL, 0, NULL);
+	
+	return new_address;
+}
+
 /** Initialize virtual hub. */
-void hub_init(void)
-{
-	size_t i;
+void hub_init(device_t *hc_dev)
+{
+	size_t i;
+	
 	for (i = 0; i < HUB_PORT_COUNT; i++) {
 		hub_port_t *port = &hub_dev.ports[i];
 		
+		port->index = (int) i + 1;
 		port->device = NULL;
 		port->state = HUB_PORT_STATE_NOT_CONFIGURED;
 		port->status_change = 0;
+		fibril_mutex_initialize(&port->guard);
 	}
 	
@@ -163,4 +191,27 @@
 	
 	dprintf(1, "virtual hub (%d ports) created", HUB_PORT_COUNT);
+
+	usb_address_t hub_address = hub_set_address(&virthub_dev);
+	if (hub_address < 0) {
+		dprintf(1, "problem changing hub address (%s)",
+		    str_error(hub_address));
+	}
+
+	dprintf(2, "virtual hub address changed to %d", hub_address);
+
+	char *id;
+	int rc = asprintf(&id, "usb&hub");
+	if (rc <= 0) {
+		return;
+	}
+	devman_handle_t hub_handle;
+	rc = child_device_register_wrapper(hc_dev, "hub", id, 10, &hub_handle);
+	if (rc != EOK) {
+		free(id);
+	}
+
+	vhc_iface.bind_address(NULL, hub_address, hub_handle);	
+
+	dprintf(2, "virtual hub has devman handle %d", (int) hub_handle);
 }
 
@@ -175,6 +226,8 @@
 	for (i = 0; i < HUB_PORT_COUNT; i++) {
 		hub_port_t *port = &hub_dev.ports[i];
+		fibril_mutex_lock(&port->guard);
 		
 		if (port->device != NULL) {
+			fibril_mutex_unlock(&port->guard);
 			continue;
 		}
@@ -191,7 +244,9 @@
 		//if (port->state == HUB_PORT_STATE_DISCONNECTED) {
 			port->state = HUB_PORT_STATE_DISABLED;
-			set_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
+			set_port_status_change_nl(port, HUB_STATUS_C_PORT_CONNECTION);
 		//}
 		
+		fibril_mutex_unlock(&port->guard);
+
 		return i;
 	}
Index: uspace/drv/vhc/hub.h
===================================================================
--- uspace/drv/vhc/hub.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/hub.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -37,8 +37,9 @@
 
 #include <usbvirt/device.h>
+#include <driver.h>
 
 #include "devices.h"
 
-#define HUB_PORT_COUNT 6
+#define HUB_PORT_COUNT 2
 
 #define BITS2BYTES(bits) \
@@ -47,5 +48,5 @@
 extern usbvirt_device_t virthub_dev;
 
-void hub_init(void);
+void hub_init(device_t *);
 size_t hub_add_device(virtdev_connection_t *);
 void hub_remove_device(virtdev_connection_t *);
Index: uspace/drv/vhc/hubintern.h
===================================================================
--- uspace/drv/vhc/hubintern.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/hubintern.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -37,4 +37,5 @@
 
 #include "hub.h"
+#include <fibril_synch.h>
 
 /** Endpoint number for status change pipe. */
@@ -121,6 +122,8 @@
 typedef struct {
 	virtdev_connection_t *device;
+	int index;
 	hub_port_state_t state;
 	uint16_t status_change;
+	fibril_mutex_t guard;
 } hub_port_t;
 
@@ -138,4 +141,5 @@
 void clear_port_status_change(hub_port_t *, uint16_t);
 void set_port_status_change(hub_port_t *, uint16_t);
+void set_port_status_change_nl(hub_port_t *, uint16_t);
 
 
Index: uspace/drv/vhc/hubops.c
===================================================================
--- uspace/drv/vhc/hubops.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/hubops.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -59,4 +59,6 @@
 static int on_get_descriptor(struct usbvirt_device *dev,
     usb_device_request_setup_packet_t *request, uint8_t *data);
+static int on_set_configuration(struct usbvirt_device *dev,
+    usb_device_request_setup_packet_t *request, uint8_t *data);
 static int on_class_request(struct usbvirt_device *dev,
     usb_device_request_setup_packet_t *request, uint8_t *data);
@@ -64,8 +66,12 @@
     usb_endpoint_t endpoint,
     void *buffer, size_t size, size_t *actual_size);
+static void set_port_state(hub_port_t *, hub_port_state_t);
+static void clear_port_status_change_nl(hub_port_t *, uint16_t);
+static void set_port_state_nl(hub_port_t *, hub_port_state_t);
 
 /** Hub operations. */
 usbvirt_device_ops_t hub_ops = {
 	.on_standard_request[USB_DEVREQ_GET_DESCRIPTOR] = on_get_descriptor,
+	.on_standard_request[USB_DEVREQ_SET_CONFIGURATION] = on_set_configuration,
 	.on_class_device_request = on_class_request,
 	.on_data = NULL,
@@ -87,27 +93,100 @@
 }
 
+/** Callback for SET_CONFIGURATION request. */
+int on_set_configuration(struct usbvirt_device *dev,
+    usb_device_request_setup_packet_t *request, uint8_t *data)
+{
+	/* We must suspend power source to all ports. */
+	size_t i;
+	for (i = 0; i < HUB_PORT_COUNT; i++) {
+		hub_port_t *port = &hub_dev.ports[i];
+		
+		set_port_state(port, HUB_PORT_STATE_POWERED_OFF);
+	}
+	
+	/* Let the framework handle the rest of the job. */
+	return EFORWARD;
+}
+
+struct delay_port_state_change {
+	suseconds_t delay;
+	hub_port_state_t old_state;
+	hub_port_state_t new_state;
+	hub_port_t *port;
+};
+
+static int set_port_state_delayed_fibril(void *arg)
+{
+	struct delay_port_state_change *change
+	    = (struct delay_port_state_change *) arg;
+	
+	async_usleep(change->delay);
+	
+	fibril_mutex_lock(&change->port->guard);
+	if (change->port->state == change->old_state) {
+		set_port_state_nl(change->port, change->new_state);
+	}
+	fibril_mutex_unlock(&change->port->guard);
+	
+	free(change);
+	
+	return EOK;
+}
+
+static void set_port_state_delayed(hub_port_t *port,
+    suseconds_t delay_time,
+    hub_port_state_t old_state, hub_port_state_t new_state)
+{
+	struct delay_port_state_change *change
+	    = malloc(sizeof(struct delay_port_state_change));
+	change->port = port;
+	change->delay = delay_time;
+	change->old_state = old_state;
+	change->new_state = new_state;
+	fid_t fibril = fibril_create(set_port_state_delayed_fibril, change);
+	if (fibril == 0) {
+		printf("Failed to create fibril\n");
+		return;
+	}
+	fibril_add_ready(fibril);
+}
+
 /** Change port status and updates status change status fields.
  */
-static void set_port_state(hub_port_t *port, hub_port_state_t state)
-{
+void set_port_state(hub_port_t *port, hub_port_state_t state)
+{
+	fibril_mutex_lock(&port->guard);
+	set_port_state_nl(port, state);
+	fibril_mutex_unlock(&port->guard);
+}
+
+void set_port_state_nl(hub_port_t *port, hub_port_state_t state)
+{
+
+	dprintf(2, "setting port %d state to %d (%c) from %c (change=%u)",
+	    port->index,
+	    state, hub_port_state_as_char(state),
+	    hub_port_state_as_char(port->state),
+	    (unsigned int) port->status_change);
+	
+	if (state == HUB_PORT_STATE_POWERED_OFF) {
+		clear_port_status_change_nl(port, HUB_STATUS_C_PORT_CONNECTION);
+		clear_port_status_change_nl(port, HUB_STATUS_C_PORT_ENABLE);
+		clear_port_status_change_nl(port, HUB_STATUS_C_PORT_RESET);
+	}
+	if (state == HUB_PORT_STATE_RESUMING) {
+		set_port_state_delayed(port, 10*1000,
+		    HUB_PORT_STATE_RESUMING, HUB_PORT_STATE_ENABLED);
+	}
+	if (state == HUB_PORT_STATE_RESETTING) {
+		set_port_state_delayed(port, 10*1000,
+		    HUB_PORT_STATE_RESETTING, HUB_PORT_STATE_ENABLED);
+	}
+	if ((port->state == HUB_PORT_STATE_RESETTING)
+	    && (state == HUB_PORT_STATE_ENABLED)) {
+		set_port_status_change_nl(port, HUB_STATUS_C_PORT_RESET);
+	}
+	
 	port->state = state;
-	if (state == HUB_PORT_STATE_POWERED_OFF) {
-		clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
-		clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);
-		clear_port_status_change(port, HUB_STATUS_C_PORT_RESET);
-	}
-	if (state == HUB_PORT_STATE_RESUMING) {
-		async_usleep(10*1000);
-		if (port->state == state) {
-			set_port_state(port, HUB_PORT_STATE_ENABLED);
-		}
-	}
-	if (state == HUB_PORT_STATE_RESETTING) {
-		async_usleep(10*1000);
-		if (port->state == state) {
-			set_port_status_change(port, HUB_STATUS_C_PORT_RESET);
-			set_port_state(port, HUB_PORT_STATE_ENABLED);
-		}
-	}
 }
 
@@ -122,5 +201,5 @@
 		} \
 	} while (false); \
-	hub_port_t *portvar = &hub_dev.ports[index]
+	hub_port_t *portvar = &hub_dev.ports[index-1]
 
 
@@ -134,53 +213,80 @@
 	_GET_PORT(port, portindex);
 	
+	fibril_mutex_lock(&port->guard);
+	int rc = ENOTSUP;
+
 	switch (feature) {
 		case USB_HUB_FEATURE_PORT_ENABLE:
 			if ((port->state != HUB_PORT_STATE_NOT_CONFIGURED)
 			    && (port->state != HUB_PORT_STATE_POWERED_OFF)) {
-				set_port_state(port, HUB_PORT_STATE_DISABLED);
-			}
-			return EOK;
+				set_port_state_nl(port, HUB_PORT_STATE_DISABLED);
+			}
+			rc = EOK;
+			break;
 		
 		case USB_HUB_FEATURE_PORT_SUSPEND:
 			if (port->state != HUB_PORT_STATE_SUSPENDED) {
-				return EOK;
-			}
-			set_port_state(port, HUB_PORT_STATE_RESUMING);
-			return EOK;
+				rc = EOK;
+				break;
+			}
+			set_port_state_nl(port, HUB_PORT_STATE_RESUMING);
+			rc = EOK;
+			break;
 			
 		case USB_HUB_FEATURE_PORT_POWER:
 			if (port->state != HUB_PORT_STATE_NOT_CONFIGURED) {
-				set_port_state(port, HUB_PORT_STATE_POWERED_OFF);
-			}
-			return EOK;
+				set_port_state_nl(port, HUB_PORT_STATE_POWERED_OFF);
+			}
+			rc = EOK;
+			break;
 		
 		case USB_HUB_FEATURE_C_PORT_CONNECTION:
-			clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
-			return EOK;
+			clear_port_status_change_nl(port, HUB_STATUS_C_PORT_CONNECTION);
+			rc = EOK;
+			break;
 		
 		case USB_HUB_FEATURE_C_PORT_ENABLE:
-			clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);
-			return EOK;
+			clear_port_status_change_nl(port, HUB_STATUS_C_PORT_ENABLE);
+			rc = EOK;
+			break;
 		
 		case USB_HUB_FEATURE_C_PORT_SUSPEND:
-			clear_port_status_change(port, HUB_STATUS_C_PORT_SUSPEND);
-			return EOK;
+			clear_port_status_change_nl(port, HUB_STATUS_C_PORT_SUSPEND);
+			rc = EOK;
+			break;
 			
 		case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
-			clear_port_status_change(port, HUB_STATUS_C_PORT_OVER_CURRENT);
-			return EOK;
-	}
-	
+			clear_port_status_change_nl(port, HUB_STATUS_C_PORT_OVER_CURRENT);
+			rc = EOK;
+			break;
+
+		case USB_HUB_FEATURE_C_PORT_RESET:
+			clear_port_status_change_nl(port, HUB_STATUS_C_PORT_RESET);
+			rc = EOK;
+			break;
+	}
+	
+	fibril_mutex_unlock(&port->guard);
+
+	return rc;
+}
+
+static int get_bus_state(uint16_t portindex)
+{
 	return ENOTSUP;
 }
 
-static int get_bus_state(uint16_t portindex)
-{
-	return ENOTSUP;
-}
-
-static int get_hub_descriptor(uint8_t descriptor_type,
-    uint8_t descriptor_index, uint16_t length)
-{
+static int get_hub_descriptor(struct usbvirt_device *dev,
+    uint8_t descriptor_index,
+    uint8_t descriptor_type, uint16_t length)
+{
+	if (descriptor_type == USB_DESCTYPE_HUB) {
+		int rc = dev->control_transfer_reply(dev, 0,
+		    &hub_descriptor, hub_descriptor.length);
+
+		return rc;
+
+	}
+
 	return ENOTSUP;
 }
@@ -198,4 +304,6 @@
 	_GET_PORT(port, portindex);
 	
+	fibril_mutex_lock(&port->guard);
+
 	uint32_t status;
 	status = MAKE_BYTE(
@@ -225,4 +333,8 @@
 	status |= (port->status_change << 16);
 	
+	fibril_mutex_unlock(&port->guard);
+
+	dprintf(2, "GetPortStatus(port=%d, status=%u)\n", (int)portindex,
+	    (unsigned int) status);
 	return virthub_dev.control_transfer_reply(&virthub_dev, 0, &status, 4);
 }
@@ -238,24 +350,33 @@
 	_GET_PORT(port, portindex);
 	
+	fibril_mutex_lock(&port->guard);
+
+	int rc = ENOTSUP;
+
 	switch (feature) {
 		case USB_HUB_FEATURE_PORT_RESET:
 			if (port->state != HUB_PORT_STATE_POWERED_OFF) {
-				set_port_state(port, HUB_PORT_STATE_RESETTING);
-			}
-			return EOK;
+				set_port_state_nl(port, HUB_PORT_STATE_RESETTING);
+			}
+			rc = EOK;
+			break;
 		
 		case USB_HUB_FEATURE_PORT_SUSPEND:
 			if (port->state == HUB_PORT_STATE_ENABLED) {
-				set_port_state(port, HUB_PORT_STATE_SUSPENDED);
-			}
-			return EOK;
+				set_port_state_nl(port, HUB_PORT_STATE_SUSPENDED);
+			}
+			rc = EOK;
+			break;
 		
 		case USB_HUB_FEATURE_PORT_POWER:
 			if (port->state == HUB_PORT_STATE_POWERED_OFF) {
-				set_port_state(port, HUB_PORT_STATE_DISCONNECTED);
-			}
-			return EOK;
-	}
-	return ENOTSUP;
+				set_port_state_nl(port, HUB_PORT_STATE_DISCONNECTED);
+			}
+			rc = EOK;
+			break;
+	}
+
+	fibril_mutex_unlock(&port->guard);
+	return rc;
 }
 
@@ -267,5 +388,5 @@
     usb_device_request_setup_packet_t *request, uint8_t *data)
 {	
-	dprintf(2, "hub class request (%d)\n", (int) request->request);
+	dprintf(2, "hub class request (%d)", (int) request->request);
 	
 	uint8_t recipient = request->request_type & 31;
@@ -298,5 +419,5 @@
 			
 		case USB_HUB_REQUEST_GET_DESCRIPTOR:
-			return get_hub_descriptor(request->value_low,
+			return get_hub_descriptor(dev, request->value_low,
 			    request->value_high, request->length);
 			
@@ -316,4 +437,6 @@
 			
 		default:
+			dprintf(0, "WARN: unknown request (%d)!\n",
+			    request->request);
 			break;
 	}
@@ -325,12 +448,31 @@
 }
 
+void clear_port_status_change_nl(hub_port_t *port, uint16_t change)
+{
+	port->status_change &= (~change);
+	dprintf(2, "cleared port %d status change %d (%u)", port->index,
+	    (int)change, (unsigned int) port->status_change);
+}
+
+void set_port_status_change_nl(hub_port_t *port, uint16_t change)
+{
+	port->status_change |= change;
+	dprintf(2, "set port %d status change %d (%u)", port->index,
+	    (int)change, (unsigned int) port->status_change);
+
+}
+
 void clear_port_status_change(hub_port_t *port, uint16_t change)
 {
-	port->status_change &= (~change);
+	fibril_mutex_lock(&port->guard);
+	clear_port_status_change_nl(port, change);
+	fibril_mutex_unlock(&port->guard);
 }
 
 void set_port_status_change(hub_port_t *port, uint16_t change)
 {
-	port->status_change |= change;
+	fibril_mutex_lock(&port->guard);
+	set_port_status_change_nl(port, change);
+	fibril_mutex_unlock(&port->guard);
 }
 
@@ -350,7 +492,9 @@
 		hub_port_t *port = &hub_dev.ports[i];
 		
+		fibril_mutex_lock(&port->guard);
 		if (port->status_change != 0) {
 			change_map |= (1 << (i + 1));
 		}
+		fibril_mutex_unlock(&port->guard);
 	}
 	
Index: uspace/drv/vhc/vhcd.h
===================================================================
--- uspace/drv/vhc/vhcd.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/drv/vhc/vhcd.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -36,4 +36,6 @@
 #define VHCD_VHCD_H_
 
+#include <usb/debug.h>
+
 #define NAME "vhc"
 #define NAME_DEV "hcd-virt-dev"
@@ -43,6 +45,6 @@
 #define DEVMAP_PATH_DEV NAMESPACE "/" NAME_DEV
 
-extern int debug_level;
-void dprintf(int, const char *, ...);
+#define dprintf(level, format, ...) \
+	usb_dprintf(NAME, (level), format "\n", ##__VA_ARGS__)
 void dprintf_inval_call(int, ipc_call_t, ipcarg_t);
 
Index: uspace/lib/c/generic/adt/char_map.c
===================================================================
--- uspace/lib/c/generic/adt/char_map.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/c/generic/adt/char_map.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -90,8 +90,8 @@
 	}
 
-	map->items[map->next]->c = * identifier;
-	++ identifier;
-	++ map->next;
-	if ((length > 1) || ((length == 0) && (*identifier))) {
+	map->items[map->next]->c = *identifier;
+	identifier++;
+	map->next++;
+	if ((length > 1) || ((length == 0) && *identifier)) {
 		map->items[map->next - 1]->value = CHAR_MAP_NULL;
 		return char_map_add_item(map->items[map->next - 1], identifier,
@@ -142,14 +142,13 @@
     const int value)
 {
-	if (char_map_is_valid(map) && (identifier) &&
-	    ((length) || (*identifier))) {
+	if (char_map_is_valid(map) && identifier && (length || *identifier)) {
 		int index;
 
-		for (index = 0; index < map->next; ++ index) {
+		for (index = 0; index < map->next; index++) {
 			if (map->items[index]->c != *identifier)
 				continue;
 				
-			++ identifier;
-			if((length > 1) || ((length == 0) && (*identifier))) {
+			identifier++;
+			if((length > 1) || ((length == 0) && *identifier)) {
 				return char_map_add(map->items[index],
 				    identifier, length ? length - 1 : 0, value);
@@ -178,5 +177,5 @@
 
 		map->magic = 0;
-		for (index = 0; index < map->next; ++index)
+		for (index = 0; index < map->next; index++)
 			char_map_destroy(map->items[index]);
 
@@ -207,10 +206,10 @@
 		return NULL;
 
-	if (length || (*identifier)) {
+	if (length || *identifier) {
 		int index;
 
-		for (index = 0; index < map->next; ++index) {
+		for (index = 0; index < map->next; index++) {
 			if (map->items[index]->c == *identifier) {
-				++identifier;
+				identifier++;
 				if (length == 1)
 					return map->items[index];
Index: uspace/lib/c/generic/devman.c
===================================================================
--- uspace/lib/c/generic/devman.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/c/generic/devman.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -116,7 +116,8 @@
 {
 	ipc_call_t answer;
-	async_send_1(phone, DEVMAN_ADD_MATCH_ID, match_id->score, &answer);
+	aid_t req = async_send_1(phone, DEVMAN_ADD_MATCH_ID, match_id->score, &answer);
 	int retval = async_data_write_start(phone, match_id->id, str_size(match_id->id));
-	return retval;	
+	async_wait_for(req, NULL);
+	return retval;
 }
 
Index: uspace/lib/c/include/adt/generic_field.h
===================================================================
--- uspace/lib/c/include/adt/generic_field.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/c/include/adt/generic_field.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -91,5 +91,5 @@
 			} \
 			field->items[field->next] = value; \
-			++field->next; \
+			field->next++; \
 			field->items[field->next] = NULL; \
 			return field->next - 1; \
@@ -108,5 +108,5 @@
 			int index; \
 			field->magic = 0; \
-			for (index = 0; index < field->next; ++ index) { \
+			for (index = 0; index < field->next; index++) { \
 				if (field->items[index]) \
 					free(field->items[index]); \
Index: uspace/lib/c/include/errno.h
===================================================================
--- uspace/lib/c/include/errno.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/c/include/errno.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -83,8 +83,6 @@
 #define ENOTCONN	(-10057)
 
-/** The requested operation was not performed.
- *  Try again later.
- */
-#define TRY_AGAIN	(-11002)
+/** The requested operation was not performed. Try again later. */
+#define EAGAIN		(-11002)
 
 /** No data.
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -54,4 +54,14 @@
 	DEV_IFACE_ID(DEV_FIRST_CUSTOM_METHOD_IDX)
 
+/*
+ * The first argument is actually method (as the "real" method is used
+ * for indexing into interfaces.
+ */
+
+#define DEV_IPC_GET_ARG1(call) IPC_GET_ARG2((call))
+#define DEV_IPC_GET_ARG2(call) IPC_GET_ARG3((call))
+#define DEV_IPC_GET_ARG3(call) IPC_GET_ARG4((call))
+#define DEV_IPC_GET_ARG4(call) IPC_GET_ARG5((call))
+
 
 #endif
Index: uspace/lib/c/include/ipc/vfs.h
===================================================================
--- uspace/lib/c/include/ipc/vfs.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/c/include/ipc/vfs.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -36,6 +36,7 @@
 #define LIBC_IPC_VFS_H_
 
+#include <ipc/ipc.h>
 #include <sys/types.h>
-#include <ipc/ipc.h>
+#include <bool.h>
 
 #define FS_NAME_MAXLEN  20
@@ -55,4 +56,6 @@
 	/** Unique identifier of the fs. */
 	char name[FS_NAME_MAXLEN + 1];
+	bool concurrent_read_write;
+	bool write_retains_size;
 } vfs_info_t;
 
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/drv/generic/driver.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -381,4 +381,61 @@
 }
 
+/** Wrapper for child_device_register for devices with single match id.
+ *
+ * @param parent Parent device.
+ * @param child_name Child device name.
+ * @param child_match_id Child device match id.
+ * @param child_match_score Child device match score.
+ * @return Error code.
+ */
+int child_device_register_wrapper(device_t *parent, const char *child_name,
+    const char *child_match_id, int child_match_score,
+    devman_handle_t *child_handle)
+{
+	device_t *child = NULL;
+	match_id_t *match_id = NULL;
+	int rc;
+
+	child = create_device();
+	if (child == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	child->name = child_name;
+
+	match_id = create_match_id();
+	if (match_id == NULL) {
+		rc = ENOMEM;
+		goto failure;
+	}
+
+	match_id->id = child_match_id;
+	match_id->score = child_match_score;
+	add_match_id(&child->match_ids, match_id);
+
+	rc = child_device_register(child, parent);
+	if (EOK != rc)
+		goto failure;
+
+	if (child_handle != NULL) {
+		*child_handle = child->handle;
+	}
+	return EOK;
+
+failure:
+	if (match_id != NULL) {
+		match_id->id = NULL;
+		delete_match_id(match_id);
+	}
+
+	if (child != NULL) {
+		child->name = NULL;
+		delete_device(child);
+	}
+
+	return rc;
+}
+
 int driver_main(driver_t *drv)
 {
Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -108,5 +108,5 @@
 	}
 
-	devman_handle_t handle = IPC_GET_ARG1(*call);
+	devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
 
 	usb_address_t address;
@@ -122,5 +122,5 @@
     ipc_callid_t callid, ipc_call_t *call)
 {
-	ipcarg_t buffer_hash = IPC_GET_ARG1(*call);
+	ipcarg_t buffer_hash = DEV_IPC_GET_ARG1(*call);
 	async_transaction_t * trans = (async_transaction_t *)buffer_hash;
 	if (trans == NULL) {
@@ -144,5 +144,5 @@
 		accepted_size = trans->size;
 	}
-	async_data_read_finalize(callid, trans->buffer, accepted_size);
+	async_data_read_finalize(cid, trans->buffer, accepted_size);
 
 	ipc_answer_1(callid, EOK, accepted_size);
@@ -211,6 +211,6 @@
 	}
 
-	usb_address_t address = (usb_address_t) IPC_GET_ARG1(*call);
-	devman_handle_t handle = (devman_handle_t) IPC_GET_ARG2(*call);
+	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+	devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
 
 	int rc = usb_iface->bind_address(device, address, handle);
@@ -229,5 +229,5 @@
 	}
 
-	usb_address_t address = (usb_address_t) IPC_GET_ARG1(*call);
+	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
 
 	int rc = usb_iface->release_address(device, address);
@@ -275,8 +275,8 @@
 	}
 
-	size_t expected_len = IPC_GET_ARG3(*call);
+	size_t expected_len = DEV_IPC_GET_ARG3(*call);
 	usb_target_t target = {
-		.address = IPC_GET_ARG1(*call),
-		.endpoint = IPC_GET_ARG2(*call)
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
 	};
 
@@ -327,8 +327,8 @@
 	}
 
-	size_t len = IPC_GET_ARG3(*call);
+	size_t len = DEV_IPC_GET_ARG3(*call);
 	usb_target_t target = {
-		.address = IPC_GET_ARG1(*call),
-		.endpoint = IPC_GET_ARG2(*call)
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
 	};
 
@@ -384,6 +384,6 @@
 
 	usb_target_t target = {
-		.address = IPC_GET_ARG1(*call),
-		.endpoint = IPC_GET_ARG2(*call)
+		.address = DEV_IPC_GET_ARG1(*call),
+		.endpoint = DEV_IPC_GET_ARG2(*call)
 	};
 
Index: uspace/lib/drv/include/driver.h
===================================================================
--- uspace/lib/drv/include/driver.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/drv/include/driver.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -199,4 +199,6 @@
 
 int child_device_register(device_t *, device_t *);
+int child_device_register_wrapper(device_t *, const char *, const char *, int,
+    devman_handle_t *);
 
 
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usb/Makefile	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -33,9 +33,16 @@
 
 SOURCES = \
+	src/addrkeep.c \
+	src/class.c \
+	src/debug.c \
+	src/drvpsync.c \
 	src/hcdhubd.c \
 	src/hcdrv.c \
+	src/hidparser.c \
 	src/localdrv.c \
+	src/recognise.c \
 	src/remotedrv.c \
 	src/usb.c \
+	src/usbdrvreq.c \
 	src/usbdrv.c
 
Index: uspace/lib/usb/include/usb/classes/classes.h
===================================================================
--- uspace/lib/usb/include/usb/classes/classes.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usb/include/usb/classes/classes.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -60,4 +60,5 @@
 } usb_class_t;
 
+const char *usb_str_class(usb_class_t);
 
 #endif
Index: uspace/lib/usb/include/usb/classes/hid.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hid.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usb/include/usb/classes/hid.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -36,4 +36,8 @@
 #define LIBUSB_HID_H_
 
+#include <usb/usb.h>
+#include <driver.h>
+#include <usb/classes/hidparser.h>
+
 /** USB/HID device requests. */
 typedef enum {
@@ -54,4 +58,50 @@
 } usb_hid_protocol_t;
 
+/** Part of standard USB HID descriptor specifying one class descriptor.
+ *
+ * (See HID Specification, p.22)
+ */
+typedef struct {
+	/** Type of class descriptor (Report or Physical). */
+	uint8_t class_descriptor_type;
+	/** Length of class descriptor. */
+	uint16_t class_descriptor_length;
+} __attribute__ ((packed)) usb_standard_hid_descriptor_class_item_t;
+
+/** Standard USB HID descriptor.
+ *
+ * (See HID Specification, p.22)
+ * 
+ * It is actually only the "header" of the descriptor, as it may have arbitrary
+ * length if more than one class descritor is provided.
+ */
+typedef struct {
+	/** Size of this descriptor in bytes. */
+	uint8_t length;
+	/** Descriptor type (USB_DESCTYPE_HID). */
+	uint8_t descriptor_type;
+	/** HID Class Specification release. */
+	uint16_t spec_release;
+	/** Country code of localized hardware. */
+	uint8_t country_code;
+	/** Total number of class (i.e. Report and Physical) descriptors. */
+	uint8_t class_count;
+	/** First mandatory class descriptor info. */
+	usb_standard_hid_descriptor_class_item_t class_descriptor;
+} __attribute__ ((packed)) usb_standard_hid_descriptor_t;
+
+
+/**
+ * @brief USB/HID keyboard device type.
+ *
+ * Quite dummy right now.
+ */
+typedef struct {
+	device_t *device;
+	usb_address_t address;
+	usb_endpoint_t poll_endpoint;
+	usb_hid_report_parser_t *parser;
+} usb_hid_dev_kbd_t;
+
 #endif
 /**
Index: uspace/lib/usb/include/usb/classes/hidparser.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hidparser.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/lib/usb/include/usb/classes/hidparser.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,65 @@
+/*
+ * 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 USB HID parser.
+ */
+#ifndef LIBUSB_HIDPARSER_H_
+#define LIBUSB_HIDPARSER_H_
+
+#include <stdint.h>
+
+/** HID report parser structure. */
+typedef struct {
+} usb_hid_report_parser_t;
+
+/** HID parser callbacks for IN items. */
+typedef struct {
+	/** Callback for keyboard.
+	 *
+	 * @param key_codes Array of pressed key (including modifiers).
+	 * @param count Length of @p key_codes.
+	 * @param arg Custom argument.
+	 */
+	void (*keyboard)(const uint16_t *key_codes, size_t count, void *arg);
+} usb_hid_report_in_callbacks_t;
+
+int usb_hid_parse_report_descriptor(usb_hid_report_parser_t *parser, 
+    const uint8_t *data, size_t size);
+
+int usb_hid_parse_report(const usb_hid_report_parser_t *parser,  
+    const uint8_t *data, size_t size,
+    const usb_hid_report_in_callbacks_t *callbacks, void *arg);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/classes/hub.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hub.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usb/include/usb/classes/hub.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -177,4 +177,5 @@
 
 /** @brief hub class request codes*/
+/// \TODO these are duplicit to standart descriptors
 typedef enum {
     /**  */
@@ -213,11 +214,4 @@
 usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * sdescriptor);
 
-/**
- * @brief create hub structure instance
- * 
- * @param device
- * @return
- */
-usb_hcd_hub_info_t * usb_create_hub_info(device_t * device);
 
 
Index: uspace/lib/usb/include/usb/debug.h
===================================================================
--- uspace/lib/usb/include/usb/debug.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/lib/usb/include/usb/debug.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,42 @@
+/*
+ * 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 related functions.
+ */
+#ifndef LIBUSB_DEBUG_H_
+#define LIBUSB_DEBUG_H_
+
+void usb_dprintf(const char *tag, int level, const char *format, ...);
+void usb_dprintf_enable(const char *tag, int level);
+
+
+#endif
Index: uspace/lib/usb/include/usb/devreq.h
===================================================================
--- uspace/lib/usb/include/usb/devreq.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usb/include/usb/devreq.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -38,4 +38,6 @@
 #include <ipc/ipc.h>
 #include <async.h>
+#include <usb/usb.h>
+#include <usb/descriptor.h>
 
 /** Standard device request. */
@@ -83,4 +85,13 @@
 } __attribute__ ((packed)) usb_device_request_setup_packet_t;
 
+int usb_drv_req_set_address(int, usb_address_t, usb_address_t);
+int usb_drv_req_get_device_descriptor(int, usb_address_t,
+    usb_standard_device_descriptor_t *);
+int usb_drv_req_get_bare_configuration_descriptor(int, usb_address_t, int,
+    usb_standard_configuration_descriptor_t *);
+int usb_drv_req_get_full_configuration_descriptor(int, usb_address_t, int,
+    void *, size_t, size_t *);
+
+
 #endif
 /**
Index: uspace/lib/usb/include/usb/hcd.h
===================================================================
--- uspace/lib/usb/include/usb/hcd.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/lib/usb/include/usb/hcd.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,84 @@
+/*
+ * 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 HC driver.
+ */
+#ifndef LIBUSB_HCD_H_
+#define LIBUSB_HCD_H_
+
+#include <usb/usb.h>
+#include <fibril_synch.h>
+#include <devman.h>
+
+/** Info about used address. */
+typedef struct {
+	/** Linked list member. */
+	link_t link;
+	/** Address. */
+	usb_address_t address;
+	/** Corresponding devman handle. */
+	devman_handle_t devman_handle;
+} usb_address_keeping_used_t;
+
+/** Structure for keeping track of free and used USB addresses. */
+typedef struct {
+	/** Head of list of used addresses. */
+	link_t used_addresses;
+	/** Upper bound for USB addresses. */
+	usb_address_t max_address;
+	/** Mutex protecting used address. */
+	fibril_mutex_t used_addresses_guard;
+	/** Condition variable for used addresses. */
+	fibril_condvar_t used_addresses_condvar;
+
+	/** Condition variable mutex for default address. */
+	fibril_mutex_t default_condvar_guard;
+	/** Condition variable for default address. */
+	fibril_condvar_t default_condvar;
+	/** Whether is default address available. */
+	bool default_available;
+} usb_address_keeping_t;
+
+void usb_address_keeping_init(usb_address_keeping_t *, usb_address_t);
+
+void usb_address_keeping_reserve_default(usb_address_keeping_t *);
+void usb_address_keeping_release_default(usb_address_keeping_t *);
+
+usb_address_t usb_address_keeping_request(usb_address_keeping_t *);
+int usb_address_keeping_release(usb_address_keeping_t *, usb_address_t);
+void usb_address_keeping_devman_bind(usb_address_keeping_t *, usb_address_t,
+    devman_handle_t);
+usb_address_t usb_address_keeping_find(usb_address_keeping_t *,
+    devman_handle_t);
+
+
+#endif
Index: uspace/lib/usb/include/usb/hcdhubd.h
===================================================================
--- uspace/lib/usb/include/usb/hcdhubd.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usb/include/usb/hcdhubd.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -65,13 +65,4 @@
 } usb_hcd_attached_device_info_t;
 
-/** Information about attached hub. */
-typedef struct {
-	/** Number of ports. */
-	size_t port_count;
-	/** General device info. */
-	usb_hcd_attached_device_info_t *device;
-	/** Link to other hubs. */
-	link_t link;
-} usb_hcd_hub_info_t;
 
 /** Host controller device. */
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usb/include/usb/usb.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -69,4 +69,9 @@
 typedef int usb_address_t;
 
+/** Default USB address. */
+#define USB_ADDRESS_DEFAULT 0
+/** Maximum address number in USB 1.1. */
+#define USB11_ADDRESS_MAX 128
+
 /** USB endpoint number type.
  * Negative values could be used to indicate error.
Index: uspace/lib/usb/include/usb/usbdrv.h
===================================================================
--- uspace/lib/usb/include/usb/usbdrv.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usb/include/usb/usbdrv.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -36,6 +36,8 @@
 #define LIBUSB_USBDRV_H_
 
-#include "usb.h"
+#include <usb/usb.h>
 #include <driver.h>
+#include <usb/devreq.h>
+#include <usb/descriptor.h>
 
 int usb_drv_hc_connect(device_t *, unsigned int);
@@ -54,4 +56,9 @@
     void *, size_t, size_t *, usb_handle_t *);
 
+int usb_drv_psync_interrupt_out(int, usb_target_t, void *, size_t);
+int usb_drv_psync_interrupt_in(int, usb_target_t, void *, size_t, size_t *);
+
+
+
 int usb_drv_async_control_write_setup(int, usb_target_t,
     void *, size_t, usb_handle_t *);
@@ -60,4 +67,12 @@
 int usb_drv_async_control_write_status(int, usb_target_t,
     usb_handle_t *);
+
+int usb_drv_psync_control_write_setup(int, usb_target_t, void *, size_t);
+int usb_drv_psync_control_write_data(int, usb_target_t, void *, size_t);
+int usb_drv_psync_control_write_status(int, usb_target_t);
+
+int usb_drv_psync_control_write(int, usb_target_t,
+    void *, size_t, void *, size_t);
+
 
 int usb_drv_async_control_read_setup(int, usb_target_t,
@@ -68,5 +83,19 @@
     usb_handle_t *);
 
+int usb_drv_psync_control_read_setup(int, usb_target_t, void *, size_t);
+int usb_drv_psync_control_read_data(int, usb_target_t, void *, size_t, size_t *);
+int usb_drv_psync_control_read_status(int, usb_target_t);
+
+int usb_drv_psync_control_read(int, usb_target_t,
+    void *, size_t, void *, size_t, size_t *);
+
+
+
 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/addrkeep.c
===================================================================
--- uspace/lib/usb/src/addrkeep.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/lib/usb/src/addrkeep.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,341 @@
+/*
+ * 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 Address keeping.
+ */
+#include <usb/hcd.h>
+#include <errno.h>
+#include <assert.h>
+
+/** For loop over all used addresses in address keeping.
+ *
+ * @param link Iterator.
+ * @param addresses Addresses keeping structure to iterate.
+ */
+#define for_all_used_addresses(link, addresses) \
+	for (link = (addresses)->used_addresses.next; \
+	    link != &(addresses)->used_addresses; \
+	    link = link->next)
+
+/** Get instance of usb_address_keeping_used_t. */
+#define used_address_get_instance(lnk) \
+	list_get_instance(lnk, usb_address_keeping_used_t, link)
+
+/** Invalid value of devman handle. */
+#define INVALID_DEVMAN_HANDLE \
+	((devman_handle_t)-1)
+
+/** Creates structure for used USB address.
+ *
+ * @param address USB address.
+ * @return Initialized structure.
+ * @retval NULL Out of memory.
+ */
+static usb_address_keeping_used_t *usb_address_keeping_used_create(
+    usb_address_t address)
+{
+	usb_address_keeping_used_t *info
+	    = malloc(sizeof(usb_address_keeping_used_t));
+	if (info == NULL) {
+		return NULL;
+	}
+
+	info->address = address;
+	info->devman_handle = INVALID_DEVMAN_HANDLE;
+	list_initialize(&info->link);
+	return info;
+}
+
+/** Destroys structure for used USB address.
+ *
+ * @param info Structure to be destroyed.
+ */
+static void usb_address_keeping_used_destroy(usb_address_keeping_used_t *info)
+{
+	free(info);
+}
+
+/** Find used USB address structure by USB address.
+ *
+ * It is expected that guard mutex is already locked.
+ *
+ * @param addresses Address keeping info.
+ * @param address Address to be found.
+ * @return Structure describing looked for address.
+ * @retval NULL Address not found.
+ */
+static usb_address_keeping_used_t *usb_address_keeping_used_find_no_lock(
+    usb_address_keeping_t *addresses, usb_address_t address)
+{
+	link_t *link;
+	for_all_used_addresses(link, addresses) {
+		usb_address_keeping_used_t *info
+		    = used_address_get_instance(link);
+
+		if (info->address == address) {
+			return info;
+		}
+	}
+
+	return NULL;
+}
+
+/** Initialize address keeping structure.
+ *
+ * @param addresses Address keeping info.
+ * @param max_address Maximum USB address (exclusive bound).
+ */
+void usb_address_keeping_init(usb_address_keeping_t *addresses,
+    usb_address_t max_address)
+{
+	/*
+	 * Items related with used addresses.
+	 */
+	addresses->max_address = max_address;
+	list_initialize(&addresses->used_addresses);
+	fibril_mutex_initialize(&addresses->used_addresses_guard);
+	fibril_condvar_initialize(&addresses->used_addresses_condvar);
+
+	/*
+	 * Items related with default address.
+	 */
+	addresses->default_available = true;
+	fibril_condvar_initialize(&addresses->default_condvar);
+	fibril_mutex_initialize(&addresses->default_condvar_guard);
+}
+
+/** Reserved default USB address.
+ *
+ * This function blocks until reserved address is available.
+ *
+ * @see usb_address_keeping_release_default
+ *
+ * @param addresses Address keeping info.
+ */
+void usb_address_keeping_reserve_default(usb_address_keeping_t *addresses)
+{
+	fibril_mutex_lock(&addresses->default_condvar_guard);
+	while (!addresses->default_available) {
+		fibril_condvar_wait(&addresses->default_condvar,
+			&addresses->default_condvar_guard);
+	}
+	fibril_mutex_unlock(&addresses->default_condvar_guard);
+}
+
+/** Releases default USB address.
+ *
+ * @see usb_address_keeping_reserve_default
+ *
+ * @param addresses Address keeping info.
+ */
+void usb_address_keeping_release_default(usb_address_keeping_t *addresses)
+{
+	fibril_mutex_lock(&addresses->default_condvar_guard);
+	addresses->default_available = true;
+	fibril_condvar_signal(&addresses->default_condvar);
+	fibril_mutex_unlock(&addresses->default_condvar_guard);
+}
+
+/** Request free address assignment.
+ *
+ * This function does not block when there are not free addresses to be
+ * assigned.
+ *
+ * @param addresses Address keeping info.
+ * @return USB address that could be used or negative error code.
+ * @retval ELIMIT No more addresses to assign.
+ * @retval ENOMEM Out of memory.
+ */
+usb_address_t usb_address_keeping_request(usb_address_keeping_t *addresses)
+{
+	usb_address_t previous_address = 0;
+	usb_address_t free_address = 0;
+
+	fibril_mutex_lock(&addresses->used_addresses_guard);
+	link_t *new_address_position;
+	if (list_empty(&addresses->used_addresses)) {
+		free_address = 1;
+		new_address_position = addresses->used_addresses.next;
+	} else {
+		for_all_used_addresses(new_address_position, addresses) {
+			usb_address_keeping_used_t *info
+			    = used_address_get_instance(new_address_position);
+			if (info->address > previous_address + 1) {
+				free_address = previous_address + 1;
+				break;
+			}
+		}
+
+		if (free_address == 0) {
+			usb_address_keeping_used_t *last
+			    = used_address_get_instance(addresses->used_addresses.next);
+			free_address = last->address + 1;
+		}
+	}
+
+	if (free_address >= addresses->max_address) {
+		free_address = ELIMIT;
+		goto leave;
+	}
+
+	usb_address_keeping_used_t *used
+	    = usb_address_keeping_used_create(free_address);
+	if (used == NULL) {
+		free_address = ENOMEM;
+		goto leave;
+	}
+
+	list_prepend(&used->link, new_address_position);
+
+leave:
+	fibril_mutex_unlock(&addresses->used_addresses_guard);
+
+	return free_address;
+}
+
+/** Release USB address.
+ *
+ * @param addresses Address keeping info.
+ * @param address Address to be released.
+ * @return Error code.
+ * @retval ENOENT Address is not in use.
+ */
+int usb_address_keeping_release(usb_address_keeping_t *addresses,
+    usb_address_t address)
+{
+	int rc = ENOENT;
+
+	fibril_mutex_lock(&addresses->used_addresses_guard);
+
+	usb_address_keeping_used_t *info
+	    = usb_address_keeping_used_find_no_lock(addresses, address);
+
+	if (info != NULL) {
+		rc = EOK;
+		list_remove(&info->link);
+		usb_address_keeping_used_destroy(info);
+	}
+
+	fibril_mutex_unlock(&addresses->used_addresses_guard);
+
+	return rc;
+}
+
+/** Bind devman handle with USB address.
+ *
+ * When the @p address is invalid (e.g. no such entry), the request
+ * is silently ignored.
+ *
+ * @param addresses Address keeping info.
+ * @param address USB address.
+ * @param handle Devman handle.
+ */
+void usb_address_keeping_devman_bind(usb_address_keeping_t *addresses,
+    usb_address_t address, devman_handle_t handle)
+{
+	fibril_mutex_lock(&addresses->used_addresses_guard);
+
+	usb_address_keeping_used_t *info
+	    = usb_address_keeping_used_find_no_lock(addresses, address);
+	if (info == NULL) {
+		goto leave;
+	}
+
+	assert(info->address == address);
+	info->devman_handle = handle;
+
+	/*
+	 * Inform that new handle was added.
+	 */
+	fibril_condvar_broadcast(&addresses->used_addresses_condvar);
+
+leave:
+	fibril_mutex_unlock(&addresses->used_addresses_guard);
+}
+
+/** Find address by its devman handle.
+ *
+ * @param addresses Address keeping info.
+ * @param handle Devman handle.
+ * @return USB address or negative error code.
+ * @retval ENOENT No such address.
+ */
+static usb_address_t usb_address_keeping_find_no_lock(
+    usb_address_keeping_t *addresses, devman_handle_t handle)
+{
+	usb_address_t address = ENOENT;
+
+	link_t *link;
+	for_all_used_addresses(link, addresses) {
+		usb_address_keeping_used_t *info
+		    = used_address_get_instance(link);
+
+		if (info->devman_handle == handle) {
+			address = info->address;
+			break;
+		}
+	}
+
+	return address;
+}
+
+/** Find USB address by its devman handle.
+ *
+ * This function blocks until corresponding address is found.
+ *
+ * @param addresses Address keeping info.
+ * @param handle Devman handle.
+ * @return USB address or negative error code.
+ */
+usb_address_t usb_address_keeping_find(usb_address_keeping_t *addresses,
+    devman_handle_t handle)
+{
+	usb_address_t address = ENOENT;
+
+	fibril_mutex_lock(&addresses->used_addresses_guard);
+	while (true) {
+		address = usb_address_keeping_find_no_lock(addresses, handle);
+		if (address != ENOENT) {
+			break;
+		}
+		fibril_condvar_wait(&addresses->used_addresses_condvar,
+		    &addresses->used_addresses_guard);
+	}
+
+	fibril_mutex_unlock(&addresses->used_addresses_guard);
+
+	return address;
+}
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/class.c
===================================================================
--- uspace/lib/usb/src/class.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/lib/usb/src/class.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -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/debug.c
===================================================================
--- uspace/lib/usb/src/debug.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/lib/usb/src/debug.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -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);
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/drvpsync.c
===================================================================
--- uspace/lib/usb/src/drvpsync.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/lib/usb/src/drvpsync.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,218 @@
+/*
+ * 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 Implementation of pseudo-synchronous transfers.
+ */
+#include <usb/usbdrv.h>
+#include <usbhc_iface.h>
+#include <errno.h>
+
+int usb_drv_psync_interrupt_out(int phone, usb_target_t target,
+    void *buffer, size_t size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_interrupt_out(phone, target, buffer, size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+int usb_drv_psync_interrupt_in(int phone, usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_interrupt_in(phone, target, buffer, size,
+	    actual_size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+
+
+int usb_drv_psync_control_write_setup(int phone, usb_target_t target,
+    void *buffer, size_t size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_write_setup(phone, target, buffer, size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+int usb_drv_psync_control_write_data(int phone, usb_target_t target,
+    void *buffer, size_t size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_write_data(phone, target, buffer, size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+int usb_drv_psync_control_write_status(int phone, usb_target_t target)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_write_status(phone, target, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+
+/** Perform complete control write transaction over USB.
+ *
+ * The DATA stage is performed only when @p data is not NULL and
+ * @p data_size is greater than zero.
+ *
+ * @param phone Open phone to host controller.
+ * @param target Target device and endpoint.
+ * @param setup_packet Setup packet data.
+ * @param setup_packet_size Size of the setup packet.
+ * @param data Data to be sent.
+ * @param data_size Size of the @p data buffer.
+ * @return Error code.
+ */
+int usb_drv_psync_control_write(int phone, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data, size_t data_size)
+{
+	int rc;
+	
+	rc = usb_drv_psync_control_write_setup(phone, target,
+	    setup_packet, setup_packet_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if ((data != NULL) && (data_size > 0)) {
+		rc = usb_drv_psync_control_write_data(phone, target,
+		    data, data_size);
+		if (rc != EOK) {
+			return rc;
+		}
+	}
+
+	rc = usb_drv_psync_control_write_status(phone, target);
+
+	return rc;
+}
+
+
+int usb_drv_psync_control_read_setup(int phone, usb_target_t target,
+    void *buffer, size_t size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_read_setup(phone, target, buffer, size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+int usb_drv_psync_control_read_data(int phone, usb_target_t target,
+    void *buffer, size_t size, size_t *actual_size)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_read_data(phone, target, buffer, size,
+	    actual_size, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+int usb_drv_psync_control_read_status(int phone, usb_target_t target)
+{
+	usb_handle_t h;
+	int rc;
+	rc = usb_drv_async_control_read_status(phone, target, &h);
+	if (rc != EOK) {
+		return rc;
+	}
+	return usb_drv_async_wait_for(h);
+}
+
+
+/** Perform complete control read transaction over USB.
+ *
+ * @param phone Open phone to host controller.
+ * @param target Target device and endpoint.
+ * @param setup_packet Setup packet data.
+ * @param setup_packet_size Size of the setup packet.
+ * @param data Storage for read data.
+ * @param data_size Size of the @p data buffer.
+ * @param actual_data_size Storage for number of actually transferred data from
+ *        device.
+ * @return Error code.
+ */
+int usb_drv_psync_control_read(int phone, usb_target_t target,
+    void *setup_packet, size_t setup_packet_size,
+    void *data, size_t data_size, size_t *actual_data_size)
+{
+	int rc;
+	
+	rc = usb_drv_psync_control_read_setup(phone, target,
+	    setup_packet, setup_packet_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_drv_psync_control_read_data(phone, target,
+	    data, data_size, actual_data_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = usb_drv_psync_control_read_status(phone, target);
+
+	return rc;
+}
+
+
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/hidparser.c
===================================================================
--- uspace/lib/usb/src/hidparser.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/lib/usb/src/hidparser.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,84 @@
+/*
+ * 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 HID parser implementation.
+ */
+#include <usb/classes/hidparser.h>
+#include <errno.h>
+
+/** Parse HID report descriptor.
+ *
+ * @param parser Opaque HID report parser structure.
+ * @param data Data describing the report.
+ * @param size Size of the descriptor in bytes.
+ * @return Error code.
+ */
+int usb_hid_parse_report_descriptor(usb_hid_report_parser_t *parser, 
+    const uint8_t *data, size_t size)
+{
+	return ENOTSUP;
+}
+
+/** Parse and act upon a HID report.
+ *
+ * @see usb_hid_parse_report_descriptor
+ *
+ * @param parser Opaque HID report parser structure.
+ * @param data Data for the report.
+ * @param size Size of the data in bytes.
+ * @param callbacks Callbacks for report actions.
+ * @param arg Custom argument (passed through to the callbacks).
+ * @return Error code.
+ */
+int usb_hid_parse_report(const usb_hid_report_parser_t *parser,  
+    const uint8_t *data, size_t size,
+    const usb_hid_report_in_callbacks_t *callbacks, void *arg)
+{
+	int i;
+	
+	// TODO: parse report
+	
+	uint16_t keys[6];
+	
+	for (i = 0; i < 6; ++i) {
+		keys[i] = data[i];
+	}
+	
+	callbacks->keyboard(keys, 6, arg);
+	
+	return EOK;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/recognise.c
===================================================================
--- uspace/lib/usb/src/recognise.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/lib/usb/src/recognise.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,322 @@
+/*
+ * 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;
+}
+
+/** Add match ids based on configuration descriptor.
+ *
+ * @param hc Open phone to host controller.
+ * @param matches Match ids list to add matches to.
+ * @param address USB address of the attached device.
+ * @return Error code.
+ */
+static int usb_add_config_descriptor_match_ids(int hc,
+    match_id_list_t *matches, usb_address_t address,
+    int config_count)
+{
+	int final_rc = EOK;
+	
+	int config_index;
+	for (config_index = 0; config_index < config_count; config_index++) {
+		int rc;
+		usb_standard_configuration_descriptor_t config_descriptor;
+		rc = usb_drv_req_get_bare_configuration_descriptor(hc,
+		    address,  config_index, &config_descriptor);
+		if (rc != EOK) {
+			final_rc = rc;
+			continue;
+		}
+
+		size_t full_config_descriptor_size;
+		void *full_config_descriptor
+		    = malloc(config_descriptor.total_length);
+		rc = usb_drv_req_get_full_configuration_descriptor(hc,
+		    address, config_index,
+		    full_config_descriptor, config_descriptor.total_length,
+		    &full_config_descriptor_size);
+		if (rc != EOK) {
+			final_rc = rc;
+			continue;
+		}
+		if (full_config_descriptor_size
+		    != config_descriptor.total_length) {
+			final_rc = ERANGE;
+			continue;
+		}
+
+		/*
+		 * Iterate through config descriptor to find the interface
+		 * descriptors.
+		 */
+		size_t position = sizeof(config_descriptor);
+		while (position + 1 < full_config_descriptor_size) {
+			uint8_t *current_descriptor
+			    = ((uint8_t *) full_config_descriptor) + position;
+			uint8_t cur_descr_len = current_descriptor[0];
+			uint8_t cur_descr_type = current_descriptor[1];
+			
+			position += cur_descr_len;
+			
+			if (cur_descr_type != USB_DESCTYPE_INTERFACE) {
+				continue;
+			}
+			/*
+			 * Finally, we found an interface descriptor.
+			 */
+			usb_standard_interface_descriptor_t *interface
+			    = (usb_standard_interface_descriptor_t *)
+			    current_descriptor;
+			
+			rc = usb_add_match_id(matches, 50,
+			    "usb&interface&class=%s",
+			    usb_str_class(interface->interface_class));
+			if (rc != EOK) {
+				final_rc = rc;
+				break;
+			}
+		}
+	}
+	
+	return final_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 points to interface we skip adding
+	 * class directly.
+	 */
+	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;
+		}
+	}
+	/*
+	 * Go through all configurations and add matches
+	 * based on interface class.
+	 */
+	rc = usb_add_config_descriptor_match_ids(hc, matches,
+	    address, device_descriptor.configuration_count);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/*
+	 * 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;
+
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usb/src/remotedrv.c
===================================================================
--- uspace/lib/usb/src/remotedrv.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usb/src/remotedrv.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -300,5 +300,5 @@
  */
 static void remote_in_callback(usb_hc_device_t *hc,
-    usb_transaction_outcome_t outcome, size_t actual_size, void *arg)
+    size_t actual_size, usb_transaction_outcome_t outcome, void *arg)
 {
 	transfer_info_t *transfer = (transfer_info_t *) arg;
Index: uspace/lib/usb/src/usbdrv.c
===================================================================
--- uspace/lib/usb/src/usbdrv.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usb/src/usbdrv.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -36,4 +36,5 @@
 #include <usbhc_iface.h>
 #include <errno.h>
+#include <str_error.h>
 
 /** Information about pending transaction on HC. */
@@ -71,5 +72,5 @@
 	devman_handle_t handle;
 
-	rc = devman_device_get_handle("/vhc", &handle, 0);
+	rc = devman_device_get_handle("/virt/usbhc", &handle, 0);
 	if (rc != EOK) {
 		return rc;
@@ -90,8 +91,10 @@
 {
 	ipcarg_t address;
-	int rc = async_req_1_1(phone, IPC_M_USBHC_GET_ADDRESS,
+	int rc = async_req_2_1(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_GET_ADDRESS,
 	    dev->handle, &address);
 
 	if (rc != EOK) {
+		printf("usb_drv_get_my_address over %d failed: %s\n", phone, str_error(rc));
 		return rc;
 	}
@@ -107,5 +110,6 @@
 int usb_drv_reserve_default_address(int phone)
 {
-	return async_req_0_0(phone, IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS);
+	return async_req_1_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS);
 }
 
@@ -117,5 +121,6 @@
 int usb_drv_release_default_address(int phone)
 {
-	return async_req_0_0(phone, IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS);
+	return async_req_1_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS);
 }
 
@@ -128,5 +133,6 @@
 {
 	ipcarg_t address;
-	int rc = async_req_0_1(phone, IPC_M_USBHC_REQUEST_ADDRESS, &address);
+	int rc = async_req_1_1(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_REQUEST_ADDRESS, &address);
 	if (rc != EOK) {
 		return rc;
@@ -146,5 +152,6 @@
     devman_handle_t handle)
 {
-	int rc = async_req_2_0(phone, IPC_M_USBHC_BIND_ADDRESS,
+	int rc = async_req_3_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_BIND_ADDRESS,
 	    address, handle);
 
@@ -160,5 +167,6 @@
 int usb_drv_release_address(int phone, usb_address_t address)
 {
-	return async_req_1_0(phone, IPC_M_USBHC_RELEASE_ADDRESS, address);
+	return async_req_2_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_RELEASE_ADDRESS, address);
 }
 
Index: uspace/lib/usb/src/usbdrvreq.c
===================================================================
--- uspace/lib/usb/src/usbdrvreq.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
+++ uspace/lib/usb/src/usbdrvreq.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -0,0 +1,243 @@
+/*
+ * 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 USB driver - standard USB requests (implementation).
+ */
+#include <usb/usbdrv.h>
+#include <errno.h>
+
+/** Change address of connected device.
+ *
+ * @see usb_drv_reserve_default_address
+ * @see usb_drv_release_default_address
+ * @see usb_drv_request_address
+ * @see usb_drv_release_address
+ * @see usb_drv_bind_address
+ *
+ * @param phone Open phone to HC driver.
+ * @param old_address Current address.
+ * @param address Address to be set.
+ * @return Error code.
+ */
+int usb_drv_req_set_address(int phone, usb_address_t old_address,
+    usb_address_t new_address)
+{
+	/* Prepare the target. */
+	usb_target_t target = {
+		.address = old_address,
+		.endpoint = 0
+	};
+
+	/* Prepare the setup packet. */
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 0,
+		.request = USB_DEVREQ_SET_ADDRESS,
+		.index = 0,
+		.length = 0,
+	};
+	setup_packet.value = new_address;
+
+	int rc = usb_drv_psync_control_write(phone, target,
+	    &setup_packet, sizeof(setup_packet), NULL, 0);
+
+	return rc;
+}
+
+/** Retrieve device descriptor of connected USB device.
+ *
+ * @param[in] phone Open phone to HC driver.
+ * @param[in] address Device USB address.
+ * @param[out] descriptor Storage for the device descriptor.
+ * @return Error code.
+ * @retval EBADMEM @p descriptor is NULL.
+ */
+int usb_drv_req_get_device_descriptor(int phone, usb_address_t address,
+    usb_standard_device_descriptor_t *descriptor)
+{
+	if (descriptor == NULL) {
+		return EBADMEM;
+	}
+
+	/* Prepare the target. */
+	usb_target_t target = {
+		.address = address,
+		.endpoint = 0
+	};
+
+	/* Prepare the setup packet. */
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 128,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.index = 0,
+		.length = sizeof(usb_standard_device_descriptor_t)
+	};
+	setup_packet.value_high = USB_DESCTYPE_DEVICE;
+	setup_packet.value_low = 0;
+
+	/* Prepare local descriptor. */
+	size_t actually_transferred = 0;
+	usb_standard_device_descriptor_t descriptor_tmp;
+
+	/* Perform the control read transaction. */
+	int rc = usb_drv_psync_control_read(phone, target,
+	    &setup_packet, sizeof(setup_packet),
+	    &descriptor_tmp, sizeof(descriptor_tmp), &actually_transferred);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Verify that all data has been transferred. */
+	if (actually_transferred < sizeof(descriptor_tmp)) {
+		return ELIMIT;
+	}
+
+	/* Everything is okay, copy the descriptor. */
+	memcpy(descriptor, &descriptor_tmp,
+	    sizeof(descriptor_tmp));
+
+	return EOK;
+}
+
+
+/** Retrieve configuration descriptor of connected USB device.
+ *
+ * The function does not retrieve additional data binded with configuration
+ * descriptor (such as its interface and endpoint descriptors) - use
+ * usb_drv_req_get_full_configuration_descriptor() instead.
+ *
+ * @param[in] phone Open phone to HC driver.
+ * @param[in] address Device USB address.
+ * @param[in] index Configuration descriptor index.
+ * @param[out] descriptor Storage for the configuration descriptor.
+ * @return Error code.
+ * @retval EBADMEM @p descriptor is NULL.
+ */
+int usb_drv_req_get_bare_configuration_descriptor(int phone,
+    usb_address_t address, int index,
+    usb_standard_configuration_descriptor_t *descriptor)
+{
+	if (descriptor == NULL) {
+		return EBADMEM;
+	}
+
+	/* Prepare the target. */
+	usb_target_t target = {
+		.address = address,
+		.endpoint = 0
+	};
+
+	/* Prepare the setup packet. */
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 128,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.index = 0,
+		.length = sizeof(usb_standard_configuration_descriptor_t)
+	};
+	setup_packet.value_high = USB_DESCTYPE_CONFIGURATION;
+	setup_packet.value_low = index;
+
+	/* Prepare local descriptor. */
+	size_t actually_transferred = 0;
+	usb_standard_configuration_descriptor_t descriptor_tmp;
+
+	/* Perform the control read transaction. */
+	int rc = usb_drv_psync_control_read(phone, target,
+	    &setup_packet, sizeof(setup_packet),
+	    &descriptor_tmp, sizeof(descriptor_tmp), &actually_transferred);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* Verify that all data has been transferred. */
+	if (actually_transferred < sizeof(descriptor_tmp)) {
+		return ELIMIT;
+	}
+
+	/* Everything is okay, copy the descriptor. */
+	memcpy(descriptor, &descriptor_tmp,
+	    sizeof(descriptor_tmp));
+
+	return EOK;
+}
+
+/** Retrieve full configuration descriptor of connected USB device.
+ *
+ * @warning The @p buffer might be touched (i.e. its contents changed)
+ * even when error occurres.
+ *
+ * @param[in] phone Open phone to HC driver.
+ * @param[in] address Device USB address.
+ * @param[in] index Configuration descriptor index.
+ * @param[out] buffer Buffer for the whole configuration descriptor.
+ * @param[in] buffer_size Size of the prepared @p buffer.
+ * @param[out] actual_buffer_size Bytes actually transfered.
+ * @return Error code.
+ * @retval EBADMEM @p descriptor is NULL.
+ */
+int usb_drv_req_get_full_configuration_descriptor(int phone,
+    usb_address_t address, int index,
+    void *buffer, size_t buffer_size, size_t *actual_buffer_size)
+{
+	if (buffer == NULL) {
+		return EBADMEM;
+	}
+
+	/* Prepare the target. */
+	usb_target_t target = {
+		.address = address,
+		.endpoint = 0
+	};
+
+	/* Prepare the setup packet. */
+	usb_device_request_setup_packet_t setup_packet = {
+		.request_type = 128,
+		.request = USB_DEVREQ_GET_DESCRIPTOR,
+		.index = 0,
+		.length = buffer_size
+	};
+	setup_packet.value_high = USB_DESCTYPE_CONFIGURATION;
+	setup_packet.value_low = index;
+
+	/* Perform the control read transaction. */
+	int rc = usb_drv_psync_control_read(phone, target,
+	    &setup_packet, sizeof(setup_packet),
+	    buffer, buffer_size, actual_buffer_size);
+
+	return rc;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/usbvirt/src/callback.c
===================================================================
--- uspace/lib/usbvirt/src/callback.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usbvirt/src/callback.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -153,5 +153,5 @@
 	 * If the request was processed, we will send data back.
 	 */
-	if (rc == EOK) {
+	if ((rc == EOK) && (expected_len > 0)) {
 		size_t receive_len;
 		ipc_callid_t callid;
Index: uspace/lib/usbvirt/src/main.c
===================================================================
--- uspace/lib/usbvirt/src/main.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usbvirt/src/main.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -183,5 +183,5 @@
 /** Create necessary phones for communication with virtual HCD.
  * This function wraps following calls:
- * -# open <code>/dev/devices/\\vhc</code> for reading
+ * -# open <code>/dev/devices/\\virt\\usbhc for reading
  * -# access phone of file opened in previous step
  * -# create callback through just opened phone
@@ -203,5 +203,5 @@
 	}
 	
-	const char *vhc_path = "/vhc";
+	const char *vhc_path = "/virt/usbhc";
 	int rc;
 	devman_handle_t handle;
Index: uspace/lib/usbvirt/src/transaction.c
===================================================================
--- uspace/lib/usbvirt/src/transaction.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/lib/usbvirt/src/transaction.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -183,4 +183,6 @@
 				actual_size = size;
 			}
+			device->lib_debug(device, 1, USBVIRT_DEBUGTAG_TRANSACTION,
+			    "in transaction: will copy %zu bytes", actual_size);
 			if (actual_size > 0) {
 				memcpy(buffer, transfer->data, actual_size);
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/devman/devman.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -516,6 +516,4 @@
 /** Notify driver about the devices to which it was assigned.
  *
- * The driver's mutex must be locked.
- *
  * @param driver	The driver to which the devices are passed.
  */
@@ -526,18 +524,75 @@
 	int phone;
 
-	printf(NAME ": pass_devices_to_driver\n");
-
-	phone = ipc_connect_me_to(driver->phone, DRIVER_DEVMAN, 0, 0);
-	if (phone > 0) {
-		
+	printf(NAME ": pass_devices_to_driver(`%s')\n", driver->name);
+
+	fibril_mutex_lock(&driver->driver_mutex);
+
+	phone = async_connect_me_to(driver->phone, DRIVER_DEVMAN, 0, 0);
+
+	if (phone < 0) {
+		fibril_mutex_unlock(&driver->driver_mutex);
+		return;
+	}
+
+	/*
+	 * Go through devices list as long as there is some device
+	 * that has not been passed to the driver.
+	 */
+	link = driver->devices.next;
+	while (link != &driver->devices) {
+		dev = list_get_instance(link, node_t, driver_devices);
+		if (dev->passed_to_driver) {
+			link = link->next;
+			continue;
+		}
+
+		/*
+		 * We remove the device from the list to allow safe adding
+		 * of new devices (no one will touch our item this way).
+		 */
+		list_remove(link);
+
+		/*
+		 * Unlock to avoid deadlock when adding device
+		 * handled by itself.
+		 */
+		fibril_mutex_unlock(&driver->driver_mutex);
+
+		add_device(phone, driver, dev, tree);
+
+		/*
+		 * Lock again as we will work with driver's
+		 * structure.
+		 */
+		fibril_mutex_lock(&driver->driver_mutex);
+
+		/*
+		 * Insert the device back.
+		 * The order is not relevant here so no harm is done
+		 * (actually, the order would be preserved in most cases).
+		 */
+		list_append(link, &driver->devices);
+
+		/*
+		 * Restart the cycle to go through all devices again.
+		 */
 		link = driver->devices.next;
-		while (link != &driver->devices) {
-			dev = list_get_instance(link, node_t, driver_devices);
-			add_device(phone, driver, dev, tree);
-			link = link->next;
-		}
-		
-		ipc_hangup(phone);
-	}
+	}
+
+	ipc_hangup(phone);
+
+	/*
+	 * Once we passed all devices to the driver, we need to mark the
+	 * driver as running.
+	 * It is vital to do it here and inside critical section.
+	 *
+	 * If we would change the state earlier, other devices added to
+	 * the driver would be added to the device list and started
+	 * immediately and possibly started here as well.
+	 */
+	printf(NAME ": driver %s goes into running state.\n", driver->name);
+	driver->state = DRIVER_RUNNING;
+
+	fibril_mutex_unlock(&driver->driver_mutex);
 }
 
@@ -553,6 +608,5 @@
 void initialize_running_driver(driver_t *driver, dev_tree_t *tree)
 {
-	printf(NAME ": initialize_running_driver\n");
-	fibril_mutex_lock(&driver->driver_mutex);
+	printf(NAME ": initialize_running_driver (`%s')\n", driver->name);
 	
 	/*
@@ -561,9 +615,4 @@
 	 */
 	pass_devices_to_driver(driver, tree);
-	
-	/* Change driver's state to running. */
-	driver->state = DRIVER_RUNNING;
-	
-	fibril_mutex_unlock(&driver->driver_mutex);
 }
 
@@ -637,5 +686,4 @@
 }
 
-
 /** Pass a device to running driver.
  *
@@ -645,5 +693,10 @@
 void add_device(int phone, driver_t *drv, node_t *node, dev_tree_t *tree)
 {
-	printf(NAME ": add_device\n");
+	/*
+	 * We do not expect to have driver's mutex locked as we do not
+	 * access any structures that would affect driver_t.
+	 */
+	printf(NAME ": add_device (driver `%s', device `%s')\n", drv->name,
+	    node->name);
 	
 	ipcarg_t rc;
@@ -657,4 +710,5 @@
 		parent_handle = 0;
 	}
+
 	aid_t req = async_send_2(phone, DRIVER_ADD_DEVICE, node->handle,
 	    parent_handle, &answer);
@@ -666,7 +720,8 @@
 		/* TODO handle error */
 	}
-	
+
 	/* Wait for answer from the driver. */
 	async_wait_for(req, &rc);
+
 	switch(rc) {
 	case EOK:
@@ -681,4 +736,6 @@
 	}
 	
+	node->passed_to_driver = true;
+
 	return;
 }
@@ -706,12 +763,15 @@
 	attach_driver(node, drv);
 	
+	fibril_mutex_lock(&drv->driver_mutex);
 	if (drv->state == DRIVER_NOT_STARTED) {
 		/* Start the driver. */
 		start_driver(drv);
 	}
-	
-	if (drv->state == DRIVER_RUNNING) {
+	bool is_running = drv->state == DRIVER_RUNNING;
+	fibril_mutex_unlock(&drv->driver_mutex);
+
+	if (is_running) {
 		/* Notify the driver about the new device. */
-		int phone = ipc_connect_me_to(drv->phone, DRIVER_DEVMAN, 0, 0);
+		int phone = async_connect_me_to(drv->phone, DRIVER_DEVMAN, 0, 0);
 		if (phone > 0) {
 			add_device(phone, drv, node, tree);
@@ -875,5 +935,4 @@
 	node->name = dev_name;
 	if (!set_dev_path(node, parent)) {
-		fibril_rwlock_write_unlock(&tree->rwlock);
 		return false;
 	}
@@ -1097,6 +1156,8 @@
 	while (link != &class_list->classes) {
 		cl = list_get_instance(link, dev_class_t, link);
-		if (str_cmp(cl->name, class_name) == 0)
+		if (str_cmp(cl->name, class_name) == 0) {
 			return cl;
+		}
+		link = link->next;
 	}
 	
Index: uspace/srv/devman/devman.h
===================================================================
--- uspace/srv/devman/devman.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/devman/devman.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -168,4 +168,9 @@
 	 */
 	link_t devmap_link;
+
+	/**
+	 * Whether this device was already passed to the driver.
+	 */
+	bool passed_to_driver;
 };
 
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/devman/main.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -197,4 +197,11 @@
 }
 
+static int assign_driver_fibril(void *arg)
+{
+	node_t *node = (node_t *) arg;
+	assign_driver(node, &drivers_list, &device_tree);
+	return EOK;
+}
+
 /** Handle child device registration.
  *
@@ -237,10 +244,25 @@
 	
 	devman_receive_match_ids(match_count, &node->match_ids);
-	
+
+	/*
+	 * Try to find a suitable driver and assign it to the device.  We do
+	 * not want to block the current fibril that is used for processing
+	 * incoming calls: we will launch a separate fibril to handle the
+	 * driver assigning. That is because assign_driver can actually include
+	 * task spawning which could take some time.
+	 */
+	fid_t assign_fibril = fibril_create(assign_driver_fibril, node);
+	if (assign_fibril == 0) {
+		/*
+		 * Fallback in case we are out of memory.
+		 * Probably not needed as we will die soon anyway ;-).
+		 */
+		(void) assign_driver_fibril(node);
+	} else {
+		fibril_add_ready(assign_fibril);
+	}
+
 	/* Return device handle to parent's driver. */
 	ipc_answer_1(callid, EOK, node->handle);
-	
-	/* Try to find suitable driver and assign it to the device. */
-	assign_driver(node, &drivers_list, &device_tree);
 }
 
@@ -297,5 +319,5 @@
 	printf(NAME ": device '%s' added to class '%s', class name '%s' was "
 	    "asigned to it\n", dev->pathname, class_name, class_info->dev_name);
-	
+
 	ipc_answer_0(callid, EOK);
 }
Index: uspace/srv/devman/match.c
===================================================================
--- uspace/srv/devman/match.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/devman/match.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -46,5 +46,5 @@
 	if (str_cmp(driver->id, device->id) == 0) {
 		/*
-		 * The strings matches, return their score multiplied.
+		 * The strings match, return the product of their scores.
 		 */
 		return driver->score * device->score;
@@ -66,5 +66,5 @@
 	
 	/*
-	 * Go through all pairs, return the highest score obtainetd.
+	 * Go through all pairs, return the highest score obtained.
 	 */
 	int highest_score = 0;
Index: uspace/srv/fs/devfs/devfs.c
===================================================================
--- uspace/srv/fs/devfs/devfs.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/fs/devfs/devfs.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -53,4 +53,6 @@
 static vfs_info_t devfs_vfs_info = {
 	.name = NAME,
+	.concurrent_read_write = false,
+	.write_retains_size = false,
 };
 
Index: uspace/srv/fs/fat/fat.c
===================================================================
--- uspace/srv/fs/fat/fat.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/fs/fat/fat.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -52,4 +52,6 @@
 vfs_info_t fat_vfs_info = {
 	.name = NAME,
+	.concurrent_read_write = false,
+	.write_retains_size = false,	
 };
 
Index: uspace/srv/fs/tmpfs/tmpfs.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/fs/tmpfs/tmpfs.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -57,4 +57,6 @@
 vfs_info_t tmpfs_vfs_info = {
 	.name = NAME,
+	.concurrent_read_write = false,
+	.write_retains_size = false,
 };
 
Index: uspace/srv/net/il/arp/arp.c
===================================================================
--- uspace/srv/net/il/arp/arp.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/net/il/arp/arp.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -72,4 +72,7 @@
 #define NAME  "arp"
 
+/** Number of microseconds to wait for an ARP reply. */
+#define ARP_TRANS_WAIT	1000000
+
 /** ARP global data. */
 arp_globals_t arp_globals;
@@ -77,5 +80,27 @@
 DEVICE_MAP_IMPLEMENT(arp_cache, arp_device_t);
 INT_MAP_IMPLEMENT(arp_protos, arp_proto_t);
-GENERIC_CHAR_MAP_IMPLEMENT(arp_addr, measured_string_t);
+GENERIC_CHAR_MAP_IMPLEMENT(arp_addr, arp_trans_t);
+
+static void arp_clear_trans(arp_trans_t *trans)
+{
+	if (trans->hw_addr) {
+		free(trans->hw_addr);
+		trans->hw_addr = NULL;
+	}
+	fibril_condvar_broadcast(&trans->cv);
+}
+
+static void arp_clear_addr(arp_addr_t *addresses)
+{
+	int count;
+	arp_trans_t *trans;
+
+	for (count = arp_addr_count(addresses) - 1; count >= 0; count--) {
+		trans = arp_addr_items_get_index(&addresses->values, count);
+		if (trans)
+			arp_clear_trans(trans);
+	}
+}
+
 
 /** Clears the device specific data.
@@ -96,4 +121,5 @@
 			if (proto->addr_data)
 				free(proto->addr_data);
+			arp_clear_addr(&proto->addresses);
 			arp_addr_destroy(&proto->addresses);
 		}
@@ -107,5 +133,5 @@
 	arp_device_t *device;
 
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	fibril_mutex_lock(&arp_globals.lock);
 	for (count = arp_cache_count(&arp_globals.cache) - 1; count >= 0;
 	    count--) {
@@ -120,5 +146,5 @@
 	}
 	arp_cache_clear(&arp_globals.cache);
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	printf("Cache cleaned\n");
 	return EOK;
@@ -130,18 +156,22 @@
 	arp_device_t *device;
 	arp_proto_t *proto;
-
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	arp_trans_t *trans;
+
+	fibril_mutex_lock(&arp_globals.lock);
 	device = arp_cache_find(&arp_globals.cache, device_id);
 	if (!device) {
-		fibril_rwlock_write_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		return ENOENT;
 	}
 	proto = arp_protos_find(&device->protos, protocol);
 	if (!proto) {
-		fibril_rwlock_write_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		return ENOENT;
 	}
+	trans = arp_addr_find(&proto->addresses, address->value, address->length);
+	if (trans)
+		arp_clear_trans(trans);
 	arp_addr_exclude(&proto->addresses, address->value, address->length);
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	return EOK;
 }
@@ -152,13 +182,13 @@
 	arp_device_t *device;
 
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	fibril_mutex_lock(&arp_globals.lock);
 	device = arp_cache_find(&arp_globals.cache, device_id);
 	if (!device) {
-		fibril_rwlock_write_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		return ENOENT;
 	}
 	arp_clear_device(device);
 	printf("Device %d cleared\n", device_id);
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	return EOK;
 }
@@ -221,5 +251,5 @@
 	int rc;
 
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	fibril_mutex_lock(&arp_globals.lock);
 
 	/* An existing device? */
@@ -229,5 +259,5 @@
 		if (device->service != service) {
 			printf("Device %d already exists\n", device->device_id);
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			return EEXIST;
 		}
@@ -241,5 +271,5 @@
 			rc = arp_proto_create(&proto, protocol, address);
 			if (rc != EOK) {
-				fibril_rwlock_write_unlock(&arp_globals.lock);
+				fibril_mutex_unlock(&arp_globals.lock);
 				return rc;
 			}
@@ -247,5 +277,5 @@
 			    proto);
 			if (index < 0) {
-				fibril_rwlock_write_unlock(&arp_globals.lock);
+				fibril_mutex_unlock(&arp_globals.lock);
 				free(proto);
 				return index;
@@ -262,5 +292,5 @@
 		device = (arp_device_t *) malloc(sizeof(arp_device_t));
 		if (!device) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			return ENOMEM;
 		}
@@ -269,5 +299,5 @@
 		rc = arp_protos_initialize(&device->protos);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			free(device);
 			return rc;
@@ -275,5 +305,5 @@
 		rc = arp_proto_create(&proto, protocol, address);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			free(device);
 			return rc;
@@ -281,5 +311,5 @@
 		index = arp_protos_add(&device->protos, proto->service, proto);
 		if (index < 0) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			arp_protos_destroy(&device->protos);
 			free(device);
@@ -293,5 +323,5 @@
 		    arp_globals.client_connection);
 		if (device->phone < 0) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			arp_protos_destroy(&device->protos);
 			free(device);
@@ -303,5 +333,5 @@
 		    &device->packet_dimension);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			arp_protos_destroy(&device->protos);
 			free(device);
@@ -313,5 +343,5 @@
 		    &device->addr_data);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			arp_protos_destroy(&device->protos);
 			free(device);
@@ -323,5 +353,5 @@
 		    &device->broadcast_addr, &device->broadcast_data);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			free(device->addr);
 			free(device->addr_data);
@@ -334,5 +364,5 @@
 		    device);
 		if (rc != EOK) {
-			fibril_rwlock_write_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			free(device->addr);
 			free(device->addr_data);
@@ -347,5 +377,5 @@
 		    device->service, protocol);
 	}
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	
 	return EOK;
@@ -363,9 +393,9 @@
 	int rc;
 
-	fibril_rwlock_initialize(&arp_globals.lock);
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	fibril_mutex_initialize(&arp_globals.lock);
+	fibril_mutex_lock(&arp_globals.lock);
 	arp_globals.client_connection = client_connection;
 	rc = arp_cache_initialize(&arp_globals.cache);
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	
 	return rc;
@@ -383,12 +413,12 @@
 	arp_device_t *device;
 
-	fibril_rwlock_write_lock(&arp_globals.lock);
+	fibril_mutex_lock(&arp_globals.lock);
 	device = arp_cache_find(&arp_globals.cache, device_id);
 	if (!device) {
-		fibril_rwlock_write_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		return ENOENT;
 	}
 	device->packet_dimension.content = mtu;
-	fibril_rwlock_write_unlock(&arp_globals.lock);
+	fibril_mutex_unlock(&arp_globals.lock);
 	printf("arp - device %d changed mtu to %zu\n\n", device_id, mtu);
 	return EOK;
@@ -421,5 +451,5 @@
 	arp_device_t *device;
 	arp_proto_t *proto;
-	measured_string_t *hw_source;
+	arp_trans_t *trans;
 	uint8_t *src_hw;
 	uint8_t *src_proto;
@@ -452,13 +482,13 @@
 	des_hw = src_proto + header->protocol_length;
 	des_proto = des_hw + header->hardware_length;
-	hw_source = arp_addr_find(&proto->addresses, (char *) src_proto,
+	trans = arp_addr_find(&proto->addresses, (char *) src_proto,
 	    CONVERT_SIZE(uint8_t, char, header->protocol_length));
 	/* Exists? */
-	if (hw_source) {
-		if (hw_source->length != CONVERT_SIZE(uint8_t, char,
+	if (trans && trans->hw_addr) {
+		if (trans->hw_addr->length != CONVERT_SIZE(uint8_t, char,
 		    header->hardware_length)) {
 			return EINVAL;
 		}
-		memcpy(hw_source->value, src_hw, hw_source->length);
+		memcpy(trans->hw_addr->value, src_hw, trans->hw_addr->length);
 	}
 	/* Is my protocol address? */
@@ -470,16 +500,27 @@
 	    proto->addr->length)) {
 		/* Not already updated? */
-		if (!hw_source) {
-			hw_source = measured_string_create_bulk((char *) src_hw,
-			    CONVERT_SIZE(uint8_t, char,
+		if (!trans) {
+			trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
+			if (!trans)
+				return ENOMEM;
+			trans->hw_addr = NULL;
+			fibril_condvar_initialize(&trans->cv);
+			rc = arp_addr_add(&proto->addresses, (char *) src_proto,
+			    CONVERT_SIZE(uint8_t, char, header->protocol_length),
+			    trans);
+			if (rc != EOK) {
+				/* The generic char map has already freed trans! */
+				return rc;
+			}
+		}
+		if (!trans->hw_addr) {
+			trans->hw_addr = measured_string_create_bulk(
+			    (char *) src_hw, CONVERT_SIZE(uint8_t, char,
 			    header->hardware_length));
-			if (!hw_source)
+			if (!trans->hw_addr)
 				return ENOMEM;
 
-			rc = arp_addr_add(&proto->addresses, (char *) src_proto,
-			    CONVERT_SIZE(uint8_t, char,
-			    header->protocol_length), hw_source);
-			if (rc != EOK)
-				return rc;
+			/* Notify the fibrils that wait for the translation. */
+			fibril_condvar_broadcast(&trans->cv);
 		}
 		if (ntohs(header->operation) == ARPOP_REQUEST) {
@@ -490,5 +531,5 @@
 			memcpy(src_hw, device->addr->value,
 			    device->packet_dimension.addr_len);
-			memcpy(des_hw, hw_source->value,
+			memcpy(des_hw, trans->hw_addr->value,
 			    header->hardware_length);
 			
@@ -516,36 +557,51 @@
  * @param[in] protocol	The protocol service.
  * @param[in] target	The target protocol address.
- * @return		The hardware address of the target.
- * @return		NULL if the target parameter is NULL.
- * @return		NULL if the device is not found.
- * @return		NULL if the device packet is too small to send a
- *			request.
- * @return		NULL if the hardware address is not found in the cache.
- */
-static measured_string_t *
+ * @param[out] translation Where the hardware address of the target is stored.
+ * @return		EOK on success.
+ * @return		EAGAIN if the caller should try again.
+ * @return		Other error codes in case of error.
+ */
+static int
 arp_translate_message(device_id_t device_id, services_t protocol,
-    measured_string_t *target)
+    measured_string_t *target, measured_string_t **translation)
 {
 	arp_device_t *device;
 	arp_proto_t *proto;
-	measured_string_t *addr;
+	arp_trans_t *trans;
 	size_t length;
 	packet_t *packet;
 	arp_header_t *header;
-
-	if (!target)
-		return NULL;
+	bool retry = false;
+	int rc;
+
+restart:
+	if (!target || !translation)
+		return EBADMEM;
 
 	device = arp_cache_find(&arp_globals.cache, device_id);
 	if (!device)
-		return NULL;
+		return ENOENT;
 
 	proto = arp_protos_find(&device->protos, protocol);
 	if (!proto || (proto->addr->length != target->length))
-		return NULL;
-
-	addr = arp_addr_find(&proto->addresses, target->value, target->length);
-	if (addr)
-		return addr;
+		return ENOENT;
+
+	trans = arp_addr_find(&proto->addresses, target->value, target->length);
+	if (trans) {
+		if (trans->hw_addr) {
+			*translation = trans->hw_addr;
+			return EOK;
+		}
+		if (retry)
+			return EAGAIN;
+		rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
+		    ARP_TRANS_WAIT);
+		if (rc == ETIMEOUT)
+			return ENOENT;
+		retry = true;
+		goto restart;
+	}
+	if (retry)
+		return EAGAIN;
 
 	/* ARP packet content size = header + (address + translation) * 2 */
@@ -553,5 +609,5 @@
 	    CONVERT_SIZE(char, uint8_t, device->addr->length));
 	if (length > device->packet_dimension.content)
-		return NULL;
+		return ELIMIT;
 
 	packet = packet_get_4_remote(arp_globals.net_phone,
@@ -559,10 +615,10 @@
 	    length, device->packet_dimension.suffix);
 	if (!packet)
-		return NULL;
+		return ENOMEM;
 
 	header = (arp_header_t *) packet_suffix(packet, length);
 	if (!header) {
 		pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
-		return NULL;
+		return ENOMEM;
 	}
 
@@ -583,13 +639,32 @@
 	memcpy(((uint8_t *) header) + length, target->value, target->length);
 
-	if (packet_set_addr(packet, (uint8_t *) device->addr->value,
+	rc = packet_set_addr(packet, (uint8_t *) device->addr->value,
 	    (uint8_t *) device->broadcast_addr->value,
-	    CONVERT_SIZE(char, uint8_t, device->addr->length)) != EOK) {
+	    CONVERT_SIZE(char, uint8_t, device->addr->length));
+	if (rc != EOK) {
 		pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
-		return NULL;
+		return rc;
 	}
 
 	nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
-	return NULL;
+
+	trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
+	if (!trans)
+		return ENOMEM;
+	trans->hw_addr = NULL;
+	fibril_condvar_initialize(&trans->cv);
+	rc = arp_addr_add(&proto->addresses, target->value, target->length,
+	    trans);
+	if (rc != EOK) {
+		/* The generic char map has already freed trans! */
+		return rc;
+	}
+	
+	rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
+	    ARP_TRANS_WAIT);
+	if (rc == ETIMEOUT)
+		return ENOENT;
+	retry = true;
+	goto restart;
 }
 
@@ -642,15 +717,19 @@
 			return rc;
 		
-		fibril_rwlock_read_lock(&arp_globals.lock);
-		translation = arp_translate_message(IPC_GET_DEVICE(call),
-		    IPC_GET_SERVICE(call), address);
+		fibril_mutex_lock(&arp_globals.lock);
+		rc = arp_translate_message(IPC_GET_DEVICE(call),
+		    IPC_GET_SERVICE(call), address, &translation);
 		free(address);
 		free(data);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&arp_globals.lock);
+			return rc;
+		}
 		if (!translation) {
-			fibril_rwlock_read_unlock(&arp_globals.lock);
+			fibril_mutex_unlock(&arp_globals.lock);
 			return ENOENT;
 		}
 		rc = measured_strings_reply(translation, 1);
-		fibril_rwlock_read_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		return rc;
 
@@ -682,5 +761,5 @@
 			return rc;
 		
-		fibril_rwlock_read_lock(&arp_globals.lock);
+		fibril_mutex_lock(&arp_globals.lock);
 		do {
 			next = pq_detach(packet);
@@ -692,5 +771,5 @@
 			packet = next;
 		} while (packet);
-		fibril_rwlock_read_unlock(&arp_globals.lock);
+		fibril_mutex_unlock(&arp_globals.lock);
 		
 		return EOK;
Index: uspace/srv/net/il/arp/arp.h
===================================================================
--- uspace/srv/net/il/arp/arp.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/net/il/arp/arp.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -65,4 +65,9 @@
 typedef struct arp_proto arp_proto_t;
 
+/** Type definition of the ARP address translation record.
+ * @see arp_trans
+ */
+typedef struct arp_trans arp_trans_t;
+
 /** ARP address map.
  *
@@ -70,5 +75,5 @@
  * @see generic_char_map.h
  */
-GENERIC_CHAR_MAP_DECLARE(arp_addr, measured_string_t);
+GENERIC_CHAR_MAP_DECLARE(arp_addr, arp_trans_t);
 
 /** ARP address cache.
@@ -89,9 +94,9 @@
 struct arp_device {
 	/** Actual device hardware address. */
-	measured_string_t * addr;
+	measured_string_t *addr;
 	/** Actual device hardware address data. */
 	char *addr_data;
 	/** Broadcast device hardware address. */
-	measured_string_t * broadcast_addr;
+	measured_string_t *broadcast_addr;
 	/** Broadcast device hardware address data. */
 	char *broadcast_data;
@@ -129,5 +134,5 @@
 	int net_phone;
 	/** Safety lock. */
-	fibril_rwlock_t lock;
+	fibril_mutex_t lock;
 };
 
@@ -144,6 +149,18 @@
 };
 
+/** ARP address translation record. */
+struct arp_trans {
+	/**
+	 * Hardware address for the translation. NULL denotes an incomplete
+	 * record with possible waiters.
+	 */ 
+	measured_string_t *hw_addr;
+	/** Condition variable used for waiting for completion of the record. */
+	fibril_condvar_t cv;
+};
+
 #endif
 
 /** @}
  */
+
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/vfs/vfs.h	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -172,4 +172,5 @@
 
 extern fs_handle_t fs_name_to_handle(char *, bool);
+extern vfs_info_t *fs_handle_to_info(fs_handle_t);
 
 extern int vfs_lookup_internal(char *, int, vfs_lookup_res_t *,
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/vfs/vfs_ops.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -781,4 +781,5 @@
 static void vfs_rdwr(ipc_callid_t rid, ipc_call_t *request, bool read)
 {
+	vfs_info_t *vi;
 
 	/*
@@ -807,9 +808,13 @@
 	fibril_mutex_lock(&file->lock);
 
+	vi = fs_handle_to_info(file->node->fs_handle);
+	assert(vi);
+
 	/*
 	 * Lock the file's node so that no other client can read/write to it at
-	 * the same time.
-	 */
-	if (read)
+	 * the same time unless the FS supports concurrent reads/writes and its
+	 * write implementation does not modify the file size.
+	 */
+	if (read || (vi->concurrent_read_write && vi->write_retains_size))
 		fibril_rwlock_read_lock(&file->node->contents_rwlock);
 	else
@@ -857,5 +862,5 @@
 	
 	/* Unlock the VFS node. */
-	if (read)
+	if (read || (vi->concurrent_read_write && vi->write_retains_size))
 		fibril_rwlock_read_unlock(&file->node->contents_rwlock);
 	else {
Index: uspace/srv/vfs/vfs_register.c
===================================================================
--- uspace/srv/vfs/vfs_register.c	(revision 84439d7c2ebefbea307e636b8e8316fb8f84e090)
+++ uspace/srv/vfs/vfs_register.c	(revision 75732daeac84e2935c03d316ed5cb327455ac6a3)
@@ -333,4 +333,27 @@
 }
 
+/** Find the VFS info structure.
+ *
+ * @param handle	FS handle for which the VFS info structure is sought.
+ * @return		VFS info structure on success or NULL otherwise.
+ */
+vfs_info_t *fs_handle_to_info(fs_handle_t handle)
+{
+	vfs_info_t *info = NULL;
+	link_t *cur;
+
+	fibril_mutex_lock(&fs_head_lock);
+	for (cur = fs_head.next; cur != &fs_head; cur = cur->next) {
+		fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
+		if (fs->fs_handle == handle) { 
+			info = &fs->vfs_info;
+			break;
+		}
+	}
+	fibril_mutex_unlock(&fs_head_lock);
+
+	return info;
+}
+
 /**
  * @}
