Index: .bzrignore
===================================================================
--- .bzrignore	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ .bzrignore	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -62,72 +62,22 @@
 ./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/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
 ./uspace/drv/usbkbd/usbkbd
 ./uspace/drv/vhc/vhc
Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ HelenOS.config	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ boot/Makefile.common	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -111,4 +111,7 @@
 RD_DRVS = \
 	root \
+	rootvirt \
+	test1 \
+	test2 \
 	vhc
 
@@ -142,7 +145,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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ boot/arch/amd64/Makefile.inc	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -37,9 +37,10 @@
 
 RD_DRVS += \
-	rootia32 \
+	rootpc \
 	pciintel \
 	isa \
 	ns8250 \
 	uhci \
+	usbhub \
 	usbkbd
 	
Index: boot/arch/mips32/include/arch.h
===================================================================
--- boot/arch/mips32/include/arch.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ boot/arch/mips32/include/arch.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -40,5 +40,5 @@
 
 #define MSIM_VIDEORAM_ADDRESS  0xb0000000
-#define MSIM_DORDER_ADDRESS    0xb0000004
+#define MSIM_DORDER_ADDRESS    0xb0000100
 
 #ifndef __ASM__
Index: contrib/conf/msim.conf
===================================================================
--- contrib/conf/msim.conf	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ contrib/conf/msim.conf	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -16,3 +16,3 @@
 add dprinter printer 0x10000000
 add dkeyboard keyboard 0x10000000 2
