Index: .bzrignore
===================================================================
--- .bzrignore	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ .bzrignore	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -44,4 +44,6 @@
 ./uspace/app/getterm/getterm
 ./uspace/app/init/init
+./uspace/app/kill/kill
+./uspace/app/killall/killall
 ./uspace/app/klog/klog
 ./uspace/app/mkfat/mkfat
@@ -52,4 +54,5 @@
 ./uspace/app/ping/ping
 ./uspace/app/redir/redir
+./uspace/app/sysinfo/sysinfo
 ./uspace/app/sbi/sbi
 ./uspace/app/stats/stats
@@ -64,4 +67,5 @@
 ./uspace/app/usbinfo/usbinfo
 ./uspace/app/virtusbkbd/vuk
+./uspace/app/websrv/websrv
 ./uspace/dist/app/*
 ./uspace/dist/cfg/net/general
Index: Makefile
===================================================================
--- Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -28,4 +28,5 @@
 
 CSCOPE = cscope
+CHECK = tools/check.sh
 CONFIG = tools/config.py
 AUTOTOOL = tools/autotool.py
@@ -41,5 +42,5 @@
 CONFIG_HEADER = config.h
 
-.PHONY: all precheck cscope autotool config_auto config_default config distclean clean
+.PHONY: all precheck cscope autotool config_auto config_default config distclean clean check
 
 all: $(COMMON_MAKEFILE) $(COMMON_HEADER) $(CONFIG_MAKEFILE) $(CONFIG_HEADER)
@@ -54,4 +55,12 @@
 cscope:
 	find kernel boot uspace -regex '^.*\.[chsS]$$' | xargs $(CSCOPE) -b -k -u -f$(CSCOPE).out
+
+# Pre-integration build check
+check: $(CHECK)
+ifdef JOBS 
+	$(CHECK) -j $(JOBS)
+else
+	$(CHECK)
+endif
 
 $(COMMON_MAKEFILE): autotool
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ boot/Makefile.common	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -101,4 +101,6 @@
 	$(USPACE_PATH)/srv/hw/bus/usb/hcd/virtual/vhcd \
 	$(USPACE_PATH)/srv/net/netif/lo/lo \
+	$(USPACE_PATH)/srv/net/nil/eth/eth \
+	$(USPACE_PATH)/srv/net/nil/nildummy/nildummy \
 	$(USPACE_PATH)/srv/net/il/arp/arp \
 	$(USPACE_PATH)/srv/net/il/ip/ip \
@@ -117,10 +119,4 @@
 RD_DRV_CFG = 
 
-ifneq ($(CONFIG_NETIF_NIL_BUNDLE),y)
-	RD_SRVS_NON_ESSENTIAL += \
-		$(USPACE_PATH)/srv/net/nil/eth/eth \
-		$(USPACE_PATH)/srv/net/nil/nildummy/nildummy
-endif
-
 RD_APPS_ESSENTIAL = \
 	$(USPACE_PATH)/app/bdsh/bdsh \
@@ -130,4 +126,6 @@
 RD_APPS_NON_ESSENTIAL = \
 	$(USPACE_PATH)/app/edit/edit \
+	$(USPACE_PATH)/app/kill/kill \
+	$(USPACE_PATH)/app/killall/killall \
 	$(USPACE_PATH)/app/mkfat/mkfat \
 	$(USPACE_PATH)/app/sbi/sbi \
@@ -144,8 +142,10 @@
 	$(USPACE_PATH)/app/ping/ping \
 	$(USPACE_PATH)/app/stats/stats \
+	$(USPACE_PATH)/app/sysinfo/sysinfo \
 	$(USPACE_PATH)/app/tasks/tasks \
 	$(USPACE_PATH)/app/top/top \
 	$(USPACE_PATH)/app/usbinfo/usbinfo \
-	$(USPACE_PATH)/app/virtusbkbd/vuk
+	$(USPACE_PATH)/app/virtusbkbd/vuk \
+	$(USPACE_PATH)/app/websrv/websrv
 
 ifneq ($(CONFIG_BAREBONE),y)
Index: boot/arch/ia64/Makefile.inc
===================================================================
--- boot/arch/ia64/Makefile.inc	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ boot/arch/ia64/Makefile.inc	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -34,5 +34,5 @@
 ENDIANESS = LE
 PAGE_SIZE = 16384
-EXTRA_CFLAGS = -fno-unwind-tables -mfixed-range=f32-f127 -mno-pic
+EXTRA_CFLAGS = -fno-unwind-tables -mfixed-range=f32-f127 -mno-pic -mno-sdata
 
 RD_SRVS_NON_ESSENTIAL +=
Index: contrib/conf/net-qe.sh
===================================================================
--- contrib/conf/net-qe.sh	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ contrib/conf/net-qe.sh	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -1,9 +1,12 @@
 #!/bin/sh
 
-arguments="-vga std -M isapc -net nic,model=ne2k_isa -net user -boot d -redir udp:8080::8080 -redir udp:8081::8081 -redir tcp:8080::8080 -redir tcp:8081::8081 -cdrom image.iso"
+# Obsolete versions of QEMU
+#
+#   QEMU 0.10.2 and later 0.10.*
+#    qemu $@ -no-kqemu -vga std -M isapc -net nic,model=ne2k_isa -net user -boot d -redir udp:8080::8080 -redir udp:8081::8081 -redir tcp:8080::8080 -redir tcp:8081::8081 -cdrom image.iso
+#
+#   QEMU 0.11.* and 0.12.*
+#    qemu $@ -vga std -M isapc -net nic,model=ne2k_isa -net user -boot d -redir udp:8080::8080 -redir udp:8081::8081 -redir tcp:8080::8080 -redir tcp:8081::8081 -cdrom image.iso
 
-#qemu 0.10.2 and later 0.10.*:
-#qemu $@ -no-kqemu $arguments
-
-#qemu 0.11:
-qemu $@ $arguments
+# QEMU 0.13 and later
+qemu $@ -device ne2k_isa,irq=5,vlan=0 -net user -boot d -redir udp:8080::8080 -redir udp:8081::8081 -redir tcp:8080::8080 -redir tcp:8081::8081 -cdrom image.iso
Index: defaults/amd64/Makefile.config
===================================================================
--- defaults/amd64/Makefile.config	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ defaults/amd64/Makefile.config	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -65,4 +65,2 @@
 CONFIG_MOUNT_DATA = n
 
-# Bundle netif/nil network layer
-CONFIG_NETIF_NIL_BUNDLE = n
Index: defaults/arm32/Makefile.config
===================================================================
--- defaults/arm32/Makefile.config	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ defaults/arm32/Makefile.config	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -41,4 +41,2 @@
 CONFIG_MOUNT_DATA = n
 
-# Bundle netif/nil network layer
-CONFIG_NETIF_NIL_BUNDLE = n
Index: defaults/ia32/Makefile.config
===================================================================
--- defaults/ia32/Makefile.config	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ defaults/ia32/Makefile.config	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -71,4 +71,2 @@
 CONFIG_MOUNT_DATA = n
 
-# Bundle netif/nil network layer
-CONFIG_NETIF_NIL_BUNDLE = n
Index: defaults/ia64/Makefile.config
===================================================================
--- defaults/ia64/Makefile.config	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ defaults/ia64/Makefile.config	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -53,4 +53,2 @@
 CONFIG_MOUNT_DATA = n
 
-# Bundle netif/nil network layer
-CONFIG_NETIF_NIL_BUNDLE = n
Index: defaults/mips32/Makefile.config
===================================================================
--- defaults/mips32/Makefile.config	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ defaults/mips32/Makefile.config	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -47,4 +47,2 @@
 CONFIG_MOUNT_DATA = n
 
-# Bundle netif/nil network layer
-CONFIG_NETIF_NIL_BUNDLE = n
Index: defaults/ppc32/Makefile.config
===================================================================
--- defaults/ppc32/Makefile.config	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ defaults/ppc32/Makefile.config	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -47,4 +47,2 @@
 CONFIG_MOUNT_DATA = n
 
-# Bundle netif/nil network layer
-CONFIG_NETIF_NIL_BUNDLE = n
Index: defaults/sparc64/Makefile.config
===================================================================
--- defaults/sparc64/Makefile.config	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ defaults/sparc64/Makefile.config	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -62,4 +62,2 @@
 CONFIG_MOUNT_DATA = n
 
-# Bundle netif/nil network layer
-CONFIG_NETIF_NIL_BUNDLE = n
Index: defaults/special/Makefile.config
===================================================================
--- defaults/special/Makefile.config	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ defaults/special/Makefile.config	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -32,4 +32,2 @@
 CONFIG_START_BD = n
 
-# Bundle netif/nil network layer
-CONFIG_NETIF_NIL_BUNDLE = n
Index: kernel/arch/amd64/src/amd64.c
===================================================================
--- kernel/arch/amd64/src/amd64.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/amd64/src/amd64.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -199,4 +199,10 @@
 void arch_post_smp_init(void)
 {
+	/* Currently the only supported platform for amd64 is 'pc'. */
+	static const char *platform = "pc";
+
+	sysinfo_set_item_data("platform", NULL, (void *) platform,
+	    str_size(platform));
+
 #ifdef CONFIG_PC_KBD
 	/*
Index: kernel/arch/arm32/include/mach/integratorcp/integratorcp.h
===================================================================
--- kernel/arch/arm32/include/mach/integratorcp/integratorcp.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/arm32/include/mach/integratorcp/integratorcp.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -106,4 +106,5 @@
 extern void icp_frame_init(void);
 extern size_t icp_get_irq_count(void);
+extern const char *icp_get_platform_name(void);
 
 extern struct arm_machine_ops icp_machine_ops;
Index: kernel/arch/arm32/include/mach/testarm/testarm.h
===================================================================
--- kernel/arch/arm32/include/mach/testarm/testarm.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/arm32/include/mach/testarm/testarm.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -74,4 +74,5 @@
 extern void gxemul_frame_init(void);
 extern size_t gxemul_get_irq_count(void);
+extern const char *gxemul_get_platform_name(void);
 
 extern struct arm_machine_ops gxemul_machine_ops;
Index: kernel/arch/arm32/include/machine_func.h
===================================================================
--- kernel/arch/arm32/include/machine_func.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/arm32/include/machine_func.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -56,4 +56,5 @@
 	void (*machine_input_init)(void);
 	size_t (*machine_get_irq_count)(void);
+	const char *(*machine_get_platform_name)(void);
 };
 
Index: kernel/arch/arm32/src/mach/gta02/gta02.c
===================================================================
--- kernel/arch/arm32/src/mach/gta02/gta02.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/arm32/src/mach/gta02/gta02.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -71,4 +71,5 @@
 static void gta02_input_init(void);
 static size_t gta02_get_irq_count(void);
+static const char *gta02_get_platform_name(void);
 
 static void gta02_timer_irq_init(void);
@@ -92,5 +93,6 @@
 	gta02_output_init,
 	gta02_input_init,
-	gta02_get_irq_count
+	gta02_get_irq_count,
+	gta02_get_platform_name
 };
 
@@ -235,4 +237,9 @@
 }
 
+const char *gta02_get_platform_name(void)
+{
+	return "gta02";
+}
+
 static void gta02_timer_irq_init(void)
 {
Index: kernel/arch/arm32/src/mach/integratorcp/integratorcp.c
===================================================================
--- kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/arm32/src/mach/integratorcp/integratorcp.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -65,5 +65,6 @@
 	icp_output_init,
 	icp_input_init,
-	icp_get_irq_count
+	icp_get_irq_count,
+	icp_get_platform_name
 };
 
@@ -342,4 +343,9 @@
 }
 
+const char *icp_get_platform_name(void)
+{
+	return "integratorcp";
+}
+
 /** @}
  */
Index: kernel/arch/arm32/src/mach/testarm/testarm.c
===================================================================
--- kernel/arch/arm32/src/mach/testarm/testarm.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/arm32/src/mach/testarm/testarm.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -65,5 +65,6 @@
 	gxemul_output_init,
 	gxemul_input_init,
-	gxemul_get_irq_count
+	gxemul_get_irq_count,
+	gxemul_get_platform_name
 };
 
@@ -132,4 +133,9 @@
 }
 
+const char *gxemul_get_platform_name(void)
+{
+	return "gxemul";
+}
+
 /** Starts gxemul Real Time Clock device, which asserts regular interrupts.
  *
Index: kernel/arch/ia32/include/interrupt.h
===================================================================
--- kernel/arch/ia32/include/interrupt.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/ia32/include/interrupt.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -55,5 +55,5 @@
 #define IRQ_PIC_SPUR  7
 #define IRQ_MOUSE     12
-#define IRQ_DP8390    9
+#define IRQ_DP8390    5
 
 /* This one must have four least significant bits set to ones */
Index: kernel/arch/ia32/src/ia32.c
===================================================================
--- kernel/arch/ia32/src/ia32.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/ia32/src/ia32.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -157,4 +157,10 @@
 void arch_post_smp_init(void)
 {
+	/* Currently the only supported platform for ia32 is 'pc'. */
+	static const char *platform = "pc";
+
+	sysinfo_set_item_data("platform", NULL, (void *) platform,
+	    str_size(platform));
+
 #ifdef CONFIG_PC_KBD
 	/*
Index: kernel/arch/ia64/src/ia64.c
===================================================================
--- kernel/arch/ia64/src/ia64.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/ia64/src/ia64.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -147,4 +147,16 @@
 void arch_post_smp_init(void)
 {
+	static const char *platform;
+
+	/* Set platform name. */
+#ifdef MACHINE_ski
+	platform = "pc";
+#endif
+#ifdef MACHINE_i460GX
+	platform = "i460GX";
+#endif
+	sysinfo_set_item_data("platform", NULL, (void *) platform,
+	    str_size(platform));
+
 #ifdef MACHINE_ski
 	ski_instance_t *ski_instance = skiin_init();
Index: kernel/arch/mips32/src/mips32.c
===================================================================
--- kernel/arch/mips32/src/mips32.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/mips32/src/mips32.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -168,4 +168,19 @@
 void arch_post_smp_init(void)
 {
+	static const char *platform;
+
+	/* Set platform name. */
+#ifdef MACHINE_msim
+	platform = "msim";
+#endif
+#ifdef MACHINE_bgxemul
+	platform = "gxemul";
+#endif
+#ifdef MACHINE_lgxemul
+	platform = "gxemul";
+#endif
+	sysinfo_set_item_data("platform", NULL, (void *) platform,
+	    str_size(platform));
+
 #ifdef CONFIG_MIPS_KBD
 	/*
Index: kernel/arch/ppc32/src/ppc32.c
===================================================================
--- kernel/arch/ppc32/src/ppc32.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/ppc32/src/ppc32.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -249,4 +249,10 @@
 void arch_post_smp_init(void)
 {
+	/* Currently the only supported platform for ppc32 is 'mac'. */
+	static const char *platform = "mac";
+
+	sysinfo_set_item_data("platform", NULL, (void *) platform,
+	    str_size(platform));
+
 	ofw_tree_walk_by_device_type("mac-io", macio_register, NULL);
 }
Index: kernel/arch/sparc64/src/sun4u/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sun4u/sparc64.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/sparc64/src/sun4u/sparc64.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -50,4 +50,5 @@
 #include <ddi/irq.h>
 #include <str.h>
+#include <sysinfo/sysinfo.h>
 
 memmap_t memmap;
@@ -111,4 +112,10 @@
 void arch_post_smp_init(void)
 {
+	/* Currently the only supported platform for sparc64/sun4u is 'sun4u'. */
+	static const char *platform = "sun4u";
+
+	sysinfo_set_item_data("platform", NULL, (void *) platform,
+	    str_size(platform));
+
 	standalone_sparc64_console_init();
 }
Index: kernel/arch/sparc64/src/sun4v/sparc64.c
===================================================================
--- kernel/arch/sparc64/src/sun4v/sparc64.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/arch/sparc64/src/sun4v/sparc64.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -52,4 +52,5 @@
 #include <str.h>
 #include <arch/drivers/niagara.h>
+#include <sysinfo/sysinfo.h>
 
 memmap_t memmap;
@@ -109,4 +110,10 @@
 void arch_post_smp_init(void)
 {
+	/* Currently the only supported platform for sparc64/sun4v is 'sun4v'. */
+	static const char *platform = "sun4v";
+
+	sysinfo_set_item_data("platform", NULL, (void *) platform,
+	    str_size(platform));
+
 	niagarain_init();
 }
Index: kernel/generic/include/ddi/irq.h
===================================================================
--- kernel/generic/include/ddi/irq.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/generic/include/ddi/irq.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -54,4 +54,5 @@
 	/** Read 4 bytes from the I/O space. */
 	CMD_PIO_READ_32,
+	
 	/** Write 1 byte to the I/O space. */
 	CMD_PIO_WRITE_8,
@@ -62,12 +63,29 @@
 	
 	/**
-	 * Perform a bit test on the source argument and store the result into
-	 * the destination argument.
+	 * Write 1 byte from the source argument
+	 * to the I/O space.
+	 */
+	CMD_PIO_WRITE_A_8,
+	/**
+	 * Write 2 bytes from the source argument
+	 * to the I/O space.
+	 */
+	CMD_PIO_WRITE_A_16,
+	/**
+	 * Write 4 bytes from the source argument
+	 * to the I/O space.
+	 */
+	CMD_PIO_WRITE_A_32,
+	
+	/**
+	 * Perform a bit masking on the source argument
+	 * and store the result into the destination argument.
 	 */
 	CMD_BTEST,
 	
 	/**
-	 * Predicate the execution of the following N commands by the boolean
-	 * value of the source argument.
+	 * Predicate the execution of the following
+	 * N commands by the boolean value of the source
+	 * argument.
 	 */
 	CMD_PREDICATE,
@@ -75,4 +93,5 @@
 	/** Accept the interrupt. */
 	CMD_ACCEPT,
+	
 	/** Decline the interrupt. */
 	CMD_DECLINE,
@@ -189,4 +208,6 @@
 extern hash_table_t irq_uspace_hash_table;
 
+extern inr_t last_inr;
+
 extern void irq_init(size_t, size_t);
 extern void irq_initialize(irq_t *);
Index: kernel/generic/include/interrupt.h
===================================================================
--- kernel/generic/include/interrupt.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/generic/include/interrupt.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -60,4 +60,5 @@
 extern void fault_if_from_uspace(istate_t *, const char *, ...)
     PRINTF_ATTRIBUTE(2, 3);
+extern istate_t *istate_get(thread_t *);
 extern iroutine_t exc_register(unsigned int, const char *, bool, iroutine_t);
 extern void exc_dispatch(unsigned int, istate_t *);
Index: kernel/generic/include/proc/task.h
===================================================================
--- kernel/generic/include/proc/task.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/generic/include/proc/task.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -154,4 +154,5 @@
 
 extern sysarg_t sys_task_set_name(const char *, size_t);
+extern sysarg_t sys_task_kill(task_id_t *);
 
 #endif
Index: kernel/generic/include/syscall/syscall.h
===================================================================
--- kernel/generic/include/syscall/syscall.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/generic/include/syscall/syscall.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -47,4 +47,5 @@
 	SYS_TASK_GET_ID,
 	SYS_TASK_SET_NAME,
+	SYS_TASK_KILL,
 	SYS_PROGRAM_SPAWN_LOADER,
 	
Index: kernel/generic/src/ddi/irq.c
===================================================================
--- kernel/generic/src/ddi/irq.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/generic/src/ddi/irq.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -136,4 +136,7 @@
 static size_t buckets;
 
+/** Last valid INR. */
+inr_t last_inr = 0;
+
 /** Initialize IRQ subsystem.
  *
@@ -145,4 +148,6 @@
 {
 	buckets = chains;
+	last_inr = inrs - 1;
+
 	/*
 	 * Be smart about the choice of the hash table operations.
Index: kernel/generic/src/interrupt/interrupt.c
===================================================================
--- kernel/generic/src/interrupt/interrupt.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/generic/src/interrupt/interrupt.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -209,4 +209,23 @@
 }
 
+/** Get istate structure of a thread.
+ *
+ * Get pointer to the istate structure at the bottom of the kernel stack.
+ *
+ * This function can be called in interrupt or user context. In interrupt
+ * context the istate structure is created by the low-level exception
+ * handler. In user context the istate structure is created by the
+ * low-level syscall handler.
+ */
+istate_t *istate_get(thread_t *thread)
+{
+	/*
+	 * The istate structure should be right at the bottom of the kernel
+	 * stack.
+	 */
+	return (istate_t *) ((uint8_t *) thread->kstack + THREAD_STACK_SIZE -
+	    sizeof(istate_t));
+}
+
 #ifdef CONFIG_KCONSOLE
 
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/generic/src/ipc/irq.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -131,12 +131,11 @@
 /** Register an answerbox as a receiving end for IRQ notifications.
  *
- * @param box     Receiving answerbox.
- * @param inr     IRQ number.
- * @param devno   Device number.
- * @param imethod Interface and method to be associated
- *                with the notification.
- * @param ucode   Uspace pointer to top-half pseudocode.
- *
- * @return EBADMEM, ENOENT or EEXISTS on failure or 0 on success.
+ * @param box		Receiving answerbox.
+ * @param inr		IRQ number.
+ * @param devno		Device number.
+ * @param imethod	Interface and method to be associated with the
+ *			notification.
+ * @param ucode		Uspace pointer to top-half pseudocode.
+ * @return		EOK on success or a negative error code.
  *
  */
@@ -148,4 +147,7 @@
 		(sysarg_t) devno
 	};
+
+	if ((inr < 0) || (inr > last_inr))
+		return ELIMIT;
 	
 	irq_code_t *code;
@@ -208,8 +210,8 @@
 /** Unregister task from IRQ notification.
  *
- * @param box   Answerbox associated with the notification.
- * @param inr   IRQ number.
- * @param devno Device number.
- *
+ * @param box		Answerbox associated with the notification.
+ * @param inr		IRQ number.
+ * @param devno		Device number.
+ * @return		EOK on success or a negative error code.
  */
 int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
@@ -219,4 +221,7 @@
 		(sysarg_t) devno
 	};
+
+	if ((inr < 0) || (inr > last_inr))
+		return ELIMIT;
 	
 	irq_spinlock_lock(&irq_uspace_hash_table_lock, true);
@@ -399,4 +404,22 @@
 			    (uint32_t) code->cmds[i].value);
 			break;
+		case CMD_PIO_WRITE_A_8:
+			if (srcarg) {
+				pio_write_8((ioport8_t *) code->cmds[i].addr,
+				    (uint8_t) scratch[srcarg]);
+			}
+			break;
+		case CMD_PIO_WRITE_A_16:
+			if (srcarg) {
+				pio_write_16((ioport16_t *) code->cmds[i].addr,
+				    (uint16_t) scratch[srcarg]);
+			}
+			break;
+		case CMD_PIO_WRITE_A_32:
+			if (srcarg) {
+				pio_write_32((ioport32_t *) code->cmds[i].addr,
+				    (uint32_t) scratch[srcarg]);
+			}
+			break;
 		case CMD_BTEST:
 			if ((srcarg) && (dstarg)) {
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/generic/src/main/main.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -185,6 +185,6 @@
 	LOG("\nconfig.base=%p config.kernel_size=%zu"
 	    "\nconfig.stack_base=%p config.stack_size=%zu",
-	    config.base, config.kernel_size, config.stack_base,
-	    config.stack_size);
+	    (void *) config.base, config.kernel_size,
+	    (void *) config.stack_base, config.stack_size);
 	
 #ifdef CONFIG_KCONSOLE
@@ -242,5 +242,5 @@
 		for (i = 0; i < init.cnt; i++)
 			LOG("init[%zu].addr=%p, init[%zu].size=%zu",
-			    i, init.tasks[i].addr, i, init.tasks[i].size);
+			    i, (void *) init.tasks[i].addr, i, init.tasks[i].size);
 	} else
 		printf("No init binaries found.\n");
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/generic/src/proc/task.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -360,4 +360,23 @@
 }
 
+/** Syscall to forcefully terminate a task
+ *
+ * @param uspace_taskid Pointer to task ID in user space.
+ *
+ * @return 0 on success or an error code from @ref errno.h.
+ *
+ */
+sysarg_t sys_task_kill(task_id_t *uspace_taskid)
+{
+	task_id_t taskid;
+	int rc;
+
+	rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(taskid));
+	if (rc != 0)
+		return (sysarg_t) rc;
+
+	return (sysarg_t) task_kill(taskid);
+}
+
 /** Find task structure corresponding to task ID.
  *
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ kernel/generic/src/syscall/syscall.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -45,4 +45,5 @@
 #include <debug.h>
 #include <ddi/device.h>
+#include <interrupt.h>
 #include <ipc/sysipc.h>
 #include <synch/futex.h>
@@ -66,7 +67,13 @@
 #ifdef CONFIG_UDEBUG
 	/*
+	 * An istate_t-compatible record was created on the stack by the
+	 * low-level syscall handler. This is the userspace space state
+	 * structure.
+	 */
+	THREAD->udebug.uspace_state = istate_get(THREAD);
+
+	/*
 	 * Early check for undebugged tasks. We do not lock anything as this
 	 * test need not be precise in either direction.
-	 *
 	 */
 	if (THREAD->udebug.active)
@@ -98,4 +105,7 @@
 		udebug_stoppable_end();
 	}
+
+	/* Clear userspace state pointer */
+	THREAD->udebug.uspace_state = NULL;
 #endif
 	
@@ -120,4 +130,5 @@
 	(syshandler_t) sys_task_get_id,
 	(syshandler_t) sys_task_set_name,
+	(syshandler_t) sys_task_kill,
 	(syshandler_t) sys_program_spawn_loader,
 	
Index: tools/check.sh
===================================================================
--- tools/check.sh	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ tools/check.sh	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,89 @@
+#! /bin/bash
+
+#
+# Copyright (c) 2010 Jakub Jermar 
+# 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.
+#
+
+if [ $1" " == "-h " ];
+then
+	echo "Perform pre-integration hands-off build of all profiles."
+	echo
+	echo "Syntax:"
+	echo " $0 [-h] [args...]"
+	echo
+	echo " -h        Print this help."
+	echo " args...   All other args are passed to make (e.g. -j 6)"
+	echo
+
+	exit
+fi
+
+FAILED=""
+PASSED=""
+PROFILES=""
+DIRS=`find defaults/ -name Makefile.config | sed 's/^defaults\/\(.*\)\/Makefile.config/\1/' | sort`
+
+for D in $DIRS;
+do
+	for H in $DIRS;
+	do
+		if [ `echo $H | grep "^$D\/.*"`x != "x"  ];
+		then
+			continue 2 
+		fi
+	done
+	PROFILES="$PROFILES $D"
+done
+
+echo ">>> Going to build the following profiles:"
+echo $PROFILES
+
+for P in $PROFILES;
+do
+	echo -n ">>>> Building $P... "
+	( make distclean && make PROFILE=$P HANDS_OFF=y $1 ) >>/dev/null 2>>/dev/null
+	if [ $? -ne 0 ];
+	then
+		FAILED="$FAILED $P"
+		echo "failed."
+	else
+		PASSED="$PASSED $P"
+		echo "ok."
+	fi
+done
+
+echo ">>> Done."
+echo
+
+echo ">>> The following profiles passed:"
+echo $PASSED
+echo
+
+echo ">>> The following profiles failed:"
+echo $FAILED
+echo
+
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -38,4 +38,6 @@
 	app/getterm \
 	app/init \
+	app/kill \
+	app/killall \
 	app/klog \
 	app/mkfat \
@@ -55,4 +57,6 @@
 	app/nettest2 \
 	app/ping \
+	app/websrv \
+	app/sysinfo \
 	srv/clip \
 	srv/devmap \
@@ -79,5 +83,4 @@
 	srv/hw/char/s3c24xx_uart \
 	srv/hw/netif/dp8390 \
-	srv/net/cfg \
 	srv/net/netif/lo \
 	srv/net/il/arp \
@@ -95,13 +98,7 @@
 #
 
-ifeq ($(CONFIG_NETIF_NIL_BUNDLE),y)
-	LIBN = \
-		srv/net/nil/eth \
-		srv/net/nil/nildummy
-else
-	DIRS += \
-		srv/net/nil/eth \
-		srv/net/nil/nildummy
-endif
+DIRS += \
+	srv/net/nil/eth \
+	srv/net/nil/nildummy
 
 ## Platform-specific hardware support
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/app/init/init.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -57,9 +57,9 @@
 #define DEVFS_MOUNT_POINT  "/dev"
 
-#define SCRATCH_FS_TYPE      "tmpfs"
-#define SCRATCH_MOUNT_POINT  "/scratch"
+#define TMPFS_FS_TYPE      "tmpfs"
+#define TMPFS_MOUNT_POINT  "/tmp"
 
 #define DATA_FS_TYPE      "fat"
-#define DATA_DEVICE       "bd/disk0"
+#define DATA_DEVICE       "bd/ata1disk0"
 #define DATA_MOUNT_POINT  "/data"
 
@@ -235,9 +235,9 @@
 }
 
-static bool mount_scratch(void)
-{
-	int rc = mount(SCRATCH_FS_TYPE, SCRATCH_MOUNT_POINT, "", "", 0);
-	return mount_report("Scratch filesystem", SCRATCH_MOUNT_POINT,
-	    SCRATCH_FS_TYPE, NULL, rc);
+static bool mount_tmpfs(void)
+{
+	int rc = mount(TMPFS_FS_TYPE, TMPFS_MOUNT_POINT, "", "", 0);
+	return mount_report("Temporary filesystem", TMPFS_MOUNT_POINT,
+	    TMPFS_FS_TYPE, NULL, rc);
 }
 
@@ -271,5 +271,5 @@
 	}
 	
-	mount_scratch();
+	mount_tmpfs();
 	
 	spawn("/srv/fhc");
Index: uspace/app/kill/Makefile
===================================================================
--- uspace/app/kill/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/app/kill/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Jiri Svoboda
+# 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 =
+EXTRA_CFLAGS =
+BINARY = kill
+
+SOURCES = \
+	kill.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/kill/kill.c
===================================================================
--- uspace/app/kill/kill.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/app/kill/kill.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * 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 kill
+ * @{
+ */
+/**
+ * @file Forcefully terminate a task.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <task.h>
+#include <str_error.h>
+
+#define NAME  "kill"
+
+static void print_syntax(void)
+{
+	printf("Syntax: " NAME " <task ID>\n");
+}
+
+int main(int argc, char *argv[])
+{
+	char *eptr;
+	task_id_t taskid;
+	int rc;
+
+	if (argc != 2) {
+		print_syntax();
+		return 1;
+	}
+
+	taskid = strtoul(argv[1], &eptr, 0);
+	if (*eptr != '\0') {
+		printf("Invalid task ID argument '%s'.\n", argv[1]);
+		return 2;
+	}
+
+	rc = task_kill(taskid);
+	if (rc != EOK) {
+		printf("Failed to kill task ID %" PRIu64 ": %s\n",
+		    taskid, str_error(rc));
+		return 3;
+	}
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/killall/Makefile
===================================================================
--- uspace/app/killall/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/app/killall/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Martin Decky
+# 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 =
+EXTRA_CFLAGS =
+BINARY = killall
+
+SOURCES = \
+	killall.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/killall/killall.c
===================================================================
--- uspace/app/killall/killall.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/app/killall/killall.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2010 Martin Decky
+ * 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 killall
+ * @{
+ */
+/**
+ * @file Forcefully terminate a task specified by name.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <task.h>
+#include <stats.h>
+#include <str_error.h>
+#include <malloc.h>
+
+#define NAME  "killall"
+
+static void print_syntax(void)
+{
+	printf("Syntax: " NAME " <task name>\n");
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc != 2) {
+		print_syntax();
+		return 1;
+	}
+	
+	size_t count;
+	stats_task_t *stats_tasks = stats_get_tasks(&count);
+	
+	if (stats_tasks == NULL) {
+		fprintf(stderr, "%s: Unable to get tasks\n", NAME);
+		return 2;
+	}
+	
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if (str_cmp(stats_tasks[i].name, argv[1]) == 0) {
+			task_id_t taskid = stats_tasks[i].task_id;
+			int rc = task_kill(taskid);
+			if (rc != EOK)
+				printf("Failed to kill task ID %" PRIu64 ": %s\n",
+				    taskid, str_error(rc));
+			else
+				printf("Killed task ID %" PRIu64 "\n", taskid);
+		}
+	}
+	
+	free(stats_tasks);
+	
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/netecho/netecho.c
===================================================================
--- uspace/app/netecho/netecho.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/app/netecho/netecho.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -32,10 +32,13 @@
 
 /** @file
- * Network echo application.
- * Answers received packets.
+ * Network echo server.
+ *
+ * Sockets-based server that echoes incomming messages. If stream mode
+ * is selected, accepts incoming connections.
  */
 
-#include <malloc.h>
+#include <assert.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <str.h>
 #include <task.h>
@@ -50,178 +53,296 @@
 #include "print_error.h"
 
-/** Network echo module name. */
-#define NAME	"Network Echo"
+#define NAME "netecho"
+
+static int count = -1;
+static int family = PF_INET;
+static sock_type_t type = SOCK_DGRAM;
+static uint16_t port = 7;
+static int backlog = 3;
+static size_t size = 1024;
+static int verbose = 0;
+
+static char *reply = NULL;
+static size_t reply_length;
+
+static char *data;
 
 static void echo_print_help(void)
 {
 	printf(
-		"Network Echo aplication\n" \
-		"Usage: echo [options]\n" \
-		"Where options are:\n" \
-		"-b backlog | --backlog=size\n" \
-		"\tThe size of the accepted sockets queue. Only for SOCK_STREAM. The default is 3.\n" \
-		"\n" \
-		"-c count | --count=count\n" \
-		"\tThe number of received messages to handle. A negative number means infinity. The default is infinity.\n" \
-		"\n" \
-		"-f protocol_family | --family=protocol_family\n" \
-		"\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n"
-		"\n" \
-		"-h | --help\n" \
-		"\tShow this application help.\n"
-		"\n" \
-		"-p port_number | --port=port_number\n" \
-		"\tThe port number the application should listen at. The default is 7.\n" \
-		"\n" \
-		"-r reply_string | --reply=reply_string\n" \
-		"\tThe constant reply string. The default is the original data received.\n" \
-		"\n" \
-		"-s receive_size | --size=receive_size\n" \
-		"\tThe maximum receive data size the application should accept. The default is 1024 bytes.\n" \
-		"\n" \
-		"-t socket_type | --type=socket_type\n" \
-		"\tThe listenning socket type. Only the SOCK_DGRAM and the SOCK_STREAM are supported.\n" \
-		"\n" \
-		"-v | --verbose\n" \
-		"\tShow all output messages.\n"
+	    "Network echo server\n"
+	    "Usage: " NAME " [options]\n"
+	    "Where options are:\n"
+	    "-b backlog | --backlog=size\n"
+	    "\tThe size of the accepted sockets queue. Only for SOCK_STREAM. "
+	    "The default is 3.\n"
+	    "\n"
+	    "-c count | --count=count\n"
+	    "\tThe number of received messages to handle. A negative number "
+	    "means infinity. The default is infinity.\n"
+	    "\n"
+	    "-f protocol_family | --family=protocol_family\n"
+	    "\tThe listenning socket protocol family. Only the PF_INET and "
+	    "PF_INET6 are supported.\n"
+	    "\n"
+	    "-h | --help\n"
+	    "\tShow this application help.\n"
+	    "\n"
+	    "-p port_number | --port=port_number\n"
+	    "\tThe port number the application should listen at. The default "
+	    "is 7.\n"
+	    "\n"
+	    "-r reply_string | --reply=reply_string\n"
+	    "\tThe constant reply string. The default is the original data "
+	    "received.\n"
+	    "\n"
+	    "-s receive_size | --size=receive_size\n"
+	    "\tThe maximum receive data size the application should accept. "
+	    "The default is 1024 bytes.\n"
+	    "\n"
+	    "-t socket_type | --type=socket_type\n"
+	    "\tThe listenning socket type. Only the SOCK_DGRAM and the "
+	    "SOCK_STREAM are supported.\n"
+	    "\n"
+	    "-v | --verbose\n"
+	    "\tShow all output messages.\n"
 	);
 }
 
-int main(int argc, char *argv[])
+static int netecho_parse_option(int argc, char *argv[], int *index)
 {
-	size_t size = 1024;
-	int verbose = 0;
-	char *reply = NULL;
-	sock_type_t type = SOCK_DGRAM;
-	int count = -1;
-	int family = PF_INET;
-	uint16_t port = 7;
-	int backlog = 3;
-
-	socklen_t max_length = sizeof(struct sockaddr_in6);
-	uint8_t address_data[max_length];
-	struct sockaddr *address = (struct sockaddr *) address_data;
-	struct sockaddr_in *address_in = (struct sockaddr_in *) address;
-	struct sockaddr_in6 *address_in6 = (struct sockaddr_in6 *) address;
-	socklen_t addrlen;
-	char address_string[INET6_ADDRSTRLEN];
-	uint8_t *address_start;
-	int socket_id;
-	int listening_id;
-	char *data;
-	size_t length;
-	int index;
-	size_t reply_length;
 	int value;
 	int rc;
 
-	// parse the command line arguments
-	for (index = 1; index < argc; ++ index) {
-		if (argv[index][0] == '-') {
-			switch (argv[index][1]) {
-			case 'b':
-				rc = arg_parse_int(argc, argv, &index, &backlog, 0);
-				if (rc != EOK)
-					return rc;
-				break;
-			case 'c':
-				rc = arg_parse_int(argc, argv, &index, &count, 0);
-				if (rc != EOK)
-					return rc;
-				break;
-			case 'f':
-				rc = arg_parse_name_int(argc, argv, &index, &family, 0, socket_parse_protocol_family);
-				if (rc != EOK)
-					return rc;
-				break;
-			case 'h':
-				echo_print_help();
-				return EOK;
-				break;
-			case 'p':
-				rc = arg_parse_int(argc, argv, &index, &value, 0);
-				if (rc != EOK)
-					return rc;
-				port = (uint16_t) value;
-				break;
-			case 'r':
-				rc = arg_parse_string(argc, argv, &index, &reply, 0);
-				if (rc != EOK)
-					return rc;
-				break;
-			case 's':
-				rc = arg_parse_int(argc, argv, &index, &value, 0);
-				if (rc != EOK)
-					return rc;
-				size = (value >= 0) ? (size_t) value : 0;
-				break;
-			case 't':
-				rc = arg_parse_name_int(argc, argv, &index, &value, 0, socket_parse_socket_type);
-				if (rc != EOK)
-					return rc;
-				type = (sock_type_t) value;
-				break;
-			case 'v':
-				verbose = 1;
-				break;
-			// long options with the double minus sign ('-')
-			case '-':
-				if (str_lcmp(argv[index] + 2, "backlog=", 6) == 0) {
-					rc = arg_parse_int(argc, argv, &index, &backlog, 8);
-					if (rc != EOK)
-						return rc;
-				} else if (str_lcmp(argv[index] + 2, "count=", 6) == 0) {
-					rc = arg_parse_int(argc, argv, &index, &count, 8);
-					if (rc != EOK)
-						return rc;
-				} else if (str_lcmp(argv[index] + 2, "family=", 7) == 0) {
-					rc = arg_parse_name_int(argc, argv, &index, &family, 9, socket_parse_protocol_family);
-					if (rc != EOK)
-						return rc;
-				} else if (str_lcmp(argv[index] + 2, "help", 5) == 0) {
-					echo_print_help();
-					return EOK;
-				} else if (str_lcmp(argv[index] + 2, "port=", 5) == 0) {
-					rc = arg_parse_int(argc, argv, &index, &value, 7);
-					if (rc != EOK)
-						return rc;
-					port = (uint16_t) value;
-				} else if (str_lcmp(argv[index] + 2, "reply=", 6) == 0) {
-					rc = arg_parse_string(argc, argv, &index, &reply, 8);
-					if (rc != EOK)
-						return rc;
-				} else if (str_lcmp(argv[index] + 2, "size=", 5) == 0) {
-					rc = arg_parse_int(argc, argv, &index, &value, 7);
-					if (rc != EOK)
-						return rc;
-					size = (value >= 0) ? (size_t) value : 0;
-				} else if (str_lcmp(argv[index] + 2, "type=", 5) == 0) {
-					rc = arg_parse_name_int(argc, argv, &index, &value, 7, socket_parse_socket_type);
-					if (rc != EOK)
-						return rc;
-					type = (sock_type_t) value;
-				} else if (str_lcmp(argv[index] + 2, "verbose", 8) == 0) {
-					verbose = 1;
-				} else {
-					echo_print_help();
-					return EINVAL;
-				}
-				break;
-			default:
-				echo_print_help();
-				return EINVAL;
-			}
+	switch (argv[*index][1]) {
+	case 'b':
+		rc = arg_parse_int(argc, argv, index, &backlog, 0);
+		if (rc != EOK)
+			return rc;
+		break;
+	case 'c':
+		rc = arg_parse_int(argc, argv, index, &count, 0);
+		if (rc != EOK)
+			return rc;
+		break;
+	case 'f':
+		rc = arg_parse_name_int(argc, argv, index, &family, 0,
+		    socket_parse_protocol_family);
+		if (rc != EOK)
+			return rc;
+		break;
+	case 'h':
+		echo_print_help();
+		exit(0);
+		break;
+	case 'p':
+		rc = arg_parse_int(argc, argv, index, &value, 0);
+		if (rc != EOK)
+			return rc;
+		port = (uint16_t) value;
+		break;
+	case 'r':
+		rc = arg_parse_string(argc, argv, index, &reply, 0);
+		if (rc != EOK)
+			return rc;
+		break;
+	case 's':
+		rc = arg_parse_int(argc, argv, index, &value, 0);
+		if (rc != EOK)
+			return rc;
+		size = (value >= 0) ? (size_t) value : 0;
+		break;
+	case 't':
+		rc = arg_parse_name_int(argc, argv, index, &value, 0,
+		    socket_parse_socket_type);
+		if (rc != EOK)
+			return rc;
+		type = (sock_type_t) value;
+		break;
+	case 'v':
+		verbose = 1;
+		break;
+	/* Long options with double dash */
+	case '-':
+		if (str_lcmp(argv[*index] + 2, "backlog=", 6) == 0) {
+			rc = arg_parse_int(argc, argv, index, &backlog, 8);
+			if (rc != EOK)
+				return rc;
+		} else if (str_lcmp(argv[*index] + 2, "count=", 6) == 0) {
+			rc = arg_parse_int(argc, argv, index, &count, 8);
+			if (rc != EOK)
+				return rc;
+		} else if (str_lcmp(argv[*index] + 2, "family=", 7) == 0) {
+			rc = arg_parse_name_int(argc, argv, index, &family, 9,
+			    socket_parse_protocol_family);
+			if (rc != EOK)
+				return rc;
+		} else if (str_lcmp(argv[*index] + 2, "help", 5) == 0) {
+			echo_print_help();
+			exit(0);
+		} else if (str_lcmp(argv[*index] + 2, "port=", 5) == 0) {
+			rc = arg_parse_int(argc, argv, index, &value, 7);
+			if (rc != EOK)
+				return rc;
+			port = (uint16_t) value;
+		} else if (str_lcmp(argv[*index] + 2, "reply=", 6) == 0) {
+			rc = arg_parse_string(argc, argv, index, &reply, 8);
+			if (rc != EOK)
+				return rc;
+		} else if (str_lcmp(argv[*index] + 2, "size=", 5) == 0) {
+			rc = arg_parse_int(argc, argv, index, &value, 7);
+			if (rc != EOK)
+				return rc;
+			size = (value >= 0) ? (size_t) value : 0;
+		} else if (str_lcmp(argv[*index] + 2, "type=", 5) == 0) {
+			rc = arg_parse_name_int(argc, argv, index, &value, 7,
+			    socket_parse_socket_type);
+			if (rc != EOK)
+				return rc;
+			type = (sock_type_t) value;
+		} else if (str_lcmp(argv[*index] + 2, "verbose", 8) == 0) {
+			verbose = 1;
 		} else {
 			echo_print_help();
 			return EINVAL;
 		}
-	}
-
-	// check the buffer size
+		break;
+	default:
+		echo_print_help();
+		return EINVAL;
+	}
+
+	return EOK;
+}
+
+/** Echo one message (accept one connection and echo message).
+ *
+ * @param listening_id	Listening socket.
+ * @return		EOK on success or negative error code.
+ */
+static int netecho_socket_process_message(int listening_id)
+{
+	uint8_t address_buf[sizeof(struct sockaddr_in6)];
+
+	socklen_t addrlen;
+	int socket_id;
+	ssize_t rcv_size;
+	size_t length;
+	uint8_t *address_start;
+
+	char address_string[INET6_ADDRSTRLEN];
+	struct sockaddr_in *address_in = (struct sockaddr_in *) address_buf;
+	struct sockaddr_in6 *address_in6 = (struct sockaddr_in6 *) address_buf;
+	struct sockaddr *address = (struct sockaddr *) address_buf;
+
+	int rc;
+
+	if (type == SOCK_STREAM) {
+		/* Accept a socket if a stream socket is used */
+		addrlen = sizeof(address_buf);
+            	socket_id = accept(listening_id, (void *) address_buf, &addrlen);
+		if (socket_id <= 0) {
+			socket_print_error(stderr, socket_id, "Socket accept: ", "\n");
+		} else {
+			if (verbose)
+				printf("Socket %d accepted\n", socket_id);
+		}
+
+		assert((size_t) addrlen <= sizeof(address_buf));
+	} else {
+		socket_id = listening_id;
+	}
+
+	/* if the datagram socket is used or the stream socked was accepted */
+	if (socket_id > 0) {
+
+		/* Receive a message to echo */
+		rcv_size = recvfrom(socket_id, data, size, 0, address,
+		    &addrlen);
+		if (rcv_size < 0) {
+			socket_print_error(stderr, rcv_size, "Socket receive: ", "\n");
+		} else {
+			length = (size_t) rcv_size;
+			if (verbose) {
+				/* Print the header */
+
+				/* Get the source port and prepare the address buffer */
+				address_start = NULL;
+				switch (address->sa_family) {
+				case AF_INET:
+					port = ntohs(address_in->sin_port);
+					address_start = (uint8_t *) &address_in->sin_addr.s_addr;
+					break;
+				case AF_INET6:
+					port = ntohs(address_in6->sin6_port);
+					address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
+					break;
+				default:
+					fprintf(stderr, "Address family %u (%#x) is not supported.\n",
+					    address->sa_family, address->sa_family);
+				}
+
+				/* Parse source address */
+				if (address_start) {
+					rc = inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string));
+					if (rc != EOK) {
+						fprintf(stderr, "Received address error %d\n", rc);
+					} else {
+						data[length] = '\0';
+						printf("Socket %d received %zu bytes from %s:%d\n%s\n",
+						    socket_id, length, address_string, port, data);
+					}
+				}
+			}
+
+			/* Answer the request either with the static reply or the original data */
+			rc = sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen);
+			if (rc != EOK)
+				socket_print_error(stderr, rc, "Socket send: ", "\n");
+		}
+
+		/* Close accepted stream socket */
+		if (type == SOCK_STREAM) {
+			rc = closesocket(socket_id);
+			if (rc != EOK)
+				socket_print_error(stderr, rc, "Close socket: ", "\n");
+		}
+
+	}
+
+	return EOK;
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct sockaddr *address;;
+	struct sockaddr_in address_in;
+	struct sockaddr_in6 address_in6;
+	socklen_t addrlen;
+
+	int listening_id;
+	int index;
+	int rc;
+
+	/* Parse command line arguments */
+	for (index = 1; index < argc; ++index) {
+		if (argv[index][0] == '-') {
+			rc = netecho_parse_option(argc, argv, &index);
+			if (rc != EOK)
+				return rc;
+		} else {
+			echo_print_help();
+			return EINVAL;
+		}
+	}
+
+	/* Check buffer size */
 	if (size <= 0) {
 		fprintf(stderr, "Receive size too small (%zu). Using 1024 bytes instead.\n", size);
 		size = 1024;
 	}
-	// size plus the terminating null (\0)
+
+	/* size plus the terminating null character. */
 	data = (char *) malloc(size + 1);
 	if (!data) {
@@ -230,19 +351,20 @@
 	}
 
-	// set the reply size if set
+	/* Set the reply size if set */
 	reply_length = reply ? str_length(reply) : 0;
 
-	// prepare the address buffer
-	bzero(address_data, max_length);
+	/* Prepare the address buffer */
 	switch (family) {
 	case PF_INET:
-		address_in->sin_family = AF_INET;
-		address_in->sin_port = htons(port);
-		addrlen = sizeof(struct sockaddr_in);
+		address_in.sin_family = AF_INET;
+		address_in.sin_port = htons(port);
+		address = (struct sockaddr *) &address_in;
+		addrlen = sizeof(address_in);
 		break;
 	case PF_INET6:
-		address_in6->sin6_family = AF_INET6;
-		address_in6->sin6_port = htons(port);
-		addrlen = sizeof(struct sockaddr_in6);
+		address_in6.sin6_family = AF_INET6;
+		address_in6.sin6_port = htons(port);
+		address = (struct sockaddr *) &address_in6;
+		addrlen = sizeof(address_in6);
 		break;
 	default:
@@ -251,5 +373,5 @@
 	}
 
-	// get a listening socket
+	/* Get a listening socket */
 	listening_id = socket(family, type, 0);
 	if (listening_id < 0) {
@@ -258,12 +380,13 @@
 	}
 
-	// if the stream socket is used
+	/* if the stream socket is used */
 	if (type == SOCK_STREAM) {
-		// check the backlog
+		/* Check backlog size */
 		if (backlog <= 0) {
 			fprintf(stderr, "Accepted sockets queue size too small (%zu). Using 3 instead.\n", size);
 			backlog = 3;
 		}
-		// set the backlog
+
+		/* Set the backlog */
 		rc = listen(listening_id, backlog);
 		if (rc != EOK) {
@@ -273,5 +396,5 @@
 	}
 
-	// bind the listenning socket
+	/* Bind the listening socket */
 	rc = bind(listening_id, address, addrlen);
 	if (rc != EOK) {
@@ -283,82 +406,18 @@
 		printf("Socket %d listenning at %d\n", listening_id, port);
 
-	socket_id = listening_id;
-
-	// do count times
-	// or indefinitely if set to a negative value
+	/*
+	 * do count times
+	 * or indefinitely if set to a negative value
+	 */
 	while (count) {
-
-		addrlen = max_length;
-		if (type == SOCK_STREAM) {
-			// acceept a socket if the stream socket is used
-			socket_id = accept(listening_id, address, &addrlen);
-			if (socket_id <= 0) {
-				socket_print_error(stderr, socket_id, "Socket accept: ", "\n");
-			} else {
-				if (verbose)
-					printf("Socket %d accepted\n", socket_id);
-			}
-		}
-
-		// if the datagram socket is used or the stream socked was accepted
-		if (socket_id > 0) {
-
-			// receive an echo request
-			value = recvfrom(socket_id, data, size, 0, address, &addrlen);
-			if (value < 0) {
-				socket_print_error(stderr, value, "Socket receive: ", "\n");
-			} else {
-				length = (size_t) value;
-				if (verbose) {
-					// print the header
-
-					// get the source port and prepare the address buffer
-					address_start = NULL;
-					switch (address->sa_family) {
-					case AF_INET:
-						port = ntohs(address_in->sin_port);
-						address_start = (uint8_t *) &address_in->sin_addr.s_addr;
-						break;
-					case AF_INET6:
-						port = ntohs(address_in6->sin6_port);
-						address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
-						break;
-					default:
-						fprintf(stderr, "Address family %u (%#x) is not supported.\n",
-						    address->sa_family, address->sa_family);
-					}
-					// parse the source address
-					if (address_start) {
-						rc = inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string));
-						if (rc != EOK) {
-							fprintf(stderr, "Received address error %d\n", rc);
-						} else {
-							data[length] = '\0';
-							printf("Socket %d received %zu bytes from %s:%d\n%s\n",
-							    socket_id, length, address_string, port, data);
-						}
-					}
-				}
-
-				// answer the request either with the static reply or the original data
-				rc = sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen);
-				if (rc != EOK)
-					socket_print_error(stderr, rc, "Socket send: ", "\n");
-			}
-
-			// close the accepted stream socket
-			if (type == SOCK_STREAM) {
-				rc = closesocket(socket_id);
-				if (rc != EOK)
-					socket_print_error(stderr, rc, "Close socket: ", "\n");
-			}
-
-		}
-
-		// decrease the count if positive
+		rc = netecho_socket_process_message(listening_id);
+		if (rc != EOK)
+			break;
+
+		/* Decrease count if positive */
 		if (count > 0) {
 			count--;
 			if (verbose)
-				printf("Waiting for next %d packet(s)\n", count);
+				printf("Waiting for next %d message(s)\n", count);
 		}
 	}
@@ -367,5 +426,5 @@
 		printf("Closing the socket\n");
 
-	// close the listenning socket
+	/* Close listenning socket */
 	rc = closesocket(listening_id);
 	if (rc != EOK) {
Index: uspace/app/sysinfo/Makefile
===================================================================
--- uspace/app/sysinfo/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/app/sysinfo/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2010 Jiri Svoboda
+# 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 = ../..
+EXTRA_CFLAGS = -Iinclude
+BINARY = sysinfo
+
+SOURCES = \
+	sysinfo.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/sysinfo/sysinfo.c
===================================================================
--- uspace/app/sysinfo/sysinfo.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/app/sysinfo/sysinfo.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * 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 sysinfo
+ * @{
+ */
+/** @file sysinfo.c
+ * @brief Print value of item from sysinfo tree.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <sysinfo.h>
+#include <sys/types.h>
+
+static int print_item_val(char *ipath);
+static int print_item_data(char *ipath);
+
+static void dump_bytes_hex(char *data, size_t size);
+static void dump_bytes_text(char *data, size_t size);
+
+static void print_syntax(void);
+
+int main(int argc, char *argv[])
+{
+	int rc;
+	char *ipath;
+	sysinfo_item_tag_t tag;
+
+	if (argc != 2) {
+		print_syntax();
+		return 1;
+	}
+
+	ipath = argv[1];
+
+	tag = sysinfo_get_tag(ipath);
+
+	/* Silence warning */
+	rc = EOK;
+
+	switch (tag) {
+	case SYSINFO_VAL_UNDEFINED:
+		printf("Error: Sysinfo item '%s' not defined.\n", ipath);
+		rc = 2;
+		break;
+	case SYSINFO_VAL_VAL:
+		rc = print_item_val(ipath);
+		break;
+	case SYSINFO_VAL_DATA:
+		rc = print_item_data(ipath);
+		break;
+	}
+
+	return rc;
+}
+
+static int print_item_val(char *ipath)
+{
+	sysarg_t value;
+	int rc;
+
+	rc = sysinfo_get_value(ipath, &value);
+	if (rc != EOK) {
+		printf("Error reading item '%s'.\n", ipath);
+		return rc;
+	}
+
+	printf("%s -> %" PRIu64 " (0x%" PRIx64 ")\n", ipath,
+	    (uint64_t) value, (uint64_t) value);
+
+	return EOK;
+}
+
+static int print_item_data(char *ipath)
+{
+	void *data;
+	size_t size;
+
+	data = sysinfo_get_data(ipath, &size);
+	if (data == NULL) {
+		printf("Error reading item '%s'.\n", ipath);
+		return -1;
+	}
+
+	printf("%s -> ", ipath);
+	dump_bytes_hex(data, size);
+	fputs(" ('", stdout);
+	dump_bytes_text(data, size);
+	fputs("')\n", stdout);
+
+	return EOK;
+}
+
+static void dump_bytes_hex(char *data, size_t size)
+{
+	size_t i;
+
+	for (i = 0; i < size; ++i) {
+		if (i > 0) putchar(' ');
+		printf("0x%02x", (uint8_t) data[i]);
+	}
+}
+
+static void dump_bytes_text(char *data, size_t size)
+{
+	wchar_t c;
+	size_t offset;
+
+	offset = 0;
+
+	while (offset < size) {
+		c = str_decode(data, &offset, size);
+		printf("%lc", (wint_t) c);
+	}
+}
+
+
+static void print_syntax(void)
+{
+	printf("Syntax: sysinfo <item_path>\n");
+}
+
+/** @}
+ */
Index: uspace/app/taskdump/taskdump.c
===================================================================
--- uspace/app/taskdump/taskdump.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/app/taskdump/taskdump.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -326,5 +326,5 @@
 
 	sym_pc = fmt_sym_address(pc);
-	printf("Thread %p crashed at %s. FP = %p\n", (void *) thash,
+	printf("Thread %p: PC = %s. FP = %p\n", (void *) thash,
 	    sym_pc, (void *) fp);
 	free(sym_pc);
Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/app/tester/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -51,8 +51,7 @@
 	vfs/vfs1.c \
 	ipc/ping_pong.c \
-	ipc/register.c \
-	ipc/connect.c \
 	loop/loop1.c \
 	mm/malloc1.c \
+	hw/misc/virtchar1.c \
 	hw/serial/serial1.c
 
Index: uspace/app/tester/hw/misc/virtchar1.c
===================================================================
--- uspace/app/tester/hw/misc/virtchar1.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/app/tester/hw/misc/virtchar1.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -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 tester
+ * @brief Test the virtual char driver
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <inttypes.h>
+#include <errno.h>
+#include <str_error.h>
+#include <sys/types.h>
+#include <async.h>
+#include <device/char.h>
+#include <str.h>
+#include <vfs/vfs.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <device/char.h>
+#include "../../tester.h"
+
+#define DEVICE_PATH_NORMAL "/dev/devices/\\virt\\null"
+#define DEVICE_PATH_CLASSES "/dev/class/virt-null\\1"
+#define BUFFER_SIZE 64
+
+static const char *test_virtchar1_internal(const char *path)
+{
+	TPRINTF("Opening `%s'...\n", path);
+	int fd = open(path, O_RDONLY);
+	if (fd < 0) {
+		TPRINTF("   ...error: %s\n", str_error(fd));
+		if (fd == ENOENT) {
+			TPRINTF("   (error was ENOENT: " \
+			    "have you compiled test drivers?)\n");
+		}
+		return "Failed opening devman driver device for reading";
+	}
+	
+	TPRINTF("   ...file handle %d\n", fd);
+
+	TPRINTF(" Asking for phone...\n");
+	int phone = fd_phone(fd);
+	if (phone < 0) {
+		close(fd);
+		TPRINTF("   ...error: %s\n", str_error(phone));
+		return "Failed to get phone to device";
+	}
+	TPRINTF("   ...phone is %d\n", phone);
+	
+	TPRINTF(" Will try to read...\n");
+	size_t i;
+	char buffer[BUFFER_SIZE];
+	read_dev(phone, buffer, BUFFER_SIZE);
+	TPRINTF(" ...verifying that we read zeroes only...\n");
+	for (i = 0; i < BUFFER_SIZE; i++) {
+		if (buffer[i] != 0) {
+			return "Not all bytes are zeroes";
+		}
+	}
+	TPRINTF("   ...data read okay\n");
+	
+	/* Clean-up. */
+	TPRINTF(" Closing phones and file descriptors\n");
+	ipc_hangup(phone);
+	close(fd);
+	
+	return NULL;
+}
+
+const char *test_virtchar1(void)
+{;
+	const char *res;
+
+	res = test_virtchar1_internal(DEVICE_PATH_NORMAL);
+	if (res != NULL) {
+		return res;
+	}
+
+	res = test_virtchar1_internal(DEVICE_PATH_CLASSES);
+	if (res != NULL) {
+		return res;
+	}
+
+	return NULL;
+}
+
+/** @}
+ */
Index: uspace/app/tester/hw/misc/virtchar1.def
===================================================================
--- uspace/app/tester/hw/misc/virtchar1.def	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/app/tester/hw/misc/virtchar1.def	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,6 @@
+{
+	"virtchar1",
+	"Virtual char device test",
+	&test_virtchar1,
+	false
+},
Index: pace/app/tester/ipc/connect.c
===================================================================
--- uspace/app/tester/ipc/connect.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,73 +1,0 @@
-/*
- * Copyright (c) 2006 Ondrej Palkovsky
- * 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 <unistd.h>
-#include <atomic.h>
-#include "../tester.h"
-
-static atomic_t finish;
-
-static void callback(void *priv, int retval, ipc_call_t *data)
-{
-	atomic_set(&finish, 1);
-}
-
-const char *test_connect(void)
-{
-	TPRINTF("Connecting to %u...", IPC_TEST_SERVICE);
-	int phone = ipc_connect_me_to(PHONE_NS, IPC_TEST_SERVICE, 0, 0);
-	if (phone > 0) {
-		TPRINTF("phoneid %d\n", phone);
-	} else {
-		TPRINTF("\n");
-		return "ipc_connect_me_to() failed";
-	}
-	
-	printf("Sending synchronous message...\n");
-	int retval = ipc_call_sync_0_0(phone, IPC_TEST_METHOD);
-	TPRINTF("Received response to synchronous message\n");
-	
-	TPRINTF("Sending asynchronous message...\n");
-	atomic_set(&finish, 0);
-	ipc_call_async_0(phone, IPC_TEST_METHOD, NULL, callback, 1);
-	while (atomic_get(&finish) != 1)
-		TPRINTF(".");
-	TPRINTF("Received response to asynchronous message\n");
-	
-	TPRINTF("Hanging up...");
-	retval = ipc_hangup(phone);
-	if (retval == 0) {
-		TPRINTF("OK\n");
-	} else {
-		TPRINTF("\n");
-		return "ipc_hangup() failed";
-	}
-	
-	return NULL;
-}
Index: pace/app/tester/ipc/connect.def
===================================================================
--- uspace/app/tester/ipc/connect.def	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,6 +1,0 @@
-{
-	"connect",
-	"IPC connection test (connect to other service)",
-	&test_connect,
-	true
-},
Index: pace/app/tester/ipc/register.c
===================================================================
--- uspace/app/tester/ipc/register.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,90 +1,0 @@
-/*
- * Copyright (c) 2006 Ondrej Palkovsky
- * 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 <inttypes.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <async.h>
-#include <errno.h>
-#include "../tester.h"
-
-#define MAX_CONNECTIONS  50
-
-static int connections[MAX_CONNECTIONS];
-
-static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
-{
-	unsigned int i;
-	
-	TPRINTF("Connected phone %" PRIun " accepting\n", icall->in_phone_hash);
-	ipc_answer_0(iid, EOK);
-	for (i = 0; i < MAX_CONNECTIONS; i++) {
-		if (!connections[i]) {
-			connections[i] = icall->in_phone_hash;
-			break;
-		}
-	}
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		int retval;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			TPRINTF("Phone %" PRIun " hung up\n", icall->in_phone_hash);
-			retval = 0;
-			break;
-		case IPC_TEST_METHOD:
-			TPRINTF("Received well known message from %" PRIun ": %" PRIun "\n",
-			    icall->in_phone_hash, callid);
-			ipc_answer_0(callid, EOK);
-			break;
-		default:
-			TPRINTF("Received unknown message from %" PRIun ": %" PRIun "\n",
-			    icall->in_phone_hash, callid);
-			ipc_answer_0(callid, ENOENT);
-			break;
-		}
-	}
-}
-
-const char *test_register(void)
-{
-	async_set_client_connection(client_connection);
-	
-	sysarg_t phonead;
-	int res = ipc_connect_to_me(PHONE_NS, IPC_TEST_SERVICE, 0, 0, &phonead);
-	if (res != 0)
-		return "Failed registering IPC service";
-	
-	TPRINTF("Registered as service %u, accepting connections\n", IPC_TEST_SERVICE);
-	async_manager();
-	
-	return NULL;
-}
Index: pace/app/tester/ipc/register.def
===================================================================
--- uspace/app/tester/ipc/register.def	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,6 +1,0 @@
-{
-	"register",
-	"IPC registration test",
-	&test_register,
-	true
-},
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/app/tester/tester.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -60,10 +60,9 @@
 #include "vfs/vfs1.def"
 #include "ipc/ping_pong.def"
-#include "ipc/register.def"
-#include "ipc/connect.def"
 #include "loop/loop1.def"
 #include "mm/malloc1.def"
 #include "hw/serial/serial1.def"
 #include "adt/usbaddrkeep.def"
+#include "hw/misc/virtchar1.def"
 	{NULL, NULL, NULL, false}
 };
Index: uspace/app/tester/tester.h
===================================================================
--- uspace/app/tester/tester.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/app/tester/tester.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -77,10 +77,9 @@
 extern const char *test_vfs1(void);
 extern const char *test_ping_pong(void);
-extern const char *test_register(void);
-extern const char *test_connect(void);
 extern const char *test_loop1(void);
 extern const char *test_malloc1(void);
 extern const char *test_serial1(void);
 extern const char *test_usbaddrkeep(void);
+extern const char *test_virtchar1(void);
 
 extern test_t tests[];
Index: uspace/app/tester/vfs/vfs1.c
===================================================================
--- uspace/app/tester/vfs/vfs1.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/app/tester/vfs/vfs1.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -40,10 +40,5 @@
 #include "../tester.h"
 
-#define FS_TYPE      "tmpfs"
-#define MOUNT_POINT  "/tmp"
-#define OPTIONS      ""
-#define FLAGS        0
-
-#define TEST_DIRECTORY  MOUNT_POINT "/testdir"
+#define TEST_DIRECTORY  "/tmp/testdir"
 #define TEST_FILE       TEST_DIRECTORY "/testfile"
 #define TEST_FILE2      TEST_DIRECTORY "/nextfile"
@@ -75,23 +70,9 @@
 const char *test_vfs1(void)
 {
-	if (mkdir(MOUNT_POINT, 0) != 0)
+	int rc;
+	if ((rc = mkdir(TEST_DIRECTORY, 0)) != 0) {
+		TPRINTF("rc=%d\n", rc);
 		return "mkdir() failed";
-	TPRINTF("Created directory %s\n", MOUNT_POINT);
-	
-	int rc = mount(FS_TYPE, MOUNT_POINT, "", OPTIONS, FLAGS);
-	switch (rc) {
-	case EOK:
-		TPRINTF("Mounted %s on %s\n", FS_TYPE, MOUNT_POINT);
-		break;
-	case EBUSY:
-		TPRINTF("(INFO) Filesystem already mounted on %s\n", MOUNT_POINT);
-		break;
-	default:
-		TPRINTF("(ERR) IPC returned errno %d (is tmpfs loaded?)\n", rc);
-		return "mount() failed";
 	}
-	
-	if (mkdir(TEST_DIRECTORY, 0) != 0)
-		return "mkdir() failed";
 	TPRINTF("Created directory %s\n", TEST_DIRECTORY);
 	
Index: uspace/app/websrv/Makefile
===================================================================
--- uspace/app/websrv/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/app/websrv/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Jiri Svoboda
+# 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 =
+EXTRA_CFLAGS =
+BINARY = websrv
+
+SOURCES = \
+	websrv.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/websrv/websrv.c
===================================================================
--- uspace/app/websrv/websrv.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/app/websrv/websrv.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * 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 websrv
+ * @{
+ */
+/**
+ * @file (Less-than-skeleton) web server.
+ */
+
+#include <stdio.h>
+
+#include <net/in.h>
+#include <net/inet.h>
+#include <net/socket.h>
+
+#include <str.h>
+
+#define PORT_NUMBER 8080
+
+/** Buffer for receiving the request. */
+#define BUFFER_SIZE 1024
+static char buf[BUFFER_SIZE];
+
+/** Response to send to client. */
+static const char *response_msg =
+    "HTTP/1.0 200 OK\r\n"
+    "\r\n"
+    "<h1>Hello from HelenOS!</h1>\r\n";
+
+int main(int argc, char *argv[])
+{
+	struct sockaddr_in addr;
+	struct sockaddr_in raddr;
+
+	socklen_t raddr_len;
+
+	int listen_sd, conn_sd;
+	int rc;
+
+	size_t response_size;
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(PORT_NUMBER);
+
+	rc = inet_pton(AF_INET, "127.0.0.1", (void *) &addr.sin_addr.s_addr);
+	if (rc != EOK) {
+		printf("Error parsing network address.\n");
+		return 1;
+	}
+
+	printf("Creating socket.\n");
+
+	listen_sd = socket(PF_INET, SOCK_STREAM, 0);
+	if (listen_sd < 0) {
+		printf("Error creating listening socket.\n");
+		return 1;
+	}
+
+	rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
+	if (rc != EOK) {
+		printf("Error binding socket.\n");
+		return 1;
+	}
+
+	rc = listen(listen_sd, 1);
+	if (rc != EOK) {
+		printf("Error calling listen() (%d).\n", rc);
+		return 1;
+	}
+
+	response_size = str_size(response_msg);
+
+	printf("Listening for connections at port number %u.\n", PORT_NUMBER);
+	while (true) {
+		raddr_len = sizeof(raddr);
+		conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
+		    &raddr_len);
+
+		if (conn_sd < 0) {
+			printf("accept() failed.\n");
+			return 1;
+		}
+
+		printf("Accepted connection, sd=%d.\n", conn_sd);
+
+		printf("Wait for client request\n");
+
+		/* Really we should wait for a blank line. */
+		rc = recv(conn_sd, buf, BUFFER_SIZE, 0);
+		if (rc < 0) {
+			printf("recv() failed\n");
+			return 1;
+		}
+
+		/* Send a canned response. */
+                printf("Send response...\n");
+		rc = send(conn_sd, (void *) response_msg, response_size, 0);
+		if (rc < 0) {
+			printf("send() failed.\n");
+			return 1;
+		}
+
+		rc = closesocket(conn_sd);
+		if (rc != EOK) {
+			printf("Error closing connection socket: %d\n", rc);
+			return 1;
+		}
+
+		printf("Closed connection.\n");
+	}
+
+	/* Not reached. */
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/drv/ns8250/ns8250.c
===================================================================
--- uspace/drv/ns8250/ns8250.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/ns8250/ns8250.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -342,13 +342,13 @@
 		printf(NAME ": failed to connect to the parent driver of the "
 		    "device %s.\n", dev->name);
-		ret = EPARTY;	/* FIXME: use another EC */
+		ret = dev->parent_phone;
 		goto failed;
 	}
 	
 	/* Get hw resources. */
-	if (!get_hw_resources(dev->parent_phone, &hw_resources)) {
+	ret = get_hw_resources(dev->parent_phone, &hw_resources);
+	if (ret != EOK) {
 		printf(NAME ": failed to get hw resources for the device "
 		    "%s.\n", dev->name);
-		ret = EPARTY;	/* FIXME: use another EC */
 		goto failed;
 	}
@@ -374,5 +374,5 @@
 				printf(NAME ": i/o range assigned to the device "
 				    "%s is too small.\n", dev->name);
-				ret = EPARTY;	/* FIXME: use another EC */
+				ret = ELIMIT;
 				goto failed;
 			}
@@ -390,5 +390,5 @@
 		printf(NAME ": missing hw resource(s) for the device %s.\n",
 		    dev->name);
-		ret = EPARTY;	/* FIXME: use another EC */
+		ret = ENOENT;
 		goto failed;
 	}
Index: uspace/drv/pciintel/pci.c
===================================================================
--- uspace/drv/pciintel/pci.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/pciintel/pci.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -452,4 +452,6 @@
 static int pci_add_device(device_t *dev)
 {
+	int rc;
+
 	printf(NAME ": pci_add_device\n");
 	
@@ -466,15 +468,16 @@
 		    "parent's driver.\n");
 		delete_pci_bus_data(bus_data);
-		return EPARTY;	/* FIXME: use another EC */
+		return dev->parent_phone;
 	}
 	
 	hw_resource_list_t hw_resources;
 	
-	if (!get_hw_resources(dev->parent_phone, &hw_resources)) {
+	rc = get_hw_resources(dev->parent_phone, &hw_resources);
+	if (rc != EOK) {
 		printf(NAME ": pci_add_device failed to get hw resources for "
 		    "the device.\n");
 		delete_pci_bus_data(bus_data);
 		ipc_hangup(dev->parent_phone);
-		return EPARTY;	/* FIXME: use another EC */
+		return rc;
 	}	
 	
Index: uspace/drv/root/root.c
===================================================================
--- uspace/drv/root/root.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/root/root.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -47,4 +47,5 @@
 #include <macros.h>
 #include <inttypes.h>
+#include <sysinfo.h>
 
 #include <driver.h>
@@ -55,5 +56,5 @@
 
 #define PLATFORM_DEVICE_NAME "hw"
-#define PLATFORM_DEVICE_MATCH_ID STRING(UARCH)
+#define PLATFORM_DEVICE_MATCH_ID_FMT "platform/%s"
 #define PLATFORM_DEVICE_MATCH_SCORE 100
 
@@ -100,11 +101,41 @@
 static int add_platform_child(device_t *parent)
 {
+	char *match_id;
+	char *platform;
+	size_t platform_size;
+	int res;
+
+	/* Get platform name from sysinfo. */
+
+	platform = sysinfo_get_data("platform", &platform_size);
+	if (platform == NULL) {
+		printf(NAME ": Failed to obtain platform name.\n");
+		return ENOENT;
+	}
+
+	/* Null-terminate string. */
+	platform = realloc(platform, platform_size + 1);
+	if (platform == NULL) {
+		printf(NAME ": Memory allocation failed.\n");
+		return ENOMEM;
+	}
+
+	platform[platform_size] = '\0';
+
+	/* Construct match ID. */
+
+	if (asprintf(&match_id, PLATFORM_DEVICE_MATCH_ID_FMT, platform) == -1) {
+		printf(NAME ": Memory allocation failed.\n");
+		return ENOMEM;
+	}
+
+	/* Add child. */
+
 	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 = child_device_register_wrapper(parent, PLATFORM_DEVICE_NAME,
-	    PLATFORM_DEVICE_MATCH_ID, PLATFORM_DEVICE_MATCH_SCORE,
-	    NULL);
+	    PLATFORM_DEVICE_MATCH_SCORE, match_id);
+
+	res = child_device_register_wrapper(parent, PLATFORM_DEVICE_NAME,
+	    match_id, PLATFORM_DEVICE_MATCH_SCORE, NULL);
 
 	return res;
Index: uspace/drv/rootpc/rootpc.c
===================================================================
--- uspace/drv/rootpc/rootpc.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/rootpc/rootpc.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -28,6 +28,6 @@
 
 /**
- * @defgroup root_pc Root HW device driver for ia32 and amd64 platform.
- * @brief HelenOS root HW device driver for ia32 and amd64 platform.
+ * @defgroup root_pc PC platform driver.
+ * @brief HelenOS PC platform driver.
  * @{
  */
@@ -182,6 +182,5 @@
 	/* Register child devices. */
 	if (!rootpc_add_children(dev)) {
-		printf(NAME ": failed to add child devices for platform "
-		    "ia32.\n");
+		printf(NAME ": failed to add child devices for PC platform.\n");
 	}
 	
@@ -196,5 +195,5 @@
 int main(int argc, char *argv[])
 {
-	printf(NAME ": HelenOS rootpc device driver\n");
+	printf(NAME ": HelenOS PC platform driver\n");
 	root_pc_init();
 	return driver_main(&rootpc_driver);
Index: uspace/drv/rootpc/rootpc.ma
===================================================================
--- uspace/drv/rootpc/rootpc.ma	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/rootpc/rootpc.ma	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -1,2 +1,1 @@
-10 ia32
-10 amd64
+10 platform/pc
Index: uspace/drv/rootvirt/devices.def
===================================================================
--- uspace/drv/rootvirt/devices.def	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/rootvirt/devices.def	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -17,4 +17,8 @@
 	.match_id = "virtual&test2"
 },
+{
+	.name = "null",
+	.match_id = "virtual&test1"
+},
 #endif
 /* Virtual USB host controller. */
Index: uspace/drv/test1/Makefile
===================================================================
--- uspace/drv/test1/Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/test1/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -33,4 +33,5 @@
 
 SOURCES = \
+	char.c \
 	test1.c
 
Index: uspace/drv/test1/char.c
===================================================================
--- uspace/drv/test1/char.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/drv/test1/char.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,56 @@
+/*
+ * 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 <errno.h>
+#include <mem.h>
+#include <char.h>
+
+#include "test1.h"
+
+static int impl_char_read(device_t *dev, char *buf, size_t count) {
+	memset(buf, 0, count);
+	return count;
+}
+
+static int imp_char_write(device_t *dev, char *buf, size_t count) {
+	return count;
+}
+
+static char_iface_t char_interface = {
+	.read = &impl_char_read,
+	.write = &imp_char_write
+};
+
+device_ops_t char_device_ops = {
+	.interfaces[CHAR_DEV_IFACE] = &char_interface
+};
+
Index: uspace/drv/test1/test1.c
===================================================================
--- uspace/drv/test1/test1.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/test1/test1.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -34,7 +34,5 @@
 #include <errno.h>
 #include <str_error.h>
-#include <driver.h>
-
-#define NAME "test1"
+#include "test1.h"
 
 static int add_device(device_t *dev);
@@ -98,5 +96,8 @@
 	add_device_to_class(dev, "virtual");
 
-	if (dev->parent == NULL) {
+	if (str_cmp(dev->name, "null") == 0) {
+		dev->ops = &char_device_ops;
+		add_device_to_class(dev, "virt-null");
+	} else if (dev->parent == NULL) {
 		register_child_verbose(dev, "cloning myself ;-)", "clone",
 		    "virtual&test1", 10);
@@ -117,3 +118,2 @@
 }
 
-
Index: uspace/drv/test1/test1.h
===================================================================
--- uspace/drv/test1/test1.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/drv/test1/test1.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,40 @@
+/*
+ * 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
+ */
+#ifndef DRV_TEST1_TEST1_H_
+#define DRV_TEST1_TEST1_H_
+
+#include <driver.h>
+
+#define NAME "test1"
+
+extern device_ops_t char_device_ops;
+
+#endif
Index: uspace/drv/uhci/main.c
===================================================================
--- uspace/drv/uhci/main.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/uhci/main.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -27,4 +27,5 @@
  */
 #include <usb/hcdhubd.h>
+#include <usb_iface.h>
 #include <errno.h>
 
@@ -34,7 +35,20 @@
 #include "uhci.h"
 
+static int usb_iface_get_hc_handle(device_t *dev, devman_handle_t *handle)
+{
+	/* This shall be called only for the UHCI itself. */
+	assert(dev->parent == NULL);
+
+	*handle = dev->handle;
+	return EOK;
+}
+
+static usb_iface_t hc_usb_iface = {
+	.get_hc_handle = usb_iface_get_hc_handle
+};
 
 static device_ops_t uhci_ops = {
-	.interfaces[USBHC_DEV_IFACE] = &uhci_iface,
+	.interfaces[USB_DEV_IFACE] = &hc_usb_iface,
+	.interfaces[USBHC_DEV_IFACE] = &uhci_iface
 };
 
Index: uspace/drv/usbhub/Makefile
===================================================================
--- uspace/drv/usbhub/Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/usbhub/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -34,5 +34,7 @@
 SOURCES = \
 	main.c \
-	utils.c
+	utils.c \
+	usbhub.c \
+	usblist.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/usbhub/main.c
===================================================================
--- uspace/drv/usbhub/main.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/usbhub/main.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -32,4 +32,5 @@
 
 #include <usb/usbdrv.h>
+
 #include "usbhub.h"
 #include "usbhub_private.h"
@@ -37,4 +38,5 @@
 
 usb_general_list_t usb_hub_list;
+futex_t usb_hub_list_lock;
 
 static driver_ops_t hub_driver_ops = {
@@ -58,8 +60,12 @@
 int main(int argc, char *argv[])
 {
+	usb_dprintf_enable(NAME,1);
+	futex_initialize(&usb_hub_list_lock, 0);
 	usb_lst_init(&usb_hub_list);
+	futex_up(&usb_hub_list_lock);
 	fid_t fid = fibril_create(usb_hub_control_loop, NULL);
 	if (fid == 0) {
-		printf("%s: failed to start fibril for HUB devices\n", NAME);
+		dprintf(1, "failed to start fibril for HUB devices");
+		//printf("%s: failed to start fibril for HUB devices\n", NAME);
 		return ENOMEM;
 	}
Index: uspace/drv/usbhub/usbhub.c
===================================================================
--- uspace/drv/usbhub/usbhub.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/drv/usbhub/usbhub.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup usb hub driver
+ * @{
+ */
+/** @file
+ * @brief usb hub main functionality
+ */
+
+#include <driver.h>
+#include <bool.h>
+#include <errno.h>
+
+#include <usb_iface.h>
+#include <usb/usbdrv.h>
+#include <usb/descriptor.h>
+#include <usb/devreq.h>
+#include <usb/classes/hub.h>
+
+#include "usbhub.h"
+#include "usbhub_private.h"
+#include "port_status.h"
+
+static usb_iface_t hub_usb_iface = {
+	.get_hc_handle = usb_drv_find_hc
+};
+
+static device_ops_t hub_device_ops = {
+	.interfaces[USB_DEV_IFACE] = &hub_usb_iface
+};
+
+//*********************************************
+//
+//  hub driver code, initialization
+//
+//*********************************************
+
+usb_hub_info_t * usb_create_hub_info(device_t * device, int hc) {
+	usb_hub_info_t* result = usb_new(usb_hub_info_t);
+	//result->device = device;
+	result->port_count = -1;
+	/// \TODO is this correct? is the device stored?
+	result->device = device;
+
+
+	//printf("[usb_hub] phone to hc = %d\n", hc);
+	if (hc < 0) {
+		return result;
+	}
+	//get some hub info
+	usb_address_t addr = usb_drv_get_my_address(hc, device);
+	dprintf(1,"[usb_hub] address of newly created hub = %d", addr);
+	/*if(addr<0){
+		//return result;
+
+	}*/
+
+	result->usb_device = usb_new(usb_hcd_attached_device_info_t);
+	result->usb_device->address = addr;
+
+	// get hub descriptor
+	usb_target_t target;
+	target.address = addr;
+	target.endpoint = 0;
+	usb_device_request_setup_packet_t request;
+	//printf("[usb_hub] creating descriptor request\n");
+	usb_hub_set_descriptor_request(&request);
+
+	//printf("[usb_hub] creating serialized descriptor\n");
+	void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
+	usb_hub_descriptor_t * descriptor;
+	size_t received_size;
+	int opResult;
+	//printf("[usb_hub] starting control transaction\n");
+	opResult = usb_drv_sync_control_read(
+			hc, target, &request, serialized_descriptor,
+			USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
+	if (opResult != EOK) {
+		dprintf(1,"[usb_hub] failed when receiving hub descriptor, badcode = %d",opResult);
+		free(serialized_descriptor);
+		return result;
+	}
+	//printf("[usb_hub] deserializing descriptor\n");
+	descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
+	if(descriptor==NULL){
+		dprintf(1,"[usb_hub] could not deserialize descriptor ");
+		result->port_count = 1;///\TODO this code is only for debug!!!
+		return result;
+	}
+	//printf("[usb_hub] setting port count to %d\n",descriptor->ports_count);
+	result->port_count = descriptor->ports_count;
+	result->attached_devs = (usb_hub_attached_device_t*)
+	    malloc((result->port_count+1) * sizeof(usb_hub_attached_device_t));
+	int i;
+	for(i=0;i<result->port_count+1;++i){
+		result->attached_devs[i].devman_handle=0;
+		result->attached_devs[i].address=0;
+	}
+	//printf("[usb_hub] freeing data\n");
+	free(serialized_descriptor);
+	free(descriptor->devices_removable);
+	free(descriptor);
+
+	//finish
+
+	dprintf(1,"[usb_hub] hub info created");
+
+	return result;
+}
+
+int usb_add_hub_device(device_t *dev) {
+	dprintf(1, "add_hub_device(handle=%d)", (int) dev->handle);
+	dprintf(1,"[usb_hub] hub device");
+
+	/*
+	 * We are some (probably deeply nested) hub.
+	 * Thus, assign our own operations and explore already
+	 * connected devices.
+	 */
+	dev->ops = &hub_device_ops;
+
+	//create the hub structure
+	//get hc connection
+	int hc = usb_drv_hc_connect_auto(dev, 0);
+	if (hc < 0) {
+		return hc;
+	}
+
+	usb_hub_info_t * hub_info = usb_create_hub_info(dev, hc);
+	int port;
+	int opResult;
+	usb_device_request_setup_packet_t request;
+	usb_target_t target;
+	target.address = hub_info->usb_device->address;
+	target.endpoint = 0;
+
+	//get configuration descriptor
+	// this is not fully correct - there are more configurations
+	// and all should be checked
+	usb_standard_device_descriptor_t std_descriptor;
+	opResult = usb_drv_req_get_device_descriptor(hc, target.address,
+    &std_descriptor);
+	if(opResult!=EOK){
+		dprintf(1,"[usb_hub] could not get device descriptor, %d",opResult);
+		return opResult;
+	}
+	dprintf(1,"[usb_hub] hub has %d configurations",std_descriptor.configuration_count);
+	if(std_descriptor.configuration_count<1){
+		dprintf(1,"[usb_hub] THERE ARE NO CONFIGURATIONS AVAILABLE");
+	}
+	/// \TODO check other configurations
+	usb_standard_configuration_descriptor_t config_descriptor;
+	opResult = usb_drv_req_get_bare_configuration_descriptor(hc,
+        target.address, 0,
+        &config_descriptor);
+	if(opResult!=EOK){
+		dprintf(1,"[usb_hub] could not get configuration descriptor, %d",opResult);
+		return opResult;
+	}
+	//set configuration
+	request.request_type = 0;
+	request.request = USB_DEVREQ_SET_CONFIGURATION;
+	request.index=0;
+	request.length=0;
+	request.value_high=0;
+	request.value_low = config_descriptor.configuration_number;
+	opResult = usb_drv_sync_control_write(hc, target, &request, NULL, 0);
+	if (opResult != EOK) {
+		dprintf(1,"[usb_hub]something went wrong when setting hub`s configuration, %d", opResult);
+	}
+
+	for (port = 1; port < hub_info->port_count+1; ++port) {
+		usb_hub_set_power_port_request(&request, port);
+		opResult = usb_drv_sync_control_write(hc, target, &request, NULL, 0);
+		dprintf(1,"[usb_hub] powering port %d",port);
+		if (opResult != EOK) {
+			dprintf(1,"[usb_hub]something went wrong when setting hub`s %dth port", port);
+		}
+	}
+	//ports powered, hub seems to be enabled
+
+	ipc_hangup(hc);
+
+	//add the hub to list
+	futex_down(&usb_hub_list_lock);
+	usb_lst_append(&usb_hub_list, hub_info);
+	futex_up(&usb_hub_list_lock);
+
+	dprintf(1,"[usb_hub] hub info added to list");
+	//(void)hub_info;
+	usb_hub_check_hub_changes();
+
+	
+
+	dprintf(1,"[usb_hub] hub dev added");
+	dprintf(1,"\taddress %d, has %d ports ",
+			hub_info->usb_device->address,
+			hub_info->port_count);
+	dprintf(1,"\tused configuration %d",config_descriptor.configuration_number);
+
+	return EOK;
+	//return ENOTSUP;
+}
+
+
+
+//*********************************************
+//
+//  hub driver code, main loop
+//
+//*********************************************
+
+/**
+ * convenience function for releasing default address and writing debug info
+ * (these few lines are used too often to be written again and again)
+ * @param hc
+ * @return
+ */
+inline static int usb_hub_release_default_address(int hc){
+	int opResult;
+	dprintf(1,"[usb_hub] releasing default address");
+	opResult = usb_drv_release_default_address(hc);
+	if (opResult != EOK) {
+		dprintf(1,"[usb_hub] failed to release default address");
+	}
+	return opResult;
+}
+
+/**
+ * reset the port with new device and reserve the default address
+ * @param hc
+ * @param port
+ * @param target
+ */
+static void usb_hub_init_add_device(int hc, uint16_t port, usb_target_t target) {
+	usb_device_request_setup_packet_t request;
+	int opResult;
+	dprintf(1,"[usb_hub] some connection changed");
+	//get default address
+	opResult = usb_drv_reserve_default_address(hc);
+	if (opResult != EOK) {
+		dprintf(1,"[usb_hub] cannot assign default address, it is probably used");
+		return;
+	}
+	//reset port
+	usb_hub_set_reset_port_request(&request, port);
+	opResult = usb_drv_sync_control_write(
+			hc, target,
+			&request,
+			NULL, 0
+			);
+	if (opResult != EOK) {
+		dprintf(1,"[usb_hub] something went wrong when reseting a port");
+		usb_hub_release_default_address(hc);
+	}
+}
+
+/**
+ * finalize adding new device after port reset
+ * @param hc
+ * @param port
+ * @param target
+ */
+static void usb_hub_finalize_add_device( usb_hub_info_t * hub,
+		int hc, uint16_t port, usb_target_t target) {
+
+	int opResult;
+	dprintf(1,"[usb_hub] finalizing add device");
+	opResult = usb_hub_clear_port_feature(hc, target.address,
+	    port, USB_HUB_FEATURE_C_PORT_RESET);
+	if (opResult != EOK) {
+		dprintf(1,"[usb_hub] failed to clear port reset feature");
+		usb_hub_release_default_address(hc);
+		return;
+	}
+
+	/* Request address at from host controller. */
+	usb_address_t new_device_address = usb_drv_request_address(hc);
+	if (new_device_address < 0) {
+		dprintf(1,"[usb_hub] failed to get free USB address");
+		opResult = new_device_address;
+		usb_hub_release_default_address(hc);
+		return;
+	}
+	dprintf(1,"[usb_hub] setting new address");
+	opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
+	    new_device_address);
+
+	if (opResult != EOK) {
+		dprintf(1,"[usb_hub] could not set address for new device");
+		usb_hub_release_default_address(hc);
+		return;
+	}
+
+
+	opResult = usb_hub_release_default_address(hc);
+	if(opResult!=EOK){
+		return;
+	}
+
+	devman_handle_t child_handle;
+	opResult = usb_drv_register_child_in_devman(hc, hub->device,
+            new_device_address, &child_handle);
+	if (opResult != EOK) {
+		dprintf(1,"[usb_hub] could not start driver for new device");
+		return;
+	}
+	hub->attached_devs[port].devman_handle = child_handle;
+	hub->attached_devs[port].address = new_device_address;
+
+	opResult = usb_drv_bind_address(hc, new_device_address, child_handle);
+	if (opResult != EOK) {
+		dprintf(1,"[usb_hub] could not assign address of device in hcd");
+		return;
+	}
+	dprintf(1,"[usb_hub] new device address %d, handle %zu",
+	    new_device_address, child_handle);
+
+}
+
+/**
+ * unregister device address in hc
+ * @param hc
+ * @param port
+ * @param target
+ */
+static void usb_hub_removed_device(
+    usb_hub_info_t * hub, int hc, uint16_t port, usb_target_t target) {
+	//usb_device_request_setup_packet_t request;
+	int opResult;
+	
+	/// \TODO remove device
+
+	hub->attached_devs[port].devman_handle=0;
+	//close address
+	if(hub->attached_devs[port].address!=0){
+		opResult = usb_drv_release_address(hc,hub->attached_devs[port].address);
+		if(opResult != EOK) {
+			dprintf(1,
+					"[usb_hub] could not release address of removed device: %d"
+					,opResult);
+		}
+		hub->attached_devs[port].address = 0;
+	}else{
+		dprintf(1,
+				"[usb_hub] this is strange, disconnected device had no address");
+		//device was disconnected before it`s port was reset - return default address
+		usb_drv_release_default_address(hc);
+	}
+}
+
+/**
+ * process interrupts on given hub port
+ * @param hc
+ * @param port
+ * @param target
+ */
+static void usb_hub_process_interrupt(usb_hub_info_t * hub, int hc,
+        uint16_t port, usb_address_t address) {
+	dprintf(1,"[usb_hub] interrupt at port %d", port);
+	//determine type of change
+	usb_target_t target;
+	target.address=address;
+	target.endpoint=0;
+	usb_port_status_t status;
+	size_t rcvd_size;
+	usb_device_request_setup_packet_t request;
+	int opResult;
+	usb_hub_set_port_status_request(&request, port);
+	//endpoint 0
+
+	opResult = usb_drv_sync_control_read(
+			hc, target,
+			&request,
+			&status, 4, &rcvd_size
+			);
+	if (opResult != EOK) {
+		dprintf(1,"[usb_hub] ERROR: could not get port status");
+		return;
+	}
+	if (rcvd_size != sizeof (usb_port_status_t)) {
+		dprintf(1,"[usb_hub] ERROR: received status has incorrect size");
+		return;
+	}
+	//something connected/disconnected
+	if (usb_port_connect_change(&status)) {
+		opResult = usb_hub_clear_port_feature(hc, target.address,
+		    port, USB_HUB_FEATURE_C_PORT_CONNECTION);
+		// TODO: check opResult
+		if (usb_port_dev_connected(&status)) {
+			dprintf(1,"[usb_hub] some connection changed");
+			usb_hub_init_add_device(hc, port, target);
+		} else {
+			usb_hub_removed_device(hub, hc, port, target);
+		}
+	}
+	//port reset
+	if (usb_port_reset_completed(&status)) {
+		dprintf(1,"[usb_hub] port reset complete");
+		if (usb_port_enabled(&status)) {
+			usb_hub_finalize_add_device(hub, hc, port, target);
+		} else {
+			dprintf(1,"[usb_hub] ERROR: port reset, but port still not enabled");
+		}
+	}
+
+	usb_port_set_connect_change(&status, false);
+	usb_port_set_reset(&status, false);
+	usb_port_set_reset_completed(&status, false);
+	usb_port_set_dev_connected(&status, false);
+	if (status) {
+		dprintf(1,"[usb_hub]there was some unsupported change on port %d",port);
+	}
+	/// \TODO handle other changes
+	/// \TODO debug log for various situations
+
+}
+
+/* Check changes on all known hubs.
+ */
+void usb_hub_check_hub_changes(void) {
+	/*
+	 * Iterate through all hubs.
+	 */
+	usb_general_list_t * lst_item;
+	futex_down(&usb_hub_list_lock);
+	for (lst_item = usb_hub_list.next;
+			lst_item != &usb_hub_list;
+			lst_item = lst_item->next) {
+		futex_up(&usb_hub_list_lock);
+		usb_hub_info_t * hub_info = ((usb_hub_info_t*)lst_item->data);
+		/*
+		 * Check status change pipe of this hub.
+		 */
+
+		usb_target_t target;
+		target.address = hub_info->usb_device->address;
+		target.endpoint = 1;/// \TODO get from endpoint descriptor
+		dprintf(1,"[usb_hub] checking changes for hub at addr %d",
+		    target.address);
+
+		size_t port_count = hub_info->port_count;
+
+		/*
+		 * Connect to respective HC.
+		 */
+		int hc = usb_drv_hc_connect_auto(hub_info->device, 0);
+		if (hc < 0) {
+			continue;
+		}
+
+		/// FIXME: count properly
+		size_t byte_length = ((port_count+1) / 8) + 1;
+
+		void *change_bitmap = malloc(byte_length);
+		size_t actual_size;
+		usb_handle_t handle;
+
+		/*
+		 * Send the request.
+		 */
+		int opResult = usb_drv_async_interrupt_in(hc, target,
+				change_bitmap, byte_length, &actual_size,
+				&handle);
+
+		usb_drv_async_wait_for(handle);
+
+		if (opResult != EOK) {
+			dprintf(1,"[usb_hub] something went wrong while getting status of hub");
+			continue;
+		}
+		unsigned int port;
+		for (port = 1; port < port_count+1; ++port) {
+			bool interrupt =
+					(((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
+			if (interrupt) {
+				usb_hub_process_interrupt(
+				        hub_info, hc, port, hub_info->usb_device->address);
+			}
+		}
+		free(change_bitmap);
+
+		ipc_hangup(hc);
+		futex_down(&usb_hub_list_lock);
+	}
+	futex_up(&usb_hub_list_lock);
+}
+
+
+
+
+
+/**
+ * @}
+ */
Index: uspace/drv/usbhub/usbhub_private.h
===================================================================
--- uspace/drv/usbhub/usbhub_private.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/usbhub/usbhub_private.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -38,10 +38,16 @@
 
 #include "usbhub.h"
+#include "usblist.h"
+
 #include <adt/list.h>
 #include <bool.h>
 #include <driver.h>
+#include <futex.h>
+
 #include <usb/usb.h>
+#include <usb/usbdrv.h>
 #include <usb/classes/hub.h>
 #include <usb/devreq.h>
+#include <usb/debug.h>
 
 //************
@@ -55,49 +61,12 @@
 //************
 //
-// My private list implementation; I did not like the original helenos list
-//
-// This one does not depend on the structure of stored data
+// convenience debug printf
 //
 //************
-
-/** general list structure */
-
-
-typedef struct usb_general_list{
-	void * data;
-	struct usb_general_list * prev, * next;
-} usb_general_list_t;
-
-/** create head of usb general list */
-usb_general_list_t * usb_lst_create(void);
-
-/** initialize head of usb general list */
-void usb_lst_init(usb_general_list_t * lst);
-
-
-/** is the list empty? */
-static inline bool usb_lst_empty(usb_general_list_t * lst){
-	return lst?(lst->next==lst):true;
-}
-
-/** append data behind item */
-void usb_lst_append(usb_general_list_t * lst, void * data);
-
-/** prepend data beore item */
-void usb_lst_prepend(usb_general_list_t * lst, void * data);
-
-/** remove list item from list */
-void usb_lst_remove(usb_general_list_t * item);
-
-/** get data o specified type from list item */
-#define usb_lst_get_data(item, type)  (type *) (item->data)
-
-/** get usb_hub_info_t data from list item */
-static inline usb_hub_info_t * usb_hub_lst_get_data(usb_general_list_t * item) {
-	return usb_lst_get_data(item,usb_hub_info_t);
-}
+#define dprintf(level, format, ...) \
+	usb_dprintf(NAME, (level), format "\n", ##__VA_ARGS__)
 
 /**
- * @brief create hub structure instance
+ * create hub structure instance
  *
  * Set the address and port count information most importantly.
@@ -112,7 +81,10 @@
 extern usb_general_list_t usb_hub_list;
 
+/** lock for hub list*/
+extern futex_t usb_hub_list_lock;
+
 
 /**
- * @brief perform complete control read transaction
+ * perform complete control read transaction
  *
  * manages all three steps of transaction: setup, read and finalize
@@ -132,7 +104,7 @@
 
 /**
- * @brief perform complete control write transaction
+ * perform complete control write transaction
  *
- * maanges all three steps of transaction: setup, write and finalize
+ * manages all three steps of transaction: setup, write and finalize
  * @param phone
  * @param target
@@ -147,21 +119,4 @@
     void * sent_buffer, size_t sent_size
 );
-
-
-/**
- * set the device request to be a set address request
- * @param request
- * @param addr
- * \TODO this will be obsolete see usb/dev_req.h
- */
-static inline void usb_hub_set_set_address_request(
-usb_device_request_setup_packet_t * request, uint16_t addr
-){
-	request->index = 0;
-	request->request_type = 0;/// \TODO this is not very nice sollution, we ned constant
-	request->request = USB_DEVREQ_SET_ADDRESS;
-	request->value = addr;
-	request->length = 0;
-}
 
 /**
Index: uspace/drv/usbhub/usblist.c
===================================================================
--- uspace/drv/usbhub/usblist.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/drv/usbhub/usblist.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup usb hub driver
+ * @{
+ */
+/** @file
+ * @brief usblist implementation
+ */
+#include <sys/types.h>
+
+#include "usbhub_private.h"
+
+
+usb_general_list_t * usb_lst_create(void) {
+	usb_general_list_t* result = usb_new(usb_general_list_t);
+	usb_lst_init(result);
+	return result;
+}
+
+void usb_lst_init(usb_general_list_t * lst) {
+	lst->prev = lst;
+	lst->next = lst;
+	lst->data = NULL;
+}
+
+void usb_lst_prepend(usb_general_list_t* item, void* data) {
+	usb_general_list_t* appended = usb_new(usb_general_list_t);
+	appended->data = data;
+	appended->next = item;
+	appended->prev = item->prev;
+	item->prev->next = appended;
+	item->prev = appended;
+}
+
+void usb_lst_append(usb_general_list_t* item, void* data) {
+	usb_general_list_t* appended = usb_new(usb_general_list_t);
+	appended->data = data;
+	appended->next = item->next;
+	appended->prev = item;
+	item->next->prev = appended;
+	item->next = appended;
+}
+
+void usb_lst_remove(usb_general_list_t* item) {
+	item->next->prev = item->prev;
+	item->prev->next = item->next;
+}
+
+
+
+/**
+ * @}
+ */
+
+
Index: uspace/drv/usbhub/usblist.h
===================================================================
--- uspace/drv/usbhub/usblist.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/drv/usbhub/usblist.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef USBLIST_H
+#define	USBLIST_H
+/** @addtogroup usb hub driver
+ * @{
+ */
+/** @file
+ * @brief HC driver and hub driver.
+ *
+ * My private list implementation; I did not like the original helenos list.
+ * This one does not depend on the structure of stored data and has
+ * much simpler and more straight-forward semantics.
+ */
+
+/**
+ * general list structure
+ */
+typedef struct usb_general_list{
+	void * data;
+	struct usb_general_list * prev, * next;
+} usb_general_list_t;
+
+/** create head of usb general list */
+usb_general_list_t * usb_lst_create(void);
+
+/** initialize head of usb general list */
+void usb_lst_init(usb_general_list_t * lst);
+
+
+/** is the list empty? */
+static inline bool usb_lst_empty(usb_general_list_t * lst){
+	return lst?(lst->next==lst):true;
+}
+
+/** append data behind item */
+void usb_lst_append(usb_general_list_t * lst, void * data);
+
+/** prepend data beore item */
+void usb_lst_prepend(usb_general_list_t * lst, void * data);
+
+/** remove list item from list */
+void usb_lst_remove(usb_general_list_t * item);
+
+/** get data o specified type from list item */
+#define usb_lst_get_data(item, type)  (type *) (item->data)
+
+/** get usb_hub_info_t data from list item */
+static inline usb_hub_info_t * usb_hub_lst_get_data(usb_general_list_t * item) {
+	return usb_lst_get_data(item,usb_hub_info_t);
+}
+
+
+/**
+ * @}
+ */
+
+
+
+#endif	/* USBLIST_H */
+
Index: uspace/drv/usbhub/utils.c
===================================================================
--- uspace/drv/usbhub/utils.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/usbhub/utils.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -31,5 +31,5 @@
  */
 /** @file
- * @brief Hub driver.
+ * @brief various utilities
  */
 #include <driver.h>
@@ -90,5 +90,5 @@
 
 	if (sdescriptor[1] != USB_DESCTYPE_HUB) {
-		printf("[usb_hub] wrong descriptor %x\n",sdescriptor[1]);
+		dprintf(1,"[usb_hub] wrong descriptor %x\n",sdescriptor[1]);
 		return NULL;
 	}
@@ -102,5 +102,6 @@
 	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);
+	size_t var_size = result->ports_count / 8 + ((result->ports_count % 8 > 0)
+			? 1 : 0);
 	result->devices_removable = (uint8_t*) malloc(var_size);
 	//printf("[usb_hub] getting removable devices data \n");
@@ -198,599 +199,7 @@
 }
 
-//list implementation
-
-usb_general_list_t * usb_lst_create(void) {
-	usb_general_list_t* result = usb_new(usb_general_list_t);
-	usb_lst_init(result);
-	return result;
-}
-
-void usb_lst_init(usb_general_list_t * lst) {
-	lst->prev = lst;
-	lst->next = lst;
-	lst->data = NULL;
-}
-
-void usb_lst_prepend(usb_general_list_t* item, void* data) {
-	usb_general_list_t* appended = usb_new(usb_general_list_t);
-	appended->data = data;
-	appended->next = item;
-	appended->prev = item->prev;
-	item->prev->next = appended;
-	item->prev = appended;
-}
-
-void usb_lst_append(usb_general_list_t* item, void* data) {
-	usb_general_list_t* appended = usb_new(usb_general_list_t);
-	appended->data = data;
-	appended->next = item->next;
-	appended->prev = item;
-	item->next->prev = appended;
-	item->next = appended;
-}
-
-void usb_lst_remove(usb_general_list_t* item) {
-	item->next->prev = item->prev;
-	item->prev->next = item->next;
-}
-
-static void usb_hub_test_port_status(void) {
-	printf("[usb_hub] -------------port status test---------\n");
-	usb_port_status_t status = 0;
-
-	//printf("original status %d (should be 0)\n",(uint32_t)status);
-	usb_port_set_bit(&status, 1, 1);
-	//printf("%d =?= 2\n",(uint32_t)status);
-	if (status != 2) {
-		printf("[usb_port_status] test failed: wrong set of bit 1\n");
-		return;
-	}
-	usb_port_set_bit(&status, 3, 1);
-	if (status != 10) {
-		printf("[usb_port_status] test failed: wrong set of bit 3\n");
-		return;
-	}
-
-	usb_port_set_bit(&status, 15, 1);
-	if (status != 10 + (1 << 15)) {
-		printf("[usb_port_status] test failed: wrong set of bit 15\n");
-		return;
-	}
-	usb_port_set_bit(&status, 1, 0);
-	if (status != 8 + (1 << 15)) {
-		printf("[usb_port_status] test failed: wrong unset of bit 1\n");
-		return;
-	}
-	int i;
-	for (i = 0; i < 32; ++i) {
-		if (i == 3 || i == 15) {
-			if (!usb_port_get_bit(&status, i)) {
-				printf("[usb_port_status] test failed: wrong bit at %d\n", i);
-			}
-		} else {
-			if (usb_port_get_bit(&status, i)) {
-				printf("[usb_port_status] test failed: wrong bit at %d\n", i);
-			}
-		}
-	}
-
-	printf("test ok\n");
-
-
-	//printf("%d =?= 10\n",(uint32_t)status);
-
-	//printf("this should be 0: %d \n",usb_port_get_bit(&status,0));
-	//printf("this should be 1: %d \n",usb_port_get_bit(&status,1));
-	//printf("this should be 0: %d \n",usb_port_get_bit(&status,2));
-	//printf("this should be 1: %d \n",usb_port_get_bit(&status,3));
-	//printf("this should be 0: %d \n",usb_port_get_bit(&status,4));
-
-
-
-
-}
-
-//*********************************************
-//
-//  hub driver code, initialization
-//
-//*********************************************
-
-usb_hub_info_t * usb_create_hub_info(device_t * device, int hc) {
-	usb_hub_info_t* result = usb_new(usb_hub_info_t);
-	//result->device = device;
-	result->port_count = -1;
-	/// \TODO is this correct? is the device stored?
-	result->device = device;
-
-
-	//printf("[usb_hub] phone to hc = %d\n", hc);
-	if (hc < 0) {
-		return result;
-	}
-	//get some hub info
-	usb_address_t addr = usb_drv_get_my_address(hc, device);
-	printf("[usb_hub] addres of newly created hub = %d\n", addr);
-	/*if(addr<0){
-		//return result;
-		
-	}*/
-
-	result->usb_device = usb_new(usb_hcd_attached_device_info_t);
-	result->usb_device->address = addr;
-
-	// get hub descriptor
-	usb_target_t target;
-	target.address = addr;
-	target.endpoint = 0;
-	usb_device_request_setup_packet_t request;
-	//printf("[usb_hub] creating descriptor request\n");
-	usb_hub_set_descriptor_request(&request);
-
-	//printf("[usb_hub] creating serialized descriptor\n");
-	void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
-	usb_hub_descriptor_t * descriptor;
-	size_t received_size;
-	int opResult;
-	//printf("[usb_hub] starting control transaction\n");
-	opResult = usb_drv_sync_control_read(
-			hc, target, &request, serialized_descriptor,
-			USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
-	if (opResult != EOK) {
-		printf("[usb_hub] failed when receiving hub descriptor, badcode = %d\n",opResult);
-		///\TODO memory leak will occur here!
-		return result;
-	}
-	//printf("[usb_hub] deserializing descriptor\n");
-	descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
-	if(descriptor==NULL){
-		printf("[usb_hub] could not deserialize descriptor \n");
-		result->port_count = 1;///\TODO this code is only for debug!!!
-		return result;
-	}
-	//printf("[usb_hub] setting port count to %d\n",descriptor->ports_count);
-	result->port_count = descriptor->ports_count;
-	result->attached_devs = (usb_hub_attached_device_t*)
-	    malloc((result->port_count+1) * sizeof(usb_hub_attached_device_t));
-	int i;
-	for(i=0;i<result->port_count+1;++i){
-		result->attached_devs[i].devman_handle=0;
-		result->attached_devs[i].address=0;
-	}
-	//printf("[usb_hub] freeing data\n");
-	free(serialized_descriptor);
-	free(descriptor->devices_removable);
-	free(descriptor);
-
-	//finish
-
-	printf("[usb_hub] hub info created\n");
-
-	return result;
-}
-
-int usb_add_hub_device(device_t *dev) {
-	printf(NAME ": add_hub_device(handle=%d)\n", (int) dev->handle);
-	printf("[usb_hub] hub device\n");
-
-	/*
-	 * We are some (probably deeply nested) hub.
-	 * Thus, assign our own operations and explore already
-	 * connected devices.
-	 */
-
-	//create the hub structure
-	//get hc connection
-	/// \TODO correct params
-	int hc = usb_drv_hc_connect(dev, 0);
-
-	usb_hub_info_t * hub_info = usb_create_hub_info(dev, hc);
-	int port;
-	int opResult;
-	usb_device_request_setup_packet_t request;
-	usb_target_t target;
-	target.address = hub_info->usb_device->address;
-	target.endpoint = 0;
-
-	//get configuration descriptor
-	// this is not fully correct - there are more configurations
-	// and all should be checked
-	usb_standard_device_descriptor_t std_descriptor;
-	opResult = usb_drv_req_get_device_descriptor(hc, target.address,
-    &std_descriptor);
-	if(opResult!=EOK){
-		printf("[usb_hub] could not get device descriptor, %d\n",opResult);
-		return 1;///\TODO some proper error code needed
-	}
-	printf("[usb_hub] hub has %d configurations\n",std_descriptor.configuration_count);
-	if(std_descriptor.configuration_count<1){
-		printf("[usb_hub] THERE ARE NO CONFIGURATIONS AVAILABLE\n");
-	}
-	usb_standard_configuration_descriptor_t config_descriptor;
-	opResult = usb_drv_req_get_bare_configuration_descriptor(hc,
-        target.address, 0,
-        &config_descriptor);
-	if(opResult!=EOK){
-		printf("[usb_hub] could not get configuration descriptor, %d\n",opResult);
-		return 1;///\TODO some proper error code needed
-	}
-	//set configuration
-	request.request_type = 0;
-	request.request = USB_DEVREQ_SET_CONFIGURATION;
-	request.index=0;
-	request.length=0;
-	request.value_high=0;
-	request.value_low = config_descriptor.configuration_number;
-	opResult = usb_drv_sync_control_write(hc, target, &request, NULL, 0);
-	if (opResult != EOK) {
-		printf("[usb_hub]something went wrong when setting hub`s configuration, %d\n", opResult);
-	}
-
-
-	for (port = 1; port < hub_info->port_count+1; ++port) {
-		usb_hub_set_power_port_request(&request, port);
-		opResult = usb_drv_sync_control_write(hc, target, &request, NULL, 0);
-		printf("[usb_hub] powering port %d\n",port);
-		if (opResult != EOK) {
-			printf("[usb_hub]something went wrong when setting hub`s %dth port\n", port);
-		}
-	}
-	//ports powered, hub seems to be enabled
-	
-
-	ipc_hangup(hc);
-
-	//add the hub to list
-	usb_lst_append(&usb_hub_list, hub_info);
-	printf("[usb_hub] hub info added to list\n");
-	//(void)hub_info;
-	usb_hub_check_hub_changes();
-
-	/// \TODO start the check loop, if not already started...
-
-	//this is just a test for port status bitmap type
-	usb_hub_test_port_status();
-
-	printf("[usb_hub] hub dev added\n");
-	printf("\taddress %d, has %d ports \n",
-			hub_info->usb_device->address,
-			hub_info->port_count);
-	printf("\tused configuration %d\n",config_descriptor.configuration_number);
-
-	return EOK;
-	//return ENOTSUP;
-}
-
-//*********************************************
-//
-//  hub driver code, main loop
-//
-//*********************************************
-
-/**
- * reset the port with new device and reserve the default address
- * @param hc
- * @param port
- * @param target
- */
-static void usb_hub_init_add_device(int hc, uint16_t port, usb_target_t target) {
-	usb_device_request_setup_packet_t request;
-	int opResult;
-	printf("[usb_hub] some connection changed\n");
-	//get default address
-	opResult = usb_drv_reserve_default_address(hc);
-	if (opResult != EOK) {
-		printf("[usb_hub] cannot assign default address, it is probably used\n");
-		return;
-	}
-	//reset port
-	usb_hub_set_reset_port_request(&request, port);
-	opResult = usb_drv_sync_control_write(
-			hc, target,
-			&request,
-			NULL, 0
-			);
-	if (opResult != EOK) {
-		//continue;
-		printf("[usb_hub] something went wrong when reseting a port\n");
-	}
-}
-
-/**
- * finalize adding new device after port reset
- * @param hc
- * @param port
- * @param target
- */
-static void usb_hub_finalize_add_device( usb_hub_info_t * hub,
-		int hc, uint16_t port, usb_target_t target) {
-
-	int opResult;
-	printf("[usb_hub] finalizing add device\n");
-	opResult = usb_hub_clear_port_feature(hc, target.address,
-	    port, USB_HUB_FEATURE_C_PORT_RESET);
-	if (opResult != EOK) {
-		goto release;
-	}
-
-	/* Request address at from host controller. */
-	usb_address_t new_device_address = usb_drv_request_address(hc);
-	if (new_device_address < 0) {
-		printf("[usb_hub] failed to get free USB address\n");
-		opResult = new_device_address;
-		goto release;
-	}
-	printf("[usb_hub] setting new address\n");
-	opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
-	    new_device_address);
-
-	if (opResult != EOK) {
-		printf("[usb_hub] could not set address for new device\n");
-		goto release;
-	}
-
-release:
-	printf("[usb_hub] releasing default address\n");
-	usb_drv_release_default_address(hc);
-	if (opResult != EOK) {
-		return;
-	}
-
-	devman_handle_t child_handle;
-	opResult = usb_drv_register_child_in_devman(hc, hub->device,
-            new_device_address, &child_handle);
-	if (opResult != EOK) {
-		printf("[usb_hub] could not start driver for new device \n");
-		return;
-	}
-	hub->attached_devs[port].devman_handle = child_handle;
-	hub->attached_devs[port].address = new_device_address;
-
-	opResult = usb_drv_bind_address(hc, new_device_address, child_handle);
-	if (opResult != EOK) {
-		printf("[usb_hub] could not assign address of device in hcd \n");
-		return;
-	}
-	printf("[usb_hub] new device address %d, handle %zu\n",
-	    new_device_address, child_handle);
-	
-}
-
-/**
- * unregister device address in hc, close the port
- * @param hc
- * @param port
- * @param target
- */
-static void usb_hub_removed_device(
-    usb_hub_info_t * hub, int hc, uint16_t port, usb_target_t target) {
-	//usb_device_request_setup_packet_t request;
-	int opResult;
-	//disable port
-	/*usb_hub_set_disable_port_request(&request, port);
-	opResult = usb_drv_sync_control_write(
-			hc, target,
-			&request,
-			NULL, 0
-			);
-	if (opResult != EOK) {
-		//continue;
-		printf("[usb_hub] something went wrong when disabling a port\n");
-	}*/
-	/// \TODO remove device
-
-	hub->attached_devs[port].devman_handle=0;
-	//close address
-	if(hub->attached_devs[port].address!=0){
-		opResult = usb_drv_release_address(hc,hub->attached_devs[port].address);
-		if(opResult != EOK) {
-			printf("[usb_hub] could not release address of removed device: %d\n",opResult);
-		}
-		hub->attached_devs[port].address = 0;
-	}else{
-		printf("[usb_hub] this is strange, disconnected device had no address\n");
-		//device was disconnected before it`s port was reset - return default address
-		usb_drv_release_default_address(hc);
-	}
-}
-
-/**
- * process interrupts on given hub port
- * @param hc
- * @param port
- * @param target
- */
-static void usb_hub_process_interrupt(usb_hub_info_t * hub, int hc,
-        uint16_t port, usb_address_t address) {
-	printf("[usb_hub] interrupt at port %d\n", port);
-	//determine type of change
-	usb_target_t target;
-	target.address=address;
-	target.endpoint=0;
-	usb_port_status_t status;
-	size_t rcvd_size;
-	usb_device_request_setup_packet_t request;
-	int opResult;
-	usb_hub_set_port_status_request(&request, port);
-	//endpoint 0
-
-	opResult = usb_drv_sync_control_read(
-			hc, target,
-			&request,
-			&status, 4, &rcvd_size
-			);
-	if (opResult != EOK) {
-		printf("[usb_hub] ERROR: could not get port status\n");
-		return;
-	}
-	if (rcvd_size != sizeof (usb_port_status_t)) {
-		printf("[usb_hub] ERROR: received status has incorrect size\n");
-		return;
-	}
-	//something connected/disconnected
-	if (usb_port_connect_change(&status)) {
-		opResult = usb_hub_clear_port_feature(hc, target.address,
-		    port, USB_HUB_FEATURE_C_PORT_CONNECTION);
-		// TODO: check opResult
-		if (usb_port_dev_connected(&status)) {
-			printf("[usb_hub] some connection changed\n");
-			usb_hub_init_add_device(hc, port, target);
-		} else {
-			usb_hub_removed_device(hub, hc, port, target);
-		}
-	}
-	//port reset
-	if (usb_port_reset_completed(&status)) {
-		printf("[usb_hub] port reset complete\n");
-		if (usb_port_enabled(&status)) {
-			usb_hub_finalize_add_device(hub, hc, port, target);
-		} else {
-			printf("[usb_hub] ERROR: port reset, but port still not enabled\n");
-		}
-	}
-
-	usb_port_set_connect_change(&status, false);
-	usb_port_set_reset(&status, false);
-	usb_port_set_reset_completed(&status, false);
-	usb_port_set_dev_connected(&status, false);
-	if (status) {
-		printf("[usb_hub]there was some unsupported change on port %d\n",port);
-	}
-	/// \TODO handle other changes
-	/// \TODO debug log for various situations
-
-
-
-	/*
-	//configure device
-	usb_drv_reserve_default_address(hc);
-
-	usb_address_t new_device_address = usb_drv_request_address(hc);
-
-
-	usb_drv_release_default_address(hc);
-	 * */
-}
-
-/** Check changes on all known hubs.
- */
-void usb_hub_check_hub_changes(void) {
-	/*
-	 * Iterate through all hubs.
-	 */
-	usb_general_list_t * lst_item;
-	for (lst_item = usb_hub_list.next;
-			lst_item != &usb_hub_list;
-			lst_item = lst_item->next) {
-		usb_hub_info_t * hub_info = ((usb_hub_info_t*)lst_item->data);
-		/*
-		 * Check status change pipe of this hub.
-		 */
-
-		usb_target_t target;
-		target.address = hub_info->usb_device->address;
-		target.endpoint = 1;/// \TODO get from endpoint descriptor
-		printf("[usb_hub] checking changes for hub at addr %d\n",
-		    target.address);
-
-		size_t port_count = hub_info->port_count;
-
-		/*
-		 * Connect to respective HC.
-		 */
-		int hc = usb_drv_hc_connect(hub_info->device, 0);
-		if (hc < 0) {
-			continue;
-		}
-
-		// FIXME: count properly
-		size_t byte_length = ((port_count+1) / 8) + 1;
-
-		void *change_bitmap = malloc(byte_length);
-		size_t actual_size;
-		usb_handle_t handle;
-
-		/*
-		 * Send the request.
-		 */
-		int opResult = usb_drv_async_interrupt_in(hc, target,
-				change_bitmap, byte_length, &actual_size,
-				&handle);
-
-		usb_drv_async_wait_for(handle);
-
-		if (opResult != EOK) {
-			printf("[usb_hub] something went wrong while getting status of hub\n");
-			continue;
-		}
-		unsigned int port;
-		for (port = 1; port < port_count+1; ++port) {
-			bool interrupt = (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
-			if (interrupt) {
-				usb_hub_process_interrupt(
-				        hub_info, hc, port, hub_info->usb_device->address);
-			}
-		}
-
-
-		/*
-		 * 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 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/usbkbd/main.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -29,4 +29,7 @@
 #include <driver.h>
 #include <ipc/driver.h>
+#include <ipc/kbd.h>
+#include <io/keycode.h>
+#include <io/console.h>
 #include <errno.h>
 #include <fibril.h>
@@ -41,4 +44,49 @@
 #define GUESSED_POLL_ENDPOINT 1
 
+static void default_connection_handler(device_t *, ipc_callid_t, ipc_call_t *);
+static device_ops_t keyboard_ops = {
+	.default_handler = default_connection_handler
+};
+
+static int console_callback_phone = -1;
+
+/** Default handler for IPC methods not handled by DDF.
+ *
+ * @param dev Device handling the call.
+ * @param icallid Call id.
+ * @param icall Call data.
+ */
+void default_connection_handler(device_t *dev,
+    ipc_callid_t icallid, ipc_call_t *icall)
+{
+	sysarg_t method = IPC_GET_IMETHOD(*icall);
+
+	if (method == IPC_M_CONNECT_TO_ME) {
+		int callback = IPC_GET_ARG5(*icall);
+
+		if (console_callback_phone != -1) {
+			ipc_answer_0(icallid, ELIMIT);
+			return;
+		}
+
+		console_callback_phone = callback;
+		ipc_answer_0(icallid, EOK);
+		return;
+	}
+
+	ipc_answer_0(icallid, EINVAL);
+}
+
+static void send_key(int key, int type, wchar_t c) {
+	async_msg_4(console_callback_phone, KBD_EVENT, type, key,
+	    KM_NUM_LOCK, c);
+}
+
+static void send_alnum(int key, wchar_t c) {
+	printf(NAME ": sending key '%lc' to console\n", (wint_t) c);
+	send_key(key, KEY_PRESS, c);
+	send_key(key, KEY_RELEASE, c);
+}
+
 /*
  * Callbacks for parser
@@ -142,5 +190,5 @@
 	// get phone to my HC and save it as my parent's phone
 	// TODO: maybe not a good idea if DDF will use parent_phone
-	kbd_dev->device->parent_phone = usb_drv_hc_connect(dev, 0);
+	kbd_dev->device->parent_phone = usb_drv_hc_connect_auto(dev, 0);
 
 	kbd_dev->address = usb_drv_get_my_address(dev->parent_phone,
@@ -183,4 +231,13 @@
 		sizeof(usb_hid_report_in_callbacks_t));
 	callbacks->keyboard = usbkbd_process_keycodes;
+
+	if (console_callback_phone != -1) {
+		static size_t counter = 0;
+		counter++;
+		if (counter > 3) {
+			counter = 0;
+			send_alnum(KC_A, L'a');
+		}
+	}
 
 	usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks, 
@@ -268,5 +325,5 @@
 	 * Not supported yet, skip..
 	 */
-//	int phone = usb_drv_hc_connect(dev, 0);
+//	int phone = usb_drv_hc_connect_auto(dev, 0);
 //	if (phone < 0) {
 //		/*
@@ -289,4 +346,8 @@
 	fibril_add_ready(fid);
 
+	dev->ops = &keyboard_ops;
+
+	add_device_to_class(dev, "keyboard");
+
 	/*
 	 * Hurrah, device is initialized.
Index: uspace/drv/vhc/hcd.c
===================================================================
--- uspace/drv/vhc/hcd.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/vhc/hcd.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -46,4 +46,5 @@
 
 #include <usb/usb.h>
+#include <usb_iface.h>
 #include "vhcd.h"
 #include "hc.h"
@@ -52,6 +53,20 @@
 #include "conn.h"
 
+static int usb_iface_get_hc_handle(device_t *dev, devman_handle_t *handle)
+{
+	/* This shall be called only for VHC device. */
+	assert(dev->parent == NULL);
+
+	*handle = dev->handle;
+	return EOK;
+}
+
+static usb_iface_t hc_usb_iface = {
+	.get_hc_handle = usb_iface_get_hc_handle
+};
+
 static device_ops_t vhc_ops = {
 	.interfaces[USBHC_DEV_IFACE] = &vhc_iface,
+	.interfaces[USB_DEV_IFACE] = &hc_usb_iface,
 	.default_handler = default_connection_handler
 };
@@ -70,9 +85,4 @@
 
 	dev->ops = &vhc_ops;
-
-	/*
-	 * Initialize address management.
-	 */
-	address_init();
 
 	/*
@@ -108,6 +118,17 @@
 	printf(NAME ": virtual USB host controller driver.\n");
 
+	/*
+	 * Initialize address management.
+	 */
+	address_init();
+
+	/*
+	 * Run the transfer scheduler.
+	 */
 	hc_manager();
 
+	/*
+	 * We are also a driver within devman framework.
+	 */
 	return driver_main(&vhc_driver);
 }
Index: uspace/drv/vhc/hub.c
===================================================================
--- uspace/drv/vhc/hub.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/drv/vhc/hub.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -79,5 +79,5 @@
 	device_t *hc_dev = (device_t *) arg;
 
-	int hc = usb_drv_hc_connect(hc_dev, IPC_FLAG_BLOCKING);
+	int hc = usb_drv_hc_connect(hc_dev, hc_dev->handle, IPC_FLAG_BLOCKING);
 	if (hc < 0) {
 		printf(NAME ": failed to register root hub\n");
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -87,5 +87,5 @@
 	generic/ipc.c \
 	generic/async.c \
-	generic/async_rel.c \
+	generic/async_sess.c \
 	generic/loader.c \
 	generic/getopt.c \
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/generic/async.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -749,4 +749,6 @@
 		return ENOMEM;
 	}
+
+	_async_sess_init();
 	
 	return 0;
Index: pace/lib/c/generic/async_rel.c
===================================================================
--- uspace/lib/c/generic/async_rel.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,307 +1,0 @@
-/*
- * Copyright (c) 2010 Jakub Jermar
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libc
- * @{
- */
-/** @file
- */
-
-/**
- * This file implements simple relation support for the async framework.
- *
- * By the term "relation", we mean a logical data path between a client and a
- * server over which the client can send multiple, potentially blocking,
- * requests to the server.
- *
- * Clients and servers are naturally connected using IPC phones, thus an IPC
- * phone represents a connection between a client and a server. In one
- * connection, there can be many relations.
- *
- * Relations are useful in situations in which there is only one IPC connection
- * between the client and the server, but the client wants to be able to make
- * multiple parallel requests. Using only a single phone and without any other
- * provisions, all requests would have to be serialized. On the other hand, the
- * client can make as many parallel requests as there are active relations.
- *
- * There are several possible implementations of relations. This implementation
- * uses additional phones to represent relations. Using phones both for the
- * primary connection and also for its relations has several advantages:
- *
- * - to make a series of requests over a relation, the client can continue to
- *   use the existing async framework APIs
- * - the server supports relations by the virtue of spawning a new connection
- *   fibril, just as it does for every new connection even without relations
- * - the implementation is pretty straightforward; a very naive implementation
- *   would be to make each request using a fresh phone (that is what we have
- *   done in the past); a slightly better approach would be to cache connected
- *   phones so that they can be reused by a later relation within the same
- *   connection (that is what this implementation does)
- *
- * The main disadvantages of using phones to represent relations are:
- *
- * - if there are too many relations (even cached ones), the task may hit its
- *   limit on the maximum number of connected phones, which could prevent the
- *   task from making new IPC connections to other tasks
- * - if there are too many IPC connections already, it may be impossible to
- *   create a relation by connecting a new phone thanks to the task's limit on
- *   the maximum number of connected phones
- *
- * These problems can be helped by increasing the limit on the maximum number of
- * connected phones to some reasonable value and by limiting the number of
- * phones cached to some fraction of this limit.
- *
- * The cache itself has a mechanism to close some number of unused phones if a
- * new phone cannot be connected, but the outter world currently does not have a
- * way to ask the phone cache to shrink.
- *
- * To minimize the confusion stemming from the fact that we use phones for two
- * things (the primary IPC connection and also each relation), this file makes
- * the distinction by using the term 'key phone' for the former and 'relation
- * phone' for the latter. Under the hood, all phones remain equal, of course.
- *
- * There is a small inefficiency in that the cache repeatedly allocates and
- * deallocated the rel_node_t structures when in fact it could keep the
- * allocated structures around and reuse them later. But such a solution would
- * be effectively implementing a poor man's slab allocator while it would be
- * better to have the slab allocator ported to uspace so that everyone could
- * benefit from it.
- */
-
-#include <async_rel.h>
-#include <ipc/ipc.h>
-#include <fibril_synch.h>
-#include <adt/list.h>
-#include <adt/hash_table.h>
-#include <malloc.h>
-#include <errno.h>
-#include <assert.h>
-
-#define KEY_NODE_HASH_BUCKETS	16
-
-typedef struct {
-	link_t link;		/**< Key node hash table link. */
-	int key_phone;		/**< The phone serving as a key. */
-	link_t rel_head;	/**< List of open relation phones. */
-} key_node_t;
-
-typedef struct {
-	link_t rel_link;	/**< Link for the list of relation phones. */
-	link_t global_link;	/**< Link for the global list of phones. */
-	int rel_phone;		/**< Connected relation phone. */
-} rel_node_t;
-
-/**
- * Mutex protecting the global_rel_head list and the key_node_hash hash table.
- */
-static fibril_mutex_t async_rel_mutex;
-
-/**
- * List of all currently unused relation phones.
- */
-static LIST_INITIALIZE(global_rel_head);
-
-/**
- * Hash table containing lists of available relation phones for all key
- * phones.
- */
-static hash_table_t key_node_hash;
-
-static hash_index_t kn_hash(unsigned long *key)
-{
-	return *key % KEY_NODE_HASH_BUCKETS;
-}
-
-static int kn_compare(unsigned long *key, hash_count_t keys, link_t *item)
-{
-	key_node_t *knp = hash_table_get_instance(item, key_node_t, link);
-
-	return *key == (unsigned long) knp->key_phone;
-}
-
-static void kn_remove_callback(link_t *item)
-{
-}
-
-static hash_table_operations_t key_node_hash_ops = {
-	.hash = kn_hash,
-	.compare = kn_compare,
-	.remove_callback = kn_remove_callback
-};
-
-/** Initialize the async_rel subsystem.
- *
- * Needs to be called prior to any other interface in this file.
- */
-int async_rel_init(void)
-{
-	fibril_mutex_initialize(&async_rel_mutex);
-	list_initialize(&global_rel_head);
-	return hash_table_create(&key_node_hash, KEY_NODE_HASH_BUCKETS, 1,
-	    &key_node_hash_ops);
-}
-
-static void key_node_initialize(key_node_t *knp)
-{
-	link_initialize(&knp->link);
-	knp->key_phone = -1;
-	list_initialize(&knp->rel_head);
-}
-
-static void rel_node_initialize(rel_node_t *rnp)
-{
-	link_initialize(&rnp->rel_link);
-	link_initialize(&rnp->global_link);
-	rnp->rel_phone = -1;
-}
-
-/** Create a new relation for a connection represented by a key phone.
- *
- * @param key_phone	Phone representing the connection.
- * @return		Phone representing the new relation or a negative error
- *			code.
- */
-int async_relation_create(int key_phone)
-{
-	unsigned long key = (unsigned long) key_phone;
-	link_t *lnk;
-	key_node_t *knp;
-	rel_node_t *rnp;
-	int rel_phone;
-
-	fibril_mutex_lock(&async_rel_mutex);
-	lnk = hash_table_find(&key_node_hash, &key);
-	if (!lnk) {
-		/*
-		 * The key node was not found in the hash table. Try to allocate
-		 * and hash in a new one.
-		 */
-		knp = (key_node_t *) malloc(sizeof(key_node_t));
-		if (!knp) {
-			/*
-			 * As a possible improvement, we could make a one-time
-			 * attempt to create a phone without trying to add the
-			 * key node into the hash.
-			 */
-			fibril_mutex_unlock(&async_rel_mutex);
-			return ENOMEM;
-		}
-		key_node_initialize(knp);
-		knp->key_phone = key_phone;
-		hash_table_insert(&key_node_hash, &key, &knp->link);
-	} else {
-		/*
-		 * Found the key node.
-		 */
-		knp = hash_table_get_instance(lnk, key_node_t, link);
-	}
-
-	if (!list_empty(&knp->rel_head)) {
-		/*
-		 * There are available relation phones for the key phone.
-		 */
-		rnp = list_get_instance(knp->rel_head.next, rel_node_t,
-		    rel_link);
-		list_remove(&rnp->rel_link);
-		list_remove(&rnp->global_link);
-		
-		rel_phone = rnp->rel_phone;
-		free(rnp);
-	} else {
-		/*
-		 * There are no available relation phones for the key phone.
-		 * Make a one-time attempt to connect a new relation phone.
-		 */
-retry:
-		rel_phone = ipc_connect_me_to(key_phone, 0, 0, 0);
-		if (rel_phone >= 0) {
-			/* success, do nothing */
-		} else if (!list_empty(&global_rel_head)) {
-			/*
-			 * We did not manage to connect a new phone. But we can
-			 * try to hangup some currently unused phones and try
-			 * again.
-			 */
-			rnp = list_get_instance(global_rel_head.next,
-			    rel_node_t, global_link);
-			list_remove(&rnp->global_link);
-			list_remove(&rnp->rel_link);
-			rel_phone = rnp->rel_phone;
-			free(rnp);
-			ipc_hangup(rel_phone);
-			goto retry;
-		} else {
-			/*
-			 * This is unfortunate. We failed both to find a cached
-			 * phone or to create a new one even after cleaning up
-			 * the cache. This is most likely due to too many key
-			 * phones being kept connected.
-			 */
-			rel_phone = ELIMIT;
-		}
-	}
-
-	fibril_mutex_unlock(&async_rel_mutex);
-	return rel_phone;
-}
-
-/** Destroy a relation.
- *
- * @param key_phone	Phone representing the connection.
- * @param rel_phone	Phone representing the relation within the connection.
- */
-void async_relation_destroy(int key_phone, int rel_phone)
-{
-	unsigned long key = (unsigned long) key_phone;
-	key_node_t *knp;
-	rel_node_t *rnp;
-	link_t *lnk;
-
-	fibril_mutex_lock(&async_rel_mutex);
-	lnk = hash_table_find(&key_node_hash, &key);
-	assert(lnk);
-	knp = hash_table_get_instance(lnk, key_node_t, link);
-	rnp = (rel_node_t *) malloc(sizeof(rel_node_t));
-	if (!rnp) {
-		/*
-		 * Being unable to remember the connected relation phone here
-		 * means that we simply hangup.
-		 */
-		fibril_mutex_unlock(&async_rel_mutex);
-		ipc_hangup(rel_phone);
-		return;
-	}
-	rel_node_initialize(rnp);
-	rnp->rel_phone = rel_phone;
-	list_append(&rnp->rel_link, &knp->rel_head);
-	list_append(&rnp->global_link, &global_rel_head);
-	fibril_mutex_unlock(&async_rel_mutex);
-}
-
-/** @}
- */
Index: uspace/lib/c/generic/async_sess.c
===================================================================
--- uspace/lib/c/generic/async_sess.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/lib/c/generic/async_sess.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2010 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+/**
+ * This file implements simple session support for the async framework.
+ *
+ * By the term 'session', we mean a logical data path between a client and a
+ * server over which the client can perform multiple concurrent exchanges.
+ * Each exchange consists of one or more requests (IPC calls) which can
+ * be potentially blocking.
+ *
+ * Clients and servers are naturally connected using IPC phones, thus an IPC
+ * phone represents a session between a client and a server. In one
+ * session, there can be many outstanding exchanges. In the current
+ * implementation each concurrent exchanges takes place over a different
+ * connection (there can be at most one active exchage per connection).
+ *
+ * Sessions make it useful for a client or client API to support concurrent
+ * requests, independent of the actual implementation. Sessions provide
+ * an abstract interface to concurrent IPC communication. This is especially
+ * useful for client API stubs that aim to be reentrant (i.e. that allow
+ * themselves to be called from different fibrils and threads concurrently).
+ *
+ * There are several possible implementations of sessions. This implementation
+ * uses additional phones to represent sessions. Using phones both for the
+ * session and also for its exchages/connections has several advantages:
+ *
+ * - to make a series of exchanges over a session, the client can continue to
+ *   use the existing async framework APIs
+ * - the server supports sessions by the virtue of spawning a new connection
+ *   fibril, just as it does for every new connection even without sessions
+ * - the implementation is pretty straightforward; a very naive implementation
+ *   would be to make each exchage using a fresh phone (that is what we
+ *   have done in the past); a slightly better approach would be to cache
+ *   connections so that they can be reused by a later exchange within
+ *   the same session (that is what this implementation does)
+ *
+ * The main disadvantages of using phones to represent sessions are:
+ *
+ * - if there are too many exchanges (even cached ones), the task may hit its
+ *   limit on the maximum number of connected phones, which could prevent the
+ *   task from making new IPC connections to other tasks
+ * - if there are too many IPC connections already, it may be impossible to
+ *   create an exchange by connecting a new phone thanks to the task's limit on
+ *   the maximum number of connected phones
+ *
+ * These problems can be alleviated by increasing the limit on the maximum
+ * number of connected phones to some reasonable value and by limiting the number
+ * of cached connections to some fraction of this limit.
+ *
+ * The cache itself has a mechanism to close some number of unused phones if a
+ * new phone cannot be connected, but the outer world currently does not have a
+ * way to ask the phone cache to shrink.
+ *
+ * To minimize the confusion stemming from the fact that we use phones for two
+ * things (the session itself and also one for each data connection), this file
+ * makes the distinction by using the term 'session phone' for the former and
+ * 'data phone' for the latter. Under the hood, all phones remain equal,
+ * of course.
+ *
+ * There is a small inefficiency in that the cache repeatedly allocates and
+ * deallocates the conn_node_t structures when in fact it could keep the
+ * allocated structures around and reuse them later. But such a solution would
+ * be effectively implementing a poor man's slab allocator while it would be
+ * better to have the slab allocator ported to uspace so that everyone could
+ * benefit from it.
+ */
+
+#include <async_sess.h>
+#include <ipc/ipc.h>
+#include <fibril_synch.h>
+#include <adt/list.h>
+#include <adt/hash_table.h>
+#include <malloc.h>
+#include <errno.h>
+#include <assert.h>
+
+/** An inactive open connection. */
+typedef struct {
+	link_t sess_link;	/**< Link for the session list of inactive connections. */
+	link_t global_link;	/**< Link for the global list of inactive connectinos. */
+	int data_phone;		/**< Connected data phone. */
+} conn_node_t;
+
+/**
+ * Mutex protecting the inactive_conn_head list and the session list.
+ */
+static fibril_mutex_t async_sess_mutex;
+
+/**
+ * List of all currently inactive connections.
+ */
+static LIST_INITIALIZE(inactive_conn_head);
+
+/**
+ * List of all open sessions.
+ */
+static LIST_INITIALIZE(session_list_head);
+
+/** Initialize the async_sess subsystem.
+ *
+ * Needs to be called prior to any other interface in this file.
+ */
+void _async_sess_init(void)
+{
+	fibril_mutex_initialize(&async_sess_mutex);
+	list_initialize(&inactive_conn_head);
+	list_initialize(&session_list_head);
+}
+
+/** Create a session.
+ *
+ * Session is a logical datapath from a client task to a server task.
+ * One session can accomodate multiple concurrent exchanges. Here
+ * @a phone is a phone connected to the desired server task.
+ *
+ * This function always succeeds.
+ *
+ * @param sess	Session structure provided by caller, will be filled in.
+ * @param phone	Phone connected to the desired server task.
+ */
+void async_session_create(async_sess_t *sess, int phone)
+{
+	sess->sess_phone = phone;
+	list_initialize(&sess->conn_head);
+	
+	/* Add to list of sessions. */
+	fibril_mutex_lock(&async_sess_mutex);
+	list_append(&sess->sess_link, &session_list_head);
+	fibril_mutex_unlock(&async_sess_mutex);
+}
+
+/** Destroy a session.
+ *
+ * Dismantle session structure @a sess and release any resources (connections)
+ * held by the session.
+ *
+ * @param sess	Session to destroy.
+ */
+void async_session_destroy(async_sess_t *sess)
+{
+	conn_node_t *conn;
+
+	/* Remove from list of sessions. */
+	fibril_mutex_lock(&async_sess_mutex);
+	list_remove(&sess->sess_link);
+	fibril_mutex_unlock(&async_sess_mutex);
+
+	/* We did not connect the phone so we do not hang it up either. */
+	sess->sess_phone = -1;
+
+	/* Tear down all data connections. */
+	while (!list_empty(&sess->conn_head)) {
+		conn = list_get_instance(sess->conn_head.next, conn_node_t,
+		    sess_link);
+
+		list_remove(&conn->sess_link);
+		list_remove(&conn->global_link);
+		
+		ipc_hangup(conn->data_phone);
+		free(conn);
+	}
+}
+
+static void conn_node_initialize(conn_node_t *conn)
+{
+	link_initialize(&conn->sess_link);
+	link_initialize(&conn->global_link);
+	conn->data_phone = -1;
+}
+
+/** Start new exchange in a session.
+ *
+ * @param sess_phone	Session.
+ * @return		Phone representing the new exchange or a negative error
+ *			code.
+ */
+int async_exchange_begin(async_sess_t *sess)
+{
+	conn_node_t *conn;
+	int data_phone;
+
+	fibril_mutex_lock(&async_sess_mutex);
+
+	if (!list_empty(&sess->conn_head)) {
+		/*
+		 * There are inactive connections in the session.
+		 */
+		conn = list_get_instance(sess->conn_head.next, conn_node_t,
+		    sess_link);
+		list_remove(&conn->sess_link);
+		list_remove(&conn->global_link);
+		
+		data_phone = conn->data_phone;
+		free(conn);
+	} else {
+		/*
+		 * There are no available connections in the session.
+		 * Make a one-time attempt to connect a new data phone.
+		 */
+retry:
+		data_phone = async_connect_me_to(sess->sess_phone, 0, 0, 0);
+		if (data_phone >= 0) {
+			/* success, do nothing */
+		} else if (!list_empty(&inactive_conn_head)) {
+			/*
+			 * We did not manage to connect a new phone. But we can
+			 * try to close some of the currently inactive
+			 * connections in other sessions and try again.
+			 */
+			conn = list_get_instance(inactive_conn_head.next,
+			    conn_node_t, global_link);
+			list_remove(&conn->global_link);
+			list_remove(&conn->sess_link);
+			data_phone = conn->data_phone;
+			free(conn);
+			ipc_hangup(data_phone);
+			goto retry;
+		} else {
+			/*
+			 * This is unfortunate. We failed both to find a cached
+			 * connection or to create a new one even after cleaning up
+			 * the cache. This is most likely due to too many
+			 * open sessions (connected session phones).
+			 */
+			data_phone = ELIMIT;
+		}
+	}
+
+	fibril_mutex_unlock(&async_sess_mutex);
+	return data_phone;
+}
+
+/** Finish an exchange.
+ *
+ * @param sess		Session.
+ * @param data_phone	Phone representing the exchange within the session.
+ */
+void async_exchange_end(async_sess_t *sess, int data_phone)
+{
+	conn_node_t *conn;
+
+	fibril_mutex_lock(&async_sess_mutex);
+	conn = (conn_node_t *) malloc(sizeof(conn_node_t));
+	if (!conn) {
+		/*
+		 * Being unable to remember the connected data phone here
+		 * means that we simply hang up.
+		 */
+		fibril_mutex_unlock(&async_sess_mutex);
+		ipc_hangup(data_phone);
+		return;
+	}
+
+	conn_node_initialize(conn);
+	conn->data_phone = data_phone;
+	list_append(&conn->sess_link, &sess->conn_head);
+	list_append(&conn->global_link, &inactive_conn_head);
+	fibril_mutex_unlock(&async_sess_mutex);
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/device/hw_res.c
===================================================================
--- uspace/lib/c/generic/device/hw_res.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/generic/device/hw_res.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -38,27 +38,25 @@
 #include <malloc.h>
 
-bool get_hw_resources(int dev_phone, hw_resource_list_t *hw_resources)
+int get_hw_resources(int dev_phone, hw_resource_list_t *hw_resources)
 {
 	sysarg_t count = 0;
 	int rc = async_req_1_1(dev_phone, DEV_IFACE_ID(HW_RES_DEV_IFACE), GET_RESOURCE_LIST, &count);
 	hw_resources->count = count;
-	if (EOK != rc) {
-		return false;
-	}
+	if (rc != EOK)
+		return rc;
 	
 	size_t size = count * sizeof(hw_resource_t);
 	hw_resources->resources = (hw_resource_t *)malloc(size);
-	if (NULL == hw_resources->resources) {
-		return false;
-	}
+	if (!hw_resources->resources)
+		return ENOMEM;
 	
 	rc = async_data_read_start(dev_phone, hw_resources->resources, size);
-	if (EOK != rc) {
+	if (rc != EOK) {
 		free(hw_resources->resources);
 		hw_resources->resources = NULL;
-		return false;
+		return rc;
 	}
 	 	 
-	return true;	 
+	return EOK;
 }
 
Index: uspace/lib/c/generic/devmap.c
===================================================================
--- uspace/lib/c/generic/devmap.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/generic/devmap.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -127,5 +127,54 @@
 /** Register new device.
  *
- * @param namespace Namespace name.
+ * The @p interface is used when forwarding connection to the driver.
+ * If not 0, the first argument is the interface and the second argument
+ * is the devmap handle of the device.
+ * When the interface is zero (default), the first argument is directly
+ * the handle (to ensure backward compatibility).
+ *
+ * @param fqdn Fully qualified device name.
+ * @param[out] handle Handle to the created instance of device.
+ * @param interface Interface when forwarding.
+ *
+ */
+int devmap_device_register_with_iface(const char *fqdn,
+    devmap_handle_t *handle, sysarg_t interface)
+{
+	int phone = devmap_get_phone(DEVMAP_DRIVER, IPC_FLAG_BLOCKING);
+	
+	if (phone < 0)
+		return phone;
+	
+	async_serialize_start();
+	
+	ipc_call_t answer;
+	aid_t req = async_send_2(phone, DEVMAP_DEVICE_REGISTER, interface, 0,
+	    &answer);
+	
+	sysarg_t retval = async_data_write_start(phone, fqdn, str_size(fqdn));
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		async_serialize_end();
+		return retval;
+	}
+	
+	async_wait_for(req, &retval);
+	
+	async_serialize_end();
+	
+	if (retval != EOK) {
+		if (handle != NULL)
+			*handle = -1;
+		return retval;
+	}
+	
+	if (handle != NULL)
+		*handle = (devmap_handle_t) IPC_GET_ARG1(answer);
+	
+	return retval;
+}
+
+/** Register new device.
+ *
  * @param fqdn      Fully qualified device name.
  * @param handle    Output: Handle to the created instance of device.
@@ -134,37 +183,7 @@
 int devmap_device_register(const char *fqdn, devmap_handle_t *handle)
 {
-	int phone = devmap_get_phone(DEVMAP_DRIVER, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return phone;
-	
-	async_serialize_start();
-	
-	ipc_call_t answer;
-	aid_t req = async_send_2(phone, DEVMAP_DEVICE_REGISTER, 0, 0,
-	    &answer);
-	
-	sysarg_t retval = async_data_write_start(phone, fqdn, str_size(fqdn));
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
-		return retval;
-	}
-	
-	async_wait_for(req, &retval);
-	
-	async_serialize_end();
-	
-	if (retval != EOK) {
-		if (handle != NULL)
-			*handle = -1;
-		return retval;
-	}
-	
-	if (handle != NULL)
-		*handle = (devmap_handle_t) IPC_GET_ARG1(answer);
-	
-	return retval;
-}
+	return devmap_device_register_with_iface(fqdn, handle, 0);
+}
+
 
 int devmap_device_get_handle(const char *fqdn, devmap_handle_t *handle, unsigned int flags)
@@ -260,8 +279,8 @@
 	
 	if (flags & IPC_FLAG_BLOCKING) {
-		phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAP,
+		phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAP,
 		    DEVMAP_CONNECT_TO_DEVICE, handle);
 	} else {
-		phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
+		phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
 		    DEVMAP_CONNECT_TO_DEVICE, handle);
 	}
Index: uspace/lib/c/generic/fibril_synch.c
===================================================================
--- uspace/lib/c/generic/fibril_synch.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/generic/fibril_synch.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -139,5 +139,4 @@
 static void _fibril_mutex_unlock_unsafe(fibril_mutex_t *fm)
 {
-	assert(fm->counter <= 0);
 	if (fm->counter++ < 0) {
 		link_t *tmp;
@@ -165,7 +164,20 @@
 void fibril_mutex_unlock(fibril_mutex_t *fm)
 {
+	assert(fibril_mutex_is_locked(fm));
 	futex_down(&async_futex);
 	_fibril_mutex_unlock_unsafe(fm);
 	futex_up(&async_futex);
+}
+
+bool fibril_mutex_is_locked(fibril_mutex_t *fm)
+{
+	bool locked = false;
+	
+	futex_down(&async_futex);
+	if (fm->counter <= 0) 
+		locked = true;
+	futex_up(&async_futex);
+	
+	return locked;
 }
 
@@ -230,5 +242,4 @@
 {
 	futex_down(&async_futex);
-	assert(frw->readers || (frw->writers == 1));
 	if (frw->readers) {
 		if (--frw->readers) {
@@ -296,4 +307,5 @@
 void fibril_rwlock_read_unlock(fibril_rwlock_t *frw)
 {
+	assert(fibril_rwlock_is_read_locked(frw));
 	_fibril_rwlock_common_unlock(frw);
 }
@@ -301,5 +313,38 @@
 void fibril_rwlock_write_unlock(fibril_rwlock_t *frw)
 {
+	assert(fibril_rwlock_is_write_locked(frw));
 	_fibril_rwlock_common_unlock(frw);
+}
+
+bool fibril_rwlock_is_read_locked(fibril_rwlock_t *frw)
+{
+	bool locked = false;
+
+	futex_down(&async_futex);
+	if (frw->readers)
+		locked = true;
+	futex_up(&async_futex);
+
+	return locked;
+}
+
+bool fibril_rwlock_is_write_locked(fibril_rwlock_t *frw)
+{
+	bool locked = false;
+
+	futex_down(&async_futex);
+	if (frw->writers) {
+		assert(frw->writers == 1);
+		locked = true;
+	}
+	futex_up(&async_futex);
+
+	return locked;
+}
+
+bool fibril_rwlock_is_locked(fibril_rwlock_t *frw)
+{
+	return fibril_rwlock_is_read_locked(frw) ||
+	    fibril_rwlock_is_write_locked(frw);
 }
 
@@ -314,4 +359,6 @@
 {
 	awaiter_t wdata;
+
+	assert(fibril_mutex_is_locked(fm));
 
 	if (timeout < 0)
Index: uspace/lib/c/generic/libc.c
===================================================================
--- uspace/lib/c/generic/libc.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/generic/libc.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -50,5 +50,4 @@
 #include <ipc/ipc.h>
 #include <async.h>
-#include <async_rel.h>
 #include <as.h>
 #include <loader/pcb.h>
@@ -66,5 +65,4 @@
 	__heap_init();
 	__async_init();
-	(void) async_rel_init();
 	fibril_t *fibril = fibril_setup();
 	__tcb_set(fibril->tcb);
Index: uspace/lib/c/generic/net/icmp_api.c
===================================================================
--- uspace/lib/c/generic/net/icmp_api.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/generic/net/icmp_api.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -89,5 +89,5 @@
 	    tos, (sysarg_t) dont_fragment, NULL);
 
-	// send the address
+	/* Send the address */
 	async_data_write_start(icmp_phone, addr, (size_t) addrlen);
 
Index: uspace/lib/c/generic/net/inet.c
===================================================================
--- uspace/lib/c/generic/net/inet.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/generic/net/inet.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -64,9 +64,9 @@
 	switch (family) {
 	case AF_INET:
-		// check the output buffer size
+		/* Check output buffer size */
 		if (length < INET_ADDRSTRLEN)
 			return ENOMEM;
 			
-		// fill the buffer with the IPv4 address
+		/* Fill buffer with IPv4 address */
 		snprintf(address, length, "%hhu.%hhu.%hhu.%hhu",
 		    data[0], data[1], data[2], data[3]);
@@ -75,9 +75,9 @@
 
 	case AF_INET6:
-		// check the output buffer size
+		/* Check output buffer size */
 		if (length < INET6_ADDRSTRLEN)
 			return ENOMEM;
 		
-		// fill the buffer with the IPv6 address
+		/* Fill buffer with IPv6 address */
 		snprintf(address, length,
 		    "%hhx%hhx:%hhx%hhx:%hhx%hhx:%hhx%hhx:%hhx%hhx:%hhx%hhx:"
@@ -124,5 +124,5 @@
 		return EINVAL;
 
-	// set the processing parameters
+	/* Set processing parameters */
 	switch (family) {
 	case AF_INET:
@@ -142,5 +142,5 @@
 	}
 
-	// erase if no address
+	/* Erase if no address */
 	if (!address) {
 		bzero(data, count);
@@ -148,28 +148,30 @@
 	}
 
-	// process the string from the beginning
+	/* Process string from the beginning */
 	next = address;
 	index = 0;
 	do {
-		// if the actual character is set
+		/* If the actual character is set */
 		if (next && *next) {
 
-			// if not on the first character
+			/* If not on the first character */
 			if (index) {
-				// move to the next character
+				/* Move to the next character */
 				++next;
 			}
 
-			// parse the actual integral value
+			/* Parse the actual integral value */
 			value = strtoul(next, &last, base);
-			// remember the last problematic character
-			// should be either '.' or ':' but is ignored to be more
-			// generic
+			/*
+			 * Remember the last problematic character
+			 * should be either '.' or ':' but is ignored to be
+			 * more generic
+			 */
 			next = last;
 
-			// fill the address data byte by byte
+			/* Fill the address data byte by byte */
 			shift = bytes - 1;
 			do {
-				// like little endian
+				/* like little endian */
 				data[index + shift] = value;
 				value >>= 8;
@@ -178,5 +180,5 @@
 			index += bytes;
 		} else {
-			// erase the rest of the address
+			/* Erase the rest of the address */
 			bzero(data + index, count - index);
 			return EOK;
Index: uspace/lib/c/generic/net/modules.c
===================================================================
--- uspace/lib/c/generic/net/modules.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/generic/net/modules.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -63,5 +63,5 @@
     int answer_count)
 {
-	// choose the most efficient answer function
+	/* Choose the most efficient answer function */
 	if (answer || (!answer_count)) {
 		switch (answer_count) {
@@ -178,5 +178,5 @@
 	int phone;
 
-	// if no timeout is set
+	/* If no timeout is set */
 	if (timeout <= 0)
 		return async_connect_me_to_blocking(PHONE_NS, need, 0, 0);
@@ -187,53 +187,13 @@
 			return phone;
 
-		// end if no time is left
+		/* Abort if no time is left */
 		if (timeout <= 0)
 			return ETIMEOUT;
 
-		// wait the minimum of the module wait time and the timeout
+		/* Wait the minimum of the module wait time and the timeout */
 		usleep((timeout <= MODULE_WAIT_TIME) ?
 		    timeout : MODULE_WAIT_TIME);
 		timeout -= MODULE_WAIT_TIME;
 	}
-}
-
-/** Receives data from the other party.
- *
- * The received data buffer is allocated and returned.
- *
- * @param[out] data	The data buffer to be filled.
- * @param[out] length	The buffer length.
- * @return		EOK on success.
- * @return		EBADMEM if the data or the length parameter is NULL.
- * @return		EINVAL if the client does not send data.
- * @return		ENOMEM if there is not enough memory left.
- * @return		Other error codes as defined for the
- *			async_data_write_finalize() function.
- */
-int data_receive(void **data, size_t *length)
-{
-	ipc_callid_t callid;
-	int rc;
-
-	if (!data || !length)
-		return EBADMEM;
-
-	// fetch the request
-	if (!async_data_write_receive(&callid, length))
-		return EINVAL;
-
-	// allocate the buffer
-	*data = malloc(*length);
-	if (!*data)
-		return ENOMEM;
-
-	// fetch the data
-	rc = async_data_write_finalize(callid, *data, *length);
-	if (rc != EOK) {
-		free(data);
-		return rc;
-	}
-
-	return EOK;
 }
 
@@ -254,9 +214,9 @@
 	ipc_callid_t callid;
 
-	// fetch the request
+	/* Fetch the request */
 	if (!async_data_read_receive(&callid, &length))
 		return EINVAL;
 
-	// check the requested data size
+	/* Check the requested data size */
 	if (length < data_length) {
 		async_data_read_finalize(callid, data, length);
@@ -264,5 +224,5 @@
 	}
 
-	// send the data
+	/* Send the data */
 	return async_data_read_finalize(callid, data, data_length);
 }
@@ -282,5 +242,5 @@
 	if (answer) {
 		IPC_SET_RETVAL(*answer, 0);
-		// just to be precize
+		/* Just to be precise */
 		IPC_SET_IMETHOD(*answer, 0);
 		IPC_SET_ARG1(*answer, 0);
Index: uspace/lib/c/generic/net/packet.c
===================================================================
--- uspace/lib/c/generic/net/packet.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/generic/net/packet.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -191,5 +191,5 @@
 	}
 	gpm_destroy(&pm_globals.packet_map);
-	// leave locked
+	/* leave locked */
 }
 
Index: uspace/lib/c/generic/net/socket_client.c
===================================================================
--- uspace/lib/c/generic/net/socket_client.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/generic/net/socket_client.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -220,5 +220,5 @@
 		fibril_rwlock_read_lock(&socket_globals.lock);
 
-		// find the socket
+		/* Find the socket */
 		socket = sockets_find(socket_get_sockets(),
 		    SOCKET_GET_SOCKET_ID(call));
@@ -232,10 +232,10 @@
 		case NET_SOCKET_RECEIVED:
 			fibril_mutex_lock(&socket->receive_lock);
-			// push the number of received packet fragments
+			/* Push the number of received packet fragments */
 			rc = dyn_fifo_push(&socket->received,
 			    SOCKET_GET_DATA_FRAGMENTS(call),
 			    SOCKET_MAX_RECEIVED_SIZE);
 			if (rc == EOK) {
-				// signal the received packet
+				/* Signal the received packet */
 				fibril_condvar_signal(&socket->receive_signal);
 			}
@@ -244,10 +244,10 @@
 
 		case NET_SOCKET_ACCEPTED:
-			// push the new socket identifier
+			/* Push the new socket identifier */
 			fibril_mutex_lock(&socket->accept_lock);
 			rc = dyn_fifo_push(&socket->accepted, 1,
 			    SOCKET_MAX_ACCEPTED_SIZE);
 			if (rc == EOK) {
-				// signal the accepted socket
+				/* Signal the accepted socket */
 				fibril_condvar_signal(&socket->accept_signal);
 			}
@@ -264,5 +264,5 @@
 			fibril_rwlock_write_lock(&socket->sending_lock);
 
-			// set the data fragment size
+			/* Set the data fragment size */
 			socket->data_fragment_size =
 			    SOCKET_GET_DATA_FRAGMENT_SIZE(call);
@@ -342,5 +342,5 @@
 			socket_id = 1;
 			++count;
-		// only this branch for last_id
+		/* Only this branch for last_id */
 		} else {
 			if (socket_id < INT_MAX) {
@@ -408,5 +408,5 @@
 	int rc;
 
-	// find the appropriate service
+	/* Find the appropriate service */
 	switch (domain) {
 	case PF_INET:
@@ -457,5 +457,5 @@
 		return phone;
 
-	// create a new socket structure
+	/* Create a new socket structure */
 	socket = (socket_t *) malloc(sizeof(socket_t));
 	if (!socket)
@@ -465,5 +465,5 @@
 	fibril_rwlock_write_lock(&socket_globals.lock);
 
-	// request a new socket
+	/* Request a new socket */
 	socket_id = socket_generate_new_id();
 	if (socket_id <= 0) {
@@ -484,7 +484,7 @@
 	socket->header_size = (size_t) header_size;
 
-	// finish the new socket initialization
+	/* Finish the new socket initialization */
 	socket_initialize(socket, socket_id, phone, service);
-	// store the new socket
+	/* Store the new socket */
 	rc = sockets_add(socket_get_sockets(), socket_id, socket);
 
@@ -531,5 +531,5 @@
 	fibril_rwlock_read_lock(&socket_globals.lock);
 
-	// find the socket
+	/* Find the socket */
 	socket = sockets_find(socket_get_sockets(), socket_id);
 	if (!socket) {
@@ -538,8 +538,8 @@
 	}
 
-	// request the message
+	/* Request the message */
 	message_id = async_send_3(socket->phone, message,
 	    (sysarg_t) socket->socket_id, arg2, socket->service, NULL);
-	// send the address
+	/* Send the address */
 	async_data_write_start(socket->phone, data, datalength);
 
@@ -566,5 +566,5 @@
 		return EINVAL;
 
-	// send the address
+	/* Send the address */
 	return socket_send_data(socket_id, NET_SOCKET_BIND, 0, my_addr,
 	    (size_t) addrlen);
@@ -591,5 +591,5 @@
 	fibril_rwlock_read_lock(&socket_globals.lock);
 
-	// find the socket
+	/* Find the socket */
 	socket = sockets_find(socket_get_sockets(), socket_id);
 	if (!socket) {
@@ -598,5 +598,5 @@
 	}
 
-	// request listen backlog change
+	/* Request listen backlog change */
 	result = (int) async_req_3_0(socket->phone, NET_SOCKET_LISTEN,
 	    (sysarg_t) socket->socket_id, (sysarg_t) backlog, socket->service);
@@ -634,5 +634,5 @@
 	fibril_rwlock_write_lock(&socket_globals.lock);
 
-	// find the socket
+	/* Find the socket */
 	socket = sockets_find(socket_get_sockets(), socket_id);
 	if (!socket) {
@@ -643,10 +643,10 @@
 	fibril_mutex_lock(&socket->accept_lock);
 
-	// wait for an accepted socket
+	/* Wait for an accepted socket */
 	++ socket->blocked;
 	while (dyn_fifo_value(&socket->accepted) <= 0) {
 		fibril_rwlock_write_unlock(&socket_globals.lock);
 		fibril_condvar_wait(&socket->accept_signal, &socket->accept_lock);
-		// drop the accept lock to avoid deadlock
+		/* Drop the accept lock to avoid deadlock */
 		fibril_mutex_unlock(&socket->accept_lock);
 		fibril_rwlock_write_lock(&socket_globals.lock);
@@ -655,5 +655,5 @@
 	-- socket->blocked;
 
-	// create a new scoket
+	/* Create a new socket */
 	new_socket = (socket_t *) malloc(sizeof(socket_t));
 	if (!new_socket) {
@@ -681,10 +681,10 @@
 	}
 
-	// request accept
+	/* Request accept */
 	message_id = async_send_5(socket->phone, NET_SOCKET_ACCEPT,
 	    (sysarg_t) socket->socket_id, 0, socket->service, 0,
 	    new_socket->socket_id, &answer);
 
-	// read address
+	/* Read address */
 	ipc_data_read_start(socket->phone, cliaddr, *addrlen);
 	fibril_rwlock_write_unlock(&socket_globals.lock);
@@ -695,12 +695,12 @@
 			result = EINVAL;
 
-		// dequeue the accepted socket if successful
+		/* Dequeue the accepted socket if successful */
 		dyn_fifo_pop(&socket->accepted);
-		// set address length
+		/* Set address length */
 		*addrlen = SOCKET_GET_ADDRESS_LENGTH(answer);
 		new_socket->data_fragment_size =
 		    SOCKET_GET_DATA_FRAGMENT_SIZE(answer);
 	} else if (result == ENOTSOCK) {
-		// empty the queue if no accepted sockets
+		/* Empty the queue if no accepted sockets */
 		while (dyn_fifo_pop(&socket->accepted) > 0)
 			;
@@ -731,5 +731,5 @@
 		return EDESTADDRREQ;
 
-	// send the address
+	/* Send the address */
 	return socket_send_data(socket_id, NET_SOCKET_CONNECT, 0, serv_addr,
 	    addrlen);
@@ -744,5 +744,5 @@
 	int accepted_id;
 
-	// destroy all accepted sockets
+	/* Destroy all accepted sockets */
 	while ((accepted_id = dyn_fifo_pop(&socket->accepted)) >= 0)
 		socket_destroy(sockets_find(socket_get_sockets(), accepted_id));
@@ -780,5 +780,5 @@
 	}
 
-	// request close
+	/* Request close */
 	rc = (int) async_req_3_0(socket->phone, NET_SOCKET_CLOSE,
 	    (sysarg_t) socket->socket_id, 0, socket->service);
@@ -787,5 +787,5 @@
 		return rc;
 	}
-	// free the socket structure
+	/* Free the socket structure */
 	socket_destroy(socket);
 
@@ -833,5 +833,5 @@
 	fibril_rwlock_read_lock(&socket_globals.lock);
 
-	// find socket
+	/* Find socket */
 	socket = sockets_find(socket_get_sockets(), socket_id);
 	if (!socket) {
@@ -842,5 +842,5 @@
 	fibril_rwlock_read_lock(&socket->sending_lock);
 
-	// compute data fragment count
+	/* Compute data fragment count */
 	if (socket->data_fragment_size > 0) {
 		fragments = (datalength + socket->header_size) /
@@ -853,5 +853,5 @@
 	}
 
-	// request send
+	/* Request send */
 	message_id = async_send_5(socket->phone, message,
 	    (sysarg_t) socket->socket_id,
@@ -859,12 +859,12 @@
 	    socket->service, (sysarg_t) flags, fragments, &answer);
 
-	// send the address if given
+	/* Send the address if given */
 	if (!toaddr ||
 	    (async_data_write_start(socket->phone, toaddr, addrlen) == EOK)) {
 		if (fragments == 1) {
-			// send all if only one fragment
+			/* Send all if only one fragment */
 			async_data_write_start(socket->phone, data, datalength);
 		} else {
-			// send the first fragment
+			/* Send the first fragment */
 			async_data_write_start(socket->phone, data,
 			    socket->data_fragment_size - socket->header_size);
@@ -872,5 +872,5 @@
 			    socket->data_fragment_size - socket->header_size;
 	
-			// send the middle fragments
+			/* Send the middle fragments */
 			while (--fragments > 1) {
 				async_data_write_start(socket->phone, data,
@@ -880,5 +880,5 @@
 			}
 
-			// send the last fragment
+			/* Send the last fragment */
 			async_data_write_start(socket->phone, data,
 			    (datalength + socket->header_size) %
@@ -892,5 +892,5 @@
 	    (SOCKET_GET_DATA_FRAGMENT_SIZE(answer) !=
 	    socket->data_fragment_size)) {
-		// set the data fragment size
+		/* Set the data fragment size */
 		socket->data_fragment_size =
 		    SOCKET_GET_DATA_FRAGMENT_SIZE(answer);
@@ -917,5 +917,5 @@
 int send(int socket_id, void *data, size_t datalength, int flags)
 {
-	// without the address
+	/* Without the address */
 	return sendto_core(NET_SOCKET_SEND, socket_id, data, datalength, flags,
 	    NULL, 0);
@@ -950,5 +950,5 @@
 		return EDESTADDRREQ;
 
-	// with the address
+	/* With the address */
 	return sendto_core(NET_SOCKET_SENDTO, socket_id, data, datalength,
 	    flags, toaddr, addrlen);
@@ -966,5 +966,6 @@
  *			read. The actual address length is set. Used only if
  *			fromaddr is not NULL.
- * @return		EOK on success.
+ * @return		Positive received message size in bytes on success.
+ * @return		Zero if no more data (other side closed the connection).
  * @return		ENOTSOCK if the socket is not found.
  * @return		EBADMEM if the data parameter is NULL.
@@ -972,5 +973,5 @@
  * @return		Other error codes as defined for the spcific message.
  */
-static int
+static ssize_t
 recvfrom_core(sysarg_t message, int socket_id, void *data, size_t datalength,
     int flags, struct sockaddr *fromaddr, socklen_t *addrlen)
@@ -984,4 +985,5 @@
 	size_t index;
 	ipc_call_t answer;
+	ssize_t retval;
 
 	if (!data)
@@ -996,5 +998,5 @@
 	fibril_rwlock_read_lock(&socket_globals.lock);
 
-	// find the socket
+	/* Find the socket */
 	socket = sockets_find(socket_get_sockets(), socket_id);
 	if (!socket) {
@@ -1004,12 +1006,12 @@
 
 	fibril_mutex_lock(&socket->receive_lock);
-	// wait for a received packet
+	/* Wait for a received packet */
 	++socket->blocked;
-	while ((result = dyn_fifo_value(&socket->received)) <= 0) {
+	while ((result = dyn_fifo_value(&socket->received)) < 0) {
 		fibril_rwlock_read_unlock(&socket_globals.lock);
 		fibril_condvar_wait(&socket->receive_signal,
 		    &socket->receive_lock);
 
-		// drop the receive lock to avoid deadlock
+		/* Drop the receive lock to avoid deadlock */
 		fibril_mutex_unlock(&socket->receive_lock);
 		fibril_rwlock_read_lock(&socket_globals.lock);
@@ -1019,5 +1021,12 @@
 	fragments = (size_t) result;
 
-	// prepare lengths if more fragments
+	if (fragments == 0) {
+		/* No more data, other side has closed the connection. */
+		fibril_mutex_unlock(&socket->receive_lock);
+		fibril_rwlock_read_unlock(&socket_globals.lock);
+		return 0;
+	}
+
+	/* Prepare lengths if more fragments */
 	if (fragments > 1) {
 		lengths = (size_t *) malloc(sizeof(size_t) * fragments +
@@ -1029,19 +1038,19 @@
 		}
 
-		// request packet data
+		/* Request packet data */
 		message_id = async_send_4(socket->phone, message,
 		    (sysarg_t) socket->socket_id, 0, socket->service,
 		    (sysarg_t) flags, &answer);
 
-		// read the address if desired
+		/* Read the address if desired */
 		if(!fromaddr ||
 		    (async_data_read_start(socket->phone, fromaddr,
 		    *addrlen) == EOK)) {
-			// read the fragment lengths
+			/* Read the fragment lengths */
 			if (async_data_read_start(socket->phone, lengths,
 			    sizeof(int) * (fragments + 1)) == EOK) {
 				if (lengths[fragments] <= datalength) {
 
-					// read all fragments if long enough
+					/* Read all fragments if long enough */
 					for (index = 0; index < fragments;
 					    ++index) {
@@ -1057,15 +1066,15 @@
 
 		free(lengths);
-	} else {
-		// request packet data
+	} else { /* fragments == 1 */
+		/* Request packet data */
 		message_id = async_send_4(socket->phone, message,
 		    (sysarg_t) socket->socket_id, 0, socket->service,
 		    (sysarg_t) flags, &answer);
 
-		// read the address if desired
+		/* Read the address if desired */
 		if (!fromaddr ||
 		    (async_data_read_start(socket->phone, fromaddr,
 		        *addrlen) == EOK)) {
-			// read all if only one fragment
+			/* Read all if only one fragment */
 			async_data_read_start(socket->phone, data, datalength);
 		}
@@ -1075,16 +1084,18 @@
 	result = (int) ipc_result;
 	if (result == EOK) {
-		// dequeue the received packet
+		/* Dequeue the received packet */
 		dyn_fifo_pop(&socket->received);
-		// return read data length
-		result = SOCKET_GET_READ_DATA_LENGTH(answer);
-		// set address length
+		/* Return read data length */
+		retval = SOCKET_GET_READ_DATA_LENGTH(answer);
+		/* Set address length */
 		if (fromaddr && addrlen)
 			*addrlen = SOCKET_GET_ADDRESS_LENGTH(answer);
+	} else {
+		retval = (ssize_t) result;
 	}
 
 	fibril_mutex_unlock(&socket->receive_lock);
 	fibril_rwlock_read_unlock(&socket_globals.lock);
-	return result;
+	return retval;
 }
 
@@ -1095,5 +1106,6 @@
  * @param[in] datalength The data length.
  * @param[in] flags	Various receive flags.
- * @return		EOK on success.
+ * @return		Positive received message size in bytes on success.
+ * @return		Zero if no more data (other side closed the connection).
  * @return		ENOTSOCK if the socket is not found.
  * @return		EBADMEM if the data parameter is NULL.
@@ -1102,7 +1114,7 @@
  *			message.
  */
-int recv(int socket_id, void *data, size_t datalength, int flags)
-{
-	// without the address
+ssize_t recv(int socket_id, void *data, size_t datalength, int flags)
+{
+	/* Without the address */
 	return recvfrom_core(NET_SOCKET_RECV, socket_id, data, datalength,
 	    flags, NULL, NULL);
@@ -1118,5 +1130,6 @@
  * @param[in,out] addrlen The address length. The maximum address length is
  *			read. The actual address length is set.
- * @return		EOK on success.
+ * @return		Positive received message size in bytes on success.
+ * @return		Zero if no more data (other side closed the connection).
  * @return		ENOTSOCK if the socket is not found.
  * @return		EBADMEM if the data or fromaddr parameter is NULL.
@@ -1125,5 +1138,5 @@
  *			message.
  */
-int
+ssize_t
 recvfrom(int socket_id, void *data, size_t datalength, int flags,
     struct sockaddr *fromaddr, socklen_t *addrlen)
@@ -1135,5 +1148,5 @@
 		return NO_DATA;
 
-	// with the address
+	/* With the address */
 	return recvfrom_core(NET_SOCKET_RECVFROM, socket_id, data, datalength,
 	    flags, fromaddr, addrlen);
@@ -1170,5 +1183,5 @@
 	fibril_rwlock_read_lock(&socket_globals.lock);
 
-	// find the socket
+	/* Find the socket */
 	socket = sockets_find(socket_get_sockets(), socket_id);
 	if (!socket) {
@@ -1177,13 +1190,13 @@
 	}
 
-	// request option value
+	/* Request option value */
 	message_id = async_send_3(socket->phone, NET_SOCKET_GETSOCKOPT,
 	    (sysarg_t) socket->socket_id, (sysarg_t) optname, socket->service,
 	    NULL);
 
-	// read the length
+	/* Read the length */
 	if (async_data_read_start(socket->phone, optlen,
 	    sizeof(*optlen)) == EOK) {
-		// read the value
+		/* Read the value */
 		async_data_read_start(socket->phone, value, *optlen);
 	}
@@ -1212,5 +1225,5 @@
     size_t optlen)
 {
-	// send the value
+	/* Send the value */
 	return socket_send_data(socket_id, NET_SOCKET_SETSOCKOPT,
 	    (sysarg_t) optname, value, optlen);
Index: uspace/lib/c/generic/task.c
===================================================================
--- uspace/lib/c/generic/task.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/generic/task.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -65,9 +65,20 @@
  *
  * @return Zero on success or negative error code.
- *
  */
 int task_set_name(const char *name)
 {
 	return __SYSCALL2(SYS_TASK_SET_NAME, (sysarg_t) name, str_size(name));
+}
+
+/** Kill a task.
+ *
+ * @param task_id ID of task to kill.
+ *
+ * @return Zero on success or negative error code.
+ */
+
+int task_kill(task_id_t task_id)
+{
+	return (int) __SYSCALL1(SYS_TASK_KILL, (sysarg_t) &task_id);
 }
 
Index: uspace/lib/c/include/async.h
===================================================================
--- uspace/lib/c/include/async.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/include/async.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -37,4 +37,5 @@
 
 #include <ipc/ipc.h>
+#include <async_sess.h>
 #include <fibril.h>
 #include <sys/time.h>
Index: pace/lib/c/include/async_rel.h
===================================================================
--- uspace/lib/c/include/async_rel.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/*
- * Copyright (c) 2010 Jakub Jermar
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libc
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_ASYNC_REL_H_
-#define LIBC_ASYNC_REL_H_
-
-extern int async_rel_init(void);
-extern int async_relation_create(int);
-extern void async_relation_destroy(int, int);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/include/async_sess.h
===================================================================
--- uspace/lib/c/include/async_sess.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/lib/c/include/async_sess.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_ASYNC_SESS_H_
+#define LIBC_ASYNC_SESS_H_
+
+#include <adt/list.h>
+
+typedef struct {
+	int sess_phone;		/**< Phone for cloning off the connections. */
+	link_t conn_head;	/**< List of open data connections. */
+	link_t sess_link;	/**< Link in global list of open sessions. */
+} async_sess_t;
+
+extern void _async_sess_init(void);
+extern void async_session_create(async_sess_t *, int);
+extern void async_session_destroy(async_sess_t *);
+extern int async_exchange_begin(async_sess_t *);
+extern void async_exchange_end(async_sess_t *, int);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/device/hw_res.h
===================================================================
--- uspace/lib/c/include/device/hw_res.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/include/device/hw_res.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -95,7 +95,6 @@
 
 
-bool get_hw_resources(int dev_phone, hw_resource_list_t *hw_resources);
-
-bool enable_interrupt(int dev_phone);
+extern int get_hw_resources(int, hw_resource_list_t *);
+extern bool enable_interrupt(int);
 
 
Index: uspace/lib/c/include/devmap.h
===================================================================
--- uspace/lib/c/include/devmap.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/include/devmap.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -45,4 +45,5 @@
 extern int devmap_driver_register(const char *, async_client_conn_t);
 extern int devmap_device_register(const char *, devmap_handle_t *);
+extern int devmap_device_register_with_iface(const char *, devmap_handle_t *, sysarg_t);
 
 extern int devmap_device_get_handle(const char *, devmap_handle_t *, unsigned int);
Index: uspace/lib/c/include/fibril_synch.h
===================================================================
--- uspace/lib/c/include/fibril_synch.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/include/fibril_synch.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -105,4 +105,5 @@
 extern bool fibril_mutex_trylock(fibril_mutex_t *);
 extern void fibril_mutex_unlock(fibril_mutex_t *);
+extern bool fibril_mutex_is_locked(fibril_mutex_t *);
 
 extern void fibril_rwlock_initialize(fibril_rwlock_t *);
@@ -111,4 +112,7 @@
 extern void fibril_rwlock_read_unlock(fibril_rwlock_t *);
 extern void fibril_rwlock_write_unlock(fibril_rwlock_t *);
+extern bool fibril_rwlock_is_read_locked(fibril_rwlock_t *);
+extern bool fibril_rwlock_is_write_locked(fibril_rwlock_t *);
+extern bool fibril_rwlock_is_locked(fibril_rwlock_t *);
 
 extern void fibril_condvar_initialize(fibril_condvar_t *);
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -39,4 +39,6 @@
 	CHAR_DEV_IFACE,
 
+	/** Interface provided by any USB device. */
+	USB_DEV_IFACE,
 	/** Interface provided by USB host controller. */
 	USBHC_DEV_IFACE,
Index: uspace/lib/c/include/ipc/devman.h
===================================================================
--- uspace/lib/c/include/ipc/devman.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/include/ipc/devman.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -123,4 +123,5 @@
 	DEVMAN_CLIENT,
 	DEVMAN_CONNECT_TO_DEVICE,
+	DEVMAN_CONNECT_FROM_DEVMAP,
 	DEVMAN_CONNECT_TO_PARENTS_DEVICE
 } devman_interface_t;
Index: uspace/lib/c/include/ipc/kbd.h
===================================================================
--- uspace/lib/c/include/ipc/kbd.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/include/ipc/kbd.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -39,7 +39,8 @@
 
 #include <ipc/ipc.h>
+#include <ipc/dev_iface.h>
 
 typedef enum {
-	KBD_YIELD = IPC_FIRST_USER_METHOD,
+	KBD_YIELD = DEV_FIRST_CUSTOM_METHOD,
 	KBD_RECLAIM
 } kbd_request_t;
Index: uspace/lib/c/include/net/modules.h
===================================================================
--- uspace/lib/c/include/net/modules.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/include/net/modules.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -49,21 +49,4 @@
 #include <sys/time.h>
 
-/** Converts the data length between different types.
- *
- * @param[in] type_from	The source type.
- * @param[in] type_to	The destination type.
- * @param[in] count	The number units of the source type size.
- */
-#define CONVERT_SIZE(type_from, type_to, count) \
-	((sizeof(type_from) / sizeof(type_to)) * (count))
-
-/** Registers the module service at the name server.
- *
- * @param[in] me	The module service.
- * @param[out] phonehash The created phone hash.
- */
-#define REGISTER_ME(me, phonehash) \
-	ipc_connect_to_me(PHONE_NS, (me), 0, 0, (phonehash))
-
 /** Connect to the needed module function type definition.
  *
@@ -80,5 +63,4 @@
 extern int connect_to_service(services_t);
 extern int connect_to_service_timeout(services_t, suseconds_t);
-extern int data_receive(void **, size_t *);
 extern int data_reply(void *, size_t);
 extern void refresh_answer(ipc_call_t *, int *);
Index: uspace/lib/c/include/net/socket.h
===================================================================
--- uspace/lib/c/include/net/socket.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/include/net/socket.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -60,6 +60,6 @@
 extern int sendto(int, const void *, size_t, int, const struct sockaddr *,
     socklen_t);
-extern int recv(int, void *, size_t, int);
-extern int recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
+extern ssize_t recv(int, void *, size_t, int);
+extern ssize_t recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
 extern int getsockopt(int, int, int, void *, size_t *);
 extern int setsockopt(int, int, int, const void *, size_t);
Index: uspace/lib/c/include/task.h
===================================================================
--- uspace/lib/c/include/task.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/c/include/task.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -47,4 +47,6 @@
 extern task_id_t task_get_id(void);
 extern int task_set_name(const char *);
+extern int task_kill(task_id_t);
+
 extern task_id_t task_spawn(const char *, const char *const[], int *);
 extern int task_spawnv(task_id_t *, const char *path, const char *const []);
Index: uspace/lib/drv/Makefile
===================================================================
--- uspace/lib/drv/Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/drv/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -36,4 +36,5 @@
 	generic/dev_iface.c \
 	generic/remote_res.c \
+	generic/remote_usb.c \
 	generic/remote_usbhc.c \
 	generic/remote_char.c
Index: uspace/lib/drv/generic/dev_iface.c
===================================================================
--- uspace/lib/drv/generic/dev_iface.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/drv/generic/dev_iface.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -39,4 +39,5 @@
 #include "remote_res.h"
 #include "remote_char.h"
+#include "remote_usb.h"
 #include "remote_usbhc.h"
 
@@ -45,4 +46,5 @@
 		&remote_res_iface,
 		&remote_char_iface,
+		&remote_usb_iface,
 		&remote_usbhc_iface
 	}
Index: uspace/lib/drv/generic/remote_usb.c
===================================================================
--- uspace/lib/drv/generic/remote_usb.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/lib/drv/generic/remote_usb.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,83 @@
+/*
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#include <ipc/ipc.h>
+#include <async.h>
+#include <errno.h>
+
+#include "usb_iface.h"
+#include "driver.h"
+
+
+static void remote_usb_get_hc_handle(device_t *, void *, ipc_callid_t, ipc_call_t *);
+//static void remote_usb(device_t *, void *, ipc_callid_t, ipc_call_t *);
+
+/** Remote USB interface operations. */
+static remote_iface_func_ptr_t remote_usb_iface_ops [] = {
+	remote_usb_get_hc_handle
+};
+
+/** Remote USB interface structure.
+ */
+remote_iface_t remote_usb_iface = {
+	.method_count = sizeof(remote_usb_iface_ops) /
+	    sizeof(remote_usb_iface_ops[0]),
+	.methods = remote_usb_iface_ops
+};
+
+
+void remote_usb_get_hc_handle(device_t *device, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+
+	if (usb_iface->get_hc_handle == NULL) {
+		ipc_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	devman_handle_t handle;
+	int rc = usb_iface->get_hc_handle(device, &handle);
+	if (rc != EOK) {
+		ipc_answer_0(callid, rc);
+	}
+
+	ipc_answer_1(callid, EOK, (sysarg_t) handle);
+}
+
+
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -59,5 +59,5 @@
 //static void remote_usbhc(device_t *, void *, ipc_callid_t, ipc_call_t *);
 
-/** Remote USB interface operations. */
+/** Remote USB host controller interface operations. */
 static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
 	remote_usbhc_get_address,
@@ -84,5 +84,5 @@
 };
 
-/** Remote USB interface structure.
+/** Remote USB host controller interface structure.
  */
 remote_iface_t remote_usbhc_iface = {
Index: uspace/lib/drv/include/remote_usb.h
===================================================================
--- uspace/lib/drv/include/remote_usb.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/lib/drv/include/remote_usb.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,44 @@
+/*
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_USB_H_
+#define LIBDRV_REMOTE_USB_H_
+
+remote_iface_t remote_usb_iface;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/usb_iface.h
===================================================================
--- uspace/lib/drv/include/usb_iface.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/lib/drv/include/usb_iface.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,63 @@
+/*
+ * 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 libdrv usb
+ * @{
+ */
+/** @file
+ * @brief USB interface definition.
+ */
+
+#ifndef LIBDRV_USB_IFACE_H_
+#define LIBDRV_USB_IFACE_H_
+
+#include "driver.h"
+#include <usb/usb.h>
+typedef enum {
+	/** Tell devman handle of device host controller.
+	 * Parameters:
+	 * - none
+	 * Answer:
+	 * - EOK - request processed without errors
+	 * - ENOTSUP - this indicates invalid USB driver
+	 * Parameters of the answer:
+	 * - devman handle of HC caller is physically connected to
+	 */
+	IPC_M_USB_GET_HOST_CONTROLLER_HANDLE
+} usb_iface_funcs_t;
+
+/** USB device communication interface. */
+typedef struct {
+	int (*get_hc_handle)(device_t *, devman_handle_t *);
+} usb_iface_t;
+
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -31,5 +31,5 @@
  */
 /** @file
- * @brief USB interface definition.
+ * @brief USB host controller interface definition.
  */
 
@@ -226,5 +226,5 @@
     usbhc_iface_transfer_in_callback_t, void *);
 
-/** USB devices communication interface. */
+/** USB host controller communication interface. */
 typedef struct {
 	int (*tell_address)(device_t *, devman_handle_t, usb_address_t *);
Index: uspace/lib/packet/generic/packet_server.c
===================================================================
--- uspace/lib/packet/generic/packet_server.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/packet/generic/packet_server.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -135,6 +135,4 @@
 /** Creates a new packet of dimensions at least as given.
  *
- * Should be used only when the global data are locked.
- *
  * @param[in] length	The total length of the packet, including the header,
  *			the addresses and the data of the packet.
@@ -153,4 +151,6 @@
 	packet_t *packet;
 	int rc;
+
+	assert(fibril_mutex_is_locked(&ps_globals.lock));
 
 	// already locked
@@ -233,6 +233,4 @@
 /** Release the packet and returns it to the appropriate free packet queue.
  *
- * Should be used only when the global data are locked.
- *
  * @param[in] packet	The packet to be released.
  *
@@ -242,4 +240,6 @@
 	int index;
 	int result;
+
+	assert(fibril_mutex_is_locked(&ps_globals.lock));
 
 	for (index = 0; (index < FREE_QUEUES_COUNT - 1) &&
Index: uspace/lib/usb/include/usb/devreq.h
===================================================================
--- uspace/lib/usb/include/usb/devreq.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/usb/include/usb/devreq.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -92,4 +92,6 @@
 int usb_drv_req_get_full_configuration_descriptor(int, usb_address_t, int,
     void *, size_t, size_t *);
+int usb_drv_req_get_descriptor(int, usb_address_t, usb_request_type_t,
+    uint8_t, uint8_t, uint16_t, void *, size_t, size_t *);
 
 
Index: uspace/lib/usb/include/usb/hcdhubd.h
===================================================================
--- uspace/lib/usb/include/usb/hcdhubd.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/usb/include/usb/hcdhubd.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -207,3 +207,8 @@
 int usb_hc_add_child_device(device_t *, const char *, const char *, bool);
 
+
+/**
+ * @}
+ */
+
 #endif
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/usb/include/usb/usb.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -54,4 +54,11 @@
 	USB_DIRECTION_OUT
 } usb_direction_t;
+
+/** USB request type target. */
+typedef enum {
+	USB_REQUEST_TYPE_STANDARD = 0,
+	USB_REQUEST_TYPE_CLASS = 1,
+	USB_REQUEST_TYPE_VENDOR = 2
+} usb_request_type_t;
 
 /** USB transaction outcome. */
Index: uspace/lib/usb/include/usb/usbdrv.h
===================================================================
--- uspace/lib/usb/include/usb/usbdrv.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/usb/include/usb/usbdrv.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -41,5 +41,7 @@
 #include <usb/descriptor.h>
 
-int usb_drv_hc_connect(device_t *, unsigned int);
+int usb_drv_find_hc(device_t *, devman_handle_t *);
+int usb_drv_hc_connect(device_t *, devman_handle_t, unsigned int);
+int usb_drv_hc_connect_auto(device_t *, unsigned int);
 
 int usb_drv_reserve_default_address(int);
@@ -94,4 +96,9 @@
 int usb_drv_async_wait_for(usb_handle_t);
 
+int usb_drv_create_match_ids_from_device_descriptor(match_id_list_t *,
+    const usb_standard_device_descriptor_t *);
+int usb_drv_create_match_ids_from_configuration_descriptor(match_id_list_t *,
+    const void *, size_t);
+
 int usb_drv_create_device_match_ids(int, match_id_list_t *, usb_address_t);
 int usb_drv_register_child_in_devman(int, device_t *, usb_address_t,
Index: uspace/lib/usb/src/addrkeep.c
===================================================================
--- uspace/lib/usb/src/addrkeep.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/usb/src/addrkeep.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -187,4 +187,8 @@
 		new_address_position = addresses->used_addresses.next;
 	} else {
+		usb_address_keeping_used_t *first
+		    = used_address_get_instance(addresses->used_addresses.next);
+		previous_address = first->address;
+		
 		for_all_used_addresses(new_address_position, addresses) {
 			usb_address_keeping_used_t *info
@@ -194,4 +198,5 @@
 				break;
 			}
+			previous_address = info->address;
 		}
 
Index: uspace/lib/usb/src/hcdhubd.c
===================================================================
--- uspace/lib/usb/src/hcdhubd.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/usb/src/hcdhubd.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -36,4 +36,5 @@
 #include <usb/devreq.h>
 #include <usbhc_iface.h>
+#include <usb_iface.h>
 #include <usb/descriptor.h>
 #include <driver.h>
@@ -45,4 +46,33 @@
 #include "hcdhubd_private.h"
 
+
+static int usb_iface_get_hc_handle(device_t *dev, devman_handle_t *handle)
+{
+	assert(dev);
+	assert(dev->parent != NULL);
+
+	device_t *parent = dev->parent;
+
+	if (parent->ops && parent->ops->interfaces[USB_DEV_IFACE]) {
+		usb_iface_t *usb_iface
+		    = (usb_iface_t *) parent->ops->interfaces[USB_DEV_IFACE];
+		assert(usb_iface != NULL);
+		if (usb_iface->get_hc_handle) {
+			int rc = usb_iface->get_hc_handle(parent, handle);
+			return rc;
+		}
+	}
+
+	return ENOTSUP;
+}
+
+static usb_iface_t usb_iface = {
+	.get_hc_handle = usb_iface_get_hc_handle
+};
+
+static device_ops_t child_ops = {
+	.interfaces[USB_DEV_IFACE] = &usb_iface
+};
+
 /** Callback when new device is detected and must be handled by this driver.
  *
@@ -129,4 +159,6 @@
 	}
 	child->name = child_info->name;
+	child->parent = child_info->parent;
+	child->ops = &child_ops;
 
 	match_id = create_match_id();
Index: uspace/lib/usb/src/recognise.c
===================================================================
--- uspace/lib/usb/src/recognise.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/usb/src/recognise.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -33,4 +33,5 @@
  * @brief Functions for recognising kind of attached devices.
  */
+#include <usb_iface.h>
 #include <usb/usbdrv.h>
 #include <usb/classes/classes.h>
@@ -38,4 +39,31 @@
 #include <errno.h>
 
+static int usb_iface_get_hc_handle(device_t *dev, devman_handle_t *handle)
+{
+	assert(dev);
+	assert(dev->parent != NULL);
+
+	device_t *parent = dev->parent;
+
+	if (parent->ops && parent->ops->interfaces[USB_DEV_IFACE]) {
+		usb_iface_t *usb_iface
+		    = (usb_iface_t *) parent->ops->interfaces[USB_DEV_IFACE];
+		assert(usb_iface != NULL);
+		if (usb_iface->get_hc_handle) {
+			int rc = usb_iface->get_hc_handle(parent, handle);
+			return rc;
+		}
+	}
+
+	return ENOTSUP;
+}
+
+static usb_iface_t usb_iface = {
+	.get_hc_handle = usb_iface_get_hc_handle
+};
+
+static device_ops_t child_ops = {
+	.interfaces[USB_DEV_IFACE] = &usb_iface
+};
 
 #define BCD_INT(a) (((unsigned int)(a)) / 256)
@@ -99,4 +127,103 @@
 	
 	return rc;
+}
+
+/** Create DDF match ids from USB device descriptor.
+ *
+ * @param matches List of match ids to extend.
+ * @param device_descriptor Device descriptor returned by given device.
+ * @return Error code.
+ */
+int usb_drv_create_match_ids_from_device_descriptor(
+    match_id_list_t *matches,
+    const usb_standard_device_descriptor_t *device_descriptor)
+{
+	int rc;
+	
+	/*
+	 * Unless the vendor id is 0, the pair idVendor-idProduct
+	 * quite uniquely describes the device.
+	 */
+	if (device_descriptor->vendor_id != 0) {
+		/* First, with release number. */
+		rc = usb_add_match_id(matches, 100,
+		    "usb&vendor=%d&product=%d&release=" BCD_FMT,
+		    (int) device_descriptor->vendor_id,
+		    (int) device_descriptor->product_id,
+		    BCD_ARGS(device_descriptor->device_version));
+		if (rc != EOK) {
+			return rc;
+		}
+		
+		/* Next, without release number. */
+		rc = usb_add_match_id(matches, 90, "usb&vendor=%d&product=%d",
+		    (int) device_descriptor->vendor_id,
+		    (int) device_descriptor->product_id);
+		if (rc != EOK) {
+			return rc;
+		}
+	}	
+
+	/*
+	 * If the device class points to interface we skip adding
+	 * class directly.
+	 */
+	if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) {
+		rc = usb_add_match_id(matches, 50, "usb&class=%s",
+		    usb_str_class(device_descriptor->device_class));
+		if (rc != EOK) {
+			return rc;
+		}
+	}
+	
+	return EOK;
+}
+
+/** Create DDF match ids from USB configuration descriptor.
+ * The configuration descriptor is expected to be in the complete form,
+ * i.e. including interface, endpoint etc. descriptors.
+ *
+ * @param matches List of match ids to extend.
+ * @param config_descriptor Configuration descriptor returned by given device.
+ * @param total_size Size of the @p config_descriptor.
+ * @return Error code.
+ */
+int usb_drv_create_match_ids_from_configuration_descriptor(
+    match_id_list_t *matches,
+    const void *config_descriptor, size_t total_size)
+{
+	/*
+	 * Iterate through config descriptor to find the interface
+	 * descriptors.
+	 */
+	size_t position = sizeof(usb_standard_configuration_descriptor_t);
+	while (position + 1 < total_size) {
+		uint8_t *current_descriptor
+		    = ((uint8_t *) config_descriptor) + position;
+		uint8_t cur_descr_len = current_descriptor[0];
+		uint8_t cur_descr_type = current_descriptor[1];
+		
+		position += cur_descr_len;
+		
+		if (cur_descr_type != USB_DESCTYPE_INTERFACE) {
+			continue;
+		}
+		
+		/*
+		 * Finally, we found an interface descriptor.
+		 */
+		usb_standard_interface_descriptor_t *interface
+		    = (usb_standard_interface_descriptor_t *)
+		    current_descriptor;
+		
+		int rc = usb_add_match_id(matches, 50,
+		    "usb&interface&class=%s",
+		    usb_str_class(interface->interface_class));
+		if (rc != EOK) {
+			return rc;
+		}
+	}
+	
+	return EOK;
 }
 
@@ -141,36 +268,13 @@
 			continue;
 		}
-
-		/*
-		 * Iterate through config descriptor to find the interface
-		 * descriptors.
-		 */
-		size_t position = sizeof(config_descriptor);
-		while (position + 1 < full_config_descriptor_size) {
-			uint8_t *current_descriptor
-			    = ((uint8_t *) full_config_descriptor) + position;
-			uint8_t cur_descr_len = current_descriptor[0];
-			uint8_t cur_descr_type = current_descriptor[1];
-			
-			position += cur_descr_len;
-			
-			if (cur_descr_type != USB_DESCTYPE_INTERFACE) {
-				continue;
-			}
-			/*
-			 * Finally, we found an interface descriptor.
-			 */
-			usb_standard_interface_descriptor_t *interface
-			    = (usb_standard_interface_descriptor_t *)
-			    current_descriptor;
-			
-			rc = usb_add_match_id(matches, 50,
-			    "usb&interface&class=%s",
-			    usb_str_class(interface->interface_class));
-			if (rc != EOK) {
-				final_rc = rc;
-				break;
-			}
-		}
+		
+		rc = usb_drv_create_match_ids_from_configuration_descriptor(
+		    matches,
+		    full_config_descriptor, full_config_descriptor_size);
+		if (rc != EOK) {
+			final_rc = rc;
+			continue;
+		}
+		
 	}
 	
@@ -192,4 +296,8 @@
 {
 	int rc;
+	
+	/*
+	 * Retrieve device descriptor and add matches from it.
+	 */
 	usb_standard_device_descriptor_t device_descriptor;
 
@@ -199,41 +307,11 @@
 		return rc;
 	}
-
-	/*
-	 * Unless the vendor id is 0, the pair idVendor-idProduct
-	 * quite uniquely describes the device.
-	 */
-	if (device_descriptor.vendor_id != 0) {
-		/* First, with release number. */
-		rc = usb_add_match_id(matches, 100,
-		    "usb&vendor=%d&product=%d&release=" BCD_FMT,
-		    (int) device_descriptor.vendor_id,
-		    (int) device_descriptor.product_id,
-		    BCD_ARGS(device_descriptor.device_version));
-		if (rc != EOK) {
-			return rc;
-		}
-		
-		/* Next, without release number. */
-		rc = usb_add_match_id(matches, 90, "usb&vendor=%d&product=%d",
-		    (int) device_descriptor.vendor_id,
-		    (int) device_descriptor.product_id);
-		if (rc != EOK) {
-			return rc;
-		}
-
-	}	
-
-	/*
-	 * If the device class points to interface we skip adding
-	 * class directly.
-	 */
-	if (device_descriptor.device_class != USB_CLASS_USE_INTERFACE) {
-		rc = usb_add_match_id(matches, 50, "usb&class=%s",
-		    usb_str_class(device_descriptor.device_class));
-		if (rc != EOK) {
-			return rc;
-		}
-	}
+	
+	rc = usb_drv_create_match_ids_from_device_descriptor(matches,
+	    &device_descriptor);
+	if (rc != EOK) {
+		return rc;
+	}
+	
 	/*
 	 * Go through all configurations and add matches
@@ -285,5 +363,7 @@
 		goto failure;
 	}
+	child->parent = parent;
 	child->name = child_name;
+	child->ops = &child_ops;
 	
 	rc = usb_drv_create_device_match_ids(hc, &child->match_ids, address);
Index: uspace/lib/usb/src/usbdrv.c
===================================================================
--- uspace/lib/usb/src/usbdrv.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/usb/src/usbdrv.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -35,4 +35,5 @@
 #include <usb/usbdrv.h>
 #include <usbhc_iface.h>
+#include <usb_iface.h>
 #include <errno.h>
 #include <str_error.h>
@@ -54,4 +55,53 @@
 } transfer_info_t;
 
+/** Find handle of host controller the device is physically attached to.
+ *
+ * @param[in] dev Device looking for its host controller.
+ * @param[out] handle Host controller devman handle.
+ * @return Error code.
+ */
+int usb_drv_find_hc(device_t *dev, devman_handle_t *handle)
+{
+	if (dev == NULL) {
+		return EBADMEM;
+	}
+	if (handle == NULL) {
+		return EBADMEM;
+	}
+
+	int parent_phone = devman_parent_device_connect(dev->handle,
+	    IPC_FLAG_BLOCKING);
+	if (parent_phone < 0) {
+		return parent_phone;
+	}
+
+	devman_handle_t h;
+	int rc = async_req_1_1(parent_phone, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
+
+	ipc_hangup(parent_phone);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	*handle = h;
+
+	return EOK;
+}
+
+/** Connect to host controller the device is physically attached to.
+ *
+ * @param dev Device asking for connection.
+ * @param hc_handle Devman handle of the host controller.
+ * @param flags Connection flags (blocking connection).
+ * @return Phone to the HC or error code.
+ */
+int usb_drv_hc_connect(device_t *dev, devman_handle_t hc_handle,
+    unsigned int flags)
+{
+	return devman_device_connect(hc_handle, flags);
+}
+
 /** Connect to host controller the device is physically attached to.
  *
@@ -60,24 +110,18 @@
  * @return Phone to corresponding HC or error code.
  */
-int usb_drv_hc_connect(device_t *dev, unsigned int flags)
-{
+int usb_drv_hc_connect_auto(device_t *dev, unsigned int flags)
+{
+	int rc;
+	devman_handle_t hc_handle;
+
 	/*
 	 * Call parent hub to obtain device handle of respective HC.
 	 */
-
-	/*
-	 * FIXME: currently we connect always to virtual host controller.
-	 */
-	int rc;
-	devman_handle_t handle;
-
-	rc = devman_device_get_handle("/virt/usbhc", &handle, flags);
+	rc = usb_drv_find_hc(dev, &hc_handle);
 	if (rc != EOK) {
 		return rc;
 	}
 	
-	int phone = devman_device_connect(handle, flags);
-
-	return phone;
+	return usb_drv_hc_connect(dev, hc_handle, flags);
 }
 
Index: uspace/lib/usb/src/usbdrvreq.c
===================================================================
--- uspace/lib/usb/src/usbdrvreq.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/lib/usb/src/usbdrvreq.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -73,19 +73,23 @@
 }
 
-/** 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;
-	}
-
+/** Retrieve USB descriptor of connected USB device.
+ *
+ * @param[in] hc_phone Open phone to HC driver.
+ * @param[in] address Device USB address.
+ * @param[in] request_type Request type (standard/class/vendor).
+ * @param[in] descriptor_type Descriptor type (device/configuration/HID/...).
+ * @param[in] descriptor_index Descriptor index.
+ * @param[in] langauge Language index.
+ * @param[out] buffer Buffer where to store the retrieved descriptor.
+ * @param[in] size Size of the @p buffer.
+ * @param[out] actual_size Number of bytes actually transferred.
+ * @return Error code.
+ */
+int usb_drv_req_get_descriptor(int hc_phone, usb_address_t address,
+    usb_request_type_t request_type,
+    uint8_t descriptor_type, uint8_t descriptor_index,
+    uint16_t language,
+    void *buffer, size_t size, size_t *actual_size)
+{
 	/* Prepare the target. */
 	usb_target_t target = {
@@ -96,20 +100,43 @@
 	/* Prepare the setup packet. */
 	usb_device_request_setup_packet_t setup_packet = {
-		.request_type = 128,
+		.request_type = 128 | (request_type << 5),
 		.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. */
+		.index = language,
+		.length = (uint16_t) size,
+	};
+	setup_packet.value_high = descriptor_type;
+	setup_packet.value_low = descriptor_index;
+	
+	/* Perform CONTROL READ */
+	int rc = usb_drv_psync_control_read(hc_phone, target,
+	    &setup_packet, sizeof(setup_packet),
+	    buffer, size, actual_size);
+	
+	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;
+	}
+	
 	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);
+	int rc = usb_drv_req_get_descriptor(phone, address,
+	    USB_REQUEST_TYPE_STANDARD,
+	    USB_DESCTYPE_DEVICE, 0,
+	    0,
+	    &descriptor_tmp, sizeof(descriptor_tmp),
+	    &actually_transferred);
 
 	if (rc != EOK) {
@@ -150,29 +177,13 @@
 		return EBADMEM;
 	}
-
-	/* Prepare the target. */
-	usb_target_t target = {
-		.address = address,
-		.endpoint = 0
-	};
-
-	/* Prepare the setup packet. */
-	usb_device_request_setup_packet_t setup_packet = {
-		.request_type = 128,
-		.request = USB_DEVREQ_GET_DESCRIPTOR,
-		.index = 0,
-		.length = sizeof(usb_standard_configuration_descriptor_t)
-	};
-	setup_packet.value_high = USB_DESCTYPE_CONFIGURATION;
-	setup_packet.value_low = index;
-
-	/* Prepare local descriptor. */
+	
 	size_t actually_transferred = 0;
 	usb_standard_configuration_descriptor_t descriptor_tmp;
-
-	/* Perform the control read transaction. */
-	int rc = usb_drv_psync_control_read(phone, target,
-	    &setup_packet, sizeof(setup_packet),
-	    &descriptor_tmp, sizeof(descriptor_tmp), &actually_transferred);
+	int rc = usb_drv_req_get_descriptor(phone, address,
+	    USB_REQUEST_TYPE_STANDARD,
+	    USB_DESCTYPE_CONFIGURATION, 0,
+	    0,
+	    &descriptor_tmp, sizeof(descriptor_tmp),
+	    &actually_transferred);
 
 	if (rc != EOK) {
@@ -214,24 +225,10 @@
 	}
 
-	/* Prepare the target. */
-	usb_target_t target = {
-		.address = address,
-		.endpoint = 0
-	};
-
-	/* Prepare the setup packet. */
-	usb_device_request_setup_packet_t setup_packet = {
-		.request_type = 128,
-		.request = USB_DEVREQ_GET_DESCRIPTOR,
-		.index = 0,
-		.length = buffer_size
-	};
-	setup_packet.value_high = USB_DESCTYPE_CONFIGURATION;
-	setup_packet.value_low = index;
-
-	/* Perform the control read transaction. */
-	int rc = usb_drv_psync_control_read(phone, target,
-	    &setup_packet, sizeof(setup_packet),
-	    buffer, buffer_size, actual_buffer_size);
+	int rc = usb_drv_req_get_descriptor(phone, address,
+	    USB_REQUEST_TYPE_STANDARD,
+	    USB_DESCTYPE_CONFIGURATION, 0,
+	    0,
+	    buffer, buffer_size,
+	    actual_buffer_size);
 
 	return rc;
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -65,4 +65,5 @@
 #include <macros.h>
 
+#include "ata_hw.h"
 #include "ata_bd.h"
 
@@ -70,4 +71,7 @@
 #define NAMESPACE  "bd"
 
+/** Number of defined legacy controller base addresses. */
+#define LEGACY_CTLS 4
+
 /** Physical block size. Should be always 512. */
 static const size_t block_size = 512;
@@ -77,7 +81,15 @@
 
 /** I/O base address of the command registers. */
-static uintptr_t cmd_physical = 0x1f0;
+static uintptr_t cmd_physical;
 /** I/O base address of the control registers. */
-static uintptr_t ctl_physical = 0x170;
+static uintptr_t ctl_physical;
+
+/** I/O base addresses for legacy (ISA-compatible) controllers. */
+static ata_base_t legacy_base[LEGACY_CTLS] = {
+	{ 0x1f0, 0x3f0 },
+	{ 0x170, 0x370 },
+	{ 0x1e8, 0x3e8 },
+	{ 0x168, 0x368 }
+};
 
 static ata_cmd_t *cmd;
@@ -87,4 +99,5 @@
 static disk_t disk[MAX_DISKS];
 
+static void print_syntax(void);
 static int ata_bd_init(void);
 static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
@@ -110,9 +123,25 @@
 	int i, rc;
 	int n_disks;
+	unsigned ctl_num;
+	char *eptr;
 
 	printf(NAME ": ATA disk driver\n");
 
-	printf("I/O address %p/%p\n", (void *) ctl_physical,
-	    (void *) cmd_physical);
+	if (argc > 1) {
+		ctl_num = strtoul(argv[1], &eptr, 0);
+		if (*eptr != '\0' || ctl_num == 0 || ctl_num > 4) {
+			printf("Invalid argument.\n");
+			print_syntax();
+			return -1;
+		}
+	} else {
+		ctl_num = 1;
+	}
+
+	cmd_physical = legacy_base[ctl_num - 1].cmd;
+	ctl_physical = legacy_base[ctl_num - 1].ctl;
+
+	printf("I/O address %p/%p\n", (void *) cmd_physical,
+	    (void *) ctl_physical);
 
 	if (ata_bd_init() != EOK)
@@ -139,5 +168,5 @@
 			continue;
 		
-		snprintf(name, 16, "%s/disk%d", NAMESPACE, i);
+		snprintf(name, 16, "%s/ata%udisk%d", NAMESPACE, ctl_num, i);
 		rc = devmap_device_register(name, &disk[i].devmap_handle);
 		if (rc != EOK) {
@@ -160,4 +189,11 @@
 	/* Not reached */
 	return 0;
+}
+
+
+static void print_syntax(void)
+{
+	printf("Syntax: " NAME " <controller_number>\n");
+	printf("Controller number = 1..4\n");
 }
 
Index: uspace/srv/bd/ata_bd/ata_bd.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/bd/ata_bd/ata_bd.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -30,5 +30,5 @@
  * @{
  */
-/** @file
+/** @file ATA driver definitions.
  */
 
@@ -40,102 +40,9 @@
 #include <str.h>
 
-enum {
-	CTL_READ_START  = 0,
-	CTL_WRITE_START = 1,
-};
-
-enum {
-	STATUS_FAILURE = 0
-};
-
-enum {
-	MAX_DISKS	= 2
-};
-
-/** ATA Command Register Block. */
-typedef union {
-	/* Read/Write */
-	struct {
-		uint16_t data_port;
-		uint8_t sector_count;
-		uint8_t sector_number;
-		uint8_t cylinder_low;
-		uint8_t cylinder_high;
-		uint8_t drive_head;
-		uint8_t pad_rw0;		
-	};
-
-	/* Read Only */
-	struct {
-		uint8_t pad_ro0;
-		uint8_t error;
-		uint8_t pad_ro1[5];
-		uint8_t status;
-	};
-
-	/* Write Only */
-	struct {
-		uint8_t pad_wo0;
-		uint8_t features;
-		uint8_t pad_wo1[5];
-		uint8_t command;
-	};
-} ata_cmd_t;
-
-typedef union {
-	/* Read */
-	struct {
-		uint8_t pad0[6];
-		uint8_t alt_status;
-		uint8_t drive_address;
-	};
-
-	/* Write */
-	struct {
-		uint8_t pad1[6];
-		uint8_t device_control;
-		uint8_t pad2;
-	};
-} ata_ctl_t;
-
-enum devctl_bits {
-	DCR_SRST	= 0x04, /**< Software Reset */
-	DCR_nIEN	= 0x02  /**< Interrupt Enable (negated) */
-};
-
-enum status_bits {
-	SR_BSY		= 0x80, /**< Busy */
-	SR_DRDY		= 0x40, /**< Drive Ready */
-	SR_DWF		= 0x20, /**< Drive Write Fault */
-	SR_DSC		= 0x10, /**< Drive Seek Complete */
-	SR_DRQ		= 0x08, /**< Data Request */
-	SR_CORR		= 0x04, /**< Corrected Data */
-	SR_IDX		= 0x02, /**< Index */
-	SR_ERR		= 0x01  /**< Error */
-};
-
-enum drive_head_bits {
-	DHR_LBA		= 0x40,	/**< Use LBA addressing mode */
-	DHR_DRV		= 0x10	/**< Select device 1 */
-};
-
-enum error_bits {
-	ER_BBK		= 0x80, /**< Bad Block Detected */
-	ER_UNC		= 0x40, /**< Uncorrectable Data Error */
-	ER_MC		= 0x20, /**< Media Changed */
-	ER_IDNF		= 0x10, /**< ID Not Found */
-	ER_MCR		= 0x08, /**< Media Change Request */
-	ER_ABRT		= 0x04, /**< Aborted Command */
-	ER_TK0NF	= 0x02, /**< Track 0 Not Found */
-	ER_AMNF		= 0x01  /**< Address Mark Not Found */
-};
-
-enum ata_command {
-	CMD_READ_SECTORS	= 0x20,
-	CMD_READ_SECTORS_EXT	= 0x24,
-	CMD_WRITE_SECTORS	= 0x30,
-	CMD_WRITE_SECTORS_EXT	= 0x34,
-	CMD_IDENTIFY_DRIVE	= 0xEC
-};
+/** Base addresses for ATA I/O blocks. */
+typedef struct {
+	uintptr_t cmd;	/**< Command block base address. */
+	uintptr_t ctl;	/**< Control block base address. */
+} ata_base_t;
 
 /** Timeout definitions. Unit is 10 ms. */
@@ -144,93 +51,4 @@
 	TIMEOUT_BSY	=  100, /*  1 s */
 	TIMEOUT_DRDY	= 1000  /* 10 s */
-};
-
-/** Data returned from @c identify command. */
-typedef struct {
-	uint16_t gen_conf;
-	uint16_t cylinders;
-	uint16_t _res2;
-	uint16_t heads;
-	uint16_t _vs4;
-	uint16_t _vs5;
-	uint16_t sectors;
-	uint16_t _vs7;
-	uint16_t _vs8;
-	uint16_t _vs9;
-
-	uint16_t serial_number[10];
-	uint16_t _vs20;
-	uint16_t _vs21;
-	uint16_t vs_bytes;
-	uint16_t firmware_rev[4];
-	uint16_t model_name[20];
-
-	uint16_t max_rw_multiple;
-	uint16_t _res48;
-	uint16_t caps;
-	uint16_t _res50;
-	uint16_t pio_timing;
-	uint16_t dma_timing;
-
-	uint16_t validity;
-	uint16_t cur_cyl;
-	uint16_t cur_heads;
-	uint16_t cur_sectors;
-	uint16_t cur_capacity0;
-	uint16_t cur_capacity1;
-	uint16_t mss;
-	uint16_t total_lba28_0;
-	uint16_t total_lba28_1;
-	uint16_t sw_dma;
-	uint16_t mw_dma;
-	uint16_t pio_modes;
-	uint16_t min_mw_dma_cycle;
-	uint16_t rec_mw_dma_cycle;
-	uint16_t min_raw_pio_cycle;
-	uint16_t min_iordy_pio_cycle;
-
-	uint16_t _res69;
-	uint16_t _res70;
-	uint16_t _res71;
-	uint16_t _res72;
-	uint16_t _res73;
-	uint16_t _res74;
-
-	uint16_t queue_depth;
-	uint16_t _res76[1 + 79 - 76];
-	uint16_t version_maj;
-	uint16_t version_min;
-	uint16_t cmd_set0;
-	uint16_t cmd_set1;
-	uint16_t csf_sup_ext;
-	uint16_t csf_enabled0;
-	uint16_t csf_enabled1;
-	uint16_t csf_default;
-	uint16_t udma;
-
-	uint16_t _res89[1 + 99 - 89];
-
-	/* Total number of blocks in LBA-48 addressing */
-	uint16_t total_lba48_0;
-	uint16_t total_lba48_1;
-	uint16_t total_lba48_2;
-	uint16_t total_lba48_3;
-
-	/* Note: more fields are defined in ATA/ATAPI-7 */
-	uint16_t _res104[1 + 127 - 104];
-	uint16_t _vs128[1 + 159 - 128];
-	uint16_t _res160[1 + 255 - 160];
-} identify_data_t;
-
-enum ata_caps {
-	cap_iordy	= 0x0800,
-	cap_iordy_cbd	= 0x0400,
-	cap_lba		= 0x0200,
-	cap_dma		= 0x0100
-};
-
-/** Bits of @c identify_data_t.cmd_set1 */
-enum ata_cs1 {
-	cs1_addr48	= 0x0400	/**< 48-bit address feature set */
 };
 
@@ -269,4 +87,5 @@
 } block_coord_t;
 
+/** ATA device state structure. */
 typedef struct {
 	bool present;
Index: uspace/srv/bd/ata_bd/ata_hw.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_hw.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/srv/bd/ata_bd/ata_hw.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * 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 bd
+ * @{
+ */
+/** @file ATA hardware protocol (registers, data structures).
+ */
+
+#ifndef __ATA_HW_H__
+#define __ATA_HW_H__
+
+#include <sys/types.h>
+
+enum {
+	CTL_READ_START  = 0,
+	CTL_WRITE_START = 1,
+};
+
+enum {
+	STATUS_FAILURE = 0
+};
+
+enum {
+	MAX_DISKS	= 2
+};
+
+/** ATA Command Register Block. */
+typedef union {
+	/* Read/Write */
+	struct {
+		uint16_t data_port;
+		uint8_t sector_count;
+		uint8_t sector_number;
+		uint8_t cylinder_low;
+		uint8_t cylinder_high;
+		uint8_t drive_head;
+		uint8_t pad_rw0;
+	};
+
+	/* Read Only */
+	struct {
+		uint8_t pad_ro0;
+		uint8_t error;
+		uint8_t pad_ro1[5];
+		uint8_t status;
+	};
+
+	/* Write Only */
+	struct {
+		uint8_t pad_wo0;
+		uint8_t features;
+		uint8_t pad_wo1[5];
+		uint8_t command;
+	};
+} ata_cmd_t;
+
+typedef union {
+	/* Read */
+	struct {
+		uint8_t pad0[6];
+		uint8_t alt_status;
+		uint8_t drive_address;
+	};
+
+	/* Write */
+	struct {
+		uint8_t pad1[6];
+		uint8_t device_control;
+		uint8_t pad2;
+	};
+} ata_ctl_t;
+
+enum devctl_bits {
+	DCR_SRST	= 0x04, /**< Software Reset */
+	DCR_nIEN	= 0x02  /**< Interrupt Enable (negated) */
+};
+
+enum status_bits {
+	SR_BSY		= 0x80, /**< Busy */
+	SR_DRDY		= 0x40, /**< Drive Ready */
+	SR_DWF		= 0x20, /**< Drive Write Fault */
+	SR_DSC		= 0x10, /**< Drive Seek Complete */
+	SR_DRQ		= 0x08, /**< Data Request */
+	SR_CORR		= 0x04, /**< Corrected Data */
+	SR_IDX		= 0x02, /**< Index */
+	SR_ERR		= 0x01  /**< Error */
+};
+
+enum drive_head_bits {
+	DHR_LBA		= 0x40,	/**< Use LBA addressing mode */
+	DHR_DRV		= 0x10	/**< Select device 1 */
+};
+
+enum error_bits {
+	ER_BBK		= 0x80, /**< Bad Block Detected */
+	ER_UNC		= 0x40, /**< Uncorrectable Data Error */
+	ER_MC		= 0x20, /**< Media Changed */
+	ER_IDNF		= 0x10, /**< ID Not Found */
+	ER_MCR		= 0x08, /**< Media Change Request */
+	ER_ABRT		= 0x04, /**< Aborted Command */
+	ER_TK0NF	= 0x02, /**< Track 0 Not Found */
+	ER_AMNF		= 0x01  /**< Address Mark Not Found */
+};
+
+enum ata_command {
+	CMD_READ_SECTORS	= 0x20,
+	CMD_READ_SECTORS_EXT	= 0x24,
+	CMD_WRITE_SECTORS	= 0x30,
+	CMD_WRITE_SECTORS_EXT	= 0x34,
+	CMD_IDENTIFY_DRIVE	= 0xEC
+};
+
+/** Data returned from @c identify command. */
+typedef struct {
+	uint16_t gen_conf;
+	uint16_t cylinders;
+	uint16_t _res2;
+	uint16_t heads;
+	uint16_t _vs4;
+	uint16_t _vs5;
+	uint16_t sectors;
+	uint16_t _vs7;
+	uint16_t _vs8;
+	uint16_t _vs9;
+
+	uint16_t serial_number[10];
+	uint16_t _vs20;
+	uint16_t _vs21;
+	uint16_t vs_bytes;
+	uint16_t firmware_rev[4];
+	uint16_t model_name[20];
+
+	uint16_t max_rw_multiple;
+	uint16_t _res48;
+	uint16_t caps;
+	uint16_t _res50;
+	uint16_t pio_timing;
+	uint16_t dma_timing;
+
+	uint16_t validity;
+	uint16_t cur_cyl;
+	uint16_t cur_heads;
+	uint16_t cur_sectors;
+	uint16_t cur_capacity0;
+	uint16_t cur_capacity1;
+	uint16_t mss;
+	uint16_t total_lba28_0;
+	uint16_t total_lba28_1;
+	uint16_t sw_dma;
+	uint16_t mw_dma;
+	uint16_t pio_modes;
+	uint16_t min_mw_dma_cycle;
+	uint16_t rec_mw_dma_cycle;
+	uint16_t min_raw_pio_cycle;
+	uint16_t min_iordy_pio_cycle;
+
+	uint16_t _res69;
+	uint16_t _res70;
+	uint16_t _res71;
+	uint16_t _res72;
+	uint16_t _res73;
+	uint16_t _res74;
+
+	uint16_t queue_depth;
+	uint16_t _res76[1 + 79 - 76];
+	uint16_t version_maj;
+	uint16_t version_min;
+	uint16_t cmd_set0;
+	uint16_t cmd_set1;
+	uint16_t csf_sup_ext;
+	uint16_t csf_enabled0;
+	uint16_t csf_enabled1;
+	uint16_t csf_default;
+	uint16_t udma;
+
+	uint16_t _res89[1 + 99 - 89];
+
+	/* Total number of blocks in LBA-48 addressing */
+	uint16_t total_lba48_0;
+	uint16_t total_lba48_1;
+	uint16_t total_lba48_2;
+	uint16_t total_lba48_3;
+
+	/* Note: more fields are defined in ATA/ATAPI-7 */
+	uint16_t _res104[1 + 127 - 104];
+	uint16_t _vs128[1 + 159 - 128];
+	uint16_t _res160[1 + 255 - 160];
+} identify_data_t;
+
+enum ata_caps {
+	cap_iordy	= 0x0800,
+	cap_iordy_cbd	= 0x0400,
+	cap_lba		= 0x0200,
+	cap_dma		= 0x0100
+};
+
+/** Bits of @c identify_data_t.cmd_set1 */
+enum ata_cs1 {
+	cs1_addr48	= 0x0400	/**< 48-bit address feature set */
+};
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/devman/devman.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -62,4 +62,14 @@
 }
 
+static int devmap_devices_class_compare(unsigned long key[], hash_count_t keys,
+    link_t *item)
+{
+	dev_class_info_t *class_info
+	    = hash_table_get_instance(item, dev_class_info_t, devmap_link);
+	assert(class_info != NULL);
+
+	return (class_info->devmap_handle == (devmap_handle_t) key[0]);
+}
+
 static void devices_remove_callback(link_t *item)
 {
@@ -75,4 +85,10 @@
 	.hash = devices_hash,
 	.compare = devmap_devices_compare,
+	.remove_callback = devices_remove_callback
+};
+
+static hash_table_operations_t devmap_devices_class_ops = {
+	.hash = devices_hash,
+	.compare = devmap_devices_class_compare,
 	.remove_callback = devices_remove_callback
 };
@@ -376,4 +392,5 @@
 	printf(NAME ": create_root_node\n");
 
+	fibril_rwlock_write_lock(&tree->rwlock);
 	node = create_dev_node();
 	if (node != NULL) {
@@ -385,4 +402,5 @@
 		tree->root_node = node;
 	}
+	fibril_rwlock_write_unlock(&tree->rwlock);
 
 	return node != NULL;
@@ -447,6 +465,4 @@
 /** Start a driver
  *
- * The driver's mutex is assumed to be locked.
- *
  * @param drv		The driver's structure.
  * @return		True if the driver's task is successfully spawned, false
@@ -457,4 +473,6 @@
 	int rc;
 
+	assert(fibril_mutex_is_locked(&drv->driver_mutex));
+	
 	printf(NAME ": start_driver '%s'\n", drv->name);
 	
@@ -678,5 +696,6 @@
 	}
 	
-	devmap_device_register(devmap_pathname, &node->devmap_handle);
+	devmap_device_register_with_iface(devmap_pathname,
+	    &node->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
 	
 	tree_add_devmap_device(tree, node);
@@ -850,6 +869,4 @@
 /** Find the device node structure of the device witch has the specified handle.
  *
- * Device tree's rwlock should be held at least for reading.
- *
  * @param tree		The device tree where we look for the device node.
  * @param handle	The handle of the device.
@@ -859,5 +876,9 @@
 {
 	unsigned long key = handle;
-	link_t *link = hash_table_find(&tree->devman_devices, &key);
+	link_t *link;
+	
+	assert(fibril_rwlock_is_locked(&tree->rwlock));
+	
+	link = hash_table_find(&tree->devman_devices, &key);
 	return hash_table_get_instance(link, node_t, devman_link);
 }
@@ -915,7 +936,4 @@
 /** Insert new device into device tree.
  *
- * The device tree's rwlock should be already held exclusively when calling this
- * function.
- *
  * @param tree		The device tree.
  * @param node		The newly added device node. 
@@ -932,4 +950,5 @@
 	assert(tree != NULL);
 	assert(dev_name != NULL);
+	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
 	
 	node->name = dev_name;
@@ -1050,6 +1069,10 @@
 	
 	info = (dev_class_info_t *) malloc(sizeof(dev_class_info_t));
-	if (info != NULL)
+	if (info != NULL) {
 		memset(info, 0, sizeof(dev_class_info_t));
+		list_initialize(&info->dev_classes);
+		list_initialize(&info->devmap_link);
+		list_initialize(&info->link);
+	}
 	
 	return info;
@@ -1175,5 +1198,5 @@
 	fibril_rwlock_initialize(&class_list->rwlock);
 	hash_table_create(&class_list->devmap_devices, DEVICE_BUCKETS, 1,
-	    &devmap_devices_ops);
+	    &devmap_devices_class_ops);
 }
 
@@ -1223,4 +1246,6 @@
 	hash_table_insert(&class_list->devmap_devices, &key, &cli->devmap_link);
 	fibril_rwlock_write_unlock(&class_list->rwlock);
+
+	assert(find_devmap_class_device(class_list, cli->devmap_handle) != NULL);
 }
 
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/devman/main.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -281,5 +281,6 @@
 	 * handle.
 	 */
-	devmap_device_register(devmap_pathname, &cli->devmap_handle);
+	devmap_device_register_with_iface(devmap_pathname,
+	    &cli->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
 	
 	/*
@@ -457,6 +458,7 @@
 	
 	if (driver == NULL) {
-		printf(NAME ": devman_forward error - the device is not in %" PRIun
-		    " usable state.\n", handle);
+		printf(NAME ": devman_forward error - the device %" PRIun \
+		    " (%s) is not in usable state.\n",
+		    handle, dev->pathname);
 		ipc_answer_0(iid, ENOENT);
 		return;
@@ -486,5 +488,5 @@
 static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall)
 {
-	devmap_handle_t devmap_handle = IPC_GET_IMETHOD(*icall);
+	devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall);
 	node_t *dev;
 
@@ -503,8 +505,8 @@
 	}
 	
-	printf(NAME ": devman_connection_devmapper: forward connection to "
-	    "device %s to driver %s.\n", dev->pathname, dev->drv->name);
 	ipc_forward_fast(iid, dev->drv->phone, DRIVER_CLIENT, dev->handle, 0,
 	    IPC_FF_NONE);
+	printf(NAME ": devman_connection_devmapper: forwarded connection to "
+	    "device %s to driver %s.\n", dev->pathname, dev->drv->name);
 }
 
@@ -512,22 +514,4 @@
 static void devman_connection(ipc_callid_t iid, ipc_call_t *icall)
 {
-	/*
-	 * Silly hack to enable the device manager to register as a driver by
-	 * the device mapper. If the ipc method is not IPC_M_CONNECT_ME_TO, this
-	 * is not the forwarded connection from naming service, so it must be a
-	 * connection from the devmapper which thinks this is a devmapper-style
-	 * driver. So pretend this is a devmapper-style driver. (This does not
-	 * work for device with handle == IPC_M_CONNECT_ME_TO, because devmapper
-	 * passes device handle to the driver as an ipc method.)
-	 */
-	if (IPC_GET_IMETHOD(*icall) != IPC_M_CONNECT_ME_TO)
-		devman_connection_devmapper(iid, icall);
-
-	/*
-	 * ipc method is IPC_M_CONNECT_ME_TO, so this is forwarded connection
-	 * from naming service by which we registered as device manager, so be
-	 * device manager.
-	 */
-	
 	/* Select interface. */
 	switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
@@ -542,4 +526,8 @@
 		devman_forward(iid, icall, false);
 		break;
+	case DEVMAN_CONNECT_FROM_DEVMAP:
+		/* Someone connected through devmap node. */
+		devman_connection_devmapper(iid, icall);
+		break;
 	case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
 		/* Connect client to selected device. */
Index: uspace/srv/devmap/devmap.c
===================================================================
--- uspace/srv/devmap/devmap.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/devmap/devmap.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -46,4 +46,5 @@
 #include <str.h>
 #include <ipc/devmap.h>
+#include <assert.h>
 
 #define NAME          "devmap"
@@ -99,4 +100,6 @@
 	/** Device driver handling this device */
 	devmap_driver_t *driver;
+	/** Use this interface when forwarding to driver. */
+	sysarg_t forward_interface;
 } devmap_device_t;
 
@@ -206,13 +209,11 @@
 }
 
-/** Find namespace with given name.
- *
- * The devices_list_mutex should be already held when
- * calling this function.
- *
- */
+/** Find namespace with given name. */
 static devmap_namespace_t *devmap_namespace_find_name(const char *name)
 {
 	link_t *item;
+	
+	assert(fibril_mutex_is_locked(&devices_list_mutex));
+	
 	for (item = namespaces_list.next; item != &namespaces_list; item = item->next) {
 		devmap_namespace_t *namespace =
@@ -227,7 +228,4 @@
 /** Find namespace with given handle.
  *
- * The devices_list_mutex should be already held when
- * calling this function.
- *
  * @todo: use hash table
  *
@@ -236,4 +234,7 @@
 {
 	link_t *item;
+	
+	assert(fibril_mutex_is_locked(&devices_list_mutex));
+	
 	for (item = namespaces_list.next; item != &namespaces_list; item = item->next) {
 		devmap_namespace_t *namespace =
@@ -246,14 +247,12 @@
 }
 
-/** Find device with given name.
- *
- * The devices_list_mutex should be already held when
- * calling this function.
- *
- */
+/** Find device with given name. */
 static devmap_device_t *devmap_device_find_name(const char *ns_name,
     const char *name)
 {
 	link_t *item;
+	
+	assert(fibril_mutex_is_locked(&devices_list_mutex));
+	
 	for (item = devices_list.next; item != &devices_list; item = item->next) {
 		devmap_device_t *device =
@@ -269,7 +268,4 @@
 /** Find device with given handle.
  *
- * The devices_list_mutex should be already held when
- * calling this function.
- *
  * @todo: use hash table
  *
@@ -278,4 +274,7 @@
 {
 	link_t *item;
+	
+	assert(fibril_mutex_is_locked(&devices_list_mutex));
+	
 	for (item = devices_list.next; item != &devices_list; item = item->next) {
 		devmap_device_t *device =
@@ -288,13 +287,12 @@
 }
 
-/** Create a namespace (if not already present)
- *
- * The devices_list_mutex should be already held when
- * calling this function.
- *
- */
+/** Create a namespace (if not already present). */
 static devmap_namespace_t *devmap_namespace_create(const char *ns_name)
 {
-	devmap_namespace_t *namespace = devmap_namespace_find_name(ns_name);
+	devmap_namespace_t *namespace;
+	
+	assert(fibril_mutex_is_locked(&devices_list_mutex));
+	
+	namespace = devmap_namespace_find_name(ns_name);
 	if (namespace != NULL)
 		return namespace;
@@ -321,12 +319,9 @@
 }
 
-/** Destroy a namespace (if it is no longer needed)
- *
- * The devices_list_mutex should be already held when
- * calling this function.
- *
- */
+/** Destroy a namespace (if it is no longer needed). */
 static void devmap_namespace_destroy(devmap_namespace_t *namespace)
 {
+	assert(fibril_mutex_is_locked(&devices_list_mutex));
+
 	if (namespace->refcnt == 0) {
 		list_remove(&(namespace->namespaces));
@@ -337,37 +332,28 @@
 }
 
-/** Increase namespace reference count by including device
- *
- * The devices_list_mutex should be already held when
- * calling this function.
- *
- */
+/** Increase namespace reference count by including device. */
 static void devmap_namespace_addref(devmap_namespace_t *namespace,
     devmap_device_t *device)
 {
+	assert(fibril_mutex_is_locked(&devices_list_mutex));
+
 	device->namespace = namespace;
 	namespace->refcnt++;
 }
 
-/** Decrease namespace reference count
- *
- * The devices_list_mutex should be already held when
- * calling this function.
- *
- */
+/** Decrease namespace reference count. */
 static void devmap_namespace_delref(devmap_namespace_t *namespace)
 {
+	assert(fibril_mutex_is_locked(&devices_list_mutex));
+
 	namespace->refcnt--;
 	devmap_namespace_destroy(namespace);
 }
 
-/** Unregister device and free it
- *
- * The devices_list_mutex should be already held when
- * calling this function.
- *
- */
+/** Unregister device and free it. */
 static void devmap_device_unregister_core(devmap_device_t *device)
 {
+	assert(fibril_mutex_is_locked(&devices_list_mutex));
+
 	devmap_namespace_delref(device->namespace);
 	list_remove(&(device->devices));
@@ -517,4 +503,7 @@
 	}
 	
+	/* Set the interface, if any. */
+	device->forward_interface = IPC_GET_ARG1(*icall);
+
 	/* Get fqdn */
 	char *fqdn;
@@ -566,5 +555,5 @@
 	/* Get unique device handle */
 	device->handle = devmap_create_handle();
-	
+
 	devmap_namespace_addref(namespace, device);
 	device->driver = driver;
@@ -617,6 +606,13 @@
 	}
 	
-	ipc_forward_fast(callid, dev->driver->phone, dev->handle,
-	    IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
+	if (dev->forward_interface == 0) {
+		ipc_forward_fast(callid, dev->driver->phone,
+		    dev->handle, 0, 0,
+		    IPC_FF_NONE);
+	} else {
+		ipc_forward_fast(callid, dev->driver->phone,
+		    dev->forward_interface, dev->handle, 0,
+		    IPC_FF_NONE);
+	}
 	
 	fibril_mutex_unlock(&devices_list_mutex);
Index: uspace/srv/fs/devfs/devfs_ops.c
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/fs/devfs/devfs_ops.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -60,7 +60,8 @@
 typedef struct {
 	devmap_handle_t handle;
-	int phone;
+	int phone;		/**< When < 0, the structure is incomplete. */
 	size_t refcount;
 	link_t link;
+	fibril_condvar_t cv;	/**< Broadcast when completed. */
 } device_t;
 
@@ -227,7 +228,9 @@
 			[DEVICES_KEY_HANDLE] = (unsigned long) node->handle
 		};
-		
+		link_t *lnk;
+
 		fibril_mutex_lock(&devices_mutex);
-		link_t *lnk = hash_table_find(&devices, key);
+restart:
+		lnk = hash_table_find(&devices, key);
 		if (lnk == NULL) {
 			device_t *dev = (device_t *) malloc(sizeof(device_t));
@@ -237,18 +240,60 @@
 			}
 			
+			dev->handle = node->handle;
+			dev->phone = -1;	/* mark as incomplete */
+			dev->refcount = 1;
+			fibril_condvar_initialize(&dev->cv);
+
+			/*
+			 * Insert the incomplete device structure so that other
+			 * fibrils will not race with us when we drop the mutex
+			 * below.
+			 */
+			hash_table_insert(&devices, key, &dev->link);
+
+			/*
+			 * Drop the mutex to allow recursive devfs requests.
+			 */
+			fibril_mutex_unlock(&devices_mutex);
+
 			int phone = devmap_device_connect(node->handle, 0);
+
+			fibril_mutex_lock(&devices_mutex);
+
+			/*
+			 * Notify possible waiters about this device structure
+			 * being completed (or destroyed).
+			 */
+			fibril_condvar_broadcast(&dev->cv);
+
 			if (phone < 0) {
+				/*
+				 * Connecting failed, need to remove the
+				 * entry and free the device structure.
+				 */
+				hash_table_remove(&devices, key, DEVICES_KEYS);
 				fibril_mutex_unlock(&devices_mutex);
+
 				free(dev);
 				return ENOENT;
 			}
 			
-			dev->handle = node->handle;
+			/* Set the correct phone. */
 			dev->phone = phone;
-			dev->refcount = 1;
-			
-			hash_table_insert(&devices, key, &dev->link);
 		} else {
 			device_t *dev = hash_table_get_instance(lnk, device_t, link);
+
+			if (dev->phone < 0) {
+				/*
+				 * Wait until the device structure is completed
+				 * and start from the beginning as the device
+				 * structure might have entirely disappeared
+				 * while we were not holding the mutex in
+				 * fibril_condvar_wait().
+				 */
+				fibril_condvar_wait(&dev->cv, &devices_mutex);
+				goto restart;
+			}
+
 			dev->refcount++;
 		}
@@ -564,4 +609,5 @@
 		
 		device_t *dev = hash_table_get_instance(lnk, device_t, link);
+		assert(dev->phone >= 0);
 		
 		ipc_callid_t callid;
@@ -627,4 +673,5 @@
 		
 		device_t *dev = hash_table_get_instance(lnk, device_t, link);
+		assert(dev->phone >= 0);
 		
 		ipc_callid_t callid;
@@ -696,4 +743,5 @@
 		
 		device_t *dev = hash_table_get_instance(lnk, device_t, link);
+		assert(dev->phone >= 0);
 		dev->refcount--;
 		
@@ -743,4 +791,5 @@
 		
 		device_t *dev = hash_table_get_instance(lnk, device_t, link);
+		assert(dev->phone >= 0);
 		
 		/* Make a request at the driver */
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/hid/console/console.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -317,6 +317,7 @@
 static void change_console(console_t *cons)
 {
-	if (cons == active_console)
+	if (cons == active_console) {
 		return;
+	}
 	
 	fb_pending_flush();
@@ -458,6 +459,7 @@
 			if (IPC_GET_ARG1(call) == 1) {
 				int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
-				if (newcon != -1)
+				if (newcon != -1) {
 					change_console(&consoles[newcon]);
+				}
 			}
 			retval = 0;
@@ -710,28 +712,139 @@
 }
 
-static bool console_init(char *input)
-{
-	/* Connect to input device */
-	int input_fd = open(input, O_RDONLY);
-	if (input_fd < 0) {
-		printf(NAME ": Failed opening %s\n", input);
-		return false;
-	}
-	
-	kbd_phone = fd_phone(input_fd);
-	if (kbd_phone < 0) {
+static int connect_keyboard(char *path)
+{
+	int fd = open(path, O_RDONLY);
+	if (fd < 0) {
+		return fd;
+	}
+	
+	int phone = fd_phone(fd);
+	if (phone < 0) {
 		printf(NAME ": Failed to connect to input device\n");
-		return false;
+		return phone;
 	}
 	
 	/* NB: The callback connection is slotted for removal */
 	sysarg_t phonehash;
-	if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
+	int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, SERVICE_CONSOLE,
+	    0, 0, NULL, NULL, NULL, NULL, &phonehash);
+	if (rc != EOK) {
 		printf(NAME ": Failed to create callback from input device\n");
+		return rc;
+	}
+	
+	async_new_connection(phonehash, 0, NULL, keyboard_events);
+
+	printf(NAME ": we got a hit (new keyboard \"%s\").\n", path);
+
+	return phone;
+}
+
+/** Try to connect to given keyboard, bypassing provided libc routines.
+ *
+ * @param devmap_path Path to keyboard without /dev prefix.
+ * @return Phone or error code.
+ */
+static int connect_keyboard_bypass(char *devmap_path)
+{
+	int devmap_phone = async_connect_me_to_blocking(PHONE_NS,
+	    SERVICE_DEVMAP, DEVMAP_CLIENT, 0);
+	if (devmap_phone < 0) {
+		return devmap_phone;
+	}
+	ipc_call_t answer;
+	aid_t req = async_send_2(devmap_phone, DEVMAP_DEVICE_GET_HANDLE,
+	    0, 0,  &answer);
+
+	sysarg_t retval = async_data_write_start(devmap_phone,
+	    devmap_path, str_size(devmap_path));
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		ipc_hangup(devmap_phone);
+		return retval;
+	}
+
+	async_wait_for(req, &retval);
+
+	if (retval != EOK) {
+		ipc_hangup(devmap_phone);
+		return retval;
+	}
+
+	devmap_handle_t handle = (devmap_handle_t) IPC_GET_ARG1(answer);
+
+	ipc_hangup(devmap_phone);
+
+	int phone = async_connect_me_to(PHONE_NS,
+	    SERVICE_DEVMAP, DEVMAP_CONNECT_TO_DEVICE, handle);
+	if (phone < 0) {
+		return phone;
+	}
+
+	/* NB: The callback connection is slotted for removal */
+	sysarg_t phonehash;
+	int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, SERVICE_CONSOLE,
+	    0, 0, NULL, NULL, NULL, NULL, &phonehash);
+	if (rc != EOK) {
+		printf(NAME ": Failed to create callback from input device\n");
+		return rc;
+	}
+
+	async_new_connection(phonehash, 0, NULL, keyboard_events);
+
+	printf(NAME ": we got a hit (new keyboard \"/dev/%s\").\n",
+	    devmap_path);
+
+	return phone;
+}
+
+
+static int check_new_keyboards(void *arg)
+{
+	char *class_name = (char *) arg;
+
+	int index = 1;
+
+	while (true) {
+		async_usleep(1 * 500 * 1000);
+		char *path;
+		int rc = asprintf(&path, "class/%s\\%d", class_name, index);
+		if (rc < 0) {
+			continue;
+		}
+		rc = 0;
+		rc = connect_keyboard_bypass(path);
+		if (rc > 0) {
+			/* We do not allow unplug. */
+			index++;
+		}
+
+		free(path);
+	}
+
+	return EOK;
+}
+
+
+/** Start a fibril monitoring hot-plugged keyboards.
+ */
+static void check_new_keyboards_in_background()
+{
+	fid_t fid = fibril_create(check_new_keyboards, (void *)"keyboard");
+	if (!fid) {
+		printf(NAME ": failed to create hot-plug-watch fibril.\n");
+		return;
+	}
+	fibril_add_ready(fid);
+}
+
+static bool console_init(char *input)
+{
+	/* Connect to input device */
+	kbd_phone = connect_keyboard(input);
+	if (kbd_phone < 0) {
 		return false;
 	}
-	
-	async_new_connection(phonehash, 0, NULL, keyboard_events);
-	
+
 	/* Connect to mouse device */
 	mouse_phone = -1;
@@ -749,4 +862,5 @@
 	}
 	
+	sysarg_t phonehash;
 	if (ipc_connect_to_me(mouse_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
 		printf(NAME ": Failed to create callback from mouse device\n");
@@ -841,4 +955,7 @@
 	async_set_interrupt_received(interrupt_received);
 	
+	/* Start fibril for checking on hot-plugged keyboards. */
+	check_new_keyboards_in_background();
+
 	return true;
 }
@@ -860,5 +977,5 @@
 	if (!console_init(argv[1]))
 		return -1;
-	
+
 	printf(NAME ": Accepting connections\n");
 	async_manager();
Index: uspace/srv/hw/netif/dp8390/Makefile
===================================================================
--- uspace/srv/hw/netif/dp8390/Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/hw/netif/dp8390/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -39,8 +39,4 @@
 -include $(CONFIG_MAKEFILE)
 
-ifeq ($(CONFIG_NETIF_NIL_BUNDLE),y)
-	LIBS += $(USPACE_PREFIX)/srv/net/nil/eth/libeth.a
-endif
-
 BINARY = dp8390
 
Index: uspace/srv/hw/netif/dp8390/dp8390.c
===================================================================
--- uspace/srv/hw/netif/dp8390/dp8390.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/hw/netif/dp8390/dp8390.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -1,17 +1,23 @@
 /*
- * Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands All rights reserved. Redistribution and use of the MINIX 3 operating system 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.
- * * Neither the name of the Vrije Universiteit nor the names of the software authors or contributors may be used to endorse or promote products derived from this software without specific prior written permission.
- * * Any deviations from these conditions require written permission from the copyright holder in advance
- *
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Martin Decky
+ * 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 COPYRIGHT HOLDER OR ANY AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * 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,
@@ -20,7 +26,14 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Changes:
- *  2009 ported to HelenOS, Lukas Mejdrech
+ */
+
+/*
+ * This code is based upon the NE2000 driver for MINIX,
+ * distributed according to a BSD-style license.
+ *
+ * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
+ * Copyright (c) 1992, 1994 Philip Homburg
+ * Copyright (c) 1996 G. Falzoni
+ *
  */
 
@@ -36,472 +49,229 @@
 #include <byteorder.h>
 #include <errno.h>
-
 #include <netif_local.h>
 #include <net/packet.h>
+#include <nil_interface.h>
 #include <packet_client.h>
-
 #include "dp8390_drv.h"
 #include "dp8390_port.h"
-
-/*
- * dp8390.c
- *
- * Created:	before Dec 28, 1992 by Philip Homburg <philip@f-mnx.phicoh.com>
- *
- * Modified Mar 10 1994 by Philip Homburg
- *	Become a generic dp8390 driver.
- *
- * Modified Dec 20 1996 by G. Falzoni <falzoni@marina.scn.de>
- *	Added support for 3c503 boards.
- */
-
-#include "local.h"
 #include "dp8390.h"
-
-/** Queues the outgoing packet.
- *  @param[in] dep The network interface structure.
- *  @param[in] packet The outgoing packet.
- *  @return EOK on success.
- *  @return EINVAL 
- */
-int queue_packet(dpeth_t * dep, packet_t *packet);
-
-/** Reads a memory block byte by byte.
+#include "ne2000.h"
+
+/** Read a memory block byte by byte.
+ *
  *  @param[in] port The source address.
  *  @param[out] buf The destination buffer.
  *  @param[in] size The memory block size in bytes.
+ *
  */
 static void outsb(port_t port, void * buf, size_t size);
 
-/** Reads a memory block word by word.
+/** Read a memory block word by word.
+ *
  *  @param[in] port The source address.
  *  @param[out] buf The destination buffer.
  *  @param[in] size The memory block size in bytes.
+ *
  */
 static void outsw(port_t port, void * buf, size_t size);
 
-//static u16_t eth_ign_proto;
-//static char *progname;
-
-/* Configuration */
-/*typedef struct dp_conf
-{
-	port_t dpc_port;
-	int dpc_irq;
-	phys_bytes dpc_mem;
-	char *dpc_envvar;
-} dp_conf_t;
-*/
-//dp_conf_t dp_conf[]=	/* Card addresses */
-//{
-	/* I/O port, IRQ,  Buffer address,  Env. var. */
-/*	{ 0x280,     3,    0xD0000,        "DPETH0"	},
-	{ 0x300,     5,    0xC8000,        "DPETH1"	},
-	{ 0x380,    10,    0xD8000,        "DPETH2"	},
-};
-*/
-/* Test if dp_conf has exactly DE_PORT_NR entries.  If not then you will see
- * the error: "array size is negative".
- */
-//extern int ___dummy[DE_PORT_NR == sizeof(dp_conf)/sizeof(dp_conf[0]) ? 1 : -1];
-
-/* Card inits configured out? */
-#if !ENABLE_WDETH
-#define wdeth_probe(dep)	(0)
-#endif
-#if !ENABLE_NE2000
-#define ne_probe(dep)		(0)
-#endif
-#if !ENABLE_3C503
-#define el2_probe(dep)		(0)
-#endif
-
-/* Some clones of the dp8390 and the PC emulator 'Bochs' require the CR_STA
+/*
+ * Some clones of the dp8390 and the PC emulator 'Bochs' require the CR_STA
  * on writes to the CR register. Additional CR_STAs do not appear to hurt
- * genuine dp8390s
- */
-#define CR_EXTRA	CR_STA
-
-//#if ENABLE_PCI
-//_PROTOTYPE(static void pci_conf, (void)				);
-//#endif
-//_PROTOTYPE(static void do_vwrite, (message *mp, int from_int,
-//							int vectored)	);
-//_PROTOTYPE(static void do_vwrite_s, (message *mp, int from_int)	);
-//_PROTOTYPE(static void do_vread, (message *mp, int vectored)		);
-//_PROTOTYPE(static void do_vread_s, (message *mp)			);
-//_PROTOTYPE(static void do_init, (message *mp)				);
-//_PROTOTYPE(static void do_int, (dpeth_t *dep)				);
-//_PROTOTYPE(static void do_getstat, (message *mp)			);
-//_PROTOTYPE(static void do_getstat_s, (message *mp)			);
-//_PROTOTYPE(static void do_getname, (message *mp)			);
-//_PROTOTYPE(static void do_stop, (message *mp)				);
-_PROTOTYPE(static void dp_init, (dpeth_t *dep)				);
-//_PROTOTYPE(static void dp_confaddr, (dpeth_t *dep)			);
-_PROTOTYPE(static void dp_reinit, (dpeth_t *dep)			);
-_PROTOTYPE(static void dp_reset, (dpeth_t *dep)			);
-//_PROTOTYPE(static void dp_check_ints, (dpeth_t *dep)			);
-_PROTOTYPE(static void dp_recv, (dpeth_t *dep)				);
-_PROTOTYPE(static void dp_send, (dpeth_t *dep)				);
-//_PROTOTYPE(static void dp8390_stop, (void)				);
-_PROTOTYPE(static void dp_getblock, (dpeth_t *dep, int page,
-				size_t offset, size_t size, void *dst)	);
-_PROTOTYPE(static void dp_pio8_getblock, (dpeth_t *dep, int page,
-				size_t offset, size_t size, void *dst)	);
-_PROTOTYPE(static void dp_pio16_getblock, (dpeth_t *dep, int page,
-				size_t offset, size_t size, void *dst)	);
-_PROTOTYPE(static int dp_pkt2user, (dpeth_t *dep, int page,
-							int length) );
-//_PROTOTYPE(static int dp_pkt2user_s, (dpeth_t *dep, int page,
-//							int length)	);
-_PROTOTYPE(static void dp_user2nic, (dpeth_t *dep, iovec_dat_t *iovp, 
-		vir_bytes offset, int nic_addr, vir_bytes count) );
-//_PROTOTYPE(static void dp_user2nic_s, (dpeth_t *dep, iovec_dat_s_t *iovp, 
-//		vir_bytes offset, int nic_addr, vir_bytes count)	);
-_PROTOTYPE(static void dp_pio8_user2nic, (dpeth_t *dep,
-				iovec_dat_t *iovp, vir_bytes offset,
-				int nic_addr, vir_bytes count) );
-//_PROTOTYPE(static void dp_pio8_user2nic_s, (dpeth_t *dep,
-//				iovec_dat_s_t *iovp, vir_bytes offset,
-//				int nic_addr, vir_bytes count)		);
-_PROTOTYPE(static void dp_pio16_user2nic, (dpeth_t *dep,
-				iovec_dat_t *iovp, vir_bytes offset,
-				int nic_addr, vir_bytes count) );
-//_PROTOTYPE(static void dp_pio16_user2nic_s, (dpeth_t *dep,
-//				iovec_dat_s_t *iovp, vir_bytes offset,
-//				int nic_addr, vir_bytes count)		);
-_PROTOTYPE(static void dp_nic2user, (dpeth_t *dep, int nic_addr, 
-		iovec_dat_t *iovp, vir_bytes offset, vir_bytes count)	);
-//_PROTOTYPE(static void dp_nic2user_s, (dpeth_t *dep, int nic_addr, 
-//		iovec_dat_s_t *iovp, vir_bytes offset, vir_bytes count)	);
-_PROTOTYPE(static void dp_pio8_nic2user, (dpeth_t *dep, int nic_addr, 
-		iovec_dat_t *iovp, vir_bytes offset, vir_bytes count)	);
-//_PROTOTYPE(static void dp_pio8_nic2user_s, (dpeth_t *dep, int nic_addr, 
-//		iovec_dat_s_t *iovp, vir_bytes offset, vir_bytes count)	);
-_PROTOTYPE(static void dp_pio16_nic2user, (dpeth_t *dep, int nic_addr, 
-		iovec_dat_t *iovp, vir_bytes offset, vir_bytes count)	);
-//_PROTOTYPE(static void dp_pio16_nic2user_s, (dpeth_t *dep, int nic_addr, 
-//		iovec_dat_s_t *iovp, vir_bytes offset, vir_bytes count)	);
-_PROTOTYPE(static void dp_next_iovec, (iovec_dat_t *iovp)		);
-//_PROTOTYPE(static void dp_next_iovec_s, (iovec_dat_s_t *iovp)		);
-_PROTOTYPE(static void conf_hw, (dpeth_t *dep)				);
-//_PROTOTYPE(static void update_conf, (dpeth_t *dep, dp_conf_t *dcp)	);
-_PROTOTYPE(static void map_hw_buffer, (dpeth_t *dep)			);
-//_PROTOTYPE(static int calc_iovec_size, (iovec_dat_t *iovp)		);
-//_PROTOTYPE(static int calc_iovec_size_s, (iovec_dat_s_t *iovp)		);
-_PROTOTYPE(static void reply, (dpeth_t *dep, int err, int may_block)	);
-//_PROTOTYPE(static void mess_reply, (message *req, message *reply)	);
-_PROTOTYPE(static void get_userdata, (int user_proc,
-		vir_bytes user_addr, vir_bytes count, void *loc_addr)	);
-//_PROTOTYPE(static void get_userdata_s, (int user_proc,
-//		cp_grant_id_t grant, vir_bytes offset, vir_bytes count,
-//		void *loc_addr)	);
-//_PROTOTYPE(static void put_userdata, (int user_proc,
-//		vir_bytes user_addr, vir_bytes count, void *loc_addr)	);
-//_PROTOTYPE(static void put_userdata_s, (int user_proc,
-//		cp_grant_id_t grant, size_t count, void *loc_addr)	);
-_PROTOTYPE(static void insb, (port_t port, void *buf, size_t size)				);
-_PROTOTYPE(static void insw, (port_t port, void *buf, size_t size)				);
-//_PROTOTYPE(static void do_vir_insb, (port_t port, int proc,
-//					vir_bytes buf, size_t size)	);
-//_PROTOTYPE(static void do_vir_insw, (port_t port, int proc,
-//					vir_bytes buf, size_t size)	);
-//_PROTOTYPE(static void do_vir_outsb, (port_t port, int proc,
-//					vir_bytes buf, size_t size)	);
-//_PROTOTYPE(static void do_vir_outsw, (port_t port, int proc,
-//					vir_bytes buf, size_t size)	);
-
-int do_probe(dpeth_t * dep){
+ * genuine dp8390s.
+ */
+#define CR_EXTRA  CR_STA
+
+static void dp_init(dpeth_t *dep);
+static void dp_reinit(dpeth_t *dep);
+static void dp_reset(dpeth_t *dep);
+static void dp_recv(int nil_phone, device_id_t device_id, dpeth_t *dep);
+static int dp_pkt2user(int nil_phone, device_id_t device_id, dpeth_t *dep, int page, int length);
+static void conf_hw(dpeth_t *dep);
+static void insb(port_t port, void *buf, size_t size);
+static void insw(port_t port, void *buf, size_t size);
+
+int do_probe(dpeth_t *dep)
+{
 	/* This is the default, try to (re)locate the device. */
 	conf_hw(dep);
-	if (dep->de_mode == DEM_DISABLED)
-	{
+	if (!dep->up)
 		/* Probe failed, or the device is configured off. */
-		return EXDEV;//ENXIO;
-	}
-	if (dep->de_mode == DEM_ENABLED)
+		return EXDEV;
+	
+	if (dep->up)
 		dp_init(dep);
+	
 	return EOK;
 }
 
-/*===========================================================================*
- *				dp8390_dump				     *
- *===========================================================================*/
-void dp8390_dump(dpeth_t * dep)
-{
-//	dpeth_t *dep;
-	int /*i,*/ isr;
-
-//	printf("\n");
-//	for (i= 0, dep = &de_table[0]; i<DE_PORT_NR; i++, dep++)
-//	{
-#if XXX
-		if (dep->de_mode == DEM_DISABLED)
-			printf("dp8390 port %d is disabled\n", i);
-		else if (dep->de_mode == DEM_SINK)
-			printf("dp8390 port %d is in sink mode\n", i);
-#endif
-
-		if (dep->de_mode != DEM_ENABLED)
-//			continue;
-			return;
-
-//		printf("dp8390 statistics of port %d:\n", i);
-
-		printf("recvErr    :%8ld\t", dep->de_stat.ets_recvErr);
-		printf("sendErr    :%8ld\t", dep->de_stat.ets_sendErr);
-		printf("OVW        :%8ld\n", dep->de_stat.ets_OVW);
-
-		printf("CRCerr     :%8ld\t", dep->de_stat.ets_CRCerr);
-		printf("frameAll   :%8ld\t", dep->de_stat.ets_frameAll);
-		printf("missedP    :%8ld\n", dep->de_stat.ets_missedP);
-
-		printf("packetR    :%8ld\t", dep->de_stat.ets_packetR);
-		printf("packetT    :%8ld\t", dep->de_stat.ets_packetT);
-		printf("transDef   :%8ld\n", dep->de_stat.ets_transDef);
-
-		printf("collision  :%8ld\t", dep->de_stat.ets_collision);
-		printf("transAb    :%8ld\t", dep->de_stat.ets_transAb);
-		printf("carrSense  :%8ld\n", dep->de_stat.ets_carrSense);
-
-		printf("fifoUnder  :%8ld\t", dep->de_stat.ets_fifoUnder);
-		printf("fifoOver   :%8ld\t", dep->de_stat.ets_fifoOver);
-		printf("CDheartbeat:%8ld\n", dep->de_stat.ets_CDheartbeat);
-
-		printf("OWC        :%8ld\t", dep->de_stat.ets_OWC);
-
-		isr= inb_reg0(dep, DP_ISR);
-		printf("dp_isr = 0x%x + 0x%x, de_flags = 0x%x\n", isr,
-					inb_reg0(dep, DP_ISR), dep->de_flags);
-//	}
-}
-
-/*===========================================================================*
- *				do_init					     *
- *===========================================================================*/
-int do_init(dpeth_t * dep, int mode){
-	if (dep->de_mode == DEM_DISABLED)
-	{
-		// might call do_probe()
+/** Initialize and/or start the network interface.
+ *
+ *  @param[in,out] dep The network interface structure.
+ *
+ *  @return EOK on success.
+ *  @return EXDEV if the network interface is disabled.
+ *
+ */
+int do_init(dpeth_t *dep)
+{
+	if (!dep->up)
+		/* FIXME: Perhaps call do_probe()? */
 		return EXDEV;
-	}
-
-	if (dep->de_mode == DEM_SINK)
-	{
-//		strncpy((char *) dep->de_address.ea_addr, "ZDP", 6);
-//		dep->de_address.ea_addr[5] = port;
-//		dp_confaddr(dep);
-//		reply_mess.m_type = DL_CONF_REPLY;
-//		reply_mess.m3_i1 = mp->DL_PORT;
-//		reply_mess.m3_i2 = DE_PORT_NR;
-//		*(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address;
-//		mess_reply(mp, &reply_mess);
-//		return;
-		return EOK;
-	}
-	assert(dep->de_mode == DEM_ENABLED);
-	assert(dep->de_flags &DEF_ENABLED);
-
-	dep->de_flags &= ~(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
-
-	if (mode &DL_PROMISC_REQ)
-		dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
-	if (mode &DL_MULTI_REQ)
-		dep->de_flags |= DEF_MULTI;
-	if (mode &DL_BROAD_REQ)
-		dep->de_flags |= DEF_BROAD;
-
-//	dep->de_client = mp->m_source;
+	
+	assert(dep->up);
+	assert(dep->enabled);
+	
 	dp_reinit(dep);
-
-//	reply_mess.m_type = DL_CONF_REPLY;
-//	reply_mess.m3_i1 = mp->DL_PORT;
-//	reply_mess.m3_i2 = DE_PORT_NR;
-//	*(ether_addr_t *) reply_mess.m3_ca1 = dep->de_address;
-
-//	mess_reply(mp, &reply_mess);
 	return EOK;
 }
 
-/*===========================================================================*
- *				do_stop					     *
- *===========================================================================*/
-void do_stop(dpeth_t * dep){
-	if((dep->de_mode != DEM_SINK) && (dep->de_mode == DEM_ENABLED) && (dep->de_flags &DEF_ENABLED)){
+void do_stop(dpeth_t *dep)
+{
+	if ((dep->up) && (dep->enabled)) {
 		outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
-		(dep->de_stopf)(dep);
-
-		dep->de_flags = DEF_EMPTY;
-	}
-}
-
-int queue_packet(dpeth_t * dep, packet_t *packet){
-	packet_t *tmp;
-
-	if(dep->packet_count >= MAX_PACKETS){
-		netif_pq_release(packet_get_id(packet));
-		return ELIMIT;
-	}
-
-	tmp = dep->packet_queue;
-	while(pq_next(tmp)){
-		tmp = pq_next(tmp);
-	}
-	if(pq_add(&tmp, packet, 0, 0) != EOK){
-		return EINVAL;
-	}
-	if(! dep->packet_count){
-		dep->packet_queue = packet;
-	}
-	++ dep->packet_count;
-	return EBUSY;
-}
-
-/*===========================================================================*
- *			based on	do_vwrite				     *
- *===========================================================================*/
-int do_pwrite(dpeth_t * dep, packet_t *packet, int from_int)
-{
-//	int port, count, size;
+		ne_stop(dep);
+		
+		dep->enabled = false;
+		dep->stopped = false;
+		dep->sending = false;
+		dep->send_avail = false;
+	}
+}
+
+static void dp_user2nic(dpeth_t *dep, void *buf, size_t offset, int nic_addr, size_t size)
+{
+	size_t ecount = size & ~1;
+	
+	outb_reg0(dep, DP_ISR, ISR_RDC);
+	
+	if (dep->de_16bit) {
+		outb_reg0(dep, DP_RBCR0, ecount & 0xff);
+		outb_reg0(dep, DP_RBCR1, ecount >> 8);
+	} else {
+		outb_reg0(dep, DP_RBCR0, size & 0xff);
+		outb_reg0(dep, DP_RBCR1, size >> 8);
+	}
+	
+	outb_reg0(dep, DP_RSAR0, nic_addr & 0xff);
+	outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
+	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
+	
+	if (dep->de_16bit) {
+		void *ptr = buf + offset;
+		
+		if (ecount != 0) {
+			outsw(dep->de_data_port, ptr, ecount);
+			size -= ecount;
+			offset += ecount;
+			ptr += ecount;
+		}
+		
+		if (size) {
+			assert(size == 1);
+			
+			uint16_t two_bytes;
+			
+			memcpy(&(((uint8_t *) &two_bytes)[0]), ptr, 1);
+			outw(dep->de_data_port, two_bytes);
+		}
+	} else
+		outsb(dep->de_data_port, buf + offset, size);
+	
+	unsigned int i;
+	for (i = 0; i < 100; i++) {
+		if (inb_reg0(dep, DP_ISR) & ISR_RDC)
+			break;
+	}
+	
+	if (i == 100)
+		fprintf(stderr, "Remote DMA failed to complete\n");
+}
+
+int do_pwrite(dpeth_t *dep, packet_t *packet, int from_int)
+{
 	int size;
 	int sendq_head;
-/*	dpeth_t *dep;
-
-	port = mp->DL_PORT;
-	count = mp->DL_COUNT;
-	if (port < 0 || port >= DE_PORT_NR)
-		panic("", "dp8390: illegal port", port);
-	dep= &de_table[port];
-	dep->de_client= mp->DL_PROC;
-*/
-	if (dep->de_mode == DEM_SINK)
-	{
-		assert(!from_int);
-//		dep->de_flags |= DEF_PACK_SEND;
-		reply(dep, OK, FALSE);
-//		return;
-		return EOK;
-	}
-	assert(dep->de_mode == DEM_ENABLED);
-	assert(dep->de_flags &DEF_ENABLED);
-	if(dep->packet_queue && (! from_int)){
-//	if (dep->de_flags &DEF_SEND_AVAIL){
-//		panic("", "dp8390: send already in progress", NO_NUM);
-		return queue_packet(dep, packet);
-	}
-
-	sendq_head= dep->de_sendq_head;
-//	if (dep->de_sendq[sendq_head].sq_filled)
-//	{
-//		if (from_int)
-//			panic("", "dp8390: should not be sending\n", NO_NUM);
-//		dep->de_sendmsg= *mp;
-//		dep->de_flags |= DEF_SEND_AVAIL;
-//		reply(dep, OK, FALSE);
-//		return;
-//		return queue_packet(dep, packet);
-//	}
-//	assert(!(dep->de_flags &DEF_PACK_SEND));
-
-/*	if (vectored)
-	{
-		get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
-			(count > IOVEC_NR ? IOVEC_NR : count) *
-			sizeof(iovec_t), dep->de_write_iovec.iod_iovec);
-		dep->de_write_iovec.iod_iovec_s = count;
-		dep->de_write_iovec.iod_proc_nr = mp->DL_PROC;
-		dep->de_write_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
-
-		dep->de_tmp_iovec = dep->de_write_iovec;
-		size = calc_iovec_size(&dep->de_tmp_iovec);
-	}
-	else
-	{ 
-		dep->de_write_iovec.iod_iovec[0].iov_addr =
-			(vir_bytes) mp->DL_ADDR;
-		dep->de_write_iovec.iod_iovec[0].iov_size =
-			mp->DL_COUNT;
-		dep->de_write_iovec.iod_iovec_s = 1;
-		dep->de_write_iovec.iod_proc_nr = mp->DL_PROC;
-		dep->de_write_iovec.iod_iovec_addr = 0;
-		size= mp->DL_COUNT;
-	}
-*/
+	
+	assert(dep->up);
+	assert(dep->enabled);
+	
+	if (dep->send_avail) {
+		fprintf(stderr, "Send already in progress\n");
+		return EBUSY;
+	}
+	
+	sendq_head = dep->de_sendq_head;
+	if (dep->de_sendq[sendq_head].sq_filled) {
+		if (from_int)
+			fprintf(stderr, "dp8390: should not be sending\n");
+		dep->send_avail = true;
+		dep->sending = false;
+		
+		return EBUSY;
+	}
+	
+	assert(!dep->sending);
+	
+	void *buf = packet_get_data(packet);
 	size = packet_get_data_length(packet);
-	dep->de_write_iovec.iod_iovec[0].iov_addr = (vir_bytes) packet_get_data(packet);
-	dep->de_write_iovec.iod_iovec[0].iov_size = size;
-	dep->de_write_iovec.iod_iovec_s = 1;
-	dep->de_write_iovec.iod_iovec_addr = (uintptr_t) NULL;
-
-	if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
-	{
-		panic("", "dp8390: invalid packet size", size);
+	
+	if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED) {
+		fprintf(stderr, "dp8390: invalid packet size\n");
 		return EINVAL;
 	}
-	(dep->de_user2nicf)(dep, &dep->de_write_iovec, 0,
-		dep->de_sendq[sendq_head].sq_sendpage * DP_PAGESIZE,
-		size);
-	dep->de_sendq[sendq_head].sq_filled= TRUE;
-	if (dep->de_sendq_tail == sendq_head)
-	{
+	
+	dp_user2nic(dep, buf, 0, dep->de_sendq[sendq_head].sq_sendpage
+	    * DP_PAGESIZE, size);
+	dep->de_sendq[sendq_head].sq_filled = true;
+	
+	if (dep->de_sendq_tail == sendq_head) {
 		outb_reg0(dep, DP_TPSR, dep->de_sendq[sendq_head].sq_sendpage);
 		outb_reg0(dep, DP_TBCR1, size >> 8);
-		outb_reg0(dep, DP_TBCR0, size &0xff);
-		outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);/* there it goes.. */
-	}
-	else
-		dep->de_sendq[sendq_head].sq_size= size;
+		outb_reg0(dep, DP_TBCR0, size & 0xff);
+		outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);  /* there it goes .. */
+	} else
+		dep->de_sendq[sendq_head].sq_size = size;
 	
 	if (++sendq_head == dep->de_sendq_nr)
-		sendq_head= 0;
+		sendq_head = 0;
+	
 	assert(sendq_head < SENDQ_NR);
-	dep->de_sendq_head= sendq_head;
-
-//	dep->de_flags |= DEF_PACK_SEND;
-
-	/* If the interrupt handler called, don't send a reply. The reply
-	 * will be sent after all interrupts are handled. 
-	 */
+	dep->de_sendq_head = sendq_head;
+	dep->sending = true;
+	
 	if (from_int)
 		return EOK;
-	reply(dep, OK, FALSE);
-
-	assert(dep->de_mode == DEM_ENABLED);
-	assert(dep->de_flags &DEF_ENABLED);
+	
+	dep->sending = false;
+	
 	return EOK;
 }
 
-/*===========================================================================*
- *				dp_init					     *
- *===========================================================================*/
-void dp_init(dep)
-dpeth_t *dep;
+void dp_init(dpeth_t *dep)
 {
 	int dp_rcr_reg;
-	int i;//, r;
-
+	int i;
+	
 	/* General initialization */
-	dep->de_flags = DEF_EMPTY;
-	(*dep->de_initf)(dep);
-
-//	dp_confaddr(dep);
-
-	if (debug)
-	{
-		printf("%s: Ethernet address ", dep->de_name);
-		for (i= 0; i < 6; i++)
-			printf("%x%c", dep->de_address.ea_addr[i],
-							i < 5 ? ':' : '\n');
-	}
-
-	/* Map buffer */
-	map_hw_buffer(dep);
-
-	/* Initialization of the dp8390 following the mandatory procedure
+	dep->enabled = false;
+	dep->stopped = false;
+	dep->sending = false;
+	dep->send_avail = false;
+	ne_init(dep);
+	
+	printf("Ethernet address ");
+	for (i = 0; i < 6; i++)
+		printf("%x%c", dep->de_address.ea_addr[i], i < 5 ? ':' : '\n');
+	
+	/*
+	 * Initialization of the dp8390 following the mandatory procedure
 	 * in reference manual ("DP8390D/NS32490D NIC Network Interface
 	 * Controller", National Semiconductor, July 1995, Page 29).
 	 */
+	
 	/* Step 1: */
 	outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
+	
 	/* Step 2: */
 	if (dep->de_16bit)
@@ -509,30 +279,32 @@
 	else
 		outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES | DCR_BMS);
+	
 	/* Step 3: */
 	outb_reg0(dep, DP_RBCR0, 0);
 	outb_reg0(dep, DP_RBCR1, 0);
+	
 	/* Step 4: */
-	dp_rcr_reg = 0;
-	if (dep->de_flags &DEF_PROMISC)
-		dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM;
-	if (dep->de_flags &DEF_BROAD)
-		dp_rcr_reg |= RCR_AB;
-	if (dep->de_flags &DEF_MULTI)
-		dp_rcr_reg |= RCR_AM;
+	dp_rcr_reg = RCR_AB;  /* Enable broadcasts */
+	
 	outb_reg0(dep, DP_RCR, dp_rcr_reg);
+	
 	/* Step 5: */
 	outb_reg0(dep, DP_TCR, TCR_INTERNAL);
+	
 	/* Step 6: */
 	outb_reg0(dep, DP_BNRY, dep->de_startpage);
 	outb_reg0(dep, DP_PSTART, dep->de_startpage);
 	outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
+	
 	/* Step 7: */
 	outb_reg0(dep, DP_ISR, 0xFF);
+	
 	/* Step 8: */
 	outb_reg0(dep, DP_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE |
-		IMR_OVWE | IMR_CNTE);
+	    IMR_OVWE | IMR_CNTE);
+	
 	/* Step 9: */
 	outb_reg0(dep, DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
-
+	
 	outb_reg1(dep, DP_PAR0, dep->de_address.ea_addr[0]);
 	outb_reg1(dep, DP_PAR1, dep->de_address.ea_addr[1]);
@@ -541,5 +313,5 @@
 	outb_reg1(dep, DP_PAR4, dep->de_address.ea_addr[4]);
 	outb_reg1(dep, DP_PAR5, dep->de_address.ea_addr[5]);
-
+	
 	outb_reg1(dep, DP_MAR0, 0xff);
 	outb_reg1(dep, DP_MAR1, 0xff);
@@ -550,1081 +322,340 @@
 	outb_reg1(dep, DP_MAR6, 0xff);
 	outb_reg1(dep, DP_MAR7, 0xff);
-
+	
 	outb_reg1(dep, DP_CURR, dep->de_startpage + 1);
+	
 	/* Step 10: */
 	outb_reg0(dep, DP_CR, CR_DM_ABORT | CR_STA);
+	
 	/* Step 11: */
 	outb_reg0(dep, DP_TCR, TCR_NORMAL);
-
-	inb_reg0(dep, DP_CNTR0);		/* reset counters by reading */
+	
+	inb_reg0(dep, DP_CNTR0);  /* Reset counters by reading */
 	inb_reg0(dep, DP_CNTR1);
 	inb_reg0(dep, DP_CNTR2);
-
+	
 	/* Finish the initialization. */
-	dep->de_flags |= DEF_ENABLED;
-	for (i= 0; i<dep->de_sendq_nr; i++)
+	dep->enabled = true;
+	for (i = 0; i < dep->de_sendq_nr; i++)
 		dep->de_sendq[i].sq_filled= 0;
-	dep->de_sendq_head= 0;
-	dep->de_sendq_tail= 0;
-	if (!dep->de_prog_IO)
-	{
-		dep->de_user2nicf= dp_user2nic;
-//		dep->de_user2nicf_s= dp_user2nic_s;
-		dep->de_nic2userf= dp_nic2user;
-//		dep->de_nic2userf_s= dp_nic2user_s;
-		dep->de_getblockf= dp_getblock;
-	}
-	else if (dep->de_16bit)
-	{
-		dep->de_user2nicf= dp_pio16_user2nic;
-//		dep->de_user2nicf_s= dp_pio16_user2nic_s;
-		dep->de_nic2userf= dp_pio16_nic2user;
-//		dep->de_nic2userf_s= dp_pio16_nic2user_s;
-		dep->de_getblockf= dp_pio16_getblock;
-	}
-	else
-	{
-		dep->de_user2nicf= dp_pio8_user2nic;
-//		dep->de_user2nicf_s= dp_pio8_user2nic_s;
-		dep->de_nic2userf= dp_pio8_nic2user;
-//		dep->de_nic2userf_s= dp_pio8_nic2user_s;
-		dep->de_getblockf= dp_pio8_getblock;
-	}
-
-	/* Set the interrupt handler and policy. Do not automatically 
-	 * reenable interrupts. Return the IRQ line number on interrupts.
- 	 */
-/* 	dep->de_hook = dep->de_irq;
-	r= sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
-	if (r != OK)
-		panic("DP8390", "sys_irqsetpolicy failed", r);
-
-	r= sys_irqenable(&dep->de_hook);
-	if (r != OK)
-	{
-		panic("DP8390", "unable enable interrupts", r);
-	}
-*/
-}
-
-/*===========================================================================*
- *				dp_reinit				     *
- *===========================================================================*/
-static void dp_reinit(dep)
-dpeth_t *dep;
+	
+	dep->de_sendq_head = 0;
+	dep->de_sendq_tail = 0;
+}
+
+static void dp_reinit(dpeth_t *dep)
 {
 	int dp_rcr_reg;
-
+	
 	outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
-
-	dp_rcr_reg = 0;
-	if (dep->de_flags &DEF_PROMISC)
-		dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM;
-	if (dep->de_flags &DEF_BROAD)
-		dp_rcr_reg |= RCR_AB;
-	if (dep->de_flags &DEF_MULTI)
-		dp_rcr_reg |= RCR_AM;
+	
+	/* Enable broadcasts */
+	dp_rcr_reg = RCR_AB;
+	
 	outb_reg0(dep, DP_RCR, dp_rcr_reg);
 }
 
-/*===========================================================================*
- *				dp_reset				     *
- *===========================================================================*/
-static void dp_reset(dep)
-dpeth_t *dep;
+static void dp_reset(dpeth_t *dep)
 {
 	int i;
-
+	
 	/* Stop chip */
 	outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
 	outb_reg0(dep, DP_RBCR0, 0);
 	outb_reg0(dep, DP_RBCR1, 0);
-	for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) &ISR_RST) == 0); i++)
+	
+	for (i = 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
 		; /* Do nothing */
-	outb_reg0(dep, DP_TCR, TCR_1EXTERNAL|TCR_OFST);
-	outb_reg0(dep, DP_CR, CR_STA|CR_DM_ABORT);
+	
+	outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
+	outb_reg0(dep, DP_CR, CR_STA | CR_DM_ABORT);
 	outb_reg0(dep, DP_TCR, TCR_NORMAL);
-
-	/* Acknowledge the ISR_RDC (remote dma) interrupt. */
-	for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) &ISR_RDC) == 0); i++)
+	
+	/* Acknowledge the ISR_RDC (remote DMA) interrupt. */
+	for (i = 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) &ISR_RDC) == 0); i++)
 		; /* Do nothing */
-	outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) &~ISR_RDC);
-
-	/* Reset the transmit ring. If we were transmitting a packet, we
+	
+	outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & ~ISR_RDC);
+	
+	/*
+	 * Reset the transmit ring. If we were transmitting a packet, we
 	 * pretend that the packet is processed. Higher layers will
 	 * retransmit if the packet wasn't actually sent.
 	 */
-	dep->de_sendq_head= dep->de_sendq_tail= 0;
-	for (i= 0; i<dep->de_sendq_nr; i++)
-		dep->de_sendq[i].sq_filled= 0;
-	dp_send(dep);
-	dep->de_flags &= ~DEF_STOPPED;
-}
-
-/*===========================================================================*
- *				dp_check_ints				     *
- *===========================================================================*/
-void dp_check_ints(dep, isr)
-dpeth_t *dep;
-int isr;
-{
-	int /*isr,*/ tsr;
+	dep->de_sendq_head = 0;
+	dep->de_sendq_tail = 0;
+	
+	for (i = 0; i < dep->de_sendq_nr; i++)
+		dep->de_sendq[i].sq_filled = 0;
+	
+	dep->send_avail = false;
+	dep->stopped = false;
+}
+
+static uint8_t isr_acknowledge(dpeth_t *dep)
+{
+	uint8_t isr = inb_reg0(dep, DP_ISR);
+	if (isr != 0)
+		outb_reg0(dep, DP_ISR, isr);
+	
+	return isr;
+}
+
+void dp_check_ints(int nil_phone, device_id_t device_id, dpeth_t *dep, uint8_t isr)
+{
+	int tsr;
 	int size, sendq_tail;
-
-	if (!(dep->de_flags &DEF_ENABLED))
-		panic("", "dp8390: got premature interrupt", NO_NUM);
-
-	for(;;)
-	{
-//		isr = inb_reg0(dep, DP_ISR);
-		if (!isr)
-			break;
-		outb_reg0(dep, DP_ISR, isr);
-		if (isr &(ISR_PTX|ISR_TXE))
-		{
-			if (isr &ISR_TXE)
-			{
-#if DEBUG
- {printf("%s: got send Error\n", dep->de_name);}
-#endif
+	
+	for (; (isr & 0x7f) != 0; isr = isr_acknowledge(dep)) {
+		if (isr & (ISR_PTX | ISR_TXE)) {
+			if (isr & ISR_TXE)
 				dep->de_stat.ets_sendErr++;
+			else {
+				tsr = inb_reg0(dep, DP_TSR);
+				
+				if (tsr & TSR_PTX)
+					dep->de_stat.ets_packetT++;
+				
+				if (tsr & TSR_COL)
+					dep->de_stat.ets_collision++;
+				
+				if (tsr & TSR_ABT)
+					dep->de_stat.ets_transAb++;
+				
+				if (tsr & TSR_CRS)
+					dep->de_stat.ets_carrSense++;
+				
+				if ((tsr & TSR_FU) && (++dep->de_stat.ets_fifoUnder <= 10))
+					printf("FIFO underrun\n");
+				
+				if ((tsr & TSR_CDH) && (++dep->de_stat.ets_CDheartbeat <= 10))
+					printf("CD heart beat failure\n");
+				
+				if (tsr & TSR_OWC)
+					dep->de_stat.ets_OWC++;
 			}
-			else
-			{
-				tsr = inb_reg0(dep, DP_TSR);
-
-				if (tsr &TSR_PTX) dep->de_stat.ets_packetT++;
-#if 0	/* Reserved in later manuals, should be ignored */
-				if (!(tsr &TSR_DFR))
-				{
-					/* In most (all?) implementations of
-					 * the dp8390, this bit is set
-					 * when the packet is not deferred
-					 */
-					dep->de_stat.ets_transDef++;
-				}
-#endif
-				if (tsr &TSR_COL) dep->de_stat.ets_collision++;
-				if (tsr &TSR_ABT) dep->de_stat.ets_transAb++;
-				if (tsr &TSR_CRS) dep->de_stat.ets_carrSense++;
-				if (tsr &TSR_FU
-					&& ++dep->de_stat.ets_fifoUnder <= 10)
-				{
-					printf("%s: fifo underrun\n",
-						dep->de_name);
-				}
-				if (tsr &TSR_CDH
-					&& ++dep->de_stat.ets_CDheartbeat <= 10)
-				{
-					printf("%s: CD heart beat failure\n",
-						dep->de_name);
-				}
-				if (tsr &TSR_OWC) dep->de_stat.ets_OWC++;
-			}
-			sendq_tail= dep->de_sendq_tail;
-
-			if (!(dep->de_sendq[sendq_tail].sq_filled))
-			{
-				/* Software bug? */
-				assert(!debug);
-
-				/* Or hardware bug? */
-				printf(
-				"%s: transmit interrupt, but not sending\n",
-					dep->de_name);
+			
+			sendq_tail = dep->de_sendq_tail;
+			
+			if (!(dep->de_sendq[sendq_tail].sq_filled)) {
+				printf("PTX interrupt, but no frame to send\n");
 				continue;
 			}
-			dep->de_sendq[sendq_tail].sq_filled= 0;
+			
+			dep->de_sendq[sendq_tail].sq_filled = false;
+			
 			if (++sendq_tail == dep->de_sendq_nr)
-				sendq_tail= 0;
-			dep->de_sendq_tail= sendq_tail;
-			if (dep->de_sendq[sendq_tail].sq_filled)
-			{
-				size= dep->de_sendq[sendq_tail].sq_size;
+				sendq_tail = 0;
+			
+			dep->de_sendq_tail = sendq_tail;
+			
+			if (dep->de_sendq[sendq_tail].sq_filled) {
+				size = dep->de_sendq[sendq_tail].sq_size;
 				outb_reg0(dep, DP_TPSR,
-					dep->de_sendq[sendq_tail].sq_sendpage);
+				    dep->de_sendq[sendq_tail].sq_sendpage);
 				outb_reg0(dep, DP_TBCR1, size >> 8);
-				outb_reg0(dep, DP_TBCR0, size &0xff);
+				outb_reg0(dep, DP_TBCR0, size & 0xff);
 				outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);
 			}
-//			if (dep->de_flags &DEF_SEND_AVAIL)
-				dp_send(dep);
-		}
-
-		if (isr &ISR_PRX)
-		{
-			/* Only call dp_recv if there is a read request */
-//			if (dep->de_flags) &DEF_READING)
-				dp_recv(dep);
-		}
-		
-		if (isr &ISR_RXE) dep->de_stat.ets_recvErr++;
-		if (isr &ISR_CNT)
-		{
+			
+			dep->send_avail = false;
+		}
+		
+		if (isr & ISR_PRX)
+			dp_recv(nil_phone, device_id, dep);
+		
+		if (isr & ISR_RXE)
+			dep->de_stat.ets_recvErr++;
+		
+		if (isr & ISR_CNT) {
 			dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
 			dep->de_stat.ets_frameAll += inb_reg0(dep, DP_CNTR1);
 			dep->de_stat.ets_missedP += inb_reg0(dep, DP_CNTR2);
 		}
-		if (isr &ISR_OVW)
-		{
+		
+		if (isr & ISR_OVW)
 			dep->de_stat.ets_OVW++;
-#if 0
-			{printW(); printf(
-				"%s: got overwrite warning\n", dep->de_name);}
-#endif
-/*			if (dep->de_flags &DEF_READING)
-			{
-				printf(
-"dp_check_ints: strange: overwrite warning and pending read request\n");
-				dp_recv(dep);
-			}
-*/		}
-		if (isr &ISR_RDC)
-		{
+		
+		if (isr & ISR_RDC) {
 			/* Nothing to do */
 		}
-		if (isr &ISR_RST)
-		{
-			/* this means we got an interrupt but the ethernet 
-			 * chip is shutdown. We set the flag DEF_STOPPED,
+		
+		if (isr & ISR_RST) {
+			/*
+			 * This means we got an interrupt but the ethernet
+			 * chip is shutdown. We set the flag 'stopped'
 			 * and continue processing arrived packets. When the
 			 * receive buffer is empty, we reset the dp8390.
 			 */
-#if 0
-			 {printW(); printf(
-				"%s: NIC stopped\n", dep->de_name);}
-#endif
-			dep->de_flags |= DEF_STOPPED;
+			dep->stopped = true;
 			break;
 		}
-		isr = inb_reg0(dep, DP_ISR);
-	}
-//	if ((dep->de_flags &(DEF_READING|DEF_STOPPED)) == 
-//						(DEF_READING|DEF_STOPPED))
-	if ((dep->de_flags &DEF_STOPPED) == DEF_STOPPED)
-	{
-		/* The chip is stopped, and all arrived packets are 
-		 * delivered.
+	}
+	
+	if (dep->stopped) {
+		/*
+		 * The chip is stopped, and all arrived
+		 * frames are delivered.
 		 */
 		dp_reset(dep);
 	}
-}
-
-/*===========================================================================*
- *				dp_recv					     *
- *===========================================================================*/
-static void dp_recv(dep)
-dpeth_t *dep;
+	
+	dep->sending = false;
+}
+
+static void dp_getblock(dpeth_t *dep, int page, size_t offset, size_t size, void *dst)
+{
+	offset = page * DP_PAGESIZE + offset;
+	
+	outb_reg0(dep, DP_RBCR0, size & 0xff);
+	outb_reg0(dep, DP_RBCR1, size >> 8);
+	outb_reg0(dep, DP_RSAR0, offset & 0xff);
+	outb_reg0(dep, DP_RSAR1, offset >> 8);
+	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+	
+	if (dep->de_16bit) {
+		assert((size % 2) == 0);
+		insw(dep->de_data_port, dst, size);
+	} else
+		insb(dep->de_data_port, dst, size);
+}
+
+static void dp_recv(int nil_phone, device_id_t device_id, dpeth_t *dep)
 {
 	dp_rcvhdr_t header;
-	//unsigned pageno, curr, next;
 	int pageno, curr, next;
-	vir_bytes length;
+	size_t length;
 	int packet_processed, r;
-	u16_t eth_type;
-
-	packet_processed = FALSE;
+	uint16_t eth_type;
+	
+	packet_processed = false;
 	pageno = inb_reg0(dep, DP_BNRY) + 1;
-	if (pageno == dep->de_stoppage) pageno = dep->de_startpage;
-
-	do
-	{
+	if (pageno == dep->de_stoppage)
+		pageno = dep->de_startpage;
+	
+	do {
 		outb_reg0(dep, DP_CR, CR_PS_P1 | CR_EXTRA);
 		curr = inb_reg1(dep, DP_CURR);
 		outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
-
-		if (curr == pageno) break;
-
-		(dep->de_getblockf)(dep, pageno, (size_t)0, sizeof(header),
-			&header);
-		(dep->de_getblockf)(dep, pageno, sizeof(header) +
-			2*sizeof(ether_addr_t), sizeof(eth_type), &eth_type);
-
-		length = (header.dr_rbcl | (header.dr_rbch << 8)) -
-			sizeof(dp_rcvhdr_t);
+		
+		if (curr == pageno)
+			break;
+		
+		dp_getblock(dep, pageno, (size_t) 0, sizeof(header), &header);
+		dp_getblock(dep, pageno, sizeof(header) +
+		    2 * sizeof(ether_addr_t), sizeof(eth_type), &eth_type);
+		
+		length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t);
 		next = header.dr_next;
-		if (length < ETH_MIN_PACK_SIZE ||
-			length > ETH_MAX_PACK_SIZE_TAGGED)
-		{
-			printf("%s: packet with strange length arrived: %d\n",
-				dep->de_name, (int) length);
+		if ((length < ETH_MIN_PACK_SIZE) || (length > ETH_MAX_PACK_SIZE_TAGGED)) {
+			printf("Packet with strange length arrived: %zu\n", length);
 			next= curr;
-		}
-		else if (next < dep->de_startpage || next >= dep->de_stoppage)
-		{
-			printf("%s: strange next page\n", dep->de_name);
+		} else if ((next < dep->de_startpage) || (next >= dep->de_stoppage)) {
+			printf("Strange next page\n");
 			next= curr;
-		}
-/*		else if (eth_type == eth_ign_proto)
-		{
-*/			/* Hack: ignore packets of a given protocol, useful
-			 * if you share a net with 80 computers sending
-			 * Amoeba FLIP broadcasts.  (Protocol 0x8146.)
+		} else if (header.dr_status & RSR_FO) {
+			/*
+			 * This is very serious, so we issue a warning and
+			 * reset the buffers
 			 */
-/*			static int first= 1;
-			if (first)
-			{
-				first= 0;
-				printf("%s: dropping proto 0x%04x packets\n",
-					dep->de_name,
-					ntohs(eth_ign_proto));
-			}
-			dep->de_stat.ets_packetR++;
-		}
-*/		else if (header.dr_status &RSR_FO)
-		{
-			/* This is very serious, so we issue a warning and
-			 * reset the buffers */
-			printf("%s: fifo overrun, resetting receive buffer\n",
-				dep->de_name);
+			printf("FIFO overrun, resetting receive buffer\n");
 			dep->de_stat.ets_fifoOver++;
 			next = curr;
-		}
-		else if ((header.dr_status &RSR_PRX) && 
-					   (dep->de_flags &DEF_ENABLED))
-		{
-//			if (dep->de_safecopy_read)
-//				r = dp_pkt2user_s(dep, pageno, length);
-//			else
-				r = dp_pkt2user(dep, pageno, length);
-			if (r != OK)
+		} else if ((header.dr_status & RSR_PRX) && (dep->enabled)) {
+			r = dp_pkt2user(nil_phone, device_id, dep, pageno, length);
+			if (r != EOK)
 				return;
-
-			packet_processed = TRUE;
+			
+			packet_processed = true;
 			dep->de_stat.ets_packetR++;
 		}
+		
 		if (next == dep->de_startpage)
 			outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
 		else
 			outb_reg0(dep, DP_BNRY, next - 1);
-
+		
 		pageno = next;
-	}
-	while (!packet_processed);
-}
-
-/*===========================================================================*
- *				dp_send					     *
- *===========================================================================*/
-static void dp_send(dep)
-dpeth_t *dep;
-{
-	packet_t *packet;
-
-//	if (!(dep->de_flags &DEF_SEND_AVAIL))
-//		return;
-
-	if(dep->packet_queue){
-		packet = dep->packet_queue;
-		dep->packet_queue = pq_detach(packet);
-		do_pwrite(dep, packet, TRUE);
-		netif_pq_release(packet_get_id(packet));
-		-- dep->packet_count;
-	}
-//	if(! dep->packet_queue){
-//		dep->de_flags &= ~DEF_SEND_AVAIL;
-//	}
-/*	switch(dep->de_sendmsg.m_type)
-	{
-	case DL_WRITE:	do_vwrite(&dep->de_sendmsg, TRUE, FALSE);	break;
-	case DL_WRITEV:	do_vwrite(&dep->de_sendmsg, TRUE, TRUE);	break;
-	case DL_WRITEV_S: do_vwrite_s(&dep->de_sendmsg, TRUE);	break;
-	default:
-		panic("", "dp8390: wrong type", dep->de_sendmsg.m_type);
-		break;
-	}
-*/
-}
-
-/*===========================================================================*
- *				dp_getblock				     *
- *===========================================================================*/
-static void dp_getblock(dep, page, offset, size, dst)
-dpeth_t *dep;
-int page;
-size_t offset;
-size_t size;
-void *dst;
-{
-//	int r;
-
-	offset = page * DP_PAGESIZE + offset;
-
-	memcpy(dst, dep->de_locmem + offset, size);
-}
-
-/*===========================================================================*
- *				dp_pio8_getblock			     *
- *===========================================================================*/
-static void dp_pio8_getblock(dep, page, offset, size, dst)
-dpeth_t *dep;
-int page;
-size_t offset;
-size_t size;
-void *dst;
-{
-	offset = page * DP_PAGESIZE + offset;
-	outb_reg0(dep, DP_RBCR0, size &0xFF);
-	outb_reg0(dep, DP_RBCR1, size >> 8);
-	outb_reg0(dep, DP_RSAR0, offset &0xFF);
-	outb_reg0(dep, DP_RSAR1, offset >> 8);
+	} while (!packet_processed);
+}
+
+static void dp_nic2user(dpeth_t *dep, int nic_addr, void *buf, size_t offset, size_t size)
+{
+	size_t ecount = size & ~1;
+	
+	if (dep->de_16bit) {
+		outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
+		outb_reg0(dep, DP_RBCR1, ecount >> 8);
+	} else {
+		outb_reg0(dep, DP_RBCR0, size & 0xff);
+		outb_reg0(dep, DP_RBCR1, size >> 8);
+	}
+	
+	outb_reg0(dep, DP_RSAR0, nic_addr & 0xff);
+	outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
-
-	insb(dep->de_data_port, dst, size);
-}
-
-/*===========================================================================*
- *				dp_pio16_getblock			     *
- *===========================================================================*/
-static void dp_pio16_getblock(dep, page, offset, size, dst)
-dpeth_t *dep;
-int page;
-size_t offset;
-size_t size;
-void *dst;
-{
-	offset = page * DP_PAGESIZE + offset;
-	outb_reg0(dep, DP_RBCR0, size &0xFF);
-	outb_reg0(dep, DP_RBCR1, size >> 8);
-	outb_reg0(dep, DP_RSAR0, offset &0xFF);
-	outb_reg0(dep, DP_RSAR1, offset >> 8);
-	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
-
-	assert (!(size &1));
-	insw(dep->de_data_port, dst, size);
-}
-
-/*===========================================================================*
- *				dp_pkt2user				     *
- *===========================================================================*/
-static int dp_pkt2user(dep, page, length)
-dpeth_t *dep;
-int page, length;
+	
+	if (dep->de_16bit) {
+		void *ptr = buf + offset;
+		
+		if (ecount != 0) {
+			insw(dep->de_data_port, ptr, ecount);
+			size -= ecount;
+			offset += ecount;
+			ptr += ecount;
+		}
+		
+		if (size) {
+			assert(size == 1);
+			
+			uint16_t two_bytes = inw(dep->de_data_port);
+			memcpy(ptr, &(((uint8_t *) &two_bytes)[0]), 1);
+		}
+	} else
+		insb(dep->de_data_port, buf + offset, size);
+}
+
+static int dp_pkt2user(int nil_phone, device_id_t device_id, dpeth_t *dep, int page, int length)
 {
 	int last, count;
 	packet_t *packet;
-
-//	if (!(dep->de_flags &DEF_READING))
-//		return EGENERIC;
-
+	
 	packet = netif_packet_get_1(length);
-	if(! packet){
+	if (!packet)
 		return ENOMEM;
-	}
-	dep->de_read_iovec.iod_iovec[0].iov_addr = (vir_bytes) packet_suffix(packet, length);
-	dep->de_read_iovec.iod_iovec[0].iov_size = length;
-	dep->de_read_iovec.iod_iovec_s = 1;
-	dep->de_read_iovec.iod_iovec_addr = (uintptr_t) NULL;
-
+	
+	void *buf = packet_suffix(packet, length);
+	
 	last = page + (length - 1) / DP_PAGESIZE;
-	if (last >= dep->de_stoppage)
-	{
-		count = (dep->de_stoppage - page) * DP_PAGESIZE -
-			sizeof(dp_rcvhdr_t);
-
-		/* Save read_iovec since we need it twice. */
-		dep->de_tmp_iovec = dep->de_read_iovec;
-		(dep->de_nic2userf)(dep, page * DP_PAGESIZE +
-			sizeof(dp_rcvhdr_t), &dep->de_tmp_iovec, 0, count);
-		(dep->de_nic2userf)(dep, dep->de_startpage * DP_PAGESIZE, 
-			&dep->de_read_iovec, count, length - count);
-	}
-	else
-	{
-		(dep->de_nic2userf)(dep, page * DP_PAGESIZE +
-			sizeof(dp_rcvhdr_t), &dep->de_read_iovec, 0, length);
-	}
-
-	dep->de_read_s = length;
-	dep->de_flags |= DEF_PACK_RECV;
-//	dep->de_flags &= ~DEF_READING;
-
-	if(dep->received_count >= MAX_PACKETS){
-		netif_pq_release(packet_get_id(packet));
-		return ELIMIT;
-	}else{
-		if(pq_add(&dep->received_queue, packet, 0, 0) == EOK){
-			++ dep->received_count;
-		}else{
-			netif_pq_release(packet_get_id(packet));
-		}
-	}
-	return OK;
-}
-
-/*===========================================================================*
- *				dp_user2nic				     *
- *===========================================================================*/
-static void dp_user2nic(dep, iovp, offset, nic_addr, count)
-dpeth_t *dep;
-iovec_dat_t *iovp;
-vir_bytes offset;
-int nic_addr;
-vir_bytes count;
-{
-	vir_bytes vir_hw;//, vir_user;
-	//int bytes, i, r;
-	int i, r;
-	vir_bytes bytes;
-
-	vir_hw = (vir_bytes)dep->de_locmem + nic_addr;
-
-	i= 0;
-	while (count > 0)
-	{
-		if (i >= IOVEC_NR)
-		{
-			dp_next_iovec(iovp);
-			i= 0;
-			continue;
-		}
-		assert(i < iovp->iod_iovec_s);
-		if (offset >= iovp->iod_iovec[i].iov_size)
-		{
-			offset -= iovp->iod_iovec[i].iov_size;
-			i++;
-			continue;
-		}
-		bytes = iovp->iod_iovec[i].iov_size - offset;
-		if (bytes > count)
-			bytes = count;
-
-		r= sys_vircopy(iovp->iod_proc_nr, D,
-			iovp->iod_iovec[i].iov_addr + offset,
-			SELF, D, vir_hw, bytes);
-		if (r != OK)
-			panic("DP8390", "dp_user2nic: sys_vircopy failed", r);
-
-		count -= bytes;
-		vir_hw += bytes;
-		offset += bytes;
-	}
-	assert(count == 0);
-}
-
-/*===========================================================================*
- *				dp_pio8_user2nic			     *
- *===========================================================================*/
-static void dp_pio8_user2nic(dep, iovp, offset, nic_addr, count)
-dpeth_t *dep;
-iovec_dat_t *iovp;
-vir_bytes offset;
-int nic_addr;
-vir_bytes count;
-{
-//	phys_bytes phys_user;
-	int i;
-	vir_bytes bytes;
-
-	outb_reg0(dep, DP_ISR, ISR_RDC);
-
-	outb_reg0(dep, DP_RBCR0, count &0xFF);
-	outb_reg0(dep, DP_RBCR1, count >> 8);
-	outb_reg0(dep, DP_RSAR0, nic_addr &0xFF);
-	outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
-	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
-
-	i= 0;
-	while (count > 0)
-	{
-		if (i >= IOVEC_NR)
-		{
-			dp_next_iovec(iovp);
-			i= 0;
-			continue;
-		}
-		assert(i < iovp->iod_iovec_s);
-		if (offset >= iovp->iod_iovec[i].iov_size)
-		{
-			offset -= iovp->iod_iovec[i].iov_size;
-			i++;
-			continue;
-		}
-		bytes = iovp->iod_iovec[i].iov_size - offset;
-		if (bytes > count)
-			bytes = count;
-
-		do_vir_outsb(dep->de_data_port, iovp->iod_proc_nr,
-			iovp->iod_iovec[i].iov_addr + offset, bytes);
-		count -= bytes;
-		offset += bytes;
-	}
-	assert(count == 0);
-
-	for (i= 0; i<100; i++)
-	{
-		if (inb_reg0(dep, DP_ISR) &ISR_RDC)
-			break;
-	}
-	if (i == 100)
-	{
-		panic("", "dp8390: remote dma failed to complete", NO_NUM);
-	}
-}
-
-/*===========================================================================*
- *				dp_pio16_user2nic			     *
- *===========================================================================*/
-static void dp_pio16_user2nic(dep, iovp, offset, nic_addr, count)
-dpeth_t *dep;
-iovec_dat_t *iovp;
-vir_bytes offset;
-int nic_addr;
-vir_bytes count;
-{
-	vir_bytes vir_user;
-	vir_bytes ecount;
-	int i, r, user_proc;
-	vir_bytes bytes;
-	//u8_t two_bytes[2];
-	u16_t two_bytes;
-	int odd_byte;
-
-	ecount= (count+1) &~1;
-	odd_byte= 0;
-
-	outb_reg0(dep, DP_ISR, ISR_RDC);
-	outb_reg0(dep, DP_RBCR0, ecount &0xFF);
-	outb_reg0(dep, DP_RBCR1, ecount >> 8);
-	outb_reg0(dep, DP_RSAR0, nic_addr &0xFF);
-	outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
-	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
-
-	i= 0;
-	while (count > 0)
-	{
-		if (i >= IOVEC_NR)
-		{
-			dp_next_iovec(iovp);
-			i= 0;
-			continue;
-		}
-		assert(i < iovp->iod_iovec_s);
-		if (offset >= iovp->iod_iovec[i].iov_size)
-		{
-			offset -= iovp->iod_iovec[i].iov_size;
-			i++;
-			continue;
-		}
-		bytes = iovp->iod_iovec[i].iov_size - offset;
-		if (bytes > count)
-			bytes = count;
-
-		user_proc= iovp->iod_proc_nr;
-		vir_user= iovp->iod_iovec[i].iov_addr + offset;
-		if (odd_byte)
-		{
-			r= sys_vircopy(user_proc, D, vir_user, 
-			//	SELF, D, (vir_bytes)&two_bytes[1], 1);
-				SELF, D, (vir_bytes)&(((u8_t *)&two_bytes)[1]), 1);
-			if (r != OK)
-			{
-				panic("DP8390",
-					"dp_pio16_user2nic: sys_vircopy failed",
-					r);
-			}
-			//outw(dep->de_data_port, *(u16_t *)two_bytes);
-			outw(dep->de_data_port, two_bytes);
-			count--;
-			offset++;
-			bytes--;
-			vir_user++;
-			odd_byte= 0;
-			if (!bytes)
-				continue;
-		}
-		ecount= bytes &~1;
-		if (ecount != 0)
-		{
-			do_vir_outsw(dep->de_data_port, user_proc, vir_user,
-				ecount);
-			count -= ecount;
-			offset += ecount;
-			bytes -= ecount;
-			vir_user += ecount;
-		}
-		if (bytes)
-		{
-			assert(bytes == 1);
-			r= sys_vircopy(user_proc, D, vir_user, 
-			//	SELF, D, (vir_bytes)&two_bytes[0], 1);
-				SELF, D, (vir_bytes)&(((u8_t *)&two_bytes)[0]), 1);
-			if (r != OK)
-			{
-				panic("DP8390",
-					"dp_pio16_user2nic: sys_vircopy failed",
-					r);
-			}
-			count--;
-			offset++;
-			bytes--;
-			vir_user++;
-			odd_byte= 1;
-		}
-	}
-	assert(count == 0);
-
-	if (odd_byte)
-		//outw(dep->de_data_port, *(u16_t *)two_bytes);
-		outw(dep->de_data_port, two_bytes);
-
-	for (i= 0; i<100; i++)
-	{
-		if (inb_reg0(dep, DP_ISR) &ISR_RDC)
-			break;
-	}
-	if (i == 100)
-	{
-		panic("", "dp8390: remote dma failed to complete", NO_NUM);
-	}
-}
-
-/*===========================================================================*
- *				dp_nic2user				     *
- *===========================================================================*/
-static void dp_nic2user(dep, nic_addr, iovp, offset, count)
-dpeth_t *dep;
-int nic_addr;
-iovec_dat_t *iovp;
-vir_bytes offset;
-vir_bytes count;
-{
-	vir_bytes vir_hw;//, vir_user;
-	vir_bytes bytes;
-	int i, r;
-
-	vir_hw = (vir_bytes)dep->de_locmem + nic_addr;
-
-	i= 0;
-	while (count > 0)
-	{
-		if (i >= IOVEC_NR)
-		{
-			dp_next_iovec(iovp);
-			i= 0;
-			continue;
-		}
-		assert(i < iovp->iod_iovec_s);
-		if (offset >= iovp->iod_iovec[i].iov_size)
-		{
-			offset -= iovp->iod_iovec[i].iov_size;
-			i++;
-			continue;
-		}
-		bytes = iovp->iod_iovec[i].iov_size - offset;
-		if (bytes > count)
-			bytes = count;
-
-		r= sys_vircopy(SELF, D, vir_hw,
-			iovp->iod_proc_nr, D,
-			iovp->iod_iovec[i].iov_addr + offset, bytes);
-		if (r != OK)
-			panic("DP8390", "dp_nic2user: sys_vircopy failed", r);
-
-		count -= bytes;
-		vir_hw += bytes;
-		offset += bytes;
-	}
-	assert(count == 0);
-}
-
-/*===========================================================================*
- *				dp_pio8_nic2user			     *
- *===========================================================================*/
-static void dp_pio8_nic2user(dep, nic_addr, iovp, offset, count)
-dpeth_t *dep;
-int nic_addr;
-iovec_dat_t *iovp;
-vir_bytes offset;
-vir_bytes count;
-{
-//	phys_bytes phys_user;
-	int i;
-	vir_bytes bytes;
-
-	outb_reg0(dep, DP_RBCR0, count &0xFF);
-	outb_reg0(dep, DP_RBCR1, count >> 8);
-	outb_reg0(dep, DP_RSAR0, nic_addr &0xFF);
-	outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
-	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
-
-	i= 0;
-	while (count > 0)
-	{
-		if (i >= IOVEC_NR)
-		{
-			dp_next_iovec(iovp);
-			i= 0;
-			continue;
-		}
-		assert(i < iovp->iod_iovec_s);
-		if (offset >= iovp->iod_iovec[i].iov_size)
-		{
-			offset -= iovp->iod_iovec[i].iov_size;
-			i++;
-			continue;
-		}
-		bytes = iovp->iod_iovec[i].iov_size - offset;
-		if (bytes > count)
-			bytes = count;
-
-		do_vir_insb(dep->de_data_port, iovp->iod_proc_nr,
-			iovp->iod_iovec[i].iov_addr + offset, bytes);
-		count -= bytes;
-		offset += bytes;
-	}
-	assert(count == 0);
-}
-
-/*===========================================================================*
- *				dp_pio16_nic2user			     *
- *===========================================================================*/
-static void dp_pio16_nic2user(dep, nic_addr, iovp, offset, count)
-dpeth_t *dep;
-int nic_addr;
-iovec_dat_t *iovp;
-vir_bytes offset;
-vir_bytes count;
-{
-	vir_bytes vir_user;
-	vir_bytes ecount;
-	int i, r, user_proc;
-	vir_bytes bytes;
-	//u8_t two_bytes[2];
-	u16_t two_bytes;
-	int odd_byte;
-
-	ecount= (count+1) &~1;
-	odd_byte= 0;
-
-	outb_reg0(dep, DP_RBCR0, ecount &0xFF);
-	outb_reg0(dep, DP_RBCR1, ecount >> 8);
-	outb_reg0(dep, DP_RSAR0, nic_addr &0xFF);
-	outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
-	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
-
-	i= 0;
-	while (count > 0)
-	{
-		if (i >= IOVEC_NR)
-		{
-			dp_next_iovec(iovp);
-			i= 0;
-			continue;
-		}
-		assert(i < iovp->iod_iovec_s);
-		if (offset >= iovp->iod_iovec[i].iov_size)
-		{
-			offset -= iovp->iod_iovec[i].iov_size;
-			i++;
-			continue;
-		}
-		bytes = iovp->iod_iovec[i].iov_size - offset;
-		if (bytes > count)
-			bytes = count;
-
-		user_proc= iovp->iod_proc_nr;
-		vir_user= iovp->iod_iovec[i].iov_addr + offset;
-		if (odd_byte)
-		{
-			//r= sys_vircopy(SELF, D, (vir_bytes)&two_bytes[1],
-			r= sys_vircopy(SELF, D, (vir_bytes)&(((u8_t *)&two_bytes)[1]),
-				user_proc, D, vir_user,  1);
-			if (r != OK)
-			{
-				panic("DP8390",
-					"dp_pio16_nic2user: sys_vircopy failed",
-					r);
-			}
-			count--;
-			offset++;
-			bytes--;
-			vir_user++;
-			odd_byte= 0;
-			if (!bytes)
-				continue;
-		}
-		ecount= bytes &~1;
-		if (ecount != 0)
-		{
-			do_vir_insw(dep->de_data_port, user_proc, vir_user,
-				ecount);
-			count -= ecount;
-			offset += ecount;
-			bytes -= ecount;
-			vir_user += ecount;
-		}
-		if (bytes)
-		{
-			assert(bytes == 1);
-			//*(u16_t *)two_bytes= inw(dep->de_data_port);
-			two_bytes= inw(dep->de_data_port);
-			//r= sys_vircopy(SELF, D, (vir_bytes)&two_bytes[0],
-			r= sys_vircopy(SELF, D, (vir_bytes)&(((u8_t *)&two_bytes)[0]),
-				user_proc, D, vir_user,  1);
-			if (r != OK)
-			{
-				panic("DP8390",
-					"dp_pio16_nic2user: sys_vircopy failed",
-					r);
-			}
-			count--;
-			offset++;
-			bytes--;
-			vir_user++;
-			odd_byte= 1;
-		}
-	}
-	assert(count == 0);
-}
-
-/*===========================================================================*
- *				dp_next_iovec				     *
- *===========================================================================*/
-static void dp_next_iovec(iovp)
-iovec_dat_t *iovp;
-{
-	assert(iovp->iod_iovec_s > IOVEC_NR);
-
-	iovp->iod_iovec_s -= IOVEC_NR;
-
-	iovp->iod_iovec_addr += IOVEC_NR * sizeof(iovec_t);
-
-	get_userdata(iovp->iod_proc_nr, iovp->iod_iovec_addr, 
-		(iovp->iod_iovec_s > IOVEC_NR ? IOVEC_NR : iovp->iod_iovec_s) *
-		sizeof(iovec_t), iovp->iod_iovec); 
-}
-
-/*===========================================================================*
- *				conf_hw					     *
- *===========================================================================*/
-static void conf_hw(dep)
-dpeth_t *dep;
-{
-//	static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 	/* ,... */};
-
-//	int ifnr;
-//	dp_conf_t *dcp;
-
-//	dep->de_mode= DEM_DISABLED;	/* Superfluous */
-//	ifnr= dep-de_table;
-
-//	dcp= &dp_conf[ifnr];
-//	update_conf(dep, dcp);
-//	if (dep->de_mode != DEM_ENABLED)
-//		return;
-	if (!wdeth_probe(dep) && !ne_probe(dep) && !el2_probe(dep))
-	{
-		printf("%s: No ethernet card found at %#lx\n",
-		    dep->de_name, dep->de_base_port);
-		dep->de_mode= DEM_DISABLED;
+	if (last >= dep->de_stoppage) {
+		count = (dep->de_stoppage - page) * DP_PAGESIZE - sizeof(dp_rcvhdr_t);
+		
+		dp_nic2user(dep, page * DP_PAGESIZE + sizeof(dp_rcvhdr_t),
+		    buf, 0, count);
+		dp_nic2user(dep, dep->de_startpage * DP_PAGESIZE,
+		    buf, count, length - count);
+	} else {
+		dp_nic2user(dep, page * DP_PAGESIZE + sizeof(dp_rcvhdr_t),
+		    buf, 0, length);
+	}
+	
+	nil_received_msg(nil_phone, device_id, packet, SERVICE_NONE);
+	
+	return EOK;
+}
+
+static void conf_hw(dpeth_t *dep)
+{
+	if (!ne_probe(dep)) {
+		printf("No ethernet card found at %#lx\n", dep->de_base_port);
+		dep->up = false;
 		return;
 	}
-
-/* XXX */ if (dep->de_linmem == 0) dep->de_linmem= 0xFFFF0000;
-
-	dep->de_mode = DEM_ENABLED;
-
-	dep->de_flags = DEF_EMPTY;
-//	dep->de_stat = empty_stat;
-}
-
-/*===========================================================================*
- *				map_hw_buffer				     *
- *===========================================================================*/
-static void map_hw_buffer(dep)
-dpeth_t *dep;
-{
-//	int r;
-//	size_t o, size;
-//	char *buf, *abuf;
-
-	if (dep->de_prog_IO)
-	{
-#if 0
-		if(debug){
-			printf(
-			"map_hw_buffer: programmed I/O, no need to map buffer\n");
-		}
-#endif
-		dep->de_locmem = (char *)-dep->de_ramsize; /* trap errors */
-		return;
-	}else{
-		printf("map_hw_buffer: no buffer!\n");
-	}
-
-//	size = dep->de_ramsize + PAGE_SIZE;	/* Add PAGE_SIZE for
-//						 * alignment
-//						 */
-//	buf= malloc(size);
-//	if (buf == NULL)
-//		panic(__FILE__, "map_hw_buffer: cannot malloc size", size);
-//	o= PAGE_SIZE - ((vir_bytes)buf % PAGE_SIZE);
-//	abuf= buf + o;
-//	printf("buf at 0x%x, abuf at 0x%x\n", buf, abuf);
-
-//	r= sys_vm_map(SELF, 1 /* map */, (vir_bytes)abuf,
-//			dep->de_ramsize, (phys_bytes)dep->de_linmem);
-//	if (r != OK)
-//		panic(__FILE__, "map_hw_buffer: sys_vm_map failed", r);
-//	dep->de_locmem = abuf;
-}
-
-/*===========================================================================*
- *				reply					     *
- *===========================================================================*/
-static void reply(dep, err, may_block)
-dpeth_t *dep;
-int err;
-int may_block;
-{
-/*	message reply;
-	int status;
-	int r;
-
-	status = 0;
-	if (dep->de_flags &DEF_PACK_SEND)
-		status |= DL_PACK_SEND;
-	if (dep->de_flags &DEF_PACK_RECV)
-		status |= DL_PACK_RECV;
-
-	reply.m_type = DL_TASK_REPLY;
-	reply.DL_PORT = dep - de_table;
-	reply.DL_PROC = dep->de_client;
-	reply.DL_STAT = status | ((u32_t) err << 16);
-	reply.DL_COUNT = dep->de_read_s;
-	reply.DL_CLCK = 0;	*//* Don't know */
-/*	r= send(dep->de_client, &reply);
-
-	if (r == ELOCKED && may_block)
-	{
-#if 0
-		printf("send locked\n");
-#endif
-		return;
-	}
-
-	if (r < 0)
-		panic("", "dp8390: send failed:", r);
-	
-*/	dep->de_read_s = 0;
-//	dep->de_flags &= ~(DEF_PACK_SEND | DEF_PACK_RECV);
-}
-
-/*===========================================================================*
- *				get_userdata				     *
- *===========================================================================*/
-static void get_userdata(user_proc, user_addr, count, loc_addr)
-int user_proc;
-vir_bytes user_addr;
-vir_bytes count;
-void *loc_addr;
-{
-	int r;
-
-	r= sys_vircopy(user_proc, D, user_addr,
-		SELF, D, (vir_bytes)loc_addr, count);
-	if (r != OK)
-		panic("DP8390", "get_userdata: sys_vircopy failed", r);
+	
+	dep->up = true;
+	dep->enabled = false;
+	dep->stopped = false;
+	dep->sending = false;
+	dep->send_avail = false;
 }
 
@@ -1632,8 +663,7 @@
 {
 	size_t i;
-
-	for(i = 0; i < size; ++ i){
+	
+	for (i = 0; i < size; i++)
 		*((uint8_t *) buf + i) = inb(port);
-	}
 }
 
@@ -1641,8 +671,7 @@
 {
 	size_t i;
-
-	for(i = 0; i * 2 < size; ++ i){
+	
+	for (i = 0; i * 2 < size; i++)
 		*((uint16_t *) buf + i) = inw(port);
-	}
 }
 
@@ -1650,8 +679,7 @@
 {
 	size_t i;
-
-	for(i = 0; i < size; ++ i){
+	
+	for (i = 0; i < size; i++)
 		outb(port, *((uint8_t *) buf + i));
-	}
 }
 
@@ -1659,13 +687,8 @@
 {
 	size_t i;
-
-	for(i = 0; i * 2 < size; ++ i){
+	
+	for (i = 0; i * 2 < size; i++)
 		outw(port, *((uint16_t *) buf + i));
-	}
-}
-
-/*
- * $PchId: dp8390.c,v 1.25 2005/02/10 17:32:07 philip Exp $
- */
+}
 
 /** @}
Index: uspace/srv/hw/netif/dp8390/dp8390.h
===================================================================
--- uspace/srv/hw/netif/dp8390/dp8390.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/hw/netif/dp8390/dp8390.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -1,17 +1,23 @@
 /*
- * Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands All rights reserved. Redistribution and use of the MINIX 3 operating system 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.
- * * Neither the name of the Vrije Universiteit nor the names of the software authors or contributors may be used to endorse or promote products derived from this software without specific prior written permission.
- * * Any deviations from these conditions require written permission from the copyright holder in advance
- *
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Martin Decky
+ * 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 COPYRIGHT HOLDER OR ANY AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * 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,
@@ -20,7 +26,14 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Changes:
- *  2009 ported to HelenOS, Lukas Mejdrech
+ */
+
+/*
+ * This code is based upon the NE2000 driver for MINIX,
+ * distributed according to a BSD-style license.
+ *
+ * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
+ * Copyright (c) 1992, 1994 Philip Homburg
+ * Copyright (c) 1996 G. Falzoni
+ *
  */
 
@@ -37,73 +50,58 @@
 
 #include <net/packet.h>
-
 #include "dp8390_port.h"
-#include "local.h"
-
-/** Input/output size.
- */
-#define DP8390_IO_SIZE	0x020
-
-/*
-dp8390.h
-
-Created:	before Dec 28, 1992 by Philip Homburg
-*/
+
+/** Input/output size */
+#define DP8390_IO_SIZE  0x0020
 
 /* National Semiconductor DP8390 Network Interface Controller. */
 
-				/* Page 0, for reading ------------- */
-#define	DP_CR		0x0	/* Read side of Command Register     */
-#define	DP_CLDA0	0x1	/* Current Local Dma Address 0       */
-#define	DP_CLDA1	0x2	/* Current Local Dma Address 1       */
-#define	DP_BNRY		0x3	/* Boundary Pointer                  */
-#define	DP_TSR		0x4	/* Transmit Status Register          */
-#define	DP_NCR		0x5	/* Number of Collisions Register     */
-#define	DP_FIFO		0x6	/* Fifo ??                           */
-#define	DP_ISR		0x7	/* Interrupt Status Register         */
-#define	DP_CRDA0	0x8	/* Current Remote Dma Address 0      */
-#define	DP_CRDA1	0x9	/* Current Remote Dma Address 1      */
-#define	DP_DUM1		0xA	/* unused                            */
-#define	DP_DUM2		0xB	/* unused                            */
-#define	DP_RSR		0xC	/* Receive Status Register           */
-#define	DP_CNTR0	0xD	/* Tally Counter 0                   */
-#define	DP_CNTR1	0xE	/* Tally Counter 1                   */
-#define	DP_CNTR2	0xF	/* Tally Counter 2                   */
-
-				/* Page 0, for writing ------------- */
-#define	DP_CR		0x0	/* Write side of Command Register    */
-#define	DP_PSTART	0x1	/* Page Start Register               */
-#define	DP_PSTOP	0x2	/* Page Stop Register                */
-#define	DP_BNRY		0x3	/* Boundary Pointer                  */
-#define	DP_TPSR		0x4	/* Transmit Page Start Register      */
-#define	DP_TBCR0	0x5	/* Transmit Byte Count Register 0    */
-#define	DP_TBCR1	0x6	/* Transmit Byte Count Register 1    */
-#define	DP_ISR		0x7	/* Interrupt Status Register         */
-#define	DP_RSAR0	0x8	/* Remote Start Address Register 0   */
-#define	DP_RSAR1	0x9	/* Remote Start Address Register 1   */
-#define	DP_RBCR0	0xA	/* Remote Byte Count Register 0      */
-#define	DP_RBCR1	0xB	/* Remote Byte Count Register 1      */
-#define	DP_RCR		0xC	/* Receive Configuration Register    */
-#define	DP_TCR		0xD	/* Transmit Configuration Register   */
-#define	DP_DCR		0xE	/* Data Configuration Register       */
-#define	DP_IMR		0xF	/* Interrupt Mask Register           */
-
-				/* Page 1, read/write -------------- */
-#define	DP_CR		0x0	/* Command Register                  */
-#define	DP_PAR0		0x1	/* Physical Address Register 0       */
-#define	DP_PAR1		0x2	/* Physical Address Register 1       */
-#define	DP_PAR2		0x3	/* Physical Address Register 2       */
-#define	DP_PAR3		0x4	/* Physical Address Register 3       */
-#define	DP_PAR4		0x5	/* Physical Address Register 4       */
-#define	DP_PAR5		0x6	/* Physical Address Register 5       */
-#define	DP_CURR		0x7	/* Current Page Register             */
-#define	DP_MAR0		0x8	/* Multicast Address Register 0      */
-#define	DP_MAR1		0x9	/* Multicast Address Register 1      */
-#define	DP_MAR2		0xA	/* Multicast Address Register 2      */
-#define	DP_MAR3		0xB	/* Multicast Address Register 3      */
-#define	DP_MAR4		0xC	/* Multicast Address Register 4      */
-#define	DP_MAR5		0xD	/* Multicast Address Register 5      */
-#define	DP_MAR6		0xE	/* Multicast Address Register 6      */
-#define	DP_MAR7		0xF	/* Multicast Address Register 7      */
+/** Page 0, for reading */
+#define DP_CR     0x00  /**< Command Register */
+#define DP_CLDA0  0x01  /**< Current Local DMA Address 0 */
+#define DP_CLDA1  0x02  /**< Current Local DMA Address 1 */
+#define DP_BNRY   0x03  /**< Boundary Pointer */
+#define DP_TSR    0x04  /**< Transmit Status Register */
+#define DP_NCR    0x05  /**< Number of Collisions Register */
+#define DP_FIFO   0x06  /**< FIFO */
+#define DP_ISR    0x07  /**< Interrupt Status Register */
+#define DP_CRDA0  0x08  /**< Current Remote DMA Address 0 */
+#define DP_CRDA1  0x09  /**< Current Remote DMA Address 1 */
+#define DP_RSR    0x0c  /**< Receive Status Register */
+#define DP_CNTR0  0x0d  /**< Tally Counter 0 */
+#define DP_CNTR1  0x0e  /**< Tally Counter 1 */
+#define DP_CNTR2  0x0f  /**< Tally Counter 2 */
+
+/** Page 0, for writing */
+#define DP_PSTART  0x01  /**< Page Start Register*/
+#define DP_PSTOP   0x02  /**< Page Stop Register */
+#define DP_TPSR    0x04  /**< Transmit Page Start Register */
+#define DP_TBCR0   0x05  /**< Transmit Byte Count Register 0 */
+#define DP_TBCR1   0x06  /**< Transmit Byte Count Register 1 */
+#define DP_RSAR0   0x08  /**< Remote Start Address Register 0 */
+#define DP_RSAR1   0x09  /**< Remote Start Address Register 1 */
+#define DP_RBCR0   0x0a  /**< Remote Byte Count Register 0 */
+#define DP_RBCR1   0x0b  /**< Remote Byte Count Register 1 */
+#define DP_RCR     0x0c  /**< Receive Configuration Register */
+#define DP_TCR     0x0d  /**< Transmit Configuration Register */
+#define DP_DCR     0x0e  /**< Data Configuration Register */
+#define DP_IMR     0x0f  /**< Interrupt Mask Register */
+
+/** Page 1, read/write */
+#define DP_PAR0  0x01  /**< Physical Address Register 0 */
+#define DP_PAR1  0x02  /**< Physical Address Register 1 */
+#define DP_PAR2  0x03  /**< Physical Address Register 2 */
+#define DP_PAR3  0x04  /**< Physical Address Register 3 */
+#define DP_PAR4  0x05  /**< Physical Address Register 4 */
+#define DP_PAR5  0x06  /**< Physical Address Register 5 */
+#define DP_CURR  0x07  /**< Current Page Register */
+#define DP_MAR0  0x08  /**< Multicast Address Register 0 */
+#define DP_MAR1  0x09  /**< Multicast Address Register 1 */
+#define DP_MAR2  0x0a  /**< Multicast Address Register 2 */
+#define DP_MAR3  0x0b  /**< Multicast Address Register 3 */
+#define DP_MAR4  0x0c  /**< Multicast Address Register 4 */
+#define DP_MAR5  0x0d  /**< Multicast Address Register 5 */
+#define DP_MAR6  0x0e  /**< Multicast Address Register 6 */
+#define DP_MAR7  0x0f  /**< Multicast Address Register 7 */
 
 /* Bits in dp_cr */
@@ -199,154 +197,65 @@
 #define RSR_DFR		0x80	/* In later manuals: Deferring       */
 
-/** Type definition of the receive header.
- */
-typedef struct dp_rcvhdr
-{
-	/** Copy of rsr.
-	 */
-	u8_t dr_status;
-	/** Pointer to next packet.
-	 */
-	u8_t dr_next;
-	/** Receive Byte Count Low.
-	 */
-	u8_t dr_rbcl;
-	/** Receive Byte Count High.
-	 */
-	u8_t dr_rbch;
+/** Type definition of the receive header
+ *
+ */
+typedef struct dp_rcvhdr {
+	/** Copy of rsr */
+	uint8_t dr_status;
+	
+	/** Pointer to next packet */
+	uint8_t dr_next;
+	
+	/** Receive Byte Count Low */
+	uint8_t dr_rbcl;
+	
+	/** Receive Byte Count High */
+	uint8_t dr_rbch;
 } dp_rcvhdr_t;
 
-/** Page size.
- */
-#define DP_PAGESIZE	256
-
-/* Some macros to simplify accessing the dp8390 */
-/** Reads 1 byte from the zero page register.
+/** Page size */
+#define DP_PAGESIZE  256
+
+/** Read 1 byte from the zero page register.
  *  @param[in] dep The network interface structure.
  *  @param[in] reg The register offset.
  *  @returns The read value.
  */
-#define inb_reg0(dep, reg)		(inb(dep->de_dp8390_port+reg))
-
-/** Writes 1 byte zero page register.
+#define inb_reg0(dep, reg)  (inb(dep->de_dp8390_port + reg))
+
+/** Write 1 byte zero page register.
  *  @param[in] dep The network interface structure.
  *  @param[in] reg The register offset.
  *  @param[in] data The value to be written.
  */
-#define outb_reg0(dep, reg, data)	(outb(dep->de_dp8390_port+reg, data))
-
-/** Reads 1 byte from the first page register.
+#define outb_reg0(dep, reg, data)  (outb(dep->de_dp8390_port + reg, data))
+
+/** Read 1 byte from the first page register.
  *  @param[in] dep The network interface structure.
  *  @param[in] reg The register offset.
  *  @returns The read value.
  */
-#define inb_reg1(dep, reg)		(inb(dep->de_dp8390_port+reg))
-
-/** Writes 1 byte first page register.
+#define inb_reg1(dep, reg)  (inb(dep->de_dp8390_port + reg))
+
+/** Write 1 byte first page register.
  *  @param[in] dep The network interface structure.
  *  @param[in] reg The register offset.
  *  @param[in] data The value to be written.
  */
-#define outb_reg1(dep, reg, data)	(outb(dep->de_dp8390_port+reg, data))
-
-/* Software interface to the dp8390 driver */
-
-struct dpeth;
-struct iovec_dat;
-//struct iovec_dat_s;
-_PROTOTYPE(typedef void (*dp_initf_t), (struct dpeth *dep)		);
-_PROTOTYPE(typedef void (*dp_stopf_t), (struct dpeth *dep)		);
-_PROTOTYPE(typedef void (*dp_user2nicf_t), (struct dpeth *dep,
-			struct iovec_dat *iovp, vir_bytes offset,
-			int nic_addr, vir_bytes count) );
-//_PROTOTYPE(typedef void (*dp_user2nicf_s_t), (struct dpeth *dep,
-//			struct iovec_dat_s *iovp, vir_bytes offset,
-//			int nic_addr, vir_bytes count)			);
-_PROTOTYPE(typedef void (*dp_nic2userf_t), (struct dpeth *dep,
-			int nic_addr, struct iovec_dat *iovp,
-			vir_bytes offset, vir_bytes count) );
-//_PROTOTYPE(typedef void (*dp_nic2userf_s_t), (struct dpeth *dep,
-//			int nic_addr, struct iovec_dat_s *iovp,
-//			vir_bytes offset, vir_bytes count)		);
-//#if 0
-//_PROTOTYPE(typedef void (*dp_getheaderf_t), (struct dpeth *dep,
-//			int page, struct dp_rcvhdr *h, u16_t *eth_type)	);
-//#endif
-_PROTOTYPE(typedef void (*dp_getblock_t), (struct dpeth *dep,
-		int page, size_t offset, size_t size, void *dst)	);
-
-/* iovectors are handled IOVEC_NR entries at a time. */
-//#define IOVEC_NR	16
-// no vectors allowed
-#define IOVEC_NR	1
-
-/*
-typedef int irq_hook_t;
-*/
-typedef struct iovec_dat
-{
-  iovec_t iod_iovec[IOVEC_NR];
-  int iod_iovec_s;
-  // no direct process access
-  int iod_proc_nr;
-  vir_bytes iod_iovec_addr;
-} iovec_dat_t;
-/*
-typedef struct iovec_dat_s
-{
-  iovec_s_t iod_iovec[IOVEC_NR];
-  int iod_iovec_s;
-  int iod_proc_nr;
-  cp_grant_id_t iod_grant;
-  vir_bytes iod_iovec_offset;
-} iovec_dat_s_t;
-*/
-#define SENDQ_NR	1	/* Maximum size of the send queue */
-#define SENDQ_PAGES	6	/* 6 * DP_PAGESIZE >= 1514 bytes */
-
-/** Maximum number of waiting packets to be sent or received.
- */
-#define MAX_PACKETS	4
-
-typedef struct dpeth
-{
-	/** Outgoing packets queue.
-	 */
-	packet_t *packet_queue;
-	/** Outgoing packets count.
-	 */
-	int packet_count;
-
-	/** Received packets queue.
-	 */
-	packet_t *received_queue;
-	/** Received packets count.
-	 */
-	int received_count;
-
-	/* The de_base_port field is the starting point of the probe.
-	 * The conf routine also fills de_linmem and de_irq. If the probe
+#define outb_reg1(dep, reg, data)  (outb(dep->de_dp8390_port + reg, data))
+
+#define SENDQ_NR     2  /* Maximum size of the send queue */
+#define SENDQ_PAGES  6  /* 6 * DP_PAGESIZE >= 1514 bytes */
+
+typedef struct dpeth {
+	/*
+	 * The de_base_port field is the starting point of the probe.
+	 * The conf routine also fills de_irq. If the probe
 	 * routine knows the irq and/or memory address because they are
 	 * hardwired in the board, the probe should modify these fields.
-	 * Futhermore, the probe routine should also fill in de_initf and
-	 * de_stopf fields with the appropriate function pointers and set
-	 * de_prog_IO iff programmed I/O is to be used.
 	 */
 	port_t de_base_port;
-	phys_bytes de_linmem;
-	char *de_locmem;
 	int de_irq;
-	int de_int_pending;
-//	irq_hook_t de_hook;
-	dp_initf_t de_initf; 
-	dp_stopf_t de_stopf; 
-	int de_prog_IO;
-	char de_name[sizeof("dp8390#n")];
-
-	/* The initf function fills the following fields. Only cards that do
-	 * programmed I/O fill in the de_pata_port field.
-	 * In addition, the init routine has to fill in the sendq data
-	 * structures.
-	 */
+	
 	ether_addr_t de_address;
 	port_t de_dp8390_port;
@@ -357,75 +266,29 @@
 	int de_startpage;
 	int de_stoppage;
-
-	/* should be here - read even for ne2k isa init... */
-	char de_pci;			/* TRUE iff PCI device */
-
-#if ENABLE_PCI
-	/* PCI config */
-//	char de_pci;			/* TRUE iff PCI device */
-//	u8_t de_pcibus;	
-//	u8_t de_pcidev;	
-//	u8_t de_pcifunc;	
+	
+	/* Do it yourself send queue */
+	struct sendq {
+		int sq_filled;    /* this buffer contains a packet */
+		int sq_size;      /* with this size */
+		int sq_sendpage;  /* starting page of the buffer */
+	} de_sendq[SENDQ_NR];
+	
+	int de_sendq_nr;
+	int de_sendq_head;  /* Enqueue at the head */
+	int de_sendq_tail;  /* Dequeue at the tail */
+	
+	/* Fields for internal use by the dp8390 driver. */
+	eth_stat_t de_stat;
+	
+	/* Driver flags */
+	bool up;
+	bool enabled;
+	bool stopped;
+	bool sending;
+	bool send_avail;
+} dpeth_t;
+
 #endif
 
-	/* Do it yourself send queue */
-	struct sendq
-	{
-		int sq_filled;		/* this buffer contains a packet */
-		int sq_size;		/* with this size */
-		int sq_sendpage;	/* starting page of the buffer */
-	} de_sendq[SENDQ_NR];
-	int de_sendq_nr;
-	int de_sendq_head;		/* Enqueue at the head */
-	int de_sendq_tail;		/* Dequeue at the tail */
-
-	/* Fields for internal use by the dp8390 driver. */
-	int de_flags;
-	int de_mode;
-	eth_stat_t de_stat;
-	iovec_dat_t de_read_iovec;
-//	iovec_dat_s_t de_read_iovec_s;
-//	int de_safecopy_read;
-	iovec_dat_t de_write_iovec;
-//	iovec_dat_s_t de_write_iovec_s;
-	iovec_dat_t de_tmp_iovec;
-//	iovec_dat_s_t de_tmp_iovec_s;
-	vir_bytes de_read_s;
-//	int de_client;
-//	message de_sendmsg;
-	dp_user2nicf_t de_user2nicf; 
-//	dp_user2nicf_s_t de_user2nicf_s; 
-	dp_nic2userf_t de_nic2userf;
-//	dp_nic2userf_s_t de_nic2userf_s; 
-	dp_getblock_t de_getblockf;
-} dpeth_t;
-
-#define DEI_DEFAULT	0x8000
-
-#define DEF_EMPTY	0x000
-#define DEF_PACK_SEND	0x001
-#define DEF_PACK_RECV	0x002
-#define DEF_SEND_AVAIL	0x004
-#define DEF_READING	0x010
-#define DEF_PROMISC	0x040
-#define DEF_MULTI	0x080
-#define DEF_BROAD	0x100
-#define DEF_ENABLED	0x200
-#define DEF_STOPPED	0x400
-
-#define DEM_DISABLED	0x0
-#define DEM_SINK	0x1
-#define DEM_ENABLED	0x2
-
-//#if !__minix_vmd
-#define debug		1	/* Standard Minix lacks debug variable */
-//#endif
-
-/*
- * $PchId: dp8390.h,v 1.10 2005/02/10 17:26:06 philip Exp $
- */
-
-#endif
-
 /** @}
  */
Index: uspace/srv/hw/netif/dp8390/dp8390_drv.h
===================================================================
--- uspace/srv/hw/netif/dp8390/dp8390_drv.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/hw/netif/dp8390/dp8390_drv.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -40,11 +40,5 @@
 #include "dp8390.h"
 
-/** Initializes and/or starts the network interface.
- *  @param[in,out] dep The network interface structure.
- *  @param[in] mode The state mode.
- *  @returns EOK on success.
- *  @returns EXDEV if the network interface is disabled.
- */
-int do_init(dpeth_t *dep, int mode);
+int do_init(dpeth_t *dep);
 
 /** Stops the network interface.
@@ -55,7 +49,6 @@
 /** Processes the interrupt.
  *  @param[in,out] dep The network interface structure.
- *  @param[in] isr The interrupt status register.
  */
-void dp_check_ints(dpeth_t *dep, int isr);
+void dp_check_ints(int nil_phone, device_id_t device_id, dpeth_t *dep, uint8_t isr);
 
 /** Probes and initializes the network interface.
@@ -70,12 +63,7 @@
  *  @param[in] packet The packet t be sent.
  *  @param[in] from_int The value indicating whether the sending is initialized from the interrupt handler.
- *  @returns 
+ *  @returns
  */
 int do_pwrite(dpeth_t * dep, packet_t *packet, int from_int);
-
-/** Prints out network interface information.
- *  @param[in] dep The network interface structure.
- */
-void dp8390_dump(dpeth_t * dep);
 
 #endif
Index: uspace/srv/hw/netif/dp8390/dp8390_module.c
===================================================================
--- uspace/srv/hw/netif/dp8390/dp8390_module.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/hw/netif/dp8390/dp8390_module.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -43,5 +43,4 @@
 #include <ipc/ipc.h>
 #include <ipc/services.h>
-
 #include <net/modules.h>
 #include <packet_client.h>
@@ -51,5 +50,4 @@
 #include <netif_interface.h>
 #include <netif_local.h>
-
 #include "dp8390.h"
 #include "dp8390_drv.h"
@@ -60,27 +58,43 @@
 #define NAME  "dp8390"
 
-/** Returns the device from the interrupt call.
+/** Return the device from the interrupt call.
+ *
  *  @param[in] call The interrupt call.
- */
-#define IRQ_GET_DEVICE(call)			(device_id_t) IPC_GET_IMETHOD(*call)
-
-/** Returns the interrupt status register from the interrupt call.
+ *
+ */
+#define IRQ_GET_DEVICE(call)  ((device_id_t) IPC_GET_IMETHOD(call))
+
+/** Return the ISR from the interrupt call.
+ *
  *  @param[in] call The interrupt call.
- */
-#define IPC_GET_ISR(call)				(int) IPC_GET_ARG2(*call)
+ *
+ */
+#define IRQ_GET_ISR(call)  ((int) IPC_GET_ARG2(call))
 
 /** DP8390 kernel interrupt command sequence.
  */
-static irq_cmd_t	dp8390_cmds[] = {
-	{	.cmd = CMD_PIO_READ_8,
+static irq_cmd_t dp8390_cmds[] = {
+	{
+		.cmd = CMD_PIO_READ_8,
 		.addr = NULL,
 		.dstarg = 2
 	},
 	{
+		.cmd = CMD_BTEST,
+		.value = 0x7f,
+		.srcarg = 2,
+		.dstarg = 3,
+	},
+	{
 		.cmd = CMD_PREDICATE,
-		.value = 1,
-		.srcarg = 2
+		.value = 2,
+		.srcarg = 3
 	},
 	{
+		.cmd = CMD_PIO_WRITE_A_8,
+		.addr = NULL,
+		.srcarg = 3
+	},
+	{
 		.cmd = CMD_ACCEPT
 	}
@@ -89,5 +103,5 @@
 /** DP8390 kernel interrupt code.
  */
-static irq_code_t	dp8390_code = {
+static irq_code_t dp8390_code = {
 	sizeof(dp8390_cmds) / sizeof(irq_cmd_t),
 	dp8390_cmds
@@ -99,37 +113,25 @@
  *  @param[in] call The interrupt message.
  */
-static void irq_handler(ipc_callid_t iid, ipc_call_t * call)
-{
-	netif_device_t * device;
-	dpeth_t * dep;
-	packet_t *received;
-	device_id_t device_id;
-	int phone;
-
-	device_id = IRQ_GET_DEVICE(call);
+static void irq_handler(ipc_callid_t iid, ipc_call_t *call)
+{
+	device_id_t device_id = IRQ_GET_DEVICE(*call);
+	netif_device_t *device;
+	int nil_phone;
+	dpeth_t *dep;
+	
 	fibril_rwlock_write_lock(&netif_globals.lock);
-	if(find_device(device_id, &device) != EOK){
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return;
-	}
-	dep = (dpeth_t *) device->specific;
-	if (dep->de_mode != DEM_ENABLED){
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return;
-	}
-	assert(dep->de_flags &DEF_ENABLED);
-	dep->de_int_pending = 0;
-	dp_check_ints(dep, IPC_GET_ISR(call));
-	if(dep->received_queue){
-		received = dep->received_queue;
-		phone = device->nil_phone;
-		dep->received_queue = NULL;
-		dep->received_count = 0;
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		nil_received_msg(phone, device_id, received, SERVICE_NONE);
-	}else{
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-	}
-	ipc_answer_0(iid, EOK);
+	
+	if (find_device(device_id, &device) == EOK) {
+		nil_phone = device->nil_phone;
+		dep = (dpeth_t *) device->specific;
+	} else
+		dep = NULL;
+	
+	fibril_rwlock_write_unlock(&netif_globals.lock);
+	
+	if ((dep != NULL) && (dep->up)) {
+		assert(dep->enabled);
+		dp_check_ints(nil_phone, device_id, dep, IRQ_GET_ISR(*call));
+	}
 }
 
@@ -139,5 +141,5 @@
  *  @returns The new state.
  */
-static int change_state(netif_device_t * device, device_state_t state)
+static int change_state(netif_device_t *device, device_state_t state)
 {
 	if (device->state != state) {
@@ -153,5 +155,7 @@
 }
 
-int netif_specific_message(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
+int netif_specific_message(ipc_callid_t callid, ipc_call_t *call,
+    ipc_call_t *answer, int *answer_count)
+{
 	return ENOTSUP;
 }
@@ -162,12 +166,14 @@
 	eth_stat_t * de_stat;
 	int rc;
-
-	if(! stats){
+	
+	if (!stats)
 		return EBADMEM;
-	}
+	
 	rc = find_device(device_id, &device);
 	if (rc != EOK)
 		return rc;
+	
 	de_stat = &((dpeth_t *) device->specific)->de_stat;
+	
 	null_device_stats(stats);
 	stats->receive_errors = de_stat->ets_recvErr;
@@ -183,38 +189,41 @@
 	stats->send_heartbeat_errors = de_stat->ets_CDheartbeat;
 	stats->send_window_errors = de_stat->ets_OWC;
-	return EOK;
-}
-
-int netif_get_addr_message(device_id_t device_id, measured_string_t *address){
-	netif_device_t * device;
-	int rc;
-
-	if(! address){
+	
+	return EOK;
+}
+
+int netif_get_addr_message(device_id_t device_id, measured_string_t *address)
+{
+	netif_device_t *device;
+	int rc;
+	
+	if (!address)
 		return EBADMEM;
-	}
+	
 	rc = find_device(device_id, &device);
 	if (rc != EOK)
 		return rc;
+	
 	address->value = (char *) (&((dpeth_t *) device->specific)->de_address);
-	address->length = CONVERT_SIZE(ether_addr_t, char, 1);
-	return EOK;
-}
-
-
-
-int netif_probe_message(device_id_t device_id, int irq, uintptr_t io){
-	netif_device_t * device;
-	dpeth_t * dep;
-	int rc;
-
+	address->length = sizeof(ether_addr_t);
+	return EOK;
+}
+
+int netif_probe_message(device_id_t device_id, int irq, uintptr_t io)
+{
+	netif_device_t *device;
+	dpeth_t *dep;
+	int rc;
+	
 	device = (netif_device_t *) malloc(sizeof(netif_device_t));
-	if(! device){
+	if (!device)
 		return ENOMEM;
-	}
+	
 	dep = (dpeth_t *) malloc(sizeof(dpeth_t));
-	if(! dep){
+	if (!dep) {
 		free(device);
 		return ENOMEM;
 	}
+	
 	bzero(device, sizeof(netif_device_t));
 	bzero(dep, sizeof(dpeth_t));
@@ -224,5 +233,6 @@
 	device->state = NETIF_STOPPED;
 	dep->de_irq = irq;
-	dep->de_mode = DEM_DISABLED;
+	dep->up = false;
+	
 	//TODO address?
 	rc = pio_enable((void *) io, DP8390_IO_SIZE, (void **) &dep->de_base_port);
@@ -231,5 +241,6 @@
 		free(device);
 		return rc;
-	}	
+	}
+	
 	rc = do_probe(dep);
 	if (rc != EOK) {
@@ -238,63 +249,78 @@
 		return rc;
 	}
+	
 	rc = netif_device_map_add(&netif_globals.device_map, device->device_id, device);
-	if (rc != EOK){
+	if (rc != EOK) {
 		free(dep);
 		free(device);
 		return rc;
 	}
-	return EOK;
-}
-
-int netif_send_message(device_id_t device_id, packet_t *packet, services_t sender){
-	netif_device_t * device;
-	dpeth_t * dep;
+	
+	return EOK;
+}
+
+int netif_send_message(device_id_t device_id, packet_t *packet,
+    services_t sender)
+{
+	netif_device_t *device;
+	dpeth_t *dep;
 	packet_t *next;
 	int rc;
-
+	
 	rc = find_device(device_id, &device);
 	if (rc != EOK)
 		return rc;
-	if(device->state != NETIF_ACTIVE){
+	
+	if (device->state != NETIF_ACTIVE){
 		netif_pq_release(packet_get_id(packet));
 		return EFORWARD;
 	}
+	
 	dep = (dpeth_t *) device->specific;
-	// process packet queue
-	do{
+	
+	/* Process packet queue */
+	do {
 		next = pq_detach(packet);
-		if(do_pwrite(dep, packet, FALSE) != EBUSY){
+		
+		if (do_pwrite(dep, packet, false) != EBUSY)
 			netif_pq_release(packet_get_id(packet));
-		}
+		
 		packet = next;
-	}while(packet);
-	return EOK;
-}
-
-int netif_start_message(netif_device_t * device){
-	dpeth_t * dep;
-	int rc;
-
-	if(device->state != NETIF_ACTIVE){
+	} while (packet);
+	
+	return EOK;
+}
+
+int netif_start_message(netif_device_t * device)
+{
+	dpeth_t *dep;
+	int rc;
+	
+	if (device->state != NETIF_ACTIVE) {
 		dep = (dpeth_t *) device->specific;
 		dp8390_cmds[0].addr = (void *) (uintptr_t) (dep->de_dp8390_port + DP_ISR);
-		dp8390_cmds[2].addr = dp8390_cmds[0].addr;
+		dp8390_cmds[3].addr = dp8390_cmds[0].addr;
+		
 		rc = ipc_register_irq(dep->de_irq, device->device_id, device->device_id, &dp8390_code);
 		if (rc != EOK)
 			return rc;
-		rc = do_init(dep, DL_BROAD_REQ);
+		
+		rc = do_init(dep);
 		if (rc != EOK) {
 			ipc_unregister_irq(dep->de_irq, device->device_id);
 			return rc;
 		}
+		
 		return change_state(device, NETIF_ACTIVE);
 	}
-	return EOK;
-}
-
-int netif_stop_message(netif_device_t * device){
-	dpeth_t * dep;
-
-	if(device->state != NETIF_STOPPED){
+	
+	return EOK;
+}
+
+int netif_stop_message(netif_device_t * device)
+{
+	dpeth_t *dep;
+	
+	if (device->state != NETIF_STOPPED) {
 		dep = (dpeth_t *) device->specific;
 		do_stop(dep);
@@ -302,13 +328,13 @@
 		return change_state(device, NETIF_STOPPED);
 	}
-	return EOK;
-}
-
-int netif_initialize(void){
+	
+	return EOK;
+}
+
+int netif_initialize(void)
+{
 	sysarg_t phonehash;
-
 	async_set_interrupt_received(irq_handler);
-
-	return REGISTER_ME(SERVICE_DP8390, &phonehash);
+	return ipc_connect_to_me(PHONE_NS, SERVICE_DP8390, 0, 0, &phonehash);
 }
 
@@ -319,5 +345,5 @@
  *
  */
-static void netif_client_connection(ipc_callid_t iid, ipc_call_t * icall)
+static void netif_client_connection(ipc_callid_t iid, ipc_call_t *icall)
 {
 	/*
@@ -327,5 +353,5 @@
 	ipc_answer_0(iid, EOK);
 	
-	while(true) {
+	while (true) {
 		ipc_call_t answer;
 		int answer_count;
@@ -351,5 +377,5 @@
 }
 
-/** Starts the module.
+/** Start the module.
  *
  *  @param argc The count of the command line arguments. Ignored parameter.
@@ -362,9 +388,6 @@
 int main(int argc, char *argv[])
 {
-	int rc;
-	
 	/* Start the module */
-	rc = netif_module_start(netif_client_connection);
-	return rc;
+	return netif_module_start(netif_client_connection);
 }
 
Index: uspace/srv/hw/netif/dp8390/dp8390_port.h
===================================================================
--- uspace/srv/hw/netif/dp8390/dp8390_port.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/hw/netif/dp8390/dp8390_port.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -44,22 +44,4 @@
 #include <sys/types.h>
 
-/** Macro for difining functions.
- *  @param[in] function The function type and name definition.
- *  @param[in] params The function parameters definition.
- */
-#define _PROTOTYPE(function, params) function params
-
-/** Success error code.
- */
-#define OK	EOK
-
-/** Type definition of the unsigned byte.
- */
-typedef uint8_t u8_t;
-
-/** Type definition of the unsigned short.
- */
-typedef uint16_t u16_t;
-
 /** Compares two memory blocks.
  *  @param[in] first The first memory block.
@@ -70,5 +52,5 @@
  *  @returns 1 if the second is greater than the first.
  */
-#define memcmp(first, second, size)	bcmp((char *) (first), (char *) (second), (size))
+#define memcmp(first, second, size)  bcmp((char *) (first), (char *) (second), (size))
 
 /** Reads 1 byte.
@@ -76,5 +58,5 @@
  *  @returns The read value.
  */
-#define inb(port)	pio_read_8((ioport8_t *) (port))
+#define inb(port)  pio_read_8((ioport8_t *) (port))
 
 /** Reads 1 word (2 bytes).
@@ -82,5 +64,5 @@
  *  @returns The read value.
  */
-#define inw(port)	pio_read_16((ioport16_t *) (port))
+#define inw(port)  pio_read_16((ioport16_t *) (port))
 
 /** Writes 1 byte.
@@ -88,5 +70,5 @@
  *  @param[in] value The value to be written.
  */
-#define outb(port, value)	pio_write_8((ioport8_t *) (port), (value))
+#define outb(port, value)  pio_write_8((ioport8_t *) (port), (value))
 
 /** Writes 1 word (2 bytes).
@@ -94,86 +76,13 @@
  *  @param[in] value The value to be written.
  */
-#define outw(port, value)	pio_write_16((ioport16_t *) (port), (value))
+#define outw(port, value)  pio_write_16((ioport16_t *) (port), (value))
 
-/** Prints out the driver critical error.
- *  Does not call the system panic().
- */
-#define panic(...)	printf("%s%s%d", __VA_ARGS__)
-
-/** Copies a memory block.
- *  @param proc The source process. Ignored parameter.
- *  @param src_s Ignored parameter.
- *  @param[in] src The source address.
- *  @param me The current proces. Ignored parameter.
- *  @param dst_s Ignored parameter.
- *  @param[in] dst The destination address.
- *  @param[in] bytes The block size in bytes.
- *  @returns EOK.
- */
-#define sys_vircopy(proc, src_s, src, me, dst_s, dst, bytes)	({memcpy((void *)(dst), (void *)(src), (bytes)); EOK;})
-
-/** Reads a memory block byte by byte.
- *  @param[in] port The address to be written.
- *  @param proc The source process. Ignored parameter.
- *  @param[in] dst The destination address.
- *  @param[in] bytes The block size in bytes.
- */
-#define do_vir_insb(port, proc, dst, bytes)	insb((port), (void *)(dst), (bytes))
-
-/** Reads a memory block word by word (2 bytes).
- *  @param[in] port The address to be written.
- *  @param proc The source process. Ignored parameter.
- *  @param[in] dst The destination address.
- *  @param[in] bytes The block size in bytes.
- */
-#define do_vir_insw(port, proc, dst, bytes)	insw((port), (void *)(dst), (bytes))
-
-/** Writes a memory block byte by byte.
- *  @param[in] port The address to be written.
- *  @param proc The source process. Ignored parameter.
- *  @param[in] src The source address.
- *  @param[in] bytes The block size in bytes.
- */
-#define do_vir_outsb(port, proc, src, bytes)	outsb((port), (void *)(src), (bytes))
-
-/** Writes a memory block word by word (2 bytes).
- *  @param[in] port The address to be written.
- *  @param proc The source process. Ignored parameter.
- *  @param[in] src The source address.
- *  @param[in] bytes The block size in bytes.
- */
-#define do_vir_outsw(port, proc, src, bytes)	outsw((port), (void *)(src), (bytes))
-
-/* com.h */
-/* Bits in 'DL_MODE' field of DL requests. */
-#  define DL_NOMODE		0x0
-#  define DL_PROMISC_REQ	0x2
-#  define DL_MULTI_REQ		0x4
-#  define DL_BROAD_REQ		0x8
-
-/* const.h */
-/** True value.
- */
-#define TRUE               1	/* used for turning integers into Booleans */
-
-/** False value.
- */
-#define FALSE              0	/* used for turning integers into Booleans */
-
-/** No number value.
- */
-#define NO_NUM        0x8000	/* used as numerical argument to panic() */
-
-/* devio.h */
-//typedef u16_t port_t;
 /** Type definition of a port.
  */
 typedef long port_t;
 
-/* dl_eth.h */
 /** Ethernet statistics.
  */
-typedef struct eth_stat
-{
+typedef struct eth_stat {
 	/** Number of receive errors.
 	 */
@@ -226,46 +135,19 @@
 } eth_stat_t;
 
-/* errno.h */
-/** Generic error.
- */
-#define EGENERIC     EINVAL
-
-/* ether.h */
 /** Minimum Ethernet packet size in bytes.
  */
-#define ETH_MIN_PACK_SIZE		  60
+#define ETH_MIN_PACK_SIZE  60
 
 /** Maximum Ethernet packet size in bytes.
  */
-#define ETH_MAX_PACK_SIZE_TAGGED	1518
+#define ETH_MAX_PACK_SIZE_TAGGED  1518
 
 /** Ethernet address type definition.
  */
-typedef struct ether_addr
-{
+typedef struct ether_addr {
 	/** Address data.
 	 */
-	u8_t ea_addr[6];
+	uint8_t ea_addr[6];
 } ether_addr_t;
-
-/* type.h */
-/** Type definition of the physical addresses and lengths in bytes.
- */
-typedef unsigned long phys_bytes;
-
-/** Type definition of the virtual addresses and lengths in bytes.
- */
-typedef unsigned long vir_bytes;
-
-/** Type definition of the input/output vector.
- */
-typedef struct {
-	/** Address of an I/O buffer.
-	 */
-	vir_bytes iov_addr;
-	/** Sizeof an I/O buffer.
-	 */
-	vir_bytes iov_size;
-} iovec_t;
 
 #endif
Index: pace/srv/hw/netif/dp8390/local.h
===================================================================
--- uspace/srv/hw/netif/dp8390/local.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,99 +1,0 @@
-/*
- * Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands All rights reserved. Redistribution and use of the MINIX 3 operating system 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.
- * * Neither the name of the Vrije Universiteit nor the names of the software authors or contributors may be used to endorse or promote products derived from this software without specific prior written permission.
- * * Any deviations from these conditions require written permission from the copyright holder in advance
- *
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS ``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 COPYRIGHT HOLDER OR ANY AUTHORS OR CONTRIBUTORS 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.
- *
- * Changes:
- *  2009 ported to HelenOS, Lukas Mejdrech
- */
-
-/** @addtogroup dp8390
- *  @{
- */
-
-/** @file
- *  Network interface probe functions.
- */
-
-#ifndef __NET_NETIF_DP8390_CONFIG_H__
-#define __NET_NETIF_DP8390_CONFIG_H__
-
-#include "dp8390_port.h"
-
-/*
-local.h
-*/
-
-/** WDETH switch.
- */
-#define ENABLE_WDETH 0
-
-/** NE2000 switch.
- */
-#define ENABLE_NE2000 1
-
-/** 3C503 switch.
- */
-#define ENABLE_3C503 0
-
-/** PCI support switch.
- */
-#define ENABLE_PCI 0
-
-struct dpeth;
-
-/* 3c503.c */
-/* * Probes a 3C503 network interface.
- *  @param[in] dep The network interface structure.
- *  @returns 1 if the NE2000 network interface is present.
- *  @returns 0 otherwise.
- */
-//_PROTOTYPE(int el2_probe, (struct dpeth*dep)				);
-
-/* ne2000.c */
-/** Probes a NE2000 or NE1000 network interface.
- *  @param[in] dep The network interface structure.
- *  @returns 1 if the NE2000 network interface is present.
- *  @returns 0 otherwise.
- */
-int ne_probe(struct dpeth * dep);
-//_PROTOTYPE(int ne_probe, (struct dpeth *dep)				);
-//_PROTOTYPE(void ne_init, (struct dpeth *dep)				);
-
-/* rtl8029.c */
-/* * Probes a RTL8029 network interface.
- *  @param[in] dep The network interface structure.
- *  @returns 1 if the NE2000 network interface is present.
- *  @returns 0 otherwise.
- */
-//_PROTOTYPE(int rtl_probe, (struct dpeth *dep)				);
-
-/* wdeth.c */
-/* * Probes a WDETH network interface.
- *  @param[in] dep The network interface structure.
- *  @returns 1 if the NE2000 network interface is present.
- *  @returns 0 otherwise.
- */
-//_PROTOTYPE(int wdeth_probe, (struct dpeth*dep)				);
-
-#endif
-
-/** @}
- */
Index: uspace/srv/hw/netif/dp8390/ne2000.c
===================================================================
--- uspace/srv/hw/netif/dp8390/ne2000.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/hw/netif/dp8390/ne2000.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -1,17 +1,23 @@
 /*
- * Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands All rights reserved. Redistribution and use of the MINIX 3 operating system 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.
- * * Neither the name of the Vrije Universiteit nor the names of the software authors or contributors may be used to endorse or promote products derived from this software without specific prior written permission.
- * * Any deviations from these conditions require written permission from the copyright holder in advance
- *
- *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Martin Decky
+ * 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 COPYRIGHT HOLDER OR ANY AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * 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,
@@ -20,7 +26,14 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Changes:
- *  2009 ported to HelenOS, Lukas Mejdrech
+ */
+
+/*
+ * This code is based upon the NE2000 driver for MINIX,
+ * distributed according to a BSD-style license.
+ *
+ * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
+ * Copyright (c) 1992, 1994 Philip Homburg
+ * Copyright (c) 1996 G. Falzoni
+ *
  */
 
@@ -35,60 +48,18 @@
 #include <stdio.h>
 #include <unistd.h>
-
 #include "dp8390_port.h"
-
-/*
-ne2000.c
-
-Driver for the ne2000 ethernet cards. This file contains only the ne2000
-specific code, the rest is in dp8390.c
-
-Created:	March 15, 1994 by Philip Homburg <philip@f-mnx.phicoh.com>
-*/
-
-//#include "../drivers.h"
-
-//#include <net/gen/ether.h>
-//#include <net/gen/eth_io.h>
-//#if __minix_vmd
-//#include "config.h"
-//#endif
-
-#include "local.h"
 #include "dp8390.h"
 #include "ne2000.h"
 
-#if ENABLE_NE2000
-
-/** Number of bytes to transfer.
- */
-#define N 100
-
-//#define MILLIS_TO_TICKS(m)  (((m)*HZ/1000)+1)
-
-/** Sleeps for the defined millicesonds.
- *  @param[in] millis The number of milliseconds to sleep.
- */
-#define milli_delay(millis)	usleep((millis) * 1000)
-
-/** Type definition of the testing function.
- */
-_PROTOTYPE(typedef int (*testf_t), (dpeth_t *dep, int pos, u8_t *pat)	);
-
-/** First data pattern.
- */
-u8_t	pat0[]= {0x00, 0x00, 0x00, 0x00};
-
-/** Second data pattern.
- */
-u8_t	pat1[]= {0xFF, 0xFF, 0xFF, 0xFF};
-
-/** Third data pattern.
- */
-u8_t	pat2[]= {0xA5, 0x5A, 0x69, 0x96};
-
-/** Fourth data pattern.
- */
-u8_t	pat3[]= {0x96, 0x69, 0x5A, 0xA5};
+/** Number of bytes to transfer */
+#define N  100
+
+typedef int (*testf_t)(dpeth_t *dep, int pos, uint8_t *pat);
+
+/** Data patterns */
+uint8_t pat0[] = {0x00, 0x00, 0x00, 0x00};
+uint8_t pat1[] = {0xFF, 0xFF, 0xFF, 0xFF};
+uint8_t pat2[] = {0xA5, 0x5A, 0x69, 0x96};
+uint8_t pat3[] = {0x96, 0x69, 0x5A, 0xA5};
 
 /** Tests 8 bit NE2000 network interface.
@@ -97,7 +68,7 @@
  *  @param[in] pat The data pattern to be written.
  *  @returns True on success.
- *  @returns FALSE otherwise.
- */
-static int test_8(dpeth_t *dep, int pos, u8_t *pat);
+ *  @returns false otherwise.
+ */
+static int test_8(dpeth_t *dep, int pos, uint8_t *pat);
 
 /** Tests 16 bit NE2000 network interface.
@@ -106,24 +77,9 @@
  *  @param[in] pat The data pattern to be written.
  *  @returns True on success.
- *  @returns FALSE otherwise.
- */
-static int test_16(dpeth_t *dep, int pos, u8_t *pat);
-
-/** Stops the NE2000 network interface.
- *  @param[in,out] dep The network interface structure.
- */
-static void ne_stop(dpeth_t *dep);
-//_PROTOTYPE(static void milli_delay, (unsigned long millis)		);
-
-/** Initializes the NE2000 network interface.
- *  @param[in,out] dep The network interface structure.
- */
-void ne_init(struct dpeth *dep);
-
-/*===========================================================================*
- *				ne_probe				     *
- *===========================================================================*/
-int ne_probe(dep)
-dpeth_t *dep;
+ *  @returns false otherwise.
+ */
+static int test_16(dpeth_t *dep, int pos, uint8_t *pat);
+
+int ne_probe(dpeth_t *dep)
 {
 	int byte;
@@ -131,85 +87,73 @@
 	int loc1, loc2;
 	testf_t f;
-
-	dep->de_dp8390_port= dep->de_base_port + NE_DP8390;
-
-	/* We probe for an ne1000 or an ne2000 by testing whether the
+	
+	dep->de_dp8390_port = dep->de_base_port + NE_DP8390;
+	
+	/*
+	 * We probe for an ne1000 or an ne2000 by testing whether the
 	 * on board is reachable through the dp8390. Note that the
 	 * ne1000 is an 8bit card and has a memory region distict from
 	 * the 16bit ne2000
 	 */
-
-	for (dep->de_16bit= 0; dep->de_16bit < 2; dep->de_16bit++)
-	{
+	
+	for (dep->de_16bit = 0; dep->de_16bit < 2; dep->de_16bit++) {
 		/* Reset the ethernet card */
 		byte= inb_ne(dep, NE_RESET);
-		milli_delay(2);
+		usleep(2000);
 		outb_ne(dep, NE_RESET, byte);
-		milli_delay(2);
-
+		usleep(2000);
+		
 		/* Reset the dp8390 */
 		outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
-		for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) &ISR_RST) == 0); i++)
+		for (i = 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
 			; /* Do nothing */
-
+		
 		/* Check if the dp8390 is really there */
-		if ((inb_reg0(dep, DP_CR) &(CR_STP|CR_DM_ABORT)) !=
-			(CR_STP|CR_DM_ABORT))
-		{
+		if ((inb_reg0(dep, DP_CR) & (CR_STP | CR_DM_ABORT)) !=
+		    (CR_STP | CR_DM_ABORT))
 			return 0;
-		}
-
+		
 		/* Disable the receiver and init TCR and DCR. */
 		outb_reg0(dep, DP_RCR, RCR_MON);
 		outb_reg0(dep, DP_TCR, TCR_NORMAL);
-		if (dep->de_16bit)
-		{
+		if (dep->de_16bit) {
 			outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES |
-				DCR_BMS);
+			    DCR_BMS);
+		} else {
+			outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES |
+			    DCR_BMS);
 		}
-		else
-		{
-			outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES |
-				DCR_BMS);
+		
+		if (dep->de_16bit) {
+			loc1 = NE2000_START;
+			loc2 = NE2000_START + NE2000_SIZE - 4;
+			f = test_16;
+		} else {
+			loc1 = NE1000_START;
+			loc2 = NE1000_START + NE1000_SIZE - 4;
+			f = test_8;
 		}
-
-		if (dep->de_16bit)
-		{
-			loc1= NE2000_START;
-			loc2= NE2000_START + NE2000_SIZE - 4;
-			f= test_16;
-		}
-		else
-		{
-			loc1= NE1000_START;
-			loc2= NE1000_START + NE1000_SIZE - 4;
-			f= test_8;
-		}
-		if (f(dep, loc1, pat0) && f(dep, loc1, pat1) && 
-			f(dep, loc1, pat2) && f(dep, loc1, pat3) && 
-			f(dep, loc2, pat0) && f(dep, loc2, pat1) && 
-			f(dep, loc2, pat2) && f(dep, loc2, pat3))
-		{
-			/* We don't need a memory segment */
-			dep->de_linmem= 0;
-			if (!dep->de_pci)
-				dep->de_initf= ne_init;
-			dep->de_stopf= ne_stop;
-			dep->de_prog_IO= 1;
+		
+		if (f(dep, loc1, pat0) && f(dep, loc1, pat1) &&
+		    f(dep, loc1, pat2) && f(dep, loc1, pat3) &&
+		    f(dep, loc2, pat0) && f(dep, loc2, pat1) &&
+		    f(dep, loc2, pat2) && f(dep, loc2, pat3)) {
 			return 1;
 		}
 	}
+	
 	return 0;
 }
 
-/*===========================================================================*
- *				ne_init					     *
- *===========================================================================*/
-void ne_init(dep)
-dpeth_t *dep;
+/** Initializes the NE2000 network interface.
+ *
+ *  @param[in,out] dep The network interface structure.
+ *
+ */
+void ne_init(dpeth_t *dep)
 {
 	int i;
 	int word, sendq_nr;
-
+	
 	/* Setup a transfer to get the ethernet address. */
 	if (dep->de_16bit)
@@ -217,199 +161,138 @@
 	else
 		outb_reg0(dep, DP_RBCR0, 6);
+	
 	outb_reg0(dep, DP_RBCR1, 0);
 	outb_reg0(dep, DP_RSAR0, 0);
 	outb_reg0(dep, DP_RSAR1, 0);
 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
-
-	for (i= 0; i<6; i++)
-	{
-		if (dep->de_16bit)
-		{
-			word= inw_ne(dep, NE_DATA);
-			dep->de_address.ea_addr[i]= word;
-		}
-		else
-		{
+	
+	for (i = 0; i < 6; i++) {
+		if (dep->de_16bit) {
+			word = inw_ne(dep, NE_DATA);
+			dep->de_address.ea_addr[i] = word;
+		} else
 			dep->de_address.ea_addr[i] = inb_ne(dep, NE_DATA);
-		}
-	}
+	}
+	
 	dep->de_data_port= dep->de_base_port + NE_DATA;
-	if (dep->de_16bit)
-	{
-		dep->de_ramsize= NE2000_SIZE;
-		dep->de_offset_page= NE2000_START / DP_PAGESIZE;
-	}
-	else
-	{
-		dep->de_ramsize= NE1000_SIZE;
-		dep->de_offset_page= NE1000_START / DP_PAGESIZE;
-	}
-
+	if (dep->de_16bit) {
+		dep->de_ramsize = NE2000_SIZE;
+		dep->de_offset_page = NE2000_START / DP_PAGESIZE;
+	} else {
+		dep->de_ramsize = NE1000_SIZE;
+		dep->de_offset_page = NE1000_START / DP_PAGESIZE;
+	}
+	
 	/* Allocate one send buffer (1.5KB) per 8KB of on board memory. */
-	sendq_nr= dep->de_ramsize / 0x2000;
+	sendq_nr = dep->de_ramsize / 0x2000;
+	
 	if (sendq_nr < 1)
-		sendq_nr= 1;
+		sendq_nr = 1;
 	else if (sendq_nr > SENDQ_NR)
-		sendq_nr= SENDQ_NR;
-	dep->de_sendq_nr= sendq_nr;
-	for (i= 0; i<sendq_nr; i++)
-	{
-		dep->de_sendq[i].sq_sendpage= dep->de_offset_page +
-			i*SENDQ_PAGES;	
-	}
-
-	dep->de_startpage= dep->de_offset_page + i*SENDQ_PAGES;
-	dep->de_stoppage= dep->de_offset_page + dep->de_ramsize / DP_PAGESIZE;
-
-	/* Can't override the default IRQ. */
-	dep->de_irq &= ~DEI_DEFAULT;
-
-	if (!debug)
-	{
-		printf("%s: NE%d000 at %#lx:%d\n",
-		    dep->de_name, dep->de_16bit ? 2 : 1,
-		    dep->de_base_port, dep->de_irq);
-	}
-	else
-	{
-		printf("%s: Novell NE%d000 ethernet card at I/O address "
-		    "%#lx, memory size %#lx, irq %d\n",
-		    dep->de_name, dep->de_16bit ? 2 : 1,
-		    dep->de_base_port, dep->de_ramsize, dep->de_irq);
-	}
-}
-
-/*===========================================================================*
- *				test_8					     *
- *===========================================================================*/
-static int test_8(dep, pos, pat)
-dpeth_t *dep;
-int pos;
-u8_t *pat;
-{
-	u8_t buf[4];
-	int i;
-	int r;
-
-	outb_reg0(dep, DP_ISR, 0xFF);
-
+		sendq_nr = SENDQ_NR;
+	
+	dep->de_sendq_nr = sendq_nr;
+	for (i = 0; i < sendq_nr; i++)
+		dep->de_sendq[i].sq_sendpage = dep->de_offset_page + i * SENDQ_PAGES;
+	
+	dep->de_startpage = dep->de_offset_page + i * SENDQ_PAGES;
+	dep->de_stoppage = dep->de_offset_page + dep->de_ramsize / DP_PAGESIZE;
+	
+	printf("Novell NE%d000 ethernet card at I/O address "
+	    "%#lx, memory size %#lx, irq %d\n",
+	    dep->de_16bit ? 2 : 1, dep->de_base_port, dep->de_ramsize,
+	    dep->de_irq);
+}
+
+static int test_8(dpeth_t *dep, int pos, uint8_t *pat)
+{
+	uint8_t buf[4];
+	int i;
+	
+	outb_reg0(dep, DP_ISR, 0xff);
+	
 	/* Setup a transfer to put the pattern. */
 	outb_reg0(dep, DP_RBCR0, 4);
 	outb_reg0(dep, DP_RBCR1, 0);
-	outb_reg0(dep, DP_RSAR0, pos &0xFF);
+	outb_reg0(dep, DP_RSAR0, pos & 0xff);
 	outb_reg0(dep, DP_RSAR1, pos >> 8);
 	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
-
-	for (i= 0; i<4; i++)
+	
+	for (i = 0; i < 4; i++)
 		outb_ne(dep, NE_DATA, pat[i]);
-
-	for (i= 0; i<N; i++)
-	{
+	
+	for (i = 0; i < N; i++) {
+		if (inb_reg0(dep, DP_ISR) & ISR_RDC)
+			break;
+	}
+	
+	if (i == N) {
+		printf("NE1000 remote DMA test failed\n");
+		return 0;
+	}
+	
+	outb_reg0(dep, DP_RBCR0, 4);
+	outb_reg0(dep, DP_RBCR1, 0);
+	outb_reg0(dep, DP_RSAR0, pos & 0xff);
+	outb_reg0(dep, DP_RSAR1, pos >> 8);
+	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+	
+	for (i = 0; i < 4; i++)
+		buf[i] = inb_ne(dep, NE_DATA);
+	
+	return (memcmp(buf, pat, 4) == 0);
+}
+
+static int test_16(dpeth_t *dep, int pos, uint8_t *pat)
+{
+	uint8_t buf[4];
+	int i;
+	
+	outb_reg0(dep, DP_ISR, 0xff);
+	
+	/* Setup a transfer to put the pattern. */
+	outb_reg0(dep, DP_RBCR0, 4);
+	outb_reg0(dep, DP_RBCR1, 0);
+	outb_reg0(dep, DP_RSAR0, pos & 0xff);
+	outb_reg0(dep, DP_RSAR1, pos >> 8);
+	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
+	
+	for (i = 0; i < 4; i += 2)
+		outw_ne(dep, NE_DATA, *(uint16_t *)(pat + i));
+	
+	for (i = 0; i < N; i++) {
 		if (inb_reg0(dep, DP_ISR) &ISR_RDC)
 			break;
 	}
-	if (i == N)
-	{
-		if (debug)
-		{
-			printf("%s: NE1000 remote DMA test failed\n",
-				dep->de_name);
-		}
+	
+	if (i == N) {
+		printf("NE2000 remote DMA test failed\n");
 		return 0;
 	}
-
-	outb_reg0(dep, DP_RBCR0, 4);
-	outb_reg0(dep, DP_RBCR1, 0);
-	outb_reg0(dep, DP_RSAR0, pos &0xFF);
+	
+	outb_reg0(dep, DP_RBCR0, 4);
+	outb_reg0(dep, DP_RBCR1, 0);
+	outb_reg0(dep, DP_RSAR0, pos & 0xff);
 	outb_reg0(dep, DP_RSAR1, pos >> 8);
 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
-
-	for (i= 0; i<4; i++)
-		buf[i]= inb_ne(dep, NE_DATA);
-
-	r= (memcmp(buf, pat, 4) == 0);
-	return r;
-}
-
-/*===========================================================================*
- *				test_16					     *
- *===========================================================================*/
-static int test_16(dep, pos, pat)
-dpeth_t *dep;
-int pos;
-u8_t *pat;
-{
-	u8_t buf[4];
-	int i;
-	int r;
-
-	outb_reg0(dep, DP_ISR, 0xFF);
-
-	/* Setup a transfer to put the pattern. */
-	outb_reg0(dep, DP_RBCR0, 4);
-	outb_reg0(dep, DP_RBCR1, 0);
-	outb_reg0(dep, DP_RSAR0, pos &0xFF);
-	outb_reg0(dep, DP_RSAR1, pos >> 8);
-	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
-
-	for (i= 0; i<4; i += 2)
-	{
-		outw_ne(dep, NE_DATA, *(u16_t *)(pat+i));
-	}
-
-	for (i= 0; i<N; i++)
-	{
-		if (inb_reg0(dep, DP_ISR) &ISR_RDC)
-			break;
-	}
-	if (i == N)
-	{
-		if (debug)
-		{
-			printf("%s: NE2000 remote DMA test failed\n",
-				dep->de_name);
-		}
-		return 0;
-	}
-
-	outb_reg0(dep, DP_RBCR0, 4);
-	outb_reg0(dep, DP_RBCR1, 0);
-	outb_reg0(dep, DP_RSAR0, pos &0xFF);
-	outb_reg0(dep, DP_RSAR1, pos >> 8);
-	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
-
-	for (i= 0; i<4; i += 2)
-	{
-		*(u16_t *)(buf+i)= inw_ne(dep, NE_DATA);
-	}
-
-	r= (memcmp(buf, pat, 4) == 0);
-	return r;
-}
-
-/*===========================================================================*
- *				ne_stop					     *
- *===========================================================================*/
-static void ne_stop(dep)
-dpeth_t *dep;
-{
-	int byte;
-
+	
+	for (i = 0; i < 4; i += 2)
+		*(uint16_t *)(buf + i) = inw_ne(dep, NE_DATA);
+	
+	return (memcmp(buf, pat, 4) == 0);
+}
+
+/** Stop the NE2000 network interface.
+ *
+ *  @param[in,out] dep The network interface structure.
+ *
+ */
+void ne_stop(dpeth_t *dep)
+{
 	/* Reset the ethernet card */
-	byte= inb_ne(dep, NE_RESET);
-	milli_delay(2);
+	int byte = inb_ne(dep, NE_RESET);
+	usleep(2000);
 	outb_ne(dep, NE_RESET, byte);
 }
-/*
-static void milli_delay(unsigned long millis)
-{
-	tickdelay(MILLIS_TO_TICKS(millis));
-}
-*/
-#endif /* ENABLE_NE2000 */
-
-/*
- * $PchId: ne2000.c,v 1.10 2004/08/03 12:03:00 philip Exp $
- */
 
 /** @}
Index: uspace/srv/hw/netif/dp8390/ne2000.h
===================================================================
--- uspace/srv/hw/netif/dp8390/ne2000.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/hw/netif/dp8390/ne2000.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -1,17 +1,23 @@
 /*
- * Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands All rights reserved. Redistribution and use of the MINIX 3 operating system in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
  *
- * * 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.
- * * Neither the name of the Vrije Universiteit nor the names of the software authors or contributors may be used to endorse or promote products derived from this software without specific prior written permission.
- * * Any deviations from these conditions require written permission from the copyright holder in advance
+ * 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.
  *
- * Disclaimer
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * 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 COPYRIGHT HOLDER OR ANY AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * 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,
@@ -20,14 +26,15 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Changes:
- *  2009 ported to HelenOS, Lukas Mejdrech
  */
 
 /*
-ne2000.h
-
-Created:	March 15, 1994 by Philip Homburg <philip@f-mnx.phicoh.com>
-*/
+ * This code is based upon the NE2000 driver for MINIX,
+ * distributed according to a BSD-style license.
+ *
+ * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
+ * Copyright (c) 1992, 1994 Philip Homburg
+ * Copyright (c) 1996 G. Falzoni
+ *
+ */
 
 /** @addtogroup ne2k
@@ -43,34 +50,33 @@
 
 #include <libarch/ddi.h>
-
 #include "dp8390_port.h"
 
 /** DP8390 register offset.
  */
-#define NE_DP8390	0x00
+#define NE_DP8390  0x00
 
 /** Data register.
  */
-#define NE_DATA		0x10
+#define NE_DATA  0x10
 
 /** Reset register.
  */
-#define NE_RESET	0x1F
+#define NE_RESET  0x1f
 
 /** NE1000 data start.
  */
-#define NE1000_START	0x2000
+#define NE1000_START  0x2000
 
 /** NE1000 data size.
  */
-#define NE1000_SIZE	0x2000
+#define NE1000_SIZE  0x2000
 
 /** NE2000 data start.
  */
-#define NE2000_START	0x4000
+#define NE2000_START  0x4000
 
 /** NE2000 data size.
  */
-#define NE2000_SIZE	0x4000
+#define NE2000_SIZE  0x4000
 
 /** Reads 1 byte register.
@@ -79,5 +85,5 @@
  *  @returns The read value.
  */
-#define inb_ne(dep, reg)	(inb(dep->de_base_port+reg))
+#define inb_ne(dep, reg)  (inb(dep->de_base_port + reg))
 
 /** Writes 1 byte register.
@@ -86,5 +92,5 @@
  *  @param[in] data The value to be written.
  */
-#define outb_ne(dep, reg, data)	(outb(dep->de_base_port+reg, data))
+#define outb_ne(dep, reg, data)  (outb(dep->de_base_port + reg, data))
 
 /** Reads 1 word (2 bytes) register.
@@ -93,5 +99,5 @@
  *  @returns The read value.
  */
-#define inw_ne(dep, reg)	(inw(dep->de_base_port+reg))
+#define inw_ne(dep, reg)  (inw(dep->de_base_port + reg))
 
 /** Writes 1 word (2 bytes) register.
@@ -100,11 +106,13 @@
  *  @param[in] data The value to be written.
  */
-#define outw_ne(dep, reg, data)	(outw(dep->de_base_port+reg, data))
+#define outw_ne(dep, reg, data)  (outw(dep->de_base_port + reg, data))
 
-#endif /* __NET_NETIF_NE2000_H__ */
+struct dpeth;
 
-/*
- * $PchId: ne2000.h,v 1.4 2004/08/03 12:03:20 philip Exp $
- */
+extern int ne_probe(struct dpeth *);
+extern void ne_init(struct dpeth *);
+extern void ne_stop(struct dpeth *);
+
+#endif
 
 /** @}
Index: pace/srv/net/cfg/Makefile
===================================================================
--- uspace/srv/net/cfg/Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,60 +1,0 @@
-#
-# Copyright (c) 2010 Martin Decky
-# 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 = ../../..
-ROOT_PATH = $(USPACE_PREFIX)/..
-
-COMMON_MAKEFILE = $(ROOT_PATH)/Makefile.common
-CONFIG_MAKEFILE = $(ROOT_PATH)/Makefile.config
-
--include $(COMMON_MAKEFILE)
--include $(CONFIG_MAKEFILE)
-
-ifeq ($(CONFIG_NETIF_NIL_BUNDLE),y)
-	LO_SOURCE = lo.netif_nil_bundle
-	NE2K_SOURCE = ne2k.netif_nil_bundle
-else
-	LO_SOURCE = lo.netif_standalone
-	NE2K_SOURCE = ne2k.netif_standalone
-endif
-
-LO_TARGET = lo
-NE2K_TARGET = ne2k
-
-.PHONY: all clean
-
-all: $(LO_TARGET) $(NE2K_TARGET)
-
-clean:
-	rm -f $(LO_TARGET) $(NE2K_TARGET)
-
-$(LO_TARGET): $(LO_SOURCE)
-	cp $< $@
-
-$(NE2K_TARGET): $(NE2K_SOURCE)
-	cp $< $@
Index: uspace/srv/net/cfg/lo
===================================================================
--- uspace/srv/net/cfg/lo	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/srv/net/cfg/lo	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,13 @@
+# loopback configuration
+
+NAME=lo
+
+NETIF=lo
+NIL=nildummy
+IL=ip
+
+IP_CONFIG=static
+IP_ADDR=127.0.0.1
+IP_NETMASK=255.0.0.0
+
+MTU=15535
Index: pace/srv/net/cfg/lo.netif_nil_bundle
===================================================================
--- uspace/srv/net/cfg/lo.netif_nil_bundle	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,13 +1,0 @@
-# loopback configuration
-
-NAME=lo
-
-NETIF=lo
-NIL=lo
-IL=ip
-
-IP_CONFIG=static
-IP_ADDR=127.0.0.1
-IP_NETMASK=255.0.0.0
-
-MTU=15535
Index: pace/srv/net/cfg/lo.netif_standalone
===================================================================
--- uspace/srv/net/cfg/lo.netif_standalone	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,13 +1,0 @@
-# loopback configuration
-
-NAME=lo
-
-NETIF=lo
-NIL=nildummy
-IL=ip
-
-IP_CONFIG=static
-IP_ADDR=127.0.0.1
-IP_NETMASK=255.0.0.0
-
-MTU=15535
Index: uspace/srv/net/cfg/ne2k
===================================================================
--- uspace/srv/net/cfg/ne2k	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
+++ uspace/srv/net/cfg/ne2k	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -0,0 +1,24 @@
+# DP8390 (NE2k) configuration
+
+NAME=ne2k
+
+NETIF=dp8390
+NIL=eth
+IL=ip
+
+IRQ=5
+IO=300
+
+# 8023_2_LSAP, 8023_2_SNAP
+ETH_MODE=DIX
+ETH_DUMMY=no
+
+IP_CONFIG=static
+IP_ADDR=10.0.2.15
+IP_ROUTING=yes
+IP_NETMASK=255.255.255.240
+IP_BROADCAST=10.0.2.255
+IP_GATEWAY=10.0.2.2
+ARP=arp
+
+MTU=1492
Index: pace/srv/net/cfg/ne2k.netif_nil_bundle
===================================================================
--- uspace/srv/net/cfg/ne2k.netif_nil_bundle	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,24 +1,0 @@
-# DP8390 (NE2k) configuration
-
-NAME=ne2k
-
-NETIF=dp8390
-NIL=dp8390
-IL=ip
-
-IRQ=9
-IO=300
-
-# 8023_2_LSAP, 8023_2_SNAP
-ETH_MODE=DIX
-ETH_DUMMY=no
-
-IP_CONFIG=static
-IP_ADDR=10.0.2.15
-IP_ROUTING=yes
-IP_NETMASK=255.255.255.240
-IP_BROADCAST=10.0.2.255
-IP_GATEWAY=10.0.2.2
-ARP=arp
-
-MTU=1492
Index: pace/srv/net/cfg/ne2k.netif_standalone
===================================================================
--- uspace/srv/net/cfg/ne2k.netif_standalone	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ 	(revision )
@@ -1,24 +1,0 @@
-# DP8390 (NE2k) configuration
-
-NAME=ne2k
-
-NETIF=dp8390
-NIL=eth
-IL=ip
-
-IRQ=9
-IO=300
-
-# 8023_2_LSAP, 8023_2_SNAP
-ETH_MODE=DIX
-ETH_DUMMY=no
-
-IP_CONFIG=static
-IP_ADDR=10.0.2.15
-IP_ROUTING=yes
-IP_NETMASK=255.255.255.240
-IP_BROADCAST=10.0.2.255
-IP_GATEWAY=10.0.2.2
-ARP=arp
-
-MTU=1492
Index: uspace/srv/net/il/arp/arp.c
===================================================================
--- uspace/srv/net/il/arp/arp.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/il/arp/arp.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -483,18 +483,14 @@
 	des_proto = des_hw + header->hardware_length;
 	trans = arp_addr_find(&proto->addresses, (char *) src_proto,
-	    CONVERT_SIZE(uint8_t, char, header->protocol_length));
+	    header->protocol_length);
 	/* Exists? */
 	if (trans && trans->hw_addr) {
-		if (trans->hw_addr->length != CONVERT_SIZE(uint8_t, char,
-		    header->hardware_length)) {
+		if (trans->hw_addr->length != header->hardware_length)
 			return EINVAL;
-		}
 		memcpy(trans->hw_addr->value, src_hw, trans->hw_addr->length);
 	}
 	/* Is my protocol address? */
-	if (proto->addr->length != CONVERT_SIZE(uint8_t, char,
-	    header->protocol_length)) {
+	if (proto->addr->length != header->protocol_length)
 		return EINVAL;
-	}
 	if (!str_lcmp(proto->addr->value, (char *) des_proto,
 	    proto->addr->length)) {
@@ -507,6 +503,5 @@
 			fibril_condvar_initialize(&trans->cv);
 			rc = arp_addr_add(&proto->addresses, (char *) src_proto,
-			    CONVERT_SIZE(uint8_t, char, header->protocol_length),
-			    trans);
+			    header->protocol_length, trans);
 			if (rc != EOK) {
 				/* The generic char map has already freed trans! */
@@ -516,6 +511,5 @@
 		if (!trans->hw_addr) {
 			trans->hw_addr = measured_string_create_bulk(
-			    (char *) src_hw, CONVERT_SIZE(uint8_t, char,
-			    header->hardware_length));
+			    (char *) src_hw, header->hardware_length);
 			if (!trans->hw_addr)
 				return ENOMEM;
@@ -606,6 +600,5 @@
 
 	/* ARP packet content size = header + (address + translation) * 2 */
-	length = 8 + 2 * (CONVERT_SIZE(char, uint8_t, proto->addr->length) +
-	    CONVERT_SIZE(char, uint8_t, device->addr->length));
+	length = 8 + 2 * (proto->addr->length + device->addr->length);
 	if (length > device->packet_dimension.content)
 		return ELIMIT;
@@ -640,6 +633,5 @@
 
 	rc = packet_set_addr(packet, (uint8_t *) device->addr->value,
-	    (uint8_t *) device->broadcast_addr->value,
-	    CONVERT_SIZE(char, uint8_t, device->addr->length));
+	    (uint8_t *) device->broadcast_addr->value, device->addr->length);
 	if (rc != EOK) {
 		pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
Index: uspace/srv/net/il/arp/arp_module.c
===================================================================
--- uspace/srv/net/il/arp/arp_module.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/il/arp/arp_module.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -79,5 +79,5 @@
 		goto out;
 	
-	rc = REGISTER_ME(SERVICE_ARP, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, SERVICE_ARP, 0, 0, &phonehash);
 	if (rc != EOK)
 		goto out;
Index: uspace/srv/net/il/ip/ip.c
===================================================================
--- uspace/srv/net/il/ip/ip.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/il/ip/ip.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -442,5 +442,5 @@
 		if (route) {
 			address.value = (char *) &route->address.s_addr;
-			address.length = CONVERT_SIZE(in_addr_t, char, 1);
+			address.length = sizeof(in_addr_t);
 			
 			rc = arp_device_req(ip_netif->arp->phone,
@@ -639,5 +639,5 @@
 	if (destination) {
 		rc = packet_set_addr(packet, NULL, (uint8_t *) destination->value,
-		    CONVERT_SIZE(char, uint8_t, destination->length));
+		    destination->length);
 	} else {
 		rc = packet_set_addr(packet, NULL, NULL, 0);
@@ -687,6 +687,5 @@
 				rc = packet_set_addr(next, NULL,
 				    (uint8_t *) destination->value,
-				    CONVERT_SIZE(char, uint8_t,
-				    destination->length));
+				    destination->length);
 				if (rc != EOK) {
 				    	free(last_header);
@@ -718,5 +717,5 @@
 			rc = packet_set_addr(next, NULL,
 			    (uint8_t *) destination->value,
-			    CONVERT_SIZE(char, uint8_t, destination->length));
+			    destination->length);
 			if (rc != EOK) {
 				free(last_header);
@@ -1006,5 +1005,5 @@
 		destination.value = route->gateway.s_addr ?
 		    (char *) &route->gateway.s_addr : (char *) &dest.s_addr;
-		destination.length = CONVERT_SIZE(dest.s_addr, char, 1);
+		destination.length = sizeof(dest.s_addr);
 
 		rc = arp_translate_req(netif->arp->phone, netif->device_id,
@@ -1758,6 +1757,5 @@
 			// clear the ARP mapping if any
 			address.value = (char *) &header->destination_address;
-			address.length = CONVERT_SIZE(uint8_t, char,
-			    sizeof(header->destination_address));
+			address.length = sizeof(header->destination_address);
 			arp_clear_address_req(netif->arp->phone,
 			    netif->device_id, SERVICE_IP, &address);
@@ -1951,5 +1949,6 @@
 
 	case NET_IP_GET_ROUTE:
-		rc = data_receive((void **) &addr, &addrlen);
+		rc = async_data_write_accept((void **) &addr, false, 0, 0, 0,
+		    &addrlen);
 		if (rc != EOK)
 			return rc;
Index: uspace/srv/net/il/ip/ip_module.c
===================================================================
--- uspace/srv/net/il/ip/ip_module.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/il/ip/ip_module.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -80,5 +80,5 @@
 		goto out;
 	
-	rc = REGISTER_ME(SERVICE_IP, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, SERVICE_IP, 0, 0, &phonehash);
 	if (rc != EOK)
 		goto out;
Index: uspace/srv/net/net/net.c
===================================================================
--- uspace/srv/net/net/net.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/net/net.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -335,5 +335,5 @@
 		goto out;
 	
-	rc = REGISTER_ME(SERVICE_NETWORKING, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, SERVICE_NETWORKING, 0, 0, &phonehash);
 	if (rc != EOK)
 		goto out;
Index: uspace/srv/net/netif/lo/Makefile
===================================================================
--- uspace/srv/net/netif/lo/Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/netif/lo/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -39,8 +39,4 @@
 -include $(CONFIG_MAKEFILE)
 
-ifeq ($(CONFIG_NETIF_NIL_BUNDLE),y)
-	LIBS += $(USPACE_PREFIX)/srv/net/nil/nildummy/libnildummy.a
-endif
-
 BINARY = lo
 
Index: uspace/srv/net/netif/lo/lo.c
===================================================================
--- uspace/srv/net/netif/lo/lo.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/netif/lo/lo.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -166,5 +166,5 @@
 	sysarg_t phonehash;
 
-	return REGISTER_ME(SERVICE_LO, &phonehash);
+	return ipc_connect_to_me(PHONE_NS, SERVICE_LO, 0, 0, &phonehash);
 }
 
Index: uspace/srv/net/nil/eth/Makefile
===================================================================
--- uspace/srv/net/nil/eth/Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/nil/eth/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -39,9 +39,5 @@
 -include $(CONFIG_MAKEFILE)
 
-ifeq ($(CONFIG_NETIF_NIL_BUNDLE),y)
-	LIBRARY = libeth
-else
-	BINARY = eth
-endif
+BINARY = eth
 
 SOURCES = \
Index: uspace/srv/net/nil/eth/eth.c
===================================================================
--- uspace/srv/net/nil/eth/eth.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/nil/eth/eth.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -201,6 +201,5 @@
 
 	eth_globals.broadcast_addr =
-	    measured_string_create_bulk("\xFF\xFF\xFF\xFF\xFF\xFF",
-	    CONVERT_SIZE(uint8_t, char, ETH_ADDR));
+	    measured_string_create_bulk("\xFF\xFF\xFF\xFF\xFF\xFF", ETH_ADDR);
 	if (!eth_globals.broadcast_addr) {
 		rc = ENOMEM;
Index: uspace/srv/net/nil/eth/eth_module.c
===================================================================
--- uspace/srv/net/nil/eth/eth_module.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/nil/eth/eth_module.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -66,5 +66,5 @@
 		goto out;
 
-	rc = REGISTER_ME(SERVICE_ETHERNET, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, SERVICE_ETHERNET, 0, 0, &phonehash);
 	if (rc != EOK)
 		goto out;
Index: uspace/srv/net/nil/nildummy/Makefile
===================================================================
--- uspace/srv/net/nil/nildummy/Makefile	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/nil/nildummy/Makefile	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -39,9 +39,5 @@
 -include $(CONFIG_MAKEFILE)
 
-ifeq ($(CONFIG_NETIF_NIL_BUNDLE),y)
-	LIBRARY = libnildummy
-else
-	BINARY = nildummy
-endif
+BINARY = nildummy
 
 SOURCES = \
Index: uspace/srv/net/nil/nildummy/nildummy_module.c
===================================================================
--- uspace/srv/net/nil/nildummy/nildummy_module.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/nil/nildummy/nildummy_module.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -67,5 +67,5 @@
 		goto out;
 	
-	rc = REGISTER_ME(SERVICE_NILDUMMY, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, SERVICE_NILDUMMY, 0, 0, &phonehash);
 	if (rc != EOK)
 		goto out;
Index: uspace/srv/net/tl/icmp/icmp.c
===================================================================
--- uspace/srv/net/tl/icmp/icmp.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/tl/icmp/icmp.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -529,5 +529,5 @@
 	icmp_code_t code;
 	int rc;
-
+	
 	switch (error) {
 	case SERVICE_NONE:
Index: uspace/srv/net/tl/icmp/icmp_module.c
===================================================================
--- uspace/srv/net/tl/icmp/icmp_module.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/tl/icmp/icmp_module.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -74,5 +74,5 @@
 		goto out;
 
-	rc = REGISTER_ME(SERVICE_ICMP, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, SERVICE_ICMP, 0, 0, &phonehash);
 	if (rc != EOK)
 		goto out;
Index: uspace/srv/net/tl/tcp/tcp.c
===================================================================
--- uspace/srv/net/tl/tcp/tcp.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/tl/tcp/tcp.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -205,4 +205,5 @@
 static int tcp_queue_received_packet(socket_core_t *, tcp_socket_data_t *,
     packet_t *, int, size_t);
+static void tcp_queue_received_end_of_data(socket_core_t *socket);
 
 static int tcp_received_msg(device_id_t, packet_t *, services_t, services_t);
@@ -453,5 +454,5 @@
 
 has_error_service:
-	fibril_rwlock_read_unlock(&tcp_globals.lock);
+	fibril_rwlock_write_unlock(&tcp_globals.lock);
 
 	/* TODO error reporting/handling */
@@ -504,4 +505,5 @@
 	size_t offset;
 	uint32_t new_sequence_number;
+	bool forced_ack;
 	int rc;
 
@@ -512,9 +514,13 @@
 	assert(packet);
 
+	forced_ack = false;
+
 	new_sequence_number = ntohl(header->sequence_number);
 	old_incoming = socket_data->next_incoming;
 
-	if (header->finalize)
-		socket_data->fin_incoming = new_sequence_number;
+	if (header->finalize) {
+		socket_data->fin_incoming = new_sequence_number +
+		    total_length - TCP_HEADER_LENGTH(header);
+	}
 
 	/* Trim begining if containing expected data */
@@ -760,9 +766,13 @@
 		/* Release duplicite or restricted */
 		pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
-	}
-
-	/* Change state according to the acknowledging incoming fin */
-	if (IS_IN_INTERVAL_OVERFLOW(old_incoming, socket_data->fin_incoming,
-	    socket_data->next_incoming)) {
+		forced_ack = true;
+	}
+
+	/* If next in sequence is an incoming FIN */
+	if (socket_data->next_incoming == socket_data->fin_incoming) {
+		/* Advance sequence number */
+		socket_data->next_incoming += 1;
+
+		/* Handle FIN */
 		switch (socket_data->state) {
 		case TCP_SOCKET_FIN_WAIT_1:
@@ -771,5 +781,9 @@
 			socket_data->state = TCP_SOCKET_CLOSING;
 			break;
-		/*case TCP_ESTABLISHED:*/
+		case TCP_SOCKET_ESTABLISHED:
+			/* Queue end-of-data marker on the socket. */
+			tcp_queue_received_end_of_data(socket);
+			socket_data->state = TCP_SOCKET_CLOSE_WAIT;
+			break;
 		default:
 			socket_data->state = TCP_SOCKET_CLOSE_WAIT;
@@ -779,5 +793,5 @@
 
 	packet = tcp_get_packets_to_send(socket, socket_data);
-	if (!packet) {
+	if (!packet && (socket_data->next_incoming != old_incoming || forced_ack)) {
 		/* Create the notification packet */
 		rc = tcp_create_notification_packet(&packet, socket,
@@ -835,4 +849,22 @@
 
 	return EOK;
+}
+
+/** Queue end-of-data marker on the socket.
+ *
+ * Next element in the sequence space is FIN. Queue end-of-data marker
+ * on the socket.
+ *
+ * @param socket	Socket
+ */
+static void tcp_queue_received_end_of_data(socket_core_t *socket)
+{
+	assert(socket != NULL);
+
+	/* Notify the destination socket */
+	async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
+	    (sysarg_t) socket->socket_id,
+	    0, 0, 0,
+	    (sysarg_t) 0 /* 0 fragments == no more data */);
 }
 
@@ -1365,5 +1397,6 @@
 
 		case NET_SOCKET_BIND:
-			res = data_receive((void **) &addr, &addrlen);
+			res = async_data_write_accept((void **) &addr, false,
+			    0, 0, 0, &addrlen);
 			if (res != EOK)
 				break;
@@ -1402,5 +1435,6 @@
 
 		case NET_SOCKET_CONNECT:
-			res = data_receive((void **) &addr, &addrlen);
+			res = async_data_write_accept((void **) &addr, false,
+			    0, 0, 0, &addrlen);
 			if (res != EOK)
 				break;
@@ -1453,5 +1487,6 @@
 
 		case NET_SOCKET_SENDTO:
-			res = data_receive((void **) &addr, &addrlen);
+			res = async_data_write_accept((void **) &addr, false,
+			    0, 0, 0, &addrlen);
 			if (res != EOK)
 				break;
@@ -1800,4 +1835,6 @@
 			fibril_rwlock_write_unlock(socket_data->local_lock);
 
+			socket_data->state = TCP_SOCKET_SYN_SENT;
+
 			/* Send the packet */
 			printf("connecting %d\n", packet_get_id(packet));
@@ -2082,6 +2119,7 @@
 	if (!fibril) {
 		free(operation_timeout);
-		return EPARTY;	/* FIXME: use another EC */
-	}
+		return ENOMEM;
+	}
+
 //      fibril_mutex_lock(&socket_data->operation.mutex);
 	/* Start the timeout fibril */
@@ -2206,5 +2244,5 @@
 
 		tcp_prepare_operation_header(socket, socket_data, header, 0, 0);
-		rc = tcp_queue_packet(socket, socket_data, packet, 0);
+		rc = tcp_queue_packet(socket, socket_data, packet, total_length);
 		if (rc != EOK)
 			return rc;
Index: uspace/srv/net/tl/tcp/tcp_module.c
===================================================================
--- uspace/srv/net/tl/tcp/tcp_module.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/tl/tcp/tcp_module.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -75,5 +75,5 @@
 		goto out;
 
-	rc = REGISTER_ME(SERVICE_TCP, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, SERVICE_TCP, 0, 0, &phonehash);
 	if (rc != EOK)
 		goto out;
Index: uspace/srv/net/tl/udp/udp.c
===================================================================
--- uspace/srv/net/tl/udp/udp.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/tl/udp/udp.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -771,5 +771,6 @@
 
 		case NET_SOCKET_BIND:
-			res = data_receive((void **) &addr, &addrlen);
+			res = async_data_write_accept((void **) &addr, false,
+			    0, 0, 0, &addrlen);
 			if (res != EOK)
 				break;
@@ -784,5 +785,6 @@
 
 		case NET_SOCKET_SENDTO:
-			res = data_receive((void **) &addr, &addrlen);
+			res = async_data_write_accept((void **) &addr, false,
+			    0, 0, 0, &addrlen);
 			if (res != EOK)
 				break;
Index: uspace/srv/net/tl/udp/udp_module.c
===================================================================
--- uspace/srv/net/tl/udp/udp_module.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/net/tl/udp/udp_module.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -75,5 +75,5 @@
 		goto out;
 	
-	rc = REGISTER_ME(SERVICE_UDP, &phonehash);
+	rc = ipc_connect_to_me(PHONE_NS, SERVICE_UDP, 0, 0, &phonehash);
 	if (rc != EOK)
 		goto out;
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/vfs/vfs.h	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -34,4 +34,5 @@
 #define VFS_VFS_H_
 
+#include <async.h>
 #include <ipc/ipc.h>
 #include <adt/list.h>
@@ -53,6 +54,5 @@
 	vfs_info_t vfs_info;
 	fs_handle_t fs_handle;
-	fibril_mutex_t phone_lock;
-	sysarg_t phone;
+	async_sess_t session;
 } fs_info_t;
 
Index: uspace/srv/vfs/vfs_lookup.c
===================================================================
--- uspace/srv/vfs/vfs_lookup.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/vfs/vfs_lookup.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -179,6 +179,9 @@
 	fibril_mutex_unlock(&plb_mutex);
 	
-	if (((int) rc < EOK) || (!result))
+	if ((int) rc < EOK)
 		return (int) rc;
+
+	if (!result)
+		return EOK;
 	
 	result->triplet.fs_handle = (fs_handle_t) rc;
Index: uspace/srv/vfs/vfs_register.c
===================================================================
--- uspace/srv/vfs/vfs_register.c	(revision 8f748215078e8edd57ba50ab2f9598013692e7b6)
+++ uspace/srv/vfs/vfs_register.c	(revision 93fb170c39691e453743ec966fe97197a7ddbfd1)
@@ -39,5 +39,4 @@
 #include <ipc/services.h>
 #include <async.h>
-#include <async_rel.h>
 #include <fibril.h>
 #include <fibril_synch.h>
@@ -111,4 +110,6 @@
 void vfs_register(ipc_callid_t rid, ipc_call_t *request)
 {
+	int phone;
+	
 	dprintf("Processing VFS_REGISTER request received from %p.\n",
 	    request->in_phone_hash);
@@ -136,5 +137,4 @@
 	
 	link_initialize(&fs_info->fs_link);
-	fibril_mutex_initialize(&fs_info->phone_lock);
 	fs_info->vfs_info = *vfs_info;
 	free(vfs_info);
@@ -186,5 +186,7 @@
 		return;
 	}
-	fs_info->phone = IPC_GET_ARG5(call);
+	
+	phone = IPC_GET_ARG5(call);
+	async_session_create(&fs_info->session, phone);
 	ipc_answer_0(callid, EOK);
 	
@@ -200,5 +202,6 @@
 		list_remove(&fs_info->fs_link);
 		fibril_mutex_unlock(&fs_head_lock);
-		ipc_hangup(fs_info->phone);
+		async_session_destroy(&fs_info->session);
+		ipc_hangup(phone);
 		free(fs_info);
 		ipc_answer_0(callid, EINVAL);
@@ -214,5 +217,6 @@
 		list_remove(&fs_info->fs_link);
 		fibril_mutex_unlock(&fs_head_lock);
-		ipc_hangup(fs_info->phone);
+		async_session_destroy(&fs_info->session);
+		ipc_hangup(phone);
 		free(fs_info);
 		ipc_answer_0(callid, EINVAL);
@@ -269,7 +273,5 @@
 		if (fs->fs_handle == handle) {
 			fibril_mutex_unlock(&fs_head_lock);
-			fibril_mutex_lock(&fs->phone_lock);
-			phone = async_relation_create(fs->phone);
-			fibril_mutex_unlock(&fs->phone_lock);
+			phone = async_exchange_begin(&fs->session);
 
 			assert(phone > 0);
@@ -295,7 +297,5 @@
 		if (fs->fs_handle == handle) {
 			fibril_mutex_unlock(&fs_head_lock);
-			fibril_mutex_lock(&fs->phone_lock);
-			async_relation_destroy(fs->phone, phone);
-			fibril_mutex_unlock(&fs->phone_lock);
+			async_exchange_end(&fs->session, phone);
 			return;
 		}