-add dorder order 0x10000004 5
+add dorder order 0x10000100 5
Index: kernel/arch/mips32/src/exception.c
===================================================================
--- kernel/arch/mips32/src/exception.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ kernel/arch/mips32/src/exception.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -74,35 +74,35 @@
 void istate_decode(istate_t *istate)
 {
-	printf("epc=%p\tsta=%#0" PRIx32 "\t"
-	    "lo =%#0" PRIx32 "\thi =%#0" PRIx32 "\n",
+	printf("epc=%p\tsta=%#010" PRIx32 "\t"
+	    "lo =%#010" PRIx32 "\thi =%#010" PRIx32 "\n",
 	    (void *) istate->epc, istate->status,
 	    istate->lo, istate->hi);
 	
-	printf("a0 =%#0" PRIx32 "\ta1 =%#0" PRIx32 "\t"
-	    "a2 =%#0" PRIx32 "\ta3 =%#0" PRIx32 "\n",
+	printf("a0 =%#010" PRIx32 "\ta1 =%#010" PRIx32 "\t"
+	    "a2 =%#010" PRIx32 "\ta3 =%#010" PRIx32 "\n",
 	    istate->a0, istate->a1, istate->a2, istate->a3);
 	
-	printf("t0 =%#0" PRIx32 "\tt1 =%#0" PRIx32 "\t"
-	    "t2 =%#0" PRIx32 "\tt3 =%#0" PRIx32 "\n",
+	printf("t0 =%#010" PRIx32 "\tt1 =%#010" PRIx32 "\t"
+	    "t2 =%#010" PRIx32 "\tt3 =%#010" PRIx32 "\n",
 	    istate->t0, istate->t1, istate->t2, istate->t3);
 	
-	printf("t4 =%#0" PRIx32 "\tt5 =%#0" PRIx32 "\t"
-	    "t6 =%#0" PRIx32 "\tt7 =%#0" PRIx32 "\n",
+	printf("t4 =%#010" PRIx32 "\tt5 =%#010" PRIx32 "\t"
+	    "t6 =%#010" PRIx32 "\tt7 =%#010" PRIx32 "\n",
 	    istate->t4, istate->t5, istate->t6, istate->t7);
 	
-	printf("t8 =%#0" PRIx32 "\tt9 =%#0" PRIx32 "\t"
-	    "v0 =%#0" PRIx32 "\tv1 =%#0" PRIx32 "\n",
+	printf("t8 =%#010" PRIx32 "\tt9 =%#010" PRIx32 "\t"
+	    "v0 =%#010" PRIx32 "\tv1 =%#010" PRIx32 "\n",
 	    istate->t8, istate->t9, istate->v0, istate->v1);
 	
-	printf("s0 =%#0" PRIx32 "\ts1 =%#0" PRIx32 "\t"
-	    "s2 =%#0" PRIx32 "\ts3 =%#0" PRIx32 "\n",
+	printf("s0 =%#010" PRIx32 "\ts1 =%#010" PRIx32 "\t"
+	    "s2 =%#010" PRIx32 "\ts3 =%#010" PRIx32 "\n",
 	    istate->s0, istate->s1, istate->s2, istate->s3);
 	
-	printf("s4 =%#0" PRIx32 "\ts5 =%#0" PRIx32 "\t"
-	    "s6 =%#0" PRIx32 "\ts7 =%#0" PRIx32 "\n",
+	printf("s4 =%#010" PRIx32 "\ts5 =%#010" PRIx32 "\t"
+	    "s6 =%#010" PRIx32 "\ts7 =%#010" PRIx32 "\n",
 	    istate->s4, istate->s5, istate->s6, istate->s7);
 	
-	printf("s8 =%#0" PRIx32 "\tat =%#0" PRIx32 "\t"
-	    "kt0=%#0" PRIx32 "\tkt1=%#0" PRIx32 "\n",
+	printf("s8 =%#010" PRIx32 "\tat =%#010" PRIx32 "\t"
+	    "kt0=%#010" PRIx32 "\tkt1=%#010" PRIx32 "\n",
 	    istate->s8, istate->at, istate->kt0, istate->kt1);
 	
Index: kernel/arch/mips32/src/smp/dorder.c
===================================================================
--- kernel/arch/mips32/src/smp/dorder.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ kernel/arch/mips32/src/smp/dorder.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -37,5 +37,5 @@
 #include <arch/smp/dorder.h>
 
-#define MSIM_DORDER_ADDRESS  0xB0000004
+#define MSIM_DORDER_ADDRESS  0xB0000100
 
 #ifdef CONFIG_SMP
Index: tools/config.py
===================================================================
--- tools/config.py	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ tools/config.py	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -3,4 +3,5 @@
 # Copyright (c) 2006 Ondrej Palkovsky
 # Copyright (c) 2009 Martin Decky
+# Copyright (c) 2010 Jiri Svoboda
 # All rights reserved.
 #
@@ -40,11 +41,11 @@
 import xtui
 
-INPUT = sys.argv[1]
+RULES_FILE = sys.argv[1]
 MAKEFILE = 'Makefile.config'
 MACROS = 'config.h'
-PRECONF = 'defaults'
-
-def read_defaults(fname, defaults):
-	"Read saved values from last configuration run"
+PRESETS_DIR = 'defaults'
+
+def read_config(fname, config):
+	"Read saved values from last configuration run or a preset file"
 	
 	inf = open(fname, 'r')
@@ -52,18 +53,18 @@
 	for line in inf:
 		res = re.match(r'^(?:#!# )?([^#]\w*)\s*=\s*(.*?)\s*$', line)
-		if (res):
-			defaults[res.group(1)] = res.group(2)
+		if res:
+			config[res.group(1)] = res.group(2)
 	
 	inf.close()
 
-def check_condition(text, defaults, ask_names):
+def check_condition(text, config, rules):
 	"Check that the condition specified on input line is True (only CNF and DNF is supported)"
 	
 	ctype = 'cnf'
 	
-	if ((')|' in text) or ('|(' in text)):
+	if (')|' in text) or ('|(' in text):
 		ctype = 'dnf'
 	
-	if (ctype == 'cnf'):
+	if ctype == 'cnf':
 		conds = text.split('&')
 	else:
@@ -71,23 +72,23 @@
 	
 	for cond in conds:
-		if (cond.startswith('(')) and (cond.endswith(')')):
+		if cond.startswith('(') and cond.endswith(')'):
 			cond = cond[1:-1]
 		
-		inside = check_inside(cond, defaults, ctype)
+		inside = check_inside(cond, config, ctype)
 		
 		if (ctype == 'cnf') and (not inside):
 			return False
 		
-		if (ctype == 'dnf') and (inside):
+		if (ctype == 'dnf') and inside:
 			return True
 	
-	if (ctype == 'cnf'):
+	if ctype == 'cnf':
 		return True
 	return False
 
-def check_inside(text, defaults, ctype):
+def check_inside(text, config, ctype):
 	"Check for condition"
 	
-	if (ctype == 'cnf'):
+	if ctype == 'cnf':
 		conds = text.split('|')
 	else:
@@ -96,5 +97,5 @@
 	for cond in conds:
 		res = re.match(r'^(.*?)(!?=)(.*)$', cond)
-		if (not res):
+		if not res:
 			raise RuntimeError("Invalid condition: %s" % cond)
 		
@@ -103,12 +104,12 @@
 		condval = res.group(3)
 		
-		if (not condname in defaults):
+		if not condname in config:
 			varval = ''
 		else:
-			varval = defaults[condname]
+			varval = config[condname]
 			if (varval == '*'):
 				varval = 'y'
 		
-		if (ctype == 'cnf'):
+		if ctype == 'cnf':
 			if (oper == '=') and (condval == varval):
 				return True
@@ -123,11 +124,11 @@
 				return False
 	
-	if (ctype == 'cnf'):
+	if ctype == 'cnf':
 		return False
 	
 	return True
 
-def parse_config(fname, ask_names):
-	"Parse configuration file"
+def parse_rules(fname, rules):
+	"Parse rules file"
 	
 	inf = open(fname, 'r')
@@ -138,9 +139,9 @@
 	for line in inf:
 		
-		if (line.startswith('!')):
+		if line.startswith('!'):
 			# Ask a question
 			res = re.search(r'!\s*(?:\[(.*?)\])?\s*([^\s]+)\s*\((.*)\)\s*$', line)
 			
-			if (not res):
+			if not res:
 				raise RuntimeError("Weird line: %s" % line)
 			
@@ -149,10 +150,10 @@
 			vartype = res.group(3)
 			
-			ask_names.append((varname, vartype, name, choices, cond))
+			rules.append((varname, vartype, name, choices, cond))
 			name = ''
 			choices = []
 			continue
 		
-		if (line.startswith('@')):
+		if line.startswith('@'):
 			# Add new line into the 'choices' array
 			res = re.match(r'@\s*(?:\[(.*?)\])?\s*"(.*?)"\s*(.*)$', line)
@@ -164,10 +165,10 @@
 			continue
 		
-		if (line.startswith('%')):
+		if line.startswith('%'):
 			# Name of the option
 			name = line[1:].strip()
 			continue
 		
-		if ((line.startswith('#')) or (line == '\n')):
+		if line.startswith('#') or (line == '\n'):
 			# Comment or empty line
 			continue
@@ -181,5 +182,5 @@
 	"Return '*' if yes, ' ' if no"
 	
-	if (default == 'y'):
+	if default == 'y':
 		return '*'
 	
@@ -199,5 +200,5 @@
 	cnt = 0
 	for key, val in choices:
-		if ((default) and (key == default)):
+		if (default) and (key == default):
 			position = cnt
 		
@@ -207,22 +208,141 @@
 	(button, value) = xtui.choice_window(screen, name, 'Choose value', options, position)
 	
-	if (button == 'cancel'):
+	if button == 'cancel':
 		return None
 	
 	return choices[value][0]
 
-def check_choices(defaults, ask_names):
-	"Check whether all accessible variables have a default"
-	
-	for varname, vartype, name, choices, cond in ask_names:
-		if ((cond) and (not check_condition(cond, defaults, ask_names))):
+## Infer and verify configuration values.
+#
+# Augment @a config with values that can be inferred, purge invalid ones
+# 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.
+#
+def infer_verify_choices(config, rules):
+	"Infer and verify configuration values."
+	
+	for rule in rules:
+		varname, vartype, name, choices, cond = rule
+		
+		if cond and (not check_condition(cond, config, rules)):
 			continue
 		
-		if (not varname in defaults):
+		if not varname in config:
+			value = None
+		else:
+			value = config[varname]
+		
+		if not validate_rule_value(rule, value):
+			value = 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
 	
 	return True
 
-def create_output(mkname, mcname, defaults, ask_names):
+## Get default value from a 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
+		if len(choices) == 1:
+			default = choices[0][0]
+	elif vartype == 'y':
+		default = '*'
+	elif vartype == 'n':
+		default = 'n'
+	elif vartype == 'y/n':
+		default = 'y'
+	elif vartype == 'n/y':
+		default = 'n'
+	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
+#
+# @return Option (string) to ask or None which means not to ask.
+#
+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
+		if len(choices) != 1:
+			if (value == None):
+				option = "?     %s --> " % name
+			else:
+				option = "      %s [%s] --> " % (name, value)
+	elif vartype == 'y':
+		pass
+	elif vartype == 'n':
+		pass
+	elif vartype == 'y/n':
+		option = "  <%s> %s " % (yes_no(value), name)
+	elif vartype == 'n/y':
+		option ="  <%s> %s " % (yes_no(value), name)
+	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 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]:
+			return False
+	elif vartype == 'y':
+		if value != 'y':
+			return False
+	elif vartype == 'n':
+		if value != 'n':
+			return False
+	elif vartype == 'y/n':
+		if not value in ['y', 'n']:
+			return False
+	elif vartype == 'n/y':
+		if not value in ['y', 'n']:
+			return False
+	else:
+		raise RuntimeError("Unknown variable type: %s" % vartype)
+	
+	return True
+
+def create_output(mkname, mcname, config, rules):
 	"Create output configuration"
 	
@@ -238,7 +358,7 @@
 		sys.stderr.write("failed\n")
 	
-	if (len(version) == 3):
+	if len(version) == 3:
 		revision = version[1]
-		if (version[0] != 1):
+		if version[0] != 1:
 			revision += 'M'
 		revision += ' (%s)' % version[2]
@@ -259,26 +379,26 @@
 	defs = 'CONFIG_DEFS ='
 	
-	for varname, vartype, name, choices, cond in ask_names:
-		if ((cond) and (not check_condition(cond, defaults, ask_names))):
+	for varname, vartype, name, choices, cond in rules:
+		if cond and (not check_condition(cond, config, rules)):
 			continue
 		
-		if (not varname in defaults):
-			default = ''
+		if not varname in config:
+			value = ''
 		else:
-			default = defaults[varname]
-			if (default == '*'):
-				default = 'y'
-		
-		outmk.write('# %s\n%s = %s\n\n' % (name, varname, default))
-		
-		if ((vartype == "y") or (vartype == "n") or (vartype == "y/n") or (vartype == "n/y")):
-			if (default == "y"):
+			value = config[varname]
+			if (value == '*'):
+				value = 'y'
+		
+		outmk.write('# %s\n%s = %s\n\n' % (name, varname, value))
+		
+		if vartype in ["y", "n", "y/n", "n/y"]:
+			if value == "y":
 				outmc.write('/* %s */\n#define %s\n\n' % (name, varname))
 				defs += ' -D%s' % varname
 		else:
-			outmc.write('/* %s */\n#define %s %s\n#define %s_%s\n\n' % (name, varname, default, varname, default))
-			defs += ' -D%s=%s -D%s_%s' % (varname, default, varname, default)
-	
-	if (revision is not None):
+			outmc.write('/* %s */\n#define %s %s\n#define %s_%s\n\n' % (name, varname, value, varname, value))
+			defs += ' -D%s=%s -D%s_%s' % (varname, value, varname, value)
+	
+	if revision is not None:
 		outmk.write('REVISION = %s\n' % revision)
 		outmc.write('#define REVISION %s\n' % revision)
@@ -299,5 +419,7 @@
 	return list
 
-def read_preconfigured(root, fname, screen, defaults):
+## Ask user to choose a configuration profile.
+#
+def choose_profile(root, fname, screen, config):
 	options = []
 	opt2path = {}
@@ -309,5 +431,5 @@
 		canon = os.path.join(path, fname)
 		
-		if ((os.path.isdir(path)) and (os.path.exists(canon)) and (os.path.isfile(canon))):
+		if os.path.isdir(path) and os.path.exists(canon) and os.path.isfile(canon):
 			subprofile = False
 			
@@ -317,44 +439,91 @@
 				subcanon = os.path.join(subpath, fname)
 				
-				if ((os.path.isdir(subpath)) and (os.path.exists(subcanon)) and (os.path.isfile(subcanon))):
+				if os.path.isdir(subpath) and os.path.exists(subcanon) and os.path.isfile(subcanon):
 					subprofile = True
 					options.append("%s (%s)" % (name, subname))
-					opt2path[cnt] = (canon, subcanon)
+					opt2path[cnt] = [name, subname]
 					cnt += 1
 			
-			if (not subprofile):
+			if not subprofile:
 				options.append(name)
-				opt2path[cnt] = (canon, None)
+				opt2path[cnt] = [name]
 				cnt += 1
 	
 	(button, value) = xtui.choice_window(screen, 'Load preconfigured defaults', 'Choose configuration profile', options, None)
 	
-	if (button == 'cancel'):
+	if button == 'cancel':
 		return None
 	
-	read_defaults(opt2path[value][0], defaults)
-	if (opt2path[value][1] != None):
-		read_defaults(opt2path[value][1], defaults)
+	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():
-	defaults = {}
-	ask_names = []
-	
-	# Parse configuration file
-	parse_config(INPUT, ask_names)
-	
-	# Read defaults from previous run
-	if os.path.exists(MAKEFILE):
-		read_defaults(MAKEFILE, defaults)
-	
-	# Default mode: only check defaults and regenerate configuration
-	if ((len(sys.argv) >= 3) and (sys.argv[2] == 'default')):
-		if (check_choices(defaults, ask_names)):
-			create_output(MAKEFILE, MACROS, defaults, ask_names)
+	profile = None
+	config = {}
+	rules = []
+	
+	# Parse rules file
+	parse_rules(RULES_FILE, rules)
+	
+	# 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: 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
 	
-	# Check mode: only check defaults
-	if ((len(sys.argv) >= 3) and (sys.argv[2] == 'check')):
-		if (check_choices(defaults, ask_names)):
+	# 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
+	if (len(sys.argv) >= 3) and (sys.argv[2] == 'check'):
+		if infer_verify_choices(config, rules):
 			return 0
 		return 1
@@ -366,8 +535,8 @@
 		while True:
 			
-			# Cancel out all defaults which have to be deduced
-			for varname, vartype, name, choices, cond in ask_names:
-				if ((vartype == 'y') and (varname in defaults) and (defaults[varname] == '*')):
-					defaults[varname] = None
+			# Cancel out all values which have to be deduced
+			for varname, vartype, name, choices, cond in rules:
+				if (vartype == 'y') and (varname in config) and (config[varname] == '*'):
+					config[varname] = None
 			
 			options = []
@@ -377,50 +546,36 @@
 			options.append("  --- Load preconfigured defaults ... ")
 			
-			for varname, vartype, name, choices, cond in ask_names:
-				
-				if ((cond) and (not check_condition(cond, defaults, ask_names))):
+			for rule in rules:
+				varname, vartype, name, choices, cond = rule
+				
+				if cond and (not check_condition(cond, config, rules)):
 					continue
 				
-				if (varname == selname):
+				if varname == selname:
 					position = cnt
 				
-				if (not varname in defaults):
-					default = None
+				if not varname in config:
+					value = None
 				else:
-					default = defaults[varname]
-				
-				if (vartype == 'choice'):
-					# Check if the default is an acceptable value
-					if ((default) and (not default in [choice[0] for choice in choices])):
-						default = None
-						defaults.pop(varname)
-					
-					# If there is just one option, use it
-					if (len(choices) == 1):
-						defaults[varname] = choices[0][0]
-						continue
-					
-					if (default == None):
-						options.append("?     %s --> " % name)
-					else:
-						options.append("      %s [%s] --> " % (name, default))
-				elif (vartype == 'y'):
-					defaults[varname] = '*'
+					value = config[varname]
+				
+				if not validate_rule_value(rule, value):
+					value = 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 = get_rule_option(rule, value)
+				if option != None:
+					options.append(option)
+				else:
 					continue
-				elif (vartype == 'n'):
-					defaults[varname] = 'n'
-					continue
-				elif (vartype == 'y/n'):
-					if (default == None):
-						default = 'y'
-						defaults[varname] = default
-					options.append("  <%s> %s " % (yes_no(default), name))
-				elif (vartype == 'n/y'):
-					if (default == None):
-						default = 'n'
-						defaults[varname] = default
-					options.append("  <%s> %s " % (yes_no(default), name))
-				else:
-					raise RuntimeError("Unknown variable type: %s" % vartype)
 				
 				opt2row[cnt] = (varname, vartype, name, choices)
@@ -433,9 +588,9 @@
 			(button, value) = xtui.choice_window(screen, 'HelenOS configuration', 'Choose configuration option', options, position)
 			
-			if (button == 'cancel'):
+			if button == 'cancel':
 				return 'Configuration canceled'
 			
-			if (button == 'done'):
-				if (check_choices(defaults, ask_names)):
+			if button == 'done':
+				if (infer_verify_choices(config, rules)):
 					break
 				else:
@@ -443,31 +598,33 @@
 					continue
 			
-			if (value == 0):
-				read_preconfigured(PRECONF, MAKEFILE, screen, defaults)
+			if value == 0:
+				profile = choose_profile(PRESETS_DIR, MAKEFILE, screen, config)
+				if profile != None:
+					read_presets(profile, config)
 				position = 1
 				continue
 			
 			position = None
-			if (not value in opt2row):
+			if not value in opt2row:
 				raise RuntimeError("Error selecting value: %s" % value)
 			
 			(selname, seltype, name, choices) = opt2row[value]
 			
-			if (not selname in defaults):
-					default = None
+			if not selname in config:
+				value = None
 			else:
-				default = defaults[selname]
-			
-			if (seltype == 'choice'):
-				defaults[selname] = subchoice(screen, name, choices, default)
-			elif ((seltype == 'y/n') or (seltype == 'n/y')):
-				if (defaults[selname] == 'y'):
-					defaults[selname] = 'n'
+				value = config[selname]
+			
+			if seltype == 'choice':
+				config[selname] = subchoice(screen, name, choices, value)
+			elif (seltype == 'y/n') or (seltype == 'n/y'):
+				if config[selname] == 'y':
+					config[selname] = 'n'
 				else:
-					defaults[selname] = 'y'
+					config[selname] = 'y'
 	finally:
 		xtui.screen_done(screen)
 	
-	create_output(MAKEFILE, MACROS, defaults, ask_names)
+	create_output(MAKEFILE, MACROS, config, rules)
 	return 0
 
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -49,4 +49,5 @@
 	app/trace \
 	app/top \
+	app/usbinfo \
 	app/virtusbkbd \
 	app/netecho \
@@ -87,4 +88,7 @@
 	srv/net/net \
 	drv/root \
+	drv/rootvirt \
+	drv/test1 \
+	drv/test2 \
 	drv/vhc
 
@@ -110,12 +114,17 @@
 
 ifeq ($(UARCH),amd64)
+	DIRS += drv/rootpc
+	DIRS += drv/pciintel
+	DIRS += drv/isa
+	DIRS += drv/ns8250
 endif
 
 ifeq ($(UARCH),ia32)
-	DIRS += drv/rootia32
+	DIRS += drv/rootpc
 	DIRS += drv/pciintel
 	DIRS += drv/isa
 	DIRS += drv/ns8250
 	DIRS += drv/uhci
+	DIRS += drv/usbhub
 	DIRS += drv/usbkbd
 endif
Index: uspace/app/netecho/print_error.c
===================================================================
--- uspace/app/netecho/print_error.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/app/netecho/print_error.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/app/tester/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/app/tester/adt/usbaddrkeep.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/app/tester/adt/usbaddrkeep.def	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,6 @@
+{
+	"usbaddrkeep",
+	"USB address keeping structure",
+	&test_usbaddrkeep,
+	true
+},
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/app/tester/tester.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/app/tester/tester.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/app/usbinfo/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/app/usbinfo/dump.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,116 @@
+/*
+ * 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_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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/app/usbinfo/main.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,174 @@
+/*
+ * 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;
+
+	/*
+	 * 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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/app/usbinfo/usbinfo.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,53 @@
+/*
+ * 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>
+
+
+#define NAME "usbinfo"
+
+void dump_buffer(const char *, const uint8_t *, size_t);
+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/virtusbkbd.c
===================================================================
--- uspace/app/virtusbkbd/virtusbkbd.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/app/virtusbkbd/virtusbkbd.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -202,5 +202,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++) {
Index: uspace/drv/isa/isa.c
===================================================================
--- uspace/drv/isa/isa.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/isa/isa.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/ns8250/ns8250.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/pciintel/pci.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/root/root.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ 	(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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ 	(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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ 	(revision )
@@ -1,1 +1,0 @@
-10 ia32
Index: uspace/drv/rootpc/Makefile
===================================================================
--- uspace/drv/rootpc/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootpc/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootpc/rootpc.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootpc/rootpc.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,2 @@
+10 ia32
+10 amd64
Index: uspace/drv/rootvirt/Makefile
===================================================================
--- uspace/drv/rootvirt/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootvirt/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootvirt/devices.def	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootvirt/rootvirt.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/rootvirt/rootvirt.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,1 @@
+10 rootvirt
Index: uspace/drv/test1/Makefile
===================================================================
--- uspace/drv/test1/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test1/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test1/test1.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test1/test1.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,2 @@
+10 virtual&test1
+10 virtual&test1&child
Index: uspace/drv/test2/Makefile
===================================================================
--- uspace/drv/test2/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test2/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test2/test2.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/test2/test2.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,1 @@
+10 virtual&test2
Index: uspace/drv/uhci/Makefile
===================================================================
--- uspace/drv/uhci/Makefile	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/uhci/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -33,5 +33,6 @@
 
 SOURCES = \
-	main.c
+	main.c \
+	transfers.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/uhci/main.c
===================================================================
--- uspace/drv/uhci/main.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/uhci/main.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -27,55 +27,21 @@
  */
 #include <usb/hcdhubd.h>
+#include <usb/debug.h>
 #include <errno.h>
+#include "uhci.h"
 
-static int enqueue_transfer_out(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
-    void *buffer, size_t size,
-    usb_hcd_transfer_callback_out_t callback, void *arg)
-{
-	printf("UHCI: transfer OUT [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
-	    size);
-	return ENOTSUP;
-}
-
-static int enqueue_transfer_setup(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
-    void *buffer, size_t size,
-    usb_hcd_transfer_callback_out_t callback, void *arg)
-{
-	printf("UHCI: transfer SETUP [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
-	    size);
-	return ENOTSUP;
-}
-
-static int enqueue_transfer_in(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
-    void *buffer, size_t size,
-    usb_hcd_transfer_callback_in_t callback, void *arg)
-{
-	printf("UHCI: transfer IN [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
-	    size);
-	return ENOTSUP;
-}
-
-static usb_hcd_transfer_ops_t uhci_transfer_ops = {
-	.transfer_out = enqueue_transfer_out,
-	.transfer_in = enqueue_transfer_in,
-	.transfer_setup = enqueue_transfer_setup
+static device_ops_t uhci_ops = {
+	.interfaces[USBHC_DEV_IFACE] = &uhci_iface,
 };
 
-static int uhci_add_hc(usb_hc_device_t *device)
+static int uhci_add_device(device_t *device)
 {
-	device->transfer_ops = &uhci_transfer_ops;
+	usb_dprintf(NAME, 1, "uhci_add_device() called\n");
+	device->ops = &uhci_ops;
 
 	/*
 	 * We need to announce the presence of our root hub.
 	 */
+	usb_dprintf(NAME, 2, "adding root hub\n");
 	usb_hcd_add_root_hub(device);
 
@@ -83,7 +49,11 @@
 }
 
-usb_hc_driver_t uhci_driver = {
-	.name = "uhci",
-	.add_hc = uhci_add_hc
+static driver_ops_t uhci_driver_ops = {
+	.add_device = uhci_add_device,
+};
+
+static driver_t uhci_driver = {
+	.name = NAME,
+	.driver_ops = &uhci_driver_ops
 };
 
@@ -93,5 +63,7 @@
 	 * Do some global initializations.
 	 */
+	sleep(5);
+	usb_dprintf_enable(NAME, 5);
 
-	return usb_hcd_main(&uhci_driver);
+	return driver_main(&uhci_driver);
 }
Index: uspace/drv/uhci/transfers.c
===================================================================
--- uspace/drv/uhci/transfers.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/uhci/transfers.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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.
+ */
+#include <usb/hcdhubd.h>
+#include <errno.h>
+
+#include "uhci.h"
+
+static int enqueue_transfer_out(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer OUT [%d.%d (%s); %u]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
+	    size);
+
+	return ENOTSUP;
+}
+
+static int enqueue_transfer_setup(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer SETUP [%d.%d (%s); %u]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
+	    size);
+
+	return ENOTSUP;
+}
+
+static int enqueue_transfer_in(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
+    void *buffer, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer IN [%d.%d (%s); %u]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
+	    size);
+
+	return ENOTSUP;
+}
+
+
+static int get_address(device_t *dev, devman_handle_t handle,
+    usb_address_t *address)
+{
+	return ENOTSUP;
+}
+
+static int interrupt_out(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_INTERRUPT,
+	    data, size,
+	    callback, arg);
+}
+
+static int interrupt_in(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_INTERRUPT,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_setup(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_setup(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_data(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_status(device_t *dev, usb_target_t target,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_CONTROL,
+	    NULL, 0,
+	    callback, arg);
+}
+
+static int control_read_setup(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_setup(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_read_data(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_read_status(device_t *dev, usb_target_t target,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_CONTROL,
+	    NULL, 0,
+	    callback, arg);
+}
+
+
+usbhc_iface_t uhci_iface = {
+	.tell_address = get_address,
+	.interrupt_out = interrupt_out,
+	.interrupt_in = interrupt_in,
+	.control_write_setup = control_write_setup,
+	.control_write_data = control_write_data,
+	.control_write_status = control_write_status,
+	.control_read_setup = control_read_setup,
+	.control_read_data = control_read_data,
+	.control_read_status = control_read_status
+};
Index: uspace/drv/uhci/uhci.h
===================================================================
--- uspace/drv/uhci/uhci.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/uhci/uhci.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,47 @@
+/*
+ * 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 UHCI driver
+ */
+#ifndef DRV_UHCI_UHCI_H
+#define DRV_UHCI_UHCI_H
+
+#include <usbhc_iface.h>
+
+#define NAME "uhci"
+
+usbhc_iface_t uhci_iface;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/uhci/uhci.ma
===================================================================
--- uspace/drv/uhci/uhci.ma	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/uhci/uhci.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -1,3 +1,2 @@
 10 pci/ven=8086&dev=7020
-10 usb&hc=uhci
-10 usb&hc=uhci&hub
+
Index: uspace/drv/usbhub/Makefile
===================================================================
--- uspace/drv/usbhub/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/usbhub/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,38 @@
+#
+# 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 $(LIBUSB_PREFIX)/libusb.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBUSB_PREFIX)/include
+BINARY = usbhub
+
+SOURCES = \
+	main.c \
+	utils.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbhub/main.c
===================================================================
--- uspace/drv/usbhub/main.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/usbhub/main.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,45 @@
+/*
+ * 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 <usb/usbdrv.h>
+#include <driver.h>
+#include <errno.h>
+#include "usbhub.h"
+
+static driver_ops_t hub_driver_ops = {
+	.add_device = usb_add_hub_device,
+};
+
+static driver_t hub_driver = {
+	.name = "usbhub",
+	.driver_ops = &hub_driver_ops
+};
+
+int main(int argc, char *argv[])
+{
+	return driver_main(&hub_driver);
+}
Index: uspace/drv/usbhub/usbhub.h
===================================================================
--- uspace/drv/usbhub/usbhub.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/usbhub/usbhub.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,45 @@
+/*
+ * 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 Hub driver.
+ */
+#ifndef DRV_USBHUB_USBHUB_H
+#define DRV_USBHUB_USBHUB_H
+
+#define NAME "usbhub"
+
+int usb_add_hub_device(device_t *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/usbhub/usbhub.ma
===================================================================
--- uspace/drv/usbhub/usbhub.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/usbhub/usbhub.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,1 @@
+10 usb&hub
Index: uspace/drv/usbhub/utils.c
===================================================================
--- uspace/drv/usbhub/utils.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/drv/usbhub/utils.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,246 @@
+/*
+ * 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 libusb usb
+ * @{
+ */
+/** @file
+ * @brief Hub driver.
+ */
+#include <driver.h>
+#include <usb/devreq.h>
+#include <usbhc_iface.h>
+#include <usb/usbdrv.h>
+#include <usb/descriptor.h>
+#include <driver.h>
+#include <bool.h>
+#include <errno.h>
+#include <usb/classes/hub.h>
+#include "usbhub.h"
+
+static void check_hub_changes(void);
+
+size_t USB_HUB_MAX_DESCRIPTOR_SIZE = 71;
+
+//*********************************************
+//
+//  various utils
+//
+//*********************************************
+
+void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor) {
+	//base size
+	size_t size = 7;
+	//variable size according to port count
+	size_t var_size = descriptor->ports_count / 8 + ((descriptor->ports_count % 8 > 0) ? 1 : 0);
+	size += 2 * var_size;
+	uint8_t * result = (uint8_t*) malloc(size);
+	//size
+	result[0] = size;
+	//descriptor type
+	result[1] = USB_DESCTYPE_HUB;
+	result[2] = descriptor->ports_count;
+	/// @fixme handling of endianness??
+	result[3] = descriptor->hub_characteristics / 256;
+	result[4] = descriptor->hub_characteristics % 256;
+	result[5] = descriptor->pwr_on_2_good_time;
+	result[6] = descriptor->current_requirement;
+
+	size_t i;
+	for (i = 0; i < var_size; ++i) {
+		result[7 + i] = descriptor->devices_removable[i];
+	}
+	for (i = 0; i < var_size; ++i) {
+		result[7 + var_size + i] = 255;
+	}
+	return result;
+}
+
+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];
+	result->ports_count = sdescriptor[2];
+	/// @fixme handling of endianness??
+	result->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3];
+	result->pwr_on_2_good_time = sdescriptor[5];
+	result->current_requirement = sdescriptor[6];
+	size_t var_size = result->ports_count / 8 + ((result->ports_count % 8 > 0) ? 1 : 0);
+	result->devices_removable = (uint8_t*) malloc(var_size);
+
+	size_t i;
+	for (i = 0; i < var_size; ++i) {
+		result->devices_removable[i] = sdescriptor[7 + i];
+	}
+	return result;
+}
+
+
+//*********************************************
+//
+//  hub driver code
+//
+//*********************************************
+
+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));
+
+	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();
+
+	/*
+	 * We are some (probably deeply nested) hub.
+	 * Thus, assign our own operations and explore already
+	 * connected devices.
+	 */
+
+	//create the hub structure
+	usb_hcd_hub_info_t * hub_info = usb_create_hub_info(dev);
+	(void)hub_info;
+
+	return EOK;
+	//return ENOTSUP;
+}
+
+
+/** Check changes on all known hubs.
+ */
+static void check_hub_changes(void) {
+	/*
+	 * Iterate through all hubs.
+	 */
+	for (; false; ) {
+		/*
+		 * Check status change pipe of this hub.
+		 */
+		usb_target_t target = {
+			.address = 5,
+			.endpoint = 1
+		};
+
+		size_t port_count = 7;
+
+		/*
+		 * Connect to respective HC.
+		 */
+		int hc = usb_drv_hc_connect(NULL, 0);
+		if (hc < 0) {
+			continue;
+		}
+
+		// FIXME: count properly
+		size_t byte_length = (port_count / 8) + 1;
+
+		void *change_bitmap = malloc(byte_length);
+		size_t actual_size;
+		usb_handle_t handle;
+
+		/*
+		 * Send the request.
+		 * FIXME: check returned value for possible errors
+		 */
+		usb_drv_async_interrupt_in(hc, target,
+				change_bitmap, byte_length, &actual_size,
+				&handle);
+
+		usb_drv_async_wait_for(handle);
+
+		/*
+		 * TODO: handle the changes.
+		 */
+
+		/*
+		 * WARNING: sample code, will not work out of the box.
+		 * And does not contain code for checking for errors.
+		 */
+#if 0
+		/*
+		 * Before opening the port, we must acquire the default
+		 * address.
+		 */
+		usb_drv_reserve_default_address(hc);
+
+		usb_address_t new_device_address = usb_drv_request_address(hc);
+
+		// TODO: open the port
+
+		// TODO: send request for setting address to new_device_address
+
+		/*
+		 * Once new address is set, we can release the default
+		 * address.
+		 */
+		usb_drv_release_default_address(hc);
+
+		/*
+		 * Obtain descriptors and create match ids for devman.
+		 */
+
+		// TODO: get device descriptors
+
+		// TODO: create match ids
+
+		// TODO: add child device
+
+		// child_device_register sets the device handle
+		// TODO: store it here
+		devman_handle_t new_device_handle = 0;
+
+		/*
+		 * Inform the HC that the new device has devman handle
+		 * assigned.
+		 */
+		usb_drv_bind_address(hc, new_device_address, new_device_handle);
+
+		/*
+		 * That's all.
+		 */
+#endif
+
+
+		/*
+		 * Hang-up the HC-connected phone.
+		 */
+		ipc_hangup(hc);
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/usbkbd/main.c
===================================================================
--- uspace/drv/usbkbd/main.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/usbkbd/main.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -32,4 +32,6 @@
 #include <fibril.h>
 #include <usb/classes/hid.h>
+#include <usb/classes/hidparser.h>
+#include <usb/devreq.h>
 
 #define BUFFER_SIZE 32
@@ -37,4 +39,47 @@
 
 static const usb_endpoint_t CONTROL_EP = 0;
+
+/*
+ * Callbacks for parser
+ */
+static void usbkbd_process_keycodes(const uint16_t *key_codes, size_t count,
+                                    void *arg)
+{
+
+}
+
+/*
+ * Kbd functions
+ */
+static int usbkbd_get_descriptors()
+{
+	// copy-pasted:
+	
+	/* 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;
+	}
+	
+	// end of copy-paste
+}
 
 static usb_hid_dev_kbd_t *usbkbd_init_device(device_t *dev)
@@ -68,5 +113,5 @@
 
 	// TODO: get descriptors
-
+	usbkbd_get_descriptors();
 	// TODO: parse descriptors and save endpoints
 
@@ -75,5 +120,5 @@
 
 static void usbkbd_process_interrupt_in(usb_hid_dev_kbd_t *kbd_dev,
-					char *buffer, size_t actual_size)
+                                        uint8_t *buffer, size_t actual_size)
 {
 	/*
@@ -81,4 +126,11 @@
 	 * 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, callbacks, NULL);
 }
 
@@ -87,5 +139,5 @@
 	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;
Index: uspace/drv/vhc/conn.h
===================================================================
--- uspace/drv/vhc/conn.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/conn.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -38,4 +38,5 @@
 #include <usb/usb.h>
 #include <usb/hcdhubd.h>
+#include <usbhc_iface.h>
 #include "vhcd.h"
 #include "devices.h"
@@ -44,4 +45,8 @@
 
 usb_hcd_transfer_ops_t vhc_transfer_ops;
+usbhc_iface_t vhc_iface;
+
+void address_init(void);
+
 
 void default_connection_handler(device_t *, ipc_callid_t, ipc_call_t *);
Index: uspace/drv/vhc/connhost.c
===================================================================
--- uspace/drv/vhc/connhost.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/connhost.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -36,4 +36,5 @@
 #include <errno.h>
 #include <usb/usb.h>
+#include <usb/hcd.h>
 
 #include "vhcd.h"
@@ -43,7 +44,7 @@
 typedef struct {
 	usb_direction_t direction;
-	usb_hcd_transfer_callback_out_t out_callback;
-	usb_hcd_transfer_callback_in_t in_callback;
-	usb_hc_device_t *hc;
+	usbhc_iface_transfer_out_callback_t out_callback;
+	usbhc_iface_transfer_in_callback_t in_callback;
+	device_t *dev;
 	void *arg;
 } transfer_info_t;
@@ -56,10 +57,10 @@
 	switch (transfer->direction) {
 		case USB_DIRECTION_IN:
-			transfer->in_callback(transfer->hc,
-			    size, outcome,
+			transfer->in_callback(transfer->dev,
+			    outcome, size,
 			    transfer->arg);
 			break;
 		case USB_DIRECTION_OUT:
-			transfer->out_callback(transfer->hc,
+			transfer->out_callback(transfer->dev,
 			    outcome,
 			    transfer->arg);
@@ -73,5 +74,5 @@
 }
 
-static transfer_info_t *create_transfer_info(usb_hc_device_t *hc,
+static transfer_info_t *create_transfer_info(device_t *dev,
     usb_direction_t direction, void *arg)
 {
@@ -82,27 +83,22 @@
 	transfer->out_callback = NULL;
 	transfer->arg = arg;
-	transfer->hc = hc;
+	transfer->dev = dev;
 
 	return transfer;
 }
 
-static int enqueue_transfer_out(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
+static int enqueue_transfer_out(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
     void *buffer, size_t size,
-    usb_hcd_transfer_callback_out_t callback, void *arg)
-{
-	printf(NAME ": transfer OUT [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer OUT [%d.%d (%s); %zu]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
 	    size);
 
 	transfer_info_t *transfer
-	    = create_transfer_info(hc, USB_DIRECTION_OUT, arg);
+	    = create_transfer_info(dev, USB_DIRECTION_OUT, arg);
 	transfer->out_callback = callback;
-
-	usb_target_t target = {
-		.address = dev->address,
-		.endpoint = endpoint->endpoint
-	};
 
 	hc_add_transaction_to_device(false, target, buffer, size,
@@ -112,22 +108,17 @@
 }
 
-static int enqueue_transfer_setup(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
+static int enqueue_transfer_setup(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
     void *buffer, size_t size,
-    usb_hcd_transfer_callback_out_t callback, void *arg)
-{
-	printf(NAME ": transfer SETUP [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer SETUP [%d.%d (%s); %zu]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
 	    size);
 
 	transfer_info_t *transfer
-	    = create_transfer_info(hc, USB_DIRECTION_OUT, arg);
+	    = create_transfer_info(dev, USB_DIRECTION_OUT, arg);
 	transfer->out_callback = callback;
-
-	usb_target_t target = {
-		.address = dev->address,
-		.endpoint = endpoint->endpoint
-	};
 
 	hc_add_transaction_to_device(true, target, buffer, size,
@@ -137,22 +128,17 @@
 }
 
-static int enqueue_transfer_in(usb_hc_device_t *hc,
-    usb_hcd_attached_device_info_t *dev, usb_hc_endpoint_info_t *endpoint,
+static int enqueue_transfer_in(device_t *dev,
+    usb_target_t target, usb_transfer_type_t transfer_type,
     void *buffer, size_t size,
-    usb_hcd_transfer_callback_in_t callback, void *arg)
-{
-	printf(NAME ": transfer IN [%d.%d (%s); %u]\n",
-	    dev->address, endpoint->endpoint,
-	    usb_str_transfer_type(endpoint->transfer_type),
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	printf(NAME ": transfer IN [%d.%d (%s); %zu]\n",
+	    target.address, target.endpoint,
+	    usb_str_transfer_type(transfer_type),
 	    size);
 
 	transfer_info_t *transfer
-	    = create_transfer_info(hc, USB_DIRECTION_IN, arg);
+	    = create_transfer_info(dev, USB_DIRECTION_IN, arg);
 	transfer->in_callback = callback;
-
-	usb_target_t target = {
-		.address = dev->address,
-		.endpoint = endpoint->endpoint
-	};
 
 	hc_add_transaction_from_device(target, buffer, size,
@@ -163,8 +149,148 @@
 
 
-usb_hcd_transfer_ops_t vhc_transfer_ops = {
-	.transfer_out = enqueue_transfer_out,
-	.transfer_in = enqueue_transfer_in,
-	.transfer_setup = enqueue_transfer_setup
+static int interrupt_out(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_INTERRUPT,
+	    data, size,
+	    callback, arg);
+}
+
+static int interrupt_in(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_INTERRUPT,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_setup(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_setup(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_data(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_write_status(device_t *dev, usb_target_t target,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_CONTROL,
+	    NULL, 0,
+	    callback, arg);
+}
+
+static int control_read_setup(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_setup(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_read_data(device_t *dev, usb_target_t target,
+    void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	return enqueue_transfer_in(dev, target, USB_TRANSFER_CONTROL,
+	    data, size,
+	    callback, arg);
+}
+
+static int control_read_status(device_t *dev, usb_target_t target,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	return enqueue_transfer_out(dev, target, USB_TRANSFER_CONTROL,
+	    NULL, 0,
+	    callback, arg);
+}
+
+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 = {
+	.tell_address = tell_address,
+
+	.reserve_default_address = reserve_default_address,
+	.release_default_address = release_default_address,
+	.request_address = request_address,
+	.bind_address = bind_address,
+	.release_address = release_address,
+
+	.interrupt_out = interrupt_out,
+	.interrupt_in = interrupt_in,
+
+	.control_write_setup = control_write_setup,
+	.control_write_data = control_write_data,
+	.control_write_status = control_write_status,
+
+	.control_read_setup = control_read_setup,
+	.control_read_data = control_read_data,
+	.control_read_status = control_read_status
 };
 
Index: uspace/drv/vhc/debug.c
===================================================================
--- uspace/drv/vhc/debug.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/debug.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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/hcd.c
===================================================================
--- uspace/drv/vhc/hcd.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/hcd.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -52,7 +52,11 @@
 #include "conn.h"
 
+static device_ops_t vhc_ops = {
+	.interfaces[USBHC_DEV_IFACE] = &vhc_iface,
+	.default_handler = default_connection_handler
+};
 
 static int vhc_count = 0;
-static int vhc_add_device(usb_hc_device_t *dev)
+static int vhc_add_device(device_t *dev)
 {
 	/*
@@ -65,12 +69,15 @@
 	vhc_count++;
 
-	dev->transfer_ops = &vhc_transfer_ops;
-	dev->generic->ops->default_handler = default_connection_handler;
+	dev->ops = &vhc_ops;
+
+	/*
+	 * Initialize address management.
+	 */
+	address_init();
 
 	/*
 	 * 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);
@@ -79,7 +86,11 @@
 }
 
-static usb_hc_driver_t vhc_driver = {
+static driver_ops_t vhc_driver_ops = {
+	.add_device = vhc_add_device,
+};
+
+static driver_t vhc_driver = {
 	.name = NAME,
-	.add_hc = &vhc_add_device
+	.driver_ops = &vhc_driver_ops
 };
 
@@ -99,5 +110,5 @@
 	printf("%s: virtual USB host controller driver.\n", NAME);
 
-	debug_level = 10;
+	usb_dprintf_enable(NAME, 10);
 
 	fid_t fid = fibril_create(hc_manager_fibril, NULL);
@@ -114,5 +125,5 @@
 	sleep(4);
 
-	return usb_hcd_main(&vhc_driver);
+	return driver_main(&vhc_driver);
 }
 
Index: uspace/drv/vhc/hub.c
===================================================================
--- uspace/drv/vhc/hub.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/hub.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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"
 
 
@@ -148,6 +151,28 @@
 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)
+void hub_init(device_t *hc_dev)
 {
 	size_t i;
@@ -163,4 +188,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);
 }
 
Index: uspace/drv/vhc/hub.h
===================================================================
--- uspace/drv/vhc/hub.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/hub.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -37,4 +37,5 @@
 
 #include <usbvirt/device.h>
+#include <driver.h>
 
 #include "devices.h"
@@ -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/vhc.ma
===================================================================
--- uspace/drv/vhc/vhc.ma	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/vhc.ma	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -1,2 +1,2 @@
 10 usb&hc=vhc
-10 usb&hc=vhc&hub
+
Index: uspace/drv/vhc/vhcd.h
===================================================================
--- uspace/drv/vhc/vhcd.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/drv/vhc/vhcd.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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/block/libblock.c
===================================================================
--- uspace/lib/block/libblock.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/block/libblock.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -66,4 +66,5 @@
 	fibril_mutex_t lock;
 	size_t lblock_size;		/**< Logical block size. */
+	unsigned blocks_cluster;	/**< Physical blocks per block_t */
 	unsigned block_count;		/**< Total number of blocks. */
 	unsigned blocks_cached;		/**< Number of cached blocks. */
@@ -90,4 +91,5 @@
 static int get_block_size(int dev_phone, size_t *bsize);
 static int get_num_blocks(int dev_phone, aoff64_t *nblocks);
+static aoff64_t ba_ltop(devcon_t *devcon, aoff64_t lba);
 
 static devcon_t *devcon_search(devmap_handle_t devmap_handle)
@@ -259,5 +261,5 @@
 {
 	block_t *b = hash_table_get_instance(item, block_t, hash_link);
-	return b->boff == *key;
+	return b->lba == *key;
 }
 
@@ -292,6 +294,9 @@
 	cache->mode = mode;
 
-	/* No block size translation a.t.m. */
-	assert(cache->lblock_size == devcon->pblock_size);
+	/* Allow 1:1 or small-to-large block size translation */
+	if (cache->lblock_size % devcon->pblock_size != 0)
+		return ENOTSUP;
+
+	cache->blocks_cluster = cache->lblock_size / devcon->pblock_size;
 
 	if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1,
@@ -329,10 +334,10 @@
 		if (b->dirty) {
 			memcpy(devcon->comm_area, b->data, b->size);
-			rc = write_blocks(devcon, b->boff, 1);
+			rc = write_blocks(devcon, b->pba, cache->blocks_cluster);
 			if (rc != EOK)
 				return rc;
 		}
 
-		unsigned long key = b->boff;
+		unsigned long key = b->lba;
 		hash_table_remove(&cache->block_hash, &key, 1);
 		
@@ -375,5 +380,5 @@
  * 				block pointer on success.
  * @param devmap_handle		Device handle of the block device.
- * @param boff			Block offset.
+ * @param ba			Block address (logical).
  * @param flags			If BLOCK_FLAGS_NOREAD is specified, block_get()
  * 				will not read the contents of the block from the
@@ -382,5 +387,5 @@
  * @return			EOK on success or a negative error code.
  */
-int block_get(block_t **block, devmap_handle_t devmap_handle, aoff64_t boff, int flags)
+int block_get(block_t **block, devmap_handle_t devmap_handle, aoff64_t ba, int flags)
 {
 	devcon_t *devcon;
@@ -388,5 +393,5 @@
 	block_t *b;
 	link_t *l;
-	unsigned long key = boff;
+	unsigned long key = ba;
 	int rc;
 	
@@ -465,5 +470,6 @@
 				fibril_mutex_lock(&devcon->comm_area_lock);
 				memcpy(devcon->comm_area, b->data, b->size);
-				rc = write_blocks(devcon, b->boff, 1);
+				rc = write_blocks(devcon, b->pba,
+				    cache->blocks_cluster);
 				fibril_mutex_unlock(&devcon->comm_area_lock);
 				if (rc != EOK) {
@@ -495,5 +501,5 @@
 			 */
 			list_remove(&b->free_link);
-			temp_key = b->boff;
+			temp_key = b->lba;
 			hash_table_remove(&cache->block_hash, &temp_key, 1);
 		}
@@ -502,5 +508,6 @@
 		b->devmap_handle = devmap_handle;
 		b->size = cache->lblock_size;
-		b->boff = boff;
+		b->lba = ba;
+		b->pba = ba_ltop(devcon, b->lba);
 		hash_table_insert(&cache->block_hash, &key, &b->hash_link);
 
@@ -519,5 +526,5 @@
 			 */
 			fibril_mutex_lock(&devcon->comm_area_lock);
-			rc = read_blocks(devcon, b->boff, 1);
+			rc = read_blocks(devcon, b->pba, cache->blocks_cluster);
 			memcpy(b->data, devcon->comm_area, cache->lblock_size);
 			fibril_mutex_unlock(&devcon->comm_area_lock);
@@ -580,5 +587,5 @@
 		fibril_mutex_lock(&devcon->comm_area_lock);
 		memcpy(devcon->comm_area, block->data, block->size);
-		rc = write_blocks(devcon, block->boff, 1);
+		rc = write_blocks(devcon, block->pba, cache->blocks_cluster);
 		fibril_mutex_unlock(&devcon->comm_area_lock);
 		block->dirty = false;
@@ -614,5 +621,5 @@
 			 * Take the block out of the cache and free it.
 			 */
-			unsigned long key = block->boff;
+			unsigned long key = block->lba;
 			hash_table_remove(&cache->block_hash, &key, 1);
 			free(block);
@@ -712,5 +719,5 @@
  *
  * @param devmap_handle	Device handle of the block device.
- * @param ba		Address of first block.
+ * @param ba		Address of first block (physical).
  * @param cnt		Number of blocks.
  * @param src		Buffer for storing the data.
@@ -740,5 +747,5 @@
  *
  * @param devmap_handle	Device handle of the block device.
- * @param ba		Address of first block.
+ * @param ba		Address of first block (physical).
  * @param cnt		Number of blocks.
  * @param src		The data to be written.
@@ -879,4 +886,11 @@
 }
 
+/** Convert logical block address to physical block address. */
+static aoff64_t ba_ltop(devcon_t *devcon, aoff64_t lba)
+{
+	assert(devcon->cache != NULL);
+	return lba * devcon->cache->blocks_cluster;
+}
+
 /** @}
  */
Index: uspace/lib/block/libblock.h
===================================================================
--- uspace/lib/block/libblock.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/block/libblock.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -73,6 +73,8 @@
 	/** Handle of the device where the block resides. */
 	devmap_handle_t devmap_handle;
-	/** Block offset on the block device. Counted in 'size'-byte blocks. */
-	aoff64_t boff;
+	/** Logical block address */
+	aoff64_t lba;
+	/** Physical block address */
+	aoff64_t pba;
 	/** Size of the block. */
 	size_t size;
Index: uspace/lib/c/generic/adt/char_map.c
===================================================================
--- uspace/lib/c/generic/adt/char_map.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/c/generic/adt/char_map.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/c/generic/devman.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/c/include/adt/generic_field.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/c/include/errno.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/c/include/ipc/vfs.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/drv/generic/driver.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -52,4 +52,9 @@
 static void remote_usbhc_control_read_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_control_read_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_reserve_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_release_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_request_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_bind_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_release_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
 //static void remote_usbhc(device_t *, void *, ipc_callid_t, ipc_call_t *);
 
@@ -57,10 +62,21 @@
 static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
 	remote_usbhc_get_address,
+
 	remote_usbhc_get_buffer,
+
+	remote_usbhc_reserve_default_address,
+	remote_usbhc_release_default_address,
+
+	remote_usbhc_request_address,
+	remote_usbhc_bind_address,
+	remote_usbhc_release_address,
+
 	remote_usbhc_interrupt_out,
 	remote_usbhc_interrupt_in,
+
 	remote_usbhc_control_write_setup,
 	remote_usbhc_control_write_data,
 	remote_usbhc_control_write_status,
+
 	remote_usbhc_control_read_setup,
 	remote_usbhc_control_read_data,
@@ -92,5 +108,5 @@
 	}
 
-	devman_handle_t handle = IPC_GET_ARG1(*call);
+	devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
 
 	usb_address_t address;
@@ -106,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) {
@@ -128,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);
@@ -134,4 +150,88 @@
 	free(trans->buffer);
 	free(trans);
+}
+
+void remote_usbhc_reserve_default_address(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->reserve_default_address) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	int rc = usb_iface->reserve_default_address(device);
+
+	ipc_answer_0(callid, rc);
+}
+
+void remote_usbhc_release_default_address(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->release_default_address) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	int rc = usb_iface->release_default_address(device);
+
+	ipc_answer_0(callid, rc);
+}
+
+void remote_usbhc_request_address(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->request_address) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_address_t address;
+	int rc = usb_iface->request_address(device, &address);
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+	} else {
+		ipc_answer_1(callid, EOK, (ipcarg_t) address);
+	}
+}
+
+void remote_usbhc_bind_address(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->bind_address) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	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);
+
+	ipc_answer_0(callid, rc);
+}
+
+void remote_usbhc_release_address(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+
+	if (!usb_iface->release_address) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+
+	int rc = usb_iface->release_address(device, address);
+
+	ipc_answer_0(callid, rc);
 }
 
@@ -175,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)
 	};
 
@@ -227,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)
 	};
 
@@ -284,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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/drv/include/driver.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -111,4 +111,50 @@
 
 
+	/** Reserve usage of default address.
+	 * This call informs the host controller that the caller will be
+	 * using default USB address. It is duty of the HC driver to ensure
+	 * that only single entity will have it reserved.
+	 * The address is returned via IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS.
+	 * The caller can start using the address after receiving EOK
+	 * answer.
+	 */
+	IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS,
+
+	/** Release usage of default address.
+	 * @see IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS
+	 */
+	IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS,
+
+	/** Asks for address assignment by host controller.
+	 * Answer:
+	 * - ELIMIT - host controller run out of address
+	 * - EOK - address assigned
+	 * Answer arguments:
+	 * - assigned address
+	 *
+	 * The address must be released by via IPC_M_USBHC_RELEASE_ADDRESS.
+	 */
+	IPC_M_USBHC_REQUEST_ADDRESS,
+
+	/** Bind USB address with devman handle.
+	 * Parameters:
+	 * - USB address
+	 * - devman handle
+	 * Answer:
+	 * - EOK - address binded
+	 * - ENOENT - address is not in use
+	 */
+	IPC_M_USBHC_BIND_ADDRESS,
+
+	/** Release address in use.
+	 * Arguments:
+	 * - address to be released
+	 * Answer:
+	 * - ENOENT - address not in use
+	 * - EPERM - trying to release default USB address
+	 */
+	IPC_M_USBHC_RELEASE_ADDRESS,
+
+
 	/** Send interrupt data to device.
 	 * See explanation at usb_iface_funcs_t (OUT transaction).
@@ -183,4 +229,10 @@
 typedef struct {
 	int (*tell_address)(device_t *, devman_handle_t, usb_address_t *);
+
+	int (*reserve_default_address)(device_t *);
+	int (*release_default_address)(device_t *);
+	int (*request_address)(device_t *, usb_address_t *);
+	int (*bind_address)(device_t *, usb_address_t, devman_handle_t);
+	int (*release_address)(device_t *, usb_address_t);
 
 	usbhc_iface_transfer_out_t interrupt_out;
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/Makefile	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -33,10 +33,14 @@
 
 SOURCES = \
+	src/addrkeep.c \
+	src/debug.c \
+	src/drvpsync.c \
 	src/hcdhubd.c \
 	src/hcdrv.c \
-	src/hubdrv.c \
+	src/hidparser.c \
 	src/localdrv.c \
 	src/remotedrv.c \
 	src/usb.c \
+	src/usbdrvreq.c \
 	src/usbdrv.c
 
Index: uspace/lib/usb/include/usb/classes/hid.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hid.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/include/usb/classes/hid.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -38,4 +38,5 @@
 #include <usb/usb.h>
 #include <driver.h>
+#include <usb/classes/hidparser.h>
 
 /** USB/HID device requests. */
@@ -66,4 +67,5 @@
 	usb_address_t address;
 	usb_endpoint_t default_ep;
+	usb_hid_report_parser_t *parser;
 } usb_hid_dev_kbd_t;
 
Index: uspace/lib/usb/include/usb/classes/hidparser.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hidparser.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/lib/usb/include/usb/classes/hidparser.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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);
+
+int usb_hid_parse_report(const usb_hid_report_parser_t *parser,  
+    const uint8_t *data,
+    const usb_hid_report_in_callbacks_t *callbacks, void *arg);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/debug.h
===================================================================
--- uspace/lib/usb/include/usb/debug.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/lib/usb/include/usb/debug.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/include/usb/devreq.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/lib/usb/include/usb/hcd.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/include/usb/hcdhubd.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -116,4 +116,21 @@
 } usb_hcd_transfer_ops_t;
 
+/**
+ * @brief structure holding information about free and used addresses
+ *
+ * This structure should not be used outside usb hcd driver.
+ * You better consider it to be 'private'.
+ */
+typedef struct {
+	/** lower bound included in the interval */
+	usb_address_t lower_bound;
+
+	/** upper bound, excluded from the interval */
+	usb_address_t upper_bound;
+
+	/** */
+	link_t link;
+}usb_address_list_t;
+
 struct usb_hc_device {
 	/** Transfer operations. */
@@ -131,4 +148,7 @@
 	/** List of hubs operating from this HC. */
 	link_t hubs;
+
+	/** Structure with free and used addresses */
+	link_t addresses;
 
 	/** Link to other driven HCs. */
@@ -146,5 +166,22 @@
 
 int usb_hcd_main(usb_hc_driver_t *);
-int usb_hcd_add_root_hub(usb_hc_device_t *dev);
+int usb_hcd_add_root_hub(device_t *dev);
+
+/**
+ * find first not yet used address on this host controller and use it
+ * @param this_hcd
+ * @return number in the range of allowed usb addresses or
+ *     a negative number if not succesful
+ */
+usb_address_t usb_use_free_address(usb_hc_device_t * this_hcd);
+
+/**
+ * @brief free the address in the address space of this hcd.
+ *
+ * if address is not used, nothing happens
+ * @param this_hcd
+ * @param addr
+ */
+void usb_free_used_address(usb_hc_device_t * this_hcd, usb_address_t addr );
 
 
@@ -154,4 +191,5 @@
  */
 
+device_t *usb_hc_connect(device_t *);
 
 int usb_hc_async_interrupt_out(usb_hc_device_t *, usb_target_t,
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/include/usb/usb.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/include/usb/usbdrv.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -36,8 +36,16 @@
 #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);
+
+int usb_drv_reserve_default_address(int);
+int usb_drv_release_default_address(int);
+usb_address_t usb_drv_request_address(int);
+int usb_drv_bind_address(int, usb_address_t, devman_handle_t);
+int usb_drv_release_address(int, usb_address_t);
 
 usb_address_t usb_drv_get_my_address(int, device_t *);
@@ -48,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 *);
@@ -54,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,
@@ -62,5 +83,15 @@
     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);
+
 
 #endif
Index: uspace/lib/usb/src/addrkeep.c
===================================================================
--- uspace/lib/usb/src/addrkeep.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/lib/usb/src/addrkeep.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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;
+		}
+	}
+
+	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/debug.c
===================================================================
--- uspace/lib/usb/src/debug.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/lib/usb/src/debug.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/lib/usb/src/drvpsync.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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/hcdhubd.c
===================================================================
--- uspace/lib/usb/src/hcdhubd.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/src/hcdhubd.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -51,20 +51,5 @@
  */
 static int add_device(device_t *dev) {
-	bool is_hc = str_cmp(dev->name, USB_HUB_DEVICE_NAME) != 0;
-	printf("%s: add_device(name=\"%s\")\n", hc_driver->name, dev->name);
-
-	if (is_hc) {
-		/*
-		 * We are the HC itself.
-		 */
-		return usb_add_hc_device(dev);
-	} else {
-		/*
-		 * We are some (maybe deeply nested) hub.
-		 * Thus, assign our own operations and explore already
-		 * connected devices.
-		 */
-		return usb_add_hub_device(dev);
-	}
+	return ENOTSUP;
 }
 
@@ -105,13 +90,13 @@
  * @return Error code.
  */
-int usb_hcd_add_root_hub(usb_hc_device_t *dev)
+int usb_hcd_add_root_hub(device_t *dev)
 {
 	char *id;
-	int rc = asprintf(&id, "usb&hc=%s&hub", hc_driver->name);
+	int rc = asprintf(&id, "usb&hub");
 	if (rc <= 0) {
 		return rc;
 	}
 
-	rc = usb_hc_add_child_device(dev->generic, USB_HUB_DEVICE_NAME, id, true);
+	rc = usb_hc_add_child_device(dev, USB_HUB_DEVICE_NAME, id, true);
 	if (rc != EOK) {
 		free(id);
@@ -129,8 +114,7 @@
 
 /** Adds a child device fibril worker. */
-static int fibril_add_child_device(void *arg)
-{
+static int fibril_add_child_device(void *arg) {
 	struct child_device_info *child_info
-	    = (struct child_device_info *) arg;
+			= (struct child_device_info *) arg;
 	int rc;
 
@@ -156,8 +140,8 @@
 
 	printf("%s: adding child device `%s' with match \"%s\"\n",
-	    hc_driver->name, child->name, match_id->id);
+			hc_driver->name, child->name, match_id->id);
 	rc = child_device_register(child, child_info->parent);
 	printf("%s: child device `%s' registration: %s\n",
-	    hc_driver->name, child->name, str_error(rc));
+			hc_driver->name, child->name, str_error(rc));
 
 	if (rc != EOK) {
@@ -197,8 +181,7 @@
  */
 int usb_hc_add_child_device(device_t *parent, const char *name,
-    const char *match_id, bool create_fibril)
-{
+		const char *match_id, bool create_fibril) {
 	printf("%s: about to add child device `%s' (%s)\n", hc_driver->name,
-	    name, match_id);
+			name, match_id);
 
 	/*
@@ -209,5 +192,5 @@
 
 	struct child_device_info *child_info
-	    = malloc(sizeof(struct child_device_info));
+			= malloc(sizeof (struct child_device_info));
 
 	child_info->parent = parent;
@@ -233,10 +216,93 @@
  * @return USB device address or error code.
  */
-usb_address_t usb_get_address_by_handle(devman_handle_t handle)
-{
+usb_address_t usb_get_address_by_handle(devman_handle_t handle) {
 	/* TODO: search list of attached devices. */
 	return ENOENT;
 }
 
+usb_address_t usb_use_free_address(usb_hc_device_t * this_hcd) {
+	//is there free address?
+	link_t * addresses = &this_hcd->addresses;
+	if (list_empty(addresses)) return -1;
+	link_t * link_addr = addresses;
+	bool found = false;
+	usb_address_list_t * range = NULL;
+	while (!found) {
+		link_addr = link_addr->next;
+		if (link_addr == addresses) return -2;
+		range = list_get_instance(link_addr,
+				usb_address_list_t, link);
+		if (range->upper_bound - range->lower_bound > 0) {
+			found = true;
+		}
+	}
+	//now we have interval
+	int result = range->lower_bound;
+	++(range->lower_bound);
+	if (range->upper_bound - range->lower_bound == 0) {
+		list_remove(&range->link);
+		free(range);
+	}
+	return result;
+}
+
+void usb_free_used_address(usb_hc_device_t * this_hcd, usb_address_t addr) {
+	//check range
+	if (addr < usb_lowest_address || addr > usb_highest_address)
+		return;
+	link_t * addresses = &this_hcd->addresses;
+	link_t * link_addr = addresses;
+	//find 'good' interval
+	usb_address_list_t * found_range = NULL;
+	bool found = false;
+	while (!found) {
+		link_addr = link_addr->next;
+		if (link_addr == addresses) {
+			found = true;
+		} else {
+			usb_address_list_t * range = list_get_instance(link_addr,
+					usb_address_list_t, link);
+			if (	(range->lower_bound - 1 == addr) ||
+					(range->upper_bound == addr)) {
+				found = true;
+				found_range = range;
+			}
+			if (range->lower_bound - 1 > addr) {
+				found = true;
+			}
+
+		}
+	}
+	if (found_range == NULL) {
+		//no suitable range found
+		usb_address_list_t * result_range =
+				(usb_address_list_t*) malloc(sizeof (usb_address_list_t));
+		result_range->lower_bound = addr;
+		result_range->upper_bound = addr + 1;
+		list_insert_before(&result_range->link, link_addr);
+	} else {
+		//we have good range
+		if (found_range->lower_bound - 1 == addr) {
+			--found_range->lower_bound;
+		} else {
+			//only one possible case
+			++found_range->upper_bound;
+			if (found_range->link.next != addresses) {
+				usb_address_list_t * next_range =
+						list_get_instance( &found_range->link.next,
+						usb_address_list_t, link);
+				//check neighbour range
+				if (next_range->lower_bound == addr + 1) {
+					//join ranges
+					found_range->upper_bound = next_range->upper_bound;
+					list_remove(&next_range->link);
+					free(next_range);
+				}
+			}
+		}
+	}
+
+}
+
 /**
  * @}
Index: uspace/lib/usb/src/hcdhubd_private.h
===================================================================
--- uspace/lib/usb/src/hcdhubd_private.h	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/src/hcdhubd_private.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -46,5 +46,29 @@
 usb_address_t usb_get_address_by_handle(devman_handle_t);
 int usb_add_hc_device(device_t *);
-int usb_add_hub_device(device_t *);
+
+/** lowest allowed usb address */
+extern int usb_lowest_address;
+
+/** highest allowed usb address */
+extern int usb_highest_address;
+
+/**
+ * @brief initialize address list of given hcd
+ *
+ * This function should be used only for hcd initialization.
+ * It creates interval list of free addresses, thus it is initialized as
+ * list with one interval with whole address space. Using an address shrinks
+ * the interval, freeing an address extends an interval or creates a
+ * new one. 
+ *
+ * @param hcd
+ * @return
+ */
+void  usb_create_address_list(usb_hc_device_t * hcd);
+
+
+
+
+
 
 #endif
Index: uspace/lib/usb/src/hcdrv.c
===================================================================
--- uspace/lib/usb/src/hcdrv.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/src/hcdrv.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -47,10 +47,29 @@
 LIST_INITIALIZE(hc_list);
 
+/* Fake driver to have the name item initialized. */
+static usb_hc_driver_t hc_driver_fake = {
+	.name = "HCD",
+};
+
 /** Our HC driver. */
-usb_hc_driver_t *hc_driver = NULL;
+usb_hc_driver_t *hc_driver = &hc_driver_fake;
+
+int usb_lowest_address = 1;
+
+int usb_highest_address = 255;
 
 static device_ops_t usb_device_ops = {
 	.interfaces[USBHC_DEV_IFACE] = &usbhc_interface
 };
+
+
+void usb_create_address_list(usb_hc_device_t * hcd){
+	list_initialize(&hcd->addresses);
+	usb_address_list_t * range =
+			(usb_address_list_t*)malloc(sizeof(usb_address_list_t));
+	range->lower_bound = usb_lowest_address;
+	range->upper_bound = usb_highest_address + 1;
+	list_append(&range->link, &hcd->addresses);
+}
 
 static usb_hc_device_t *usb_hc_device_create(device_t *dev) {
@@ -59,4 +78,5 @@
 	list_initialize(&hc_dev->link);
 	list_initialize(&hc_dev->hubs);
+	usb_create_address_list(hc_dev);
 	list_initialize(&hc_dev->attached_devices);
 	hc_dev->transfer_ops = NULL;
@@ -71,4 +91,5 @@
 int usb_add_hc_device(device_t *dev)
 {
+	return ENOTSUP;
 	usb_hc_device_t *hc_dev = usb_hc_device_create(dev);
 
Index: uspace/lib/usb/src/hidparser.c
===================================================================
--- uspace/lib/usb/src/hidparser.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/lib/usb/src/hidparser.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ * @return Error code.
+ */
+int usb_hid_parse_report_descriptor(usb_hid_report_parser_t *parser, 
+    const uint8_t *data)
+{
+	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 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,
+    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);
+}
+
+
+/**
+ * @}
+ */
Index: pace/lib/usb/src/hubdrv.c
===================================================================
--- uspace/lib/usb/src/hubdrv.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ 	(revision )
@@ -1,278 +1,0 @@
-/*
- * 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 libusb usb
- * @{
- */
-/** @file
- * @brief Hub driver.
- */
-#include <usb/hcdhubd.h>
-#include <usb/devreq.h>
-#include <usbhc_iface.h>
-#include <usb/descriptor.h>
-#include <driver.h>
-#include <bool.h>
-#include <errno.h>
-#include <usb/classes/hub.h>
-#include "hcdhubd_private.h"
-
-static void check_hub_changes(void);
-
-size_t USB_HUB_MAX_DESCRIPTOR_SIZE = 71;
-
-//*********************************************
-//
-//  various utils
-//
-//*********************************************
-
-void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor) {
-	//base size
-	size_t size = 7;
-	//variable size according to port count
-	size_t var_size = descriptor->ports_count / 8 + ((descriptor->ports_count % 8 > 0) ? 1 : 0);
-	size += 2 * var_size;
-	uint8_t * result = (uint8_t*) malloc(size);
-	//size
-	result[0] = size;
-	//descriptor type
-	result[1] = USB_DESCTYPE_HUB;
-	result[2] = descriptor->ports_count;
-	/// @fixme handling of endianness??
-	result[3] = descriptor->hub_characteristics / 256;
-	result[4] = descriptor->hub_characteristics % 256;
-	result[5] = descriptor->pwr_on_2_good_time;
-	result[6] = descriptor->current_requirement;
-
-	size_t i;
-	for (i = 0; i < var_size; ++i) {
-		result[7 + i] = descriptor->devices_removable[i];
-	}
-	for (i = 0; i < var_size; ++i) {
-		result[7 + var_size + i] = 255;
-	}
-	return result;
-}
-
-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];
-	result->ports_count = sdescriptor[2];
-	/// @fixme handling of endianness??
-	result->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3];
-	result->pwr_on_2_good_time = sdescriptor[5];
-	result->current_requirement = sdescriptor[6];
-	size_t var_size = result->ports_count / 8 + ((result->ports_count % 8 > 0) ? 1 : 0);
-	result->devices_removable = (uint8_t*) malloc(var_size);
-
-	size_t i;
-	for (i = 0; i < var_size; ++i) {
-		result->devices_removable[i] = sdescriptor[7 + i];
-	}
-	return result;
-}
-
-
-//*********************************************
-//
-//  hub driver code
-//
-//*********************************************
-
-static void set_hub_address(usb_hc_device_t *hc, usb_address_t address);
-
-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));
-	//get parent device
-	/// @TODO this code is not correct
-	device_t * my_hcd = device;
-	while (my_hcd->parent)
-		my_hcd = my_hcd->parent;
-	//dev->
-	printf("%s: owner hcd found: %s\n", hc_driver->name, my_hcd->name);
-	//we add the hub into the first hc
-	//link_t *link_hc = hc_list.next;
-	//usb_hc_device_t *hc = list_get_instance(link_hc,
-	//		usb_hc_device_t, link);
-	//must get generic device info
-
-
-	return result;
-}
-
-/** Callback when new hub device is detected.
- *
- * @param dev New device.
- * @return Error code.
- */
-int usb_add_hub_device(device_t *dev) {
-	usb_hc_device_t *hc = list_get_instance(hc_list.next, usb_hc_device_t, link);
-	set_hub_address(hc, 5);
-
-	check_hub_changes();
-
-	/*
-	 * We are some (probably deeply nested) hub.
-	 * Thus, assign our own operations and explore already
-	 * connected devices.
-	 */
-	//insert hub into list
-	//find owner hcd
-	device_t * my_hcd = dev;
-	while (my_hcd->parent)
-		my_hcd = my_hcd->parent;
-	//dev->
-	printf("%s: owner hcd found: %s\n", hc_driver->name, my_hcd->name);
-	my_hcd = dev;
-	while (my_hcd->parent)
-		my_hcd = my_hcd->parent;
-	//dev->
-
-	printf("%s: owner hcd found: %s\n", hc_driver->name, my_hcd->name);
-
-	//create the hub structure
-	usb_hcd_hub_info_t * hub_info = usb_create_hub_info(dev);
-
-
-	//append into the list
-	//we add the hub into the first hc
-	list_append(&hub_info->link, &hc->hubs);
-
-
-
-	return EOK;
-	//return ENOTSUP;
-}
-
-/** Sample usage of usb_hc_async functions.
- * This function sets hub address using standard SET_ADDRESS request.
- *
- * @warning This function shall be removed once you are familiar with
- * the usb_hc_ API.
- *
- * @param hc Host controller the hub belongs to.
- * @param address New hub address.
- */
-static void set_hub_address(usb_hc_device_t *hc, usb_address_t address) {
-	printf("%s: setting hub address to %d\n", hc->generic->name, address);
-	usb_target_t target = {0, 0};
-	usb_handle_t handle;
-	int rc;
-
-	usb_device_request_setup_packet_t setup_packet = {
-		.request_type = 0,
-		.request = USB_DEVREQ_SET_ADDRESS,
-		.index = 0,
-		.length = 0,
-	};
-	setup_packet.value = address;
-
-	rc = usb_hc_async_control_write_setup(hc, target,
-			&setup_packet, sizeof (setup_packet), &handle);
-	if (rc != EOK) {
-		return;
-	}
-
-	rc = usb_hc_async_wait_for(handle);
-	if (rc != EOK) {
-		return;
-	}
-
-	rc = usb_hc_async_control_write_status(hc, target, &handle);
-	if (rc != EOK) {
-		return;
-	}
-
-	rc = usb_hc_async_wait_for(handle);
-	if (rc != EOK) {
-		return;
-	}
-
-	printf("%s: hub address changed\n", hc->generic->name);
-}
-
-/** Check changes on all known hubs.
- */
-static void check_hub_changes(void) {
-	/*
-	 * Iterate through all HCs.
-	 */
-	link_t *link_hc;
-	for (link_hc = hc_list.next;
-			link_hc != &hc_list;
-			link_hc = link_hc->next) {
-		usb_hc_device_t *hc = list_get_instance(link_hc,
-				usb_hc_device_t, link);
-		/*
-		 * Iterate through all their hubs.
-		 */
-		link_t *link_hub;
-		for (link_hub = hc->hubs.next;
-				link_hub != &hc->hubs;
-				link_hub = link_hub->next) {
-			usb_hcd_hub_info_t *hub = list_get_instance(link_hub,
-					usb_hcd_hub_info_t, link);
-
-			/*
-			 * Check status change pipe of this hub.
-			 */
-			usb_target_t target = {
-				.address = hub->device->address,
-				.endpoint = 1
-			};
-
-			// FIXME: count properly
-			size_t byte_length = (hub->port_count / 8) + 1;
-
-			void *change_bitmap = malloc(byte_length);
-			size_t actual_size;
-			usb_handle_t handle;
-
-			/*
-			 * Send the request.
-			 * FIXME: check returned value for possible errors
-			 */
-			usb_hc_async_interrupt_in(hc, target,
-					change_bitmap, byte_length, &actual_size,
-					&handle);
-
-			usb_hc_async_wait_for(handle);
-
-			/*
-			 * TODO: handle the changes.
-			 */
-		}
-	}
-}
-
-/**
- * @}
- */
Index: uspace/lib/usb/src/localdrv.c
===================================================================
--- uspace/lib/usb/src/localdrv.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/src/localdrv.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -39,4 +39,29 @@
 #include <errno.h>
 
+/** Find host controller when handled by current task.
+ *
+ * @param dev Device asking for connection.
+ * @return Device structure corresponding to parent host controller.
+ * @retval NULL Corresponding host controller not found.
+ */
+device_t *usb_hc_connect(device_t *dev)
+{
+	/*
+	 * FIXME: this will not work when some hub on the path is
+	 * not driven by the same task.
+	 */
+	device_t *parent = dev;
+	while (parent->parent != NULL) {
+		parent = parent->parent;
+	}
+	
+	if (dev == parent) {
+		printf("FIXME in %s:%d encountered!\n", __FILE__, __LINE__);
+		parent = NULL;
+	}
+
+	return parent;
+}
+
 /** Information about pending transaction on HC. */
 typedef struct {
Index: uspace/lib/usb/src/remotedrv.c
===================================================================
--- uspace/lib/usb/src/remotedrv.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/src/remotedrv.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usb/src/usbdrv.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -55,5 +55,5 @@
 /** Connect to host controller the device is physically attached to.
  *
- * @param handle Device handle.
+ * @param dev Device asking for connection.
  * @param flags Connection flags (blocking connection).
  * @return Phone to corresponding HC or error code.
@@ -71,5 +71,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;
@@ -98,4 +98,67 @@
 
 	return (usb_address_t) address;
+}
+
+/** Tell HC to reserve default address.
+ *
+ * @param phone Open phone to host controller driver.
+ * @return Error code.
+ */
+int usb_drv_reserve_default_address(int phone)
+{
+	return async_req_0_0(phone, IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS);
+}
+
+/** Tell HC to release default address.
+ *
+ * @param phone Open phone to host controller driver.
+ * @return Error code.
+ */
+int usb_drv_release_default_address(int phone)
+{
+	return async_req_0_0(phone, IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS);
+}
+
+/** Ask HC for free address assignment.
+ *
+ * @param phone Open phone to host controller driver.
+ * @return Assigned USB address or negative error code.
+ */
+usb_address_t usb_drv_request_address(int phone)
+{
+	ipcarg_t address;
+	int rc = async_req_0_1(phone, IPC_M_USBHC_REQUEST_ADDRESS, &address);
+	if (rc != EOK) {
+		return rc;
+	} else {
+		return (usb_address_t) address;
+	}
+}
+
+/** Inform HC about binding address with devman handle.
+ *
+ * @param phone Open phone to host controller driver.
+ * @param address Address to be binded.
+ * @param handle Devman handle of the device.
+ * @return Error code.
+ */
+int usb_drv_bind_address(int phone, usb_address_t address,
+    devman_handle_t handle)
+{
+	int rc = async_req_2_0(phone, IPC_M_USBHC_BIND_ADDRESS,
+	    address, handle);
+
+	return rc;
+}
+
+/** Inform HC about address release.
+ *
+ * @param phone Open phone to host controller driver.
+ * @param address Address to be released.
+ * @return Error code.
+ */
+int usb_drv_release_address(int phone, usb_address_t address)
+{
+	return async_req_1_0(phone, IPC_M_USBHC_RELEASE_ADDRESS, address);
 }
 
Index: uspace/lib/usb/src/usbdrvreq.c
===================================================================
--- uspace/lib/usb/src/usbdrvreq.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
+++ uspace/lib/usb/src/usbdrvreq.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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_device_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 = sizeof(usb_standard_device_descriptor_t)
+	};
+	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/main.c
===================================================================
--- uspace/lib/usbvirt/main.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/lib/usbvirt/main.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -183,7 +183,7 @@
 }
 
-/** Create necessary phones for comunication with virtual HCD.
+/** Create necessary phones for communication with virtual HCD.
  * This function wraps following calls:
- * -# open <code>/dev/devices/\\vhc for reading
+ * -# open <code>/dev/devices/\\virt\\usbhc for reading
  * -# access phone of file opened in previous step
  * -# create callback through just opened phone
@@ -193,8 +193,6 @@
  * @warning This function is wrapper for several actions and therefore
  * it is not possible - in case of error - to determine at which point
- * error occured.
- *
- * @param hcd_path HCD identification under devfs
- *     (without <code>/dev/usb/</code>).
+ * error occurred.
+ *
  * @param dev Device to connect.
  * @return EOK on success or error code from errno.h.
@@ -207,5 +205,5 @@
 	}
 	
-	const char *vhc_path = "/vhc";
+	const char *vhc_path = "/virt/usbhc";
 	int rc;
 	devman_handle_t handle;
Index: uspace/srv/bd/file_bd/file_bd.c
===================================================================
--- uspace/srv/bd/file_bd/file_bd.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -56,5 +56,7 @@
 #define NAME "file_bd"
 
-static const size_t block_size = 512;
+#define DEFAULT_BLOCK_SIZE 512
+
+static size_t block_size;
 static aoff64_t num_blocks;
 static FILE *img;
@@ -63,4 +65,5 @@
 static fibril_mutex_t dev_lock;
 
+static void print_usage(void);
 static int file_bd_init(const char *fname);
 static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
@@ -71,20 +74,53 @@
 {
 	int rc;
+	char *image_name;
+	char *device_name;
 
 	printf(NAME ": File-backed block device driver\n");
 
-	if (argc != 3) {
-		printf("Expected two arguments (image name, device name).\n");
+	block_size = DEFAULT_BLOCK_SIZE;
+
+	++argv; --argc;
+	while (*argv != NULL && (*argv)[0] == '-') {
+		/* Option */
+		if (str_cmp(*argv, "-b") == 0) {
+			if (argc < 2) {
+				printf("Argument missing.\n");
+				print_usage();
+				return -1;
+			}
+
+			rc = str_size_t(argv[1], NULL, 10, true, &block_size);
+			if (rc != EOK || block_size == 0) {
+				printf("Invalid block size '%s'.\n", argv[1]);
+				print_usage();
+				return -1;
+			}
+			++argv; --argc;
+		} else {
+			printf("Invalid option '%s'.\n", *argv);
+			print_usage();
+			return -1;
+		}
+		++argv; --argc;
+	}
+
+	if (argc < 2) {
+		printf("Missing arguments.\n");
+		print_usage();
 		return -1;
 	}
 
-	if (file_bd_init(argv[1]) != EOK)
+	image_name = argv[0];
+	device_name = argv[1];
+
+	if (file_bd_init(image_name) != EOK)
 		return -1;
 
-	rc = devmap_device_register(argv[2], &devmap_handle);
+	rc = devmap_device_register(device_name, &devmap_handle);
 	if (rc != EOK) {
 		devmap_hangup_phone(DEVMAP_DRIVER);
-		printf(NAME ": Unable to register device %s.\n",
-			argv[2]);
+		printf(NAME ": Unable to register device '%s'.\n",
+			device_name);
 		return rc;
 	}
@@ -96,4 +132,9 @@
 	/* Not reached */
 	return 0;
+}
+
+static void print_usage(void)
+{
+	printf("Usage: " NAME " [-b <block_size>] <image_file> <device_name>\n");
 }
 
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/devman/devman.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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,4 +686,5 @@
 }
 
+static FIBRIL_MUTEX_INITIALIZE(add_device_guard);
 
 /** Pass a device to running driver.
@@ -645,5 +695,12 @@
 void add_device(int phone, driver_t *drv, node_t *node, dev_tree_t *tree)
 {
-	printf(NAME ": add_device\n");
+	fibril_mutex_lock(&add_device_guard);
+
+	/*
+	 * 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 +714,5 @@
 		parent_handle = 0;
 	}
+
 	aid_t req = async_send_2(phone, DRIVER_ADD_DEVICE, node->handle,
 	    parent_handle, &answer);
@@ -666,7 +724,10 @@
 		/* TODO handle error */
 	}
-	
+
 	/* Wait for answer from the driver. */
 	async_wait_for(req, &rc);
+
+	fibril_mutex_unlock(&add_device_guard);
+
 	switch(rc) {
 	case EOK:
@@ -681,4 +742,6 @@
 	}
 	
+	node->passed_to_driver = true;
+
 	return;
 }
@@ -706,12 +769,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 +941,4 @@
 	node->name = dev_name;
 	if (!set_dev_path(node, parent)) {
-		fibril_rwlock_write_unlock(&tree->rwlock);
 		return false;
 	}
@@ -1097,6 +1162,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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/devman/devman.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/devman/main.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/devman/match.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/fs/devfs/devfs.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/fs/fat/fat.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/fs/tmpfs/tmpfs.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/net/il/arp/arp.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/net/il/arp/arp.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/vfs/vfs.h	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/vfs/vfs_ops.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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 101ef25c4b30388a9bb0c6cbf006cdbac2e5b1c1)
+++ uspace/srv/vfs/vfs_register.c	(revision 243cb862efdca342a3d56442ae4a4fe91c8c1e81)
@@ -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;
+}
+
 /**
  * @}
