Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ HelenOS.config	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -520,5 +520,5 @@
 @ "1920x1080"
 @ "1920x1200"
-! [(PLATFORM=ia32|PLATFORM=amd64)&CONFIG_HID_OUT!=none&CONFIG_FB=y] CONFIG_VESA_MODE (choice)
+! [(PLATFORM=ia32|PLATFORM=amd64)&CONFIG_HID_OUT!=none&CONFIG_FB=y] CONFIG_BFB_MODE (choice)
 
 % Default framebuffer depth
@@ -526,5 +526,5 @@
 @ "16"
 @ "24"
-! [(PLATFORM=ia32|PLATFORM=amd64)&CONFIG_HID_OUT!=none&CONFIG_FB=y] CONFIG_VESA_BPP (choice)
+! [(PLATFORM=ia32|PLATFORM=amd64)&CONFIG_HID_OUT!=none&CONFIG_FB=y] CONFIG_BFB_BPP (choice)
 
 % Start AP processors by the loader
@@ -570,5 +570,5 @@
 ! CONFIG_PCC (n/y)
 
-% Build binutils binaries 
+% Build binutils binaries
 ! CONFIG_BINUTILS (n/y)
 
@@ -576,5 +576,5 @@
 ! [CONFIG_STRIP_BINARIES!=y] CONFIG_LINE_DEBUG (n/y)
 
-# USB settings 
+# USB settings
 
 % USB release build (less logging)
@@ -588,3 +588,8 @@
 @ "ganged" Root hub ports are all powered or all off.
 @ "per_port" Powered status of every root hub port is independent.
-![PLATFORM=ia32|PLATFORM=amd64] OHCI_POWER_SWITCH (choice)
+! [PLATFORM=ia32|PLATFORM=amd64] OHCI_POWER_SWITCH (choice)
+
+% GRUB boot loader architecture
+@ "pc" GRUB for PC
+@ "efi" GRUB for UEFI
+! [PLATFORM=ia32|PLATFORM=amd64] GRUB_ARCH (choice)
Index: abi/include/ddi/arg.h
===================================================================
--- abi/include/ddi/arg.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ abi/include/ddi/arg.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -36,4 +36,6 @@
 #define ABI_DDI_ARG_H_
 
+#define DMAMEM_FLAGS_ANONYMOUS  0x01
+
 /** Structure encapsulating arguments for SYS_PHYSMEM_MAP syscall. */
 typedef struct {
Index: abi/include/syscall.h
===================================================================
--- abi/include/syscall.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ abi/include/syscall.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -85,4 +85,6 @@
 	SYS_DEVICE_ASSIGN_DEVNO,
 	SYS_PHYSMEM_MAP,
+	SYS_DMAMEM_MAP,
+	SYS_DMAMEM_UNMAP,
 	SYS_IOSPACE_ENABLE,
 	SYS_REGISTER_IRQ,
Index: boot/Makefile
===================================================================
--- boot/Makefile	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ boot/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -40,8 +40,5 @@
 	$(PACK) $(OBJCOPY) $(BFD_NAME) $(BFD_ARCH) arch/$(KARCH) $(COMPONENTS)
 
-$(INITRD).img: $(INITRD).fs
-	$(MKHORD) $(PAGE_SIZE) $< $@
-
-$(INITRD).fs: build_dist
+$(INITRD).img: build_dist
 ifeq ($(RDFMT),tmpfs)
 	$(MKTMPFS) $(DIST_PATH) $@
@@ -95,5 +92,5 @@
 
 clean_dist:
-	rm -f $(INITRD).fs $(INITRD).img $(COMPS_H) $(COMPS_C) $(LINK) $(LINK).comp *.co
+	rm -f $(INITRD).img $(COMPS_H) $(COMPS_C) $(LINK) $(LINK).comp *.co
 	rm -f $(USPACE_PATH)/dist/srv/*
 	rm -rf $(USPACE_PATH)/dist/drv/*
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ boot/Makefile.common	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -53,5 +53,4 @@
 SANDBOX = pack
 PACK = $(TOOLS_PATH)/pack.py
-MKHORD = $(TOOLS_PATH)/mkhord.py
 MKTMPFS = $(TOOLS_PATH)/mktmpfs.py
 MKFAT = $(TOOLS_PATH)/mkfat.py
@@ -124,5 +123,6 @@
 	test/test3 \
 	nic/lo \
-	nic/ne2k
+	nic/ne2k \
+	nic/e1k
 
 RD_DRV_CFG =
@@ -175,4 +175,5 @@
 	$(USPACE_PATH)/app/nettest1/nettest1 \
 	$(USPACE_PATH)/app/nettest2/nettest2 \
+	$(USPACE_PATH)/app/nettest3/nettest3 \
 	$(USPACE_PATH)/app/netecho/netecho \
 	$(USPACE_PATH)/app/ping/ping \
@@ -203,5 +204,6 @@
 	$(USPACE_PATH)/srv/net/cfg/general \
 	$(USPACE_PATH)/srv/net/cfg/lo.nic \
-	$(USPACE_PATH)/srv/net/cfg/ne2k.nic
+	$(USPACE_PATH)/srv/net/cfg/ne2k.nic \
+	$(USPACE_PATH)/srv/net/cfg/e1k.nic
 endif
 
Index: boot/Makefile.grub
===================================================================
--- boot/Makefile.grub	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ boot/Makefile.grub	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -31,31 +31,66 @@
 include Makefile.common
 
-STAGE2 = grub/stage2_eltorito
-STAGE2_IN = boot/$(STAGE2)
+GRUB = grub.$(GRUB_ARCH)
+BOOT = $(DISTROOT)/boot
+
+ELTORITO = boot/grub/$(GRUB_ARCH).img
+IMAGE = $(DISTROOT)/$(ELTORITO)
+
+ifeq ($(GRUB_ARCH),pc)
+	BOOT_CONFIG = $(BOOT)/grub/i386-pc/grub.cfg
+	MULTIBOOT_CMD = multiboot
+	MODULE_CMD = module
+endif
+ifeq ($(GRUB_ARCH),efi)
+	BOOT_CONFIG = $(BOOT)/grub/grub.cfg
+	MULTIBOOT_CMD = multiboot2
+	MODULE_CMD = module2
+endif
 
 all: $(BOOT_OUTPUT)
 
 $(BOOT_OUTPUT): build_dist
-	mkisofs -J -r -b $(STAGE2_IN) -no-emul-boot -boot-load-size 4 -boot-info-table -o $@ $(DISTROOT)/
+ifeq ($(GRUB_ARCH),pc)
+	mkisofs -J -r -input-charset utf-8 -V "HelenOS boot ISO" -eltorito-boot $(ELTORITO) -no-emul-boot -boot-load-size 64 -boot-info-table -o $@ $(DISTROOT)/
+endif
+ifeq ($(GRUB_ARCH),efi)
+	mkisofs -J -r -input-charset utf-8 -V "HelenOS boot ISO" -efi-boot $(ELTORITO) -o $@ $(DISTROOT)/
+endif
 
 build_dist: clean
-	mkdir -p $(DISTROOT)/boot/grub
-	cp $(STAGE2) $(DISTROOT)/boot/grub/
+	mkdir -p $(BOOT)
+	cp -r $(GRUB) $(BOOT)/grub
+ifeq ($(GRUB_ARCH),efi)
+	gunzip $(IMAGE)
+endif
+	
 	for module in $(COMPONENTS) ; do \
-		cp "$$module" $(DISTROOT)/boot/ ; \
+		cp "$$module" $(BOOT)/ ; \
 	done
 	
-	echo "default 0" > $(DISTROOT)/boot/grub/menu.lst
-	echo "timeout 10" >> $(DISTROOT)/boot/grub/menu.lst
-	echo "" >> $(DISTROOT)/boot/grub/menu.lst
-	echo "title=HelenOS" >> $(DISTROOT)/boot/grub/menu.lst
-	echo "	root (cd)" >> $(DISTROOT)/boot/grub/menu.lst
+	echo "set default=0" > $(BOOT_CONFIG)
+	echo "set timeout=10" >> $(BOOT_CONFIG)
+	echo "" >> $(BOOT_CONFIG)
+	
+ifeq ($(GRUB_ARCH),pc)
+	echo "insmod vbe" >> $(BOOT_CONFIG)
+	echo "insmod vga" >> $(BOOT_CONFIG)
+endif
+ifeq ($(GRUB_ARCH),efi)
+	echo "insmod efi_gop" >> $(BOOT_CONFIG)
+	echo "insmod efi_uga" >> $(BOOT_CONFIG)
+endif
+	echo "" >> $(BOOT_CONFIG)
+	
+	echo "menuentry 'HelenOS $(RELEASE)' --class helenos --class os {" >> $(BOOT_CONFIG)
 	for module in $(MODULES) ; do \
+		echo "	echo 'Loading $$module'" >> $(BOOT_CONFIG) ; \
 		if [ "$$module" = "kernel.bin" ] ; then \
-			echo "	kernel /boot/$$module" >> $(DISTROOT)/boot/grub/menu.lst ; \
+			echo "	$(MULTIBOOT_CMD) /boot/$$module" >> $(BOOT_CONFIG) ; \
 		else \
-			echo "	module /boot/$$module" >> $(DISTROOT)/boot/grub/menu.lst ; \
+			echo "	$(MODULE_CMD) /boot/$$module /boot/$$module" >> $(BOOT_CONFIG) ; \
 		fi \
 	done
+	echo "}" >> $(BOOT_CONFIG)
 
 clean:
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ boot/arch/amd64/Makefile.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -26,6 +26,4 @@
 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
-
-PAGE_SIZE = 4096
 
 RD_SRVS_ESSENTIAL += \
Index: boot/arch/arm32/Makefile.inc
===================================================================
--- boot/arch/arm32/Makefile.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ boot/arch/arm32/Makefile.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -39,5 +39,4 @@
 BITS = 32
 ENDIANESS = LE
-PAGE_SIZE = 4096
 
 RD_SRVS_ESSENTIAL += \
Index: boot/arch/ia64/Makefile.inc
===================================================================
--- boot/arch/ia64/Makefile.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ boot/arch/ia64/Makefile.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -33,5 +33,4 @@
 BITS = 64
 ENDIANESS = LE
-PAGE_SIZE = 16384
 EXTRA_CFLAGS = -fno-unwind-tables -mfixed-range=f32-f127 -mno-pic -mno-sdata
 
Index: boot/arch/mips32/Makefile.inc
===================================================================
--- boot/arch/mips32/Makefile.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ boot/arch/mips32/Makefile.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -29,5 +29,4 @@
 BFD_ARCH = mips
 BITS = 32
-PAGE_SIZE = 16384
 EXTRA_CFLAGS = -mno-abicalls -G 0 -fno-zero-initialized-in-bss -mips3 -mabi=32
 
Index: boot/arch/mips64/Makefile.inc
===================================================================
--- boot/arch/mips64/Makefile.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ boot/arch/mips64/Makefile.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -29,5 +29,4 @@
 BFD_ARCH = mips:4000
 BITS = 64
-PAGE_SIZE = 16384
 EXTRA_CFLAGS = -mno-abicalls -G 0 -fno-zero-initialized-in-bss -mips3 -mabi=64
 
Index: boot/arch/ppc32/Makefile.inc
===================================================================
--- boot/arch/ppc32/Makefile.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ boot/arch/ppc32/Makefile.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -37,5 +37,4 @@
 BITS = 32
 ENDIANESS = BE
-PAGE_SIZE = 4096
 EXTRA_CFLAGS = -mcpu=powerpc -msoft-float -m32
 
Index: boot/arch/sparc64/Makefile.inc
===================================================================
--- boot/arch/sparc64/Makefile.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ boot/arch/sparc64/Makefile.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -37,5 +37,4 @@
 BITS = 64
 ENDIANESS = BE
-PAGE_SIZE = 16384
 EXTRA_CFLAGS = -mcpu=ultrasparc -m64 -mno-fpu -mcmodel=medlow
 
Index: boot/grub.efi/COPYING
===================================================================
--- boot/grub.efi/COPYING	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/COPYING	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
Index: boot/grub.efi/README
===================================================================
--- boot/grub.efi/README	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/README	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,12 @@
+The binary files of GRUB boot loader in this directory have been created
+by compiling GRUB for the 'i386-efi' and 'x86_64-efi' targets. The combined
+32bit and 64bit EFI boot floppy image was created by modifying the
+i386-grub-mkrescue and x86_64-grub-mkrescue scripts to create EFI payloads
+which search for the bootable ISO image with the volume label
+'HelenOS boot ISO'.
+
+For licensing terms of GRUB boot loader see the file COPYING contained
+in this directory. Full version of GRUB, including its source code,
+can be downloaded from GRUB's project page:
+
+http://www.gnu.org/software/grub/
Index: boot/grub.efi/i386-efi/command.lst
===================================================================
--- boot/grub.efi/i386-efi/command.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/i386-efi/command.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,134 @@
+*acpi: acpi
+*background_image: gfxterm
+*cat: cat
+*cpuid: cpuid
+*crc: hashsum
+*echo: echo
+*functional_test: functional_test
+*gettext: gettext
+*hashsum: hashsum
+*hdparm: hdparm
+*hello: hello
+*help: help
+*hexdump: hexdump
+*inb: iorw
+*inl: iorw
+*inw: iorw
+*keystatus: keystatus
+*kfreebsd: bsd
+*knetbsd: bsd
+*kopenbsd: bsd
+*list_env: loadenv
+*load_env: loadenv
+*loopback: loopback
+*ls: ls
+*lsacpi: lsacpi
+*lspci: lspci
+*md5sum: hashsum
+*menuentry: normal
+*probe: probe
+*read_byte: memrw
+*read_dword: memrw
+*read_word: memrw
+*regexp: regexp
+*save_env: loadenv
+*search: search
+*serial: serial
+*setpci: setpci
+*sha1sum: hashsum
+*sha256sum: hashsum
+*sha512sum: hashsum
+*sleep: sleep
+*submenu: normal
+*terminfo: terminfo
+*test_blockarg: test_blockarg
+*xnu_splash: xnu
+.: configfile
+[: test
+appleloader: appleldr
+authenticate: normal
+badram: mmap
+blocklist: blocklist
+boot: boot
+break: normal
+cat: minicmd
+chainloader: chain
+clear: normal
+cmp: cmp
+configfile: configfile
+continue: normal
+cutmem: mmap
+date: date
+dump: minicmd
+exit: minicmd
+export: normal
+extract_entries_configfile: configfile
+extract_entries_source: configfile
+fakebios: loadbios
+false: true
+fix_video: fixvideo
+gptsync: gptsync
+halt: halt
+help: minicmd
+initrd: linux
+keymap: keylayouts
+kfreebsd_loadenv: bsd
+kfreebsd_module: bsd
+kfreebsd_module_elf: bsd
+knetbsd_module: bsd
+knetbsd_module_elf: bsd
+kopenbsd_ramdisk: bsd
+linux: linux
+loadbios: loadbios
+loadfont: font
+lsefimmap: lsefimmap
+lsefisystab: lsefisystab
+lsfonts: font
+lsmmap: lsmmap
+lsmod: minicmd
+lssal: lssal
+module2: multiboot2
+module: multiboot
+multiboot2: multiboot2
+multiboot: multiboot
+normal: normal
+normal_exit: normal
+outb: iorw
+outl: iorw
+outw: iorw
+parttool: parttool
+password: password
+password_pbkdf2: password_pbkdf2
+play: play
+read: read
+reboot: reboot
+return: normal
+rmmod: minicmd
+search.file: search_fs_file
+search.fs_label: search_label
+search.fs_uuid: search_fs_uuid
+setparams: normal
+shift: normal
+source: configfile
+terminal_input: terminal
+terminal_output: terminal
+test: test
+testload: testload
+true: true
+usb: usbtest
+videoinfo: videoinfo
+videotest: videotest
+write_byte: memrw
+write_dword: memrw
+write_word: memrw
+xnu_devprop_load: xnu
+xnu_kernel64: xnu
+xnu_kernel: xnu
+xnu_kext: xnu
+xnu_kextdir: xnu
+xnu_mkext: xnu
+xnu_ramdisk: xnu
+xnu_resume: xnu
+xnu_uuid: xnu_uuid
+zfs-bootfs: zfsinfo
+zfsinfo: zfsinfo
Index: boot/grub.efi/i386-efi/crypto.lst
===================================================================
--- boot/grub.efi/i386-efi/crypto.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/i386-efi/crypto.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,38 @@
+RIJNDAEL: gcry_rijndael
+RIJNDAEL192: gcry_rijndael
+RIJNDAEL256: gcry_rijndael
+AES128: gcry_rijndael
+AES-128: gcry_rijndael
+AES-192: gcry_rijndael
+AES-256: gcry_rijndael
+ARCFOUR: gcry_arcfour
+BLOWFISH: gcry_blowfish
+CAMELLIA128: gcry_camellia
+CAMELLIA192: gcry_camellia
+CAMELLIA256: gcry_camellia
+CAST5: gcry_cast5
+CRC32: gcry_crc
+CRC32RFC1510: gcry_crc
+CRC24RFC2440: gcry_crc
+DES: gcry_des
+3DES: gcry_des
+MD4: gcry_md4
+MD5: gcry_md5
+RFC2268_40: gcry_rfc2268
+AES: gcry_rijndael
+AES192: gcry_rijndael
+AES256: gcry_rijndael
+RIPEMD160: gcry_rmd160
+SEED: gcry_seed
+SERPENT128: gcry_serpent
+SERPENT192: gcry_serpent
+SERPENT256: gcry_serpent
+SHA1: gcry_sha1
+SHA224: gcry_sha256
+SHA256: gcry_sha256
+SHA512: gcry_sha512
+SHA384: gcry_sha512
+TIGER192: gcry_tiger
+TWOFISH: gcry_twofish
+TWOFISH128: gcry_twofish
+WHIRLPOOL: gcry_whirlpool
Index: boot/grub.efi/i386-efi/fs.lst
===================================================================
--- boot/grub.efi/i386-efi/fs.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/i386-efi/fs.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,25 @@
+affs
+afs
+afs_be
+befs
+befs_be
+btrfs
+cpio
+ext2
+fat
+hfs
+hfsplus
+iso9660
+jfs
+minix
+minix2
+nilfs2
+ntfs
+reiserfs
+sfs
+tar
+udf
+ufs1
+ufs2
+xfs
+zfs
Index: boot/grub.efi/i386-efi/moddep.lst
===================================================================
--- boot/grub.efi/i386-efi/moddep.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/i386-efi/moddep.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,175 @@
+videotest: font video gfxmenu
+loopback: extcmd
+gcry_des: crypto
+memrw: extcmd
+terminfo: extcmd
+part_gpt:
+read:
+lsefimmap:
+gcry_arcfour: crypto
+aout:
+elf:
+password_pbkdf2: crypto gcry_sha512 pbkdf2 normal
+gcry_seed: crypto
+bsd: elf serial extcmd video aout boot cpuid relocator mmap
+sfs: fshelp
+reiserfs: fshelp
+part_sunpc:
+gfxmenu: trig bitmap_scale gfxterm font normal bitmap video
+jfs:
+help: extcmd normal
+configfile: normal
+ohci: cs5536 usb boot pci
+afs: fshelp
+xzio: gcry_crc
+usb_keyboard: keylayouts usb
+search_fs_file:
+usbms: scsi usb
+test_blockarg: extcmd normal
+true:
+affs: fshelp
+iso9660: fshelp
+gfxterm: bitmap_scale font extcmd bitmap video
+appleldr: boot
+xfs: fshelp
+functional_test: extcmd
+sleep: extcmd normal
+memdisk:
+gcry_rijndael: crypto
+gettext:
+gcry_sha1: crypto
+cmp:
+befs_be: fshelp
+usb: pci
+hashsum: crypto extcmd normal
+halt: acpi
+search_fs_uuid:
+linux: video boot relocator mmap
+keystatus: extcmd
+part_sun:
+video_bochs: video pci video_fb
+bufio:
+usbserial_ftdi: serial usb usbserial_common
+cpuid: extcmd
+hdparm: extcmd
+gcry_blowfish: crypto
+test:
+nilfs2: fshelp
+minicmd:
+ata: scsi pci
+udf: fshelp
+gzio:
+xnu_uuid: gcry_md5
+uhci: usb pci
+terminal:
+raid:
+crypto:
+part_bsd: part_msdos
+cs5536: pci
+gcry_sha512: crypto
+password: crypto normal
+fshelp:
+xnu: bitmap_scale extcmd normal video boot bitmap relocator
+mmap:
+iorw: extcmd
+zfsinfo: zfs
+lssal:
+blocklist:
+ext2: fshelp
+part_acorn:
+videoinfo: video
+btrfs: gzio
+lsmmap: mmap
+bitmap:
+ntfs: fshelp
+multiboot: video boot relocator mmap
+gcry_crc: crypto
+png: bufio bitmap
+jpeg: bufio bitmap
+regexp: extcmd normal
+parttool: normal
+usbserial_pl2303: serial usb usbserial_common
+cpio:
+gcry_rmd160: crypto
+fat:
+zfs:
+raid6rec: raid
+lsefisystab:
+minix2:
+lsacpi: extcmd acpi
+loadenv: extcmd
+bitmap_scale: bitmap
+datehook: datetime normal
+probe: extcmd
+tar:
+loadbios: pci
+hfs:
+boot:
+keylayouts:
+kernel:
+usbtest: usb
+relocator: mmap
+acpi: extcmd mmap
+tga: bufio bitmap
+reboot:
+serial: extcmd terminfo
+befs: fshelp
+efi_uga: video pci video_fb
+dm_nv: raid
+font: bufio video
+raid5rec: raid
+datetime:
+video:
+example_functional_test: functional_test
+pci:
+hfsplus: fshelp
+gcry_cast5: crypto
+extcmd:
+gcry_whirlpool: crypto
+gcry_tiger: crypto
+fixvideo: pci
+video_fb: video
+search: search_fs_uuid search_fs_file extcmd search_label
+lspci: extcmd pci
+trig:
+afs_be: fshelp
+msdospart: parttool
+gcry_twofish: crypto
+testload:
+part_apple:
+hexdump: extcmd
+ata_pthru: ata
+pbkdf2: crypto
+gcry_sha256: crypto
+date: datetime normal
+usbserial_common: serial usb
+ls: extcmd normal
+ntfscomp: ntfs
+video_cirrus: video pci video_fb
+scsi:
+hello: extcmd
+normal: terminal gfxterm crypto extcmd boot
+cat: extcmd
+ufs1:
+mdraid09: raid
+lvm:
+chain: boot
+ufs2:
+setpci: extcmd pci
+search_label:
+gptsync:
+setjmp:
+multiboot2: video boot relocator mmap acpi
+gcry_rfc2268: crypto
+mdraid1x: raid
+play:
+part_amiga:
+efi_gop: video video_fb
+minix:
+echo: extcmd
+gcry_serpent: crypto
+gcry_md4: crypto
+gcry_md5: crypto
+part_msdos:
+gcry_camellia: crypto
+at_keyboard: keylayouts boot
Index: boot/grub.efi/i386-efi/partmap.lst
===================================================================
--- boot/grub.efi/i386-efi/partmap.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/i386-efi/partmap.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,8 @@
+part_acorn
+part_amiga
+part_apple
+part_bsd
+part_gpt
+part_msdos
+part_sun
+part_sunpc
Index: boot/grub.efi/i386-efi/parttool.lst
===================================================================
--- boot/grub.efi/i386-efi/parttool.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/i386-efi/parttool.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,1 @@
+msdos: msdospart
Index: boot/grub.efi/i386-efi/terminal.lst
===================================================================
--- boot/grub.efi/i386-efi/terminal.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/i386-efi/terminal.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,6 @@
+iat_keyboard: at_keyboard
+iserial: serial
+iserial_*: serial
+ogfxterm: gfxterm
+oserial: serial
+oserial_*: serial
Index: boot/grub.efi/i386-efi/video.lst
===================================================================
--- boot/grub.efi/i386-efi/video.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/i386-efi/video.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,4 @@
+efi_gop
+efi_uga
+video_bochs
+video_cirrus
Index: boot/grub.efi/x86_64-efi/command.lst
===================================================================
--- boot/grub.efi/x86_64-efi/command.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/x86_64-efi/command.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,134 @@
+*acpi: acpi
+*background_image: gfxterm
+*cat: cat
+*cpuid: cpuid
+*crc: hashsum
+*echo: echo
+*functional_test: functional_test
+*gettext: gettext
+*hashsum: hashsum
+*hdparm: hdparm
+*hello: hello
+*help: help
+*hexdump: hexdump
+*inb: iorw
+*inl: iorw
+*inw: iorw
+*keystatus: keystatus
+*kfreebsd: bsd
+*knetbsd: bsd
+*kopenbsd: bsd
+*list_env: loadenv
+*load_env: loadenv
+*loopback: loopback
+*ls: ls
+*lsacpi: lsacpi
+*lspci: lspci
+*md5sum: hashsum
+*menuentry: normal
+*probe: probe
+*read_byte: memrw
+*read_dword: memrw
+*read_word: memrw
+*regexp: regexp
+*save_env: loadenv
+*search: search
+*serial: serial
+*setpci: setpci
+*sha1sum: hashsum
+*sha256sum: hashsum
+*sha512sum: hashsum
+*sleep: sleep
+*submenu: normal
+*terminfo: terminfo
+*test_blockarg: test_blockarg
+*xnu_splash: xnu
+.: configfile
+[: test
+appleloader: appleldr
+authenticate: normal
+badram: mmap
+blocklist: blocklist
+boot: boot
+break: normal
+cat: minicmd
+chainloader: chain
+clear: normal
+cmp: cmp
+configfile: configfile
+continue: normal
+cutmem: mmap
+date: date
+dump: minicmd
+exit: minicmd
+export: normal
+extract_entries_configfile: configfile
+extract_entries_source: configfile
+fakebios: loadbios
+false: true
+fix_video: fixvideo
+gptsync: gptsync
+halt: halt
+help: minicmd
+initrd: linux
+keymap: keylayouts
+kfreebsd_loadenv: bsd
+kfreebsd_module: bsd
+kfreebsd_module_elf: bsd
+knetbsd_module: bsd
+knetbsd_module_elf: bsd
+kopenbsd_ramdisk: bsd
+linux: linux
+loadbios: loadbios
+loadfont: font
+lsefimmap: lsefimmap
+lsefisystab: lsefisystab
+lsfonts: font
+lsmmap: lsmmap
+lsmod: minicmd
+lssal: lssal
+module2: multiboot2
+module: multiboot
+multiboot2: multiboot2
+multiboot: multiboot
+normal: normal
+normal_exit: normal
+outb: iorw
+outl: iorw
+outw: iorw
+parttool: parttool
+password: password
+password_pbkdf2: password_pbkdf2
+play: play
+read: read
+reboot: reboot
+return: normal
+rmmod: minicmd
+search.file: search_fs_file
+search.fs_label: search_label
+search.fs_uuid: search_fs_uuid
+setparams: normal
+shift: normal
+source: configfile
+terminal_input: terminal
+terminal_output: terminal
+test: test
+testload: testload
+true: true
+usb: usbtest
+videoinfo: videoinfo
+videotest: videotest
+write_byte: memrw
+write_dword: memrw
+write_word: memrw
+xnu_devprop_load: xnu
+xnu_kernel64: xnu
+xnu_kernel: xnu
+xnu_kext: xnu
+xnu_kextdir: xnu
+xnu_mkext: xnu
+xnu_ramdisk: xnu
+xnu_resume: xnu
+xnu_uuid: xnu_uuid
+zfs-bootfs: zfsinfo
+zfsinfo: zfsinfo
Index: boot/grub.efi/x86_64-efi/crypto.lst
===================================================================
--- boot/grub.efi/x86_64-efi/crypto.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/x86_64-efi/crypto.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,38 @@
+RIJNDAEL: gcry_rijndael
+RIJNDAEL192: gcry_rijndael
+RIJNDAEL256: gcry_rijndael
+AES128: gcry_rijndael
+AES-128: gcry_rijndael
+AES-192: gcry_rijndael
+AES-256: gcry_rijndael
+ARCFOUR: gcry_arcfour
+BLOWFISH: gcry_blowfish
+CAMELLIA128: gcry_camellia
+CAMELLIA192: gcry_camellia
+CAMELLIA256: gcry_camellia
+CAST5: gcry_cast5
+CRC32: gcry_crc
+CRC32RFC1510: gcry_crc
+CRC24RFC2440: gcry_crc
+DES: gcry_des
+3DES: gcry_des
+MD4: gcry_md4
+MD5: gcry_md5
+RFC2268_40: gcry_rfc2268
+AES: gcry_rijndael
+AES192: gcry_rijndael
+AES256: gcry_rijndael
+RIPEMD160: gcry_rmd160
+SEED: gcry_seed
+SERPENT128: gcry_serpent
+SERPENT192: gcry_serpent
+SERPENT256: gcry_serpent
+SHA1: gcry_sha1
+SHA224: gcry_sha256
+SHA256: gcry_sha256
+SHA512: gcry_sha512
+SHA384: gcry_sha512
+TIGER192: gcry_tiger
+TWOFISH: gcry_twofish
+TWOFISH128: gcry_twofish
+WHIRLPOOL: gcry_whirlpool
Index: boot/grub.efi/x86_64-efi/fs.lst
===================================================================
--- boot/grub.efi/x86_64-efi/fs.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/x86_64-efi/fs.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,25 @@
+affs
+afs
+afs_be
+befs
+befs_be
+btrfs
+cpio
+ext2
+fat
+hfs
+hfsplus
+iso9660
+jfs
+minix
+minix2
+nilfs2
+ntfs
+reiserfs
+sfs
+tar
+udf
+ufs1
+ufs2
+xfs
+zfs
Index: boot/grub.efi/x86_64-efi/moddep.lst
===================================================================
--- boot/grub.efi/x86_64-efi/moddep.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/x86_64-efi/moddep.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,175 @@
+videotest: font video gfxmenu
+loopback: extcmd
+gcry_des: crypto
+memrw: extcmd
+terminfo: extcmd
+part_gpt:
+read:
+lsefimmap:
+gcry_arcfour: crypto
+aout:
+elf:
+password_pbkdf2: crypto gcry_sha512 pbkdf2 normal
+gcry_seed: crypto
+bsd: elf serial extcmd video aout boot cpuid relocator mmap
+sfs: fshelp
+reiserfs: fshelp
+part_sunpc:
+gfxmenu: trig bitmap_scale gfxterm font normal bitmap video
+jfs:
+help: extcmd normal
+configfile: normal
+ohci: cs5536 usb boot pci
+afs: fshelp
+xzio: gcry_crc
+usb_keyboard: keylayouts usb
+search_fs_file:
+usbms: scsi usb
+test_blockarg: extcmd normal
+true:
+affs: fshelp
+iso9660: fshelp
+gfxterm: bitmap_scale font extcmd bitmap video
+appleldr: boot
+xfs: fshelp
+functional_test: extcmd
+sleep: extcmd normal
+memdisk:
+gcry_rijndael: crypto
+gettext:
+gcry_sha1: crypto
+cmp:
+befs_be: fshelp
+usb: pci
+hashsum: crypto extcmd normal
+halt: acpi
+search_fs_uuid:
+linux: video boot relocator mmap
+keystatus: extcmd
+part_sun:
+video_bochs: video pci video_fb
+bufio:
+usbserial_ftdi: serial usb usbserial_common
+cpuid: extcmd
+hdparm: extcmd
+gcry_blowfish: crypto
+test:
+nilfs2: fshelp
+minicmd:
+ata: scsi pci
+udf: fshelp
+gzio:
+xnu_uuid: gcry_md5
+uhci: usb pci
+terminal:
+raid:
+crypto:
+part_bsd: part_msdos
+cs5536: pci
+gcry_sha512: crypto
+password: crypto normal
+fshelp:
+xnu: bitmap_scale extcmd normal video boot bitmap relocator
+mmap:
+iorw: extcmd
+zfsinfo: zfs
+lssal:
+blocklist:
+ext2: fshelp
+part_acorn:
+videoinfo: video
+btrfs: gzio
+lsmmap: mmap
+bitmap:
+ntfs: fshelp
+multiboot: video boot relocator mmap
+gcry_crc: crypto
+png: bufio bitmap
+jpeg: bufio bitmap
+regexp: extcmd normal
+parttool: normal
+usbserial_pl2303: serial usb usbserial_common
+cpio:
+gcry_rmd160: crypto
+fat:
+zfs:
+raid6rec: raid
+lsefisystab:
+minix2:
+lsacpi: extcmd acpi
+loadenv: extcmd
+bitmap_scale: bitmap
+datehook: datetime normal
+probe: extcmd
+tar:
+loadbios: pci
+hfs:
+boot:
+keylayouts:
+kernel:
+usbtest: usb
+relocator: mmap
+acpi: extcmd mmap
+tga: bufio bitmap
+reboot:
+serial: extcmd terminfo
+befs: fshelp
+efi_uga: video pci video_fb
+dm_nv: raid
+font: bufio video
+raid5rec: raid
+datetime:
+video:
+example_functional_test: functional_test
+pci:
+hfsplus: fshelp
+gcry_cast5: crypto
+extcmd:
+gcry_whirlpool: crypto
+gcry_tiger: crypto
+fixvideo: pci
+video_fb: video
+search: search_fs_uuid search_fs_file extcmd search_label
+lspci: extcmd pci
+trig:
+afs_be: fshelp
+msdospart: parttool
+gcry_twofish: crypto
+testload:
+part_apple:
+hexdump: extcmd
+ata_pthru: ata
+pbkdf2: crypto
+gcry_sha256: crypto
+date: datetime normal
+usbserial_common: serial usb
+ls: extcmd normal
+ntfscomp: ntfs
+video_cirrus: video pci video_fb
+scsi:
+hello: extcmd
+normal: terminal gfxterm crypto extcmd boot
+cat: extcmd
+ufs1:
+mdraid09: raid
+lvm:
+chain: boot
+ufs2:
+setpci: extcmd pci
+search_label:
+gptsync:
+setjmp:
+multiboot2: video boot relocator mmap acpi
+gcry_rfc2268: crypto
+mdraid1x: raid
+play:
+part_amiga:
+efi_gop: video video_fb
+minix:
+echo: extcmd
+gcry_serpent: crypto
+gcry_md4: crypto
+gcry_md5: crypto
+part_msdos:
+gcry_camellia: crypto
+at_keyboard: keylayouts boot
Index: boot/grub.efi/x86_64-efi/partmap.lst
===================================================================
--- boot/grub.efi/x86_64-efi/partmap.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/x86_64-efi/partmap.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,8 @@
+part_acorn
+part_amiga
+part_apple
+part_bsd
+part_gpt
+part_msdos
+part_sun
+part_sunpc
Index: boot/grub.efi/x86_64-efi/parttool.lst
===================================================================
--- boot/grub.efi/x86_64-efi/parttool.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/x86_64-efi/parttool.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,1 @@
+msdos: msdospart
Index: boot/grub.efi/x86_64-efi/terminal.lst
===================================================================
--- boot/grub.efi/x86_64-efi/terminal.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/x86_64-efi/terminal.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,6 @@
+iat_keyboard: at_keyboard
+iserial: serial
+iserial_*: serial
+ogfxterm: gfxterm
+oserial: serial
+oserial_*: serial
Index: boot/grub.efi/x86_64-efi/video.lst
===================================================================
--- boot/grub.efi/x86_64-efi/video.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.efi/x86_64-efi/video.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,4 @@
+efi_gop
+efi_uga
+video_bochs
+video_cirrus
Index: boot/grub.pc/COPYING
===================================================================
--- boot/grub.pc/COPYING	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.pc/COPYING	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
Index: boot/grub.pc/README
===================================================================
--- boot/grub.pc/README	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.pc/README	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,9 @@
+The binary files of GRUB boot loader in this directory have been created
+by compiling GRUB for the 'i386-pc' target and then using the grub-mkrescue
+script to create the El Torito boot image.
+
+For licensing terms of GRUB boot loader see the file COPYING contained
+in this directory. Full version of GRUB, including its source code,
+can be downloaded from GRUB's project page:
+
+http://www.gnu.org/software/grub/
Index: boot/grub.pc/i386-pc/command.lst
===================================================================
--- boot/grub.pc/i386-pc/command.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.pc/i386-pc/command.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,150 @@
+*acpi: acpi
+*background_image: gfxterm
+*cat: cat
+*cpuid: cpuid
+*crc: hashsum
+*drivemap: drivemap
+*echo: echo
+*functional_test: functional_test
+*gettext: gettext
+*halt: halt
+*hashsum: hashsum
+*hdparm: hdparm
+*hello: hello
+*help: help
+*hexdump: hexdump
+*inb: iorw
+*inl: iorw
+*inw: iorw
+*keystatus: keystatus
+*kfreebsd: bsd
+*knetbsd: bsd
+*kopenbsd: bsd
+*list_env: loadenv
+*load_env: loadenv
+*loopback: loopback
+*ls: ls
+*lsacpi: lsacpi
+*lspci: lspci
+*md5sum: hashsum
+*menuentry: normal
+*probe: probe
+*read_byte: memrw
+*read_dword: memrw
+*read_word: memrw
+*regexp: regexp
+*save_env: loadenv
+*search: search
+*sendkey: sendkey
+*serial: serial
+*setpci: setpci
+*sha1sum: hashsum
+*sha256sum: hashsum
+*sha512sum: hashsum
+*sleep: sleep
+*submenu: normal
+*terminfo: terminfo
+*test_blockarg: test_blockarg
+*xnu_splash: xnu
+.: configfile
+[: test
+authenticate: normal
+badram: mmap
+blocklist: blocklist
+boot: boot
+break: normal
+cat: minicmd
+chainloader: chain
+clear: normal
+cmosclean: cmostest
+cmostest: cmostest
+cmp: cmp
+configfile: configfile
+continue: normal
+cutmem: mmap
+date: date
+dump: minicmd
+efiemu_loadcore: efiemu
+efiemu_prepare: efiemu
+efiemu_unload: efiemu
+exit: minicmd
+export: normal
+extract_entries_configfile: configfile
+extract_entries_source: configfile
+extract_legacy_entries_configfile: legacycfg
+extract_legacy_entries_source: legacycfg
+false: true
+gptsync: gptsync
+help: minicmd
+initrd16: linux16
+initrd: linux
+keymap: keylayouts
+kfreebsd_loadenv: bsd
+kfreebsd_module: bsd
+kfreebsd_module_elf: bsd
+knetbsd_module: bsd
+knetbsd_module_elf: bsd
+kopenbsd_ramdisk: bsd
+legacy_check_password: legacycfg
+legacy_configfile: legacycfg
+legacy_initrd: legacycfg
+legacy_initrd_nounzip: legacycfg
+legacy_kernel: legacycfg
+legacy_password: legacycfg
+legacy_source: legacycfg
+linux16: linux16
+linux: linux
+loadfont: font
+lsapm: lsapm
+lsfonts: font
+lsmmap: lsmmap
+lsmod: minicmd
+module2: multiboot2
+module: multiboot
+multiboot2: multiboot2
+multiboot: multiboot
+normal: normal
+normal_exit: normal
+ntldr: ntldr
+outb: iorw
+outl: iorw
+outw: iorw
+parttool: parttool
+password: password
+password_pbkdf2: password_pbkdf2
+play: play
+pxe_unload: pxecmd
+read: read
+reboot: reboot
+return: normal
+rmmod: minicmd
+search.file: search_fs_file
+search.fs_label: search_label
+search.fs_uuid: search_fs_uuid
+setparams: normal
+shift: normal
+source: configfile
+terminal_input: terminal
+terminal_output: terminal
+test: test
+testload: testload
+true: true
+usb: usbtest
+vbeinfo: videoinfo
+vbetest: videotest
+videoinfo: videoinfo
+videotest: videotest
+write_byte: memrw
+write_dword: memrw
+write_word: memrw
+xnu_devprop_load: xnu
+xnu_kernel64: xnu
+xnu_kernel: xnu
+xnu_kext: xnu
+xnu_kextdir: xnu
+xnu_mkext: xnu
+xnu_ramdisk: xnu
+xnu_resume: xnu
+xnu_uuid: xnu_uuid
+zfs-bootfs: zfsinfo
+zfsinfo: zfsinfo
Index: boot/grub.pc/i386-pc/crypto.lst
===================================================================
--- boot/grub.pc/i386-pc/crypto.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.pc/i386-pc/crypto.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,38 @@
+RIJNDAEL: gcry_rijndael
+RIJNDAEL192: gcry_rijndael
+RIJNDAEL256: gcry_rijndael
+AES128: gcry_rijndael
+AES-128: gcry_rijndael
+AES-192: gcry_rijndael
+AES-256: gcry_rijndael
+ARCFOUR: gcry_arcfour
+BLOWFISH: gcry_blowfish
+CAMELLIA128: gcry_camellia
+CAMELLIA192: gcry_camellia
+CAMELLIA256: gcry_camellia
+CAST5: gcry_cast5
+CRC32: gcry_crc
+CRC32RFC1510: gcry_crc
+CRC24RFC2440: gcry_crc
+DES: gcry_des
+3DES: gcry_des
+MD4: gcry_md4
+MD5: gcry_md5
+RFC2268_40: gcry_rfc2268
+AES: gcry_rijndael
+AES192: gcry_rijndael
+AES256: gcry_rijndael
+RIPEMD160: gcry_rmd160
+SEED: gcry_seed
+SERPENT128: gcry_serpent
+SERPENT192: gcry_serpent
+SERPENT256: gcry_serpent
+SHA1: gcry_sha1
+SHA224: gcry_sha256
+SHA256: gcry_sha256
+SHA512: gcry_sha512
+SHA384: gcry_sha512
+TIGER192: gcry_tiger
+TWOFISH: gcry_twofish
+TWOFISH128: gcry_twofish
+WHIRLPOOL: gcry_whirlpool
Index: boot/grub.pc/i386-pc/fs.lst
===================================================================
--- boot/grub.pc/i386-pc/fs.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.pc/i386-pc/fs.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,26 @@
+affs
+afs
+afs_be
+befs
+befs_be
+btrfs
+cpio
+ext2
+fat
+hfs
+hfsplus
+iso9660
+jfs
+minix
+minix2
+nilfs2
+ntfs
+pxe
+reiserfs
+sfs
+tar
+udf
+ufs1
+ufs2
+xfs
+zfs
Index: boot/grub.pc/i386-pc/moddep.lst
===================================================================
--- boot/grub.pc/i386-pc/moddep.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.pc/i386-pc/moddep.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,181 @@
+videotest: font video gfxmenu
+loopback: extcmd
+gcry_des: crypto
+memrw: extcmd
+terminfo: extcmd
+part_gpt:
+read:
+gcry_arcfour: crypto
+aout:
+vga_text:
+elf:
+password_pbkdf2: crypto gcry_sha512 pbkdf2 normal
+gcry_seed: crypto
+bsd: elf serial extcmd vbe video aout boot cpuid relocator mmap
+sfs: fshelp
+reiserfs: fshelp
+part_sunpc:
+gfxmenu: trig bitmap_scale gfxterm font normal bitmap video
+jfs:
+help: extcmd normal
+configfile: normal
+ohci: cs5536 usb boot pci
+afs: fshelp
+xzio: gcry_crc
+usb_keyboard: keylayouts usb
+search_fs_file:
+vga: video video_fb
+usbms: scsi usb
+test_blockarg: extcmd normal
+true:
+affs: fshelp
+iso9660: fshelp
+gfxterm: bitmap_scale font extcmd bitmap video
+xfs: fshelp
+functional_test: extcmd
+sleep: extcmd normal
+pxecmd: pxe
+memdisk:
+gcry_rijndael: crypto
+gettext:
+gcry_sha1: crypto
+cmp:
+befs_be: fshelp
+usb: pci
+hashsum: crypto extcmd normal
+halt: extcmd acpi
+search_fs_uuid:
+linux: normal vbe video boot relocator mmap
+keystatus: extcmd
+part_sun:
+sendkey: extcmd boot
+video_bochs: video pci video_fb
+bufio:
+usbserial_ftdi: serial usb usbserial_common
+cpuid: extcmd
+hdparm: extcmd
+gcry_blowfish: crypto
+test:
+nilfs2: fshelp
+minicmd:
+ata: scsi pci
+udf: fshelp
+gzio:
+xnu_uuid: gcry_md5
+uhci: usb pci
+terminal:
+raid:
+crypto:
+part_bsd: part_msdos
+cs5536: pci
+lsapm:
+gcry_sha512: crypto
+biosdisk:
+password: crypto normal
+fshelp:
+efiemu: gcry_crc normal acpi
+xnu: bitmap_scale extcmd normal video bitmap boot relocator efiemu
+mmap: boot
+iorw: extcmd
+zfsinfo: zfs
+cmostest:
+blocklist:
+ext2: fshelp
+drivemap: extcmd boot mmap
+part_acorn:
+videoinfo: video
+btrfs: gzio
+lsmmap:
+bitmap:
+vbe: video video_fb
+ntfs: fshelp
+multiboot: vbe video boot relocator mmap lsapm
+gcry_crc: crypto
+png: bufio bitmap
+jpeg: bufio bitmap
+regexp: extcmd normal
+parttool: normal
+usbserial_pl2303: serial usb usbserial_common
+cpio:
+gcry_rmd160: crypto
+fat:
+zfs:
+raid6rec: raid
+ntldr: boot video relocator
+minix2:
+lsacpi: extcmd acpi
+loadenv: extcmd
+bitmap_scale: bitmap
+datehook: datetime normal
+probe: extcmd
+tar:
+hfs:
+boot:
+keylayouts:
+kernel:
+usbtest: usb
+relocator:
+acpi: extcmd mmap
+tga: bufio bitmap
+reboot:
+serial: extcmd terminfo
+befs: fshelp
+dm_nv: raid
+font: bufio video
+raid5rec: raid
+datetime:
+video:
+example_functional_test: functional_test
+pci:
+hfsplus: fshelp
+gcry_cast5: crypto
+extcmd:
+gcry_whirlpool: crypto
+pxe: bufio
+gcry_tiger: crypto
+video_fb: video
+search: search_fs_uuid search_fs_file extcmd search_label
+lspci: extcmd pci
+trig:
+afs_be: fshelp
+msdospart: parttool
+gcry_twofish: crypto
+testload:
+part_apple:
+hexdump: extcmd
+ata_pthru: ata
+pbkdf2: crypto
+gcry_sha256: crypto
+date: datetime normal
+usbserial_common: serial usb
+ls: extcmd normal
+ntfscomp: ntfs
+video_cirrus: video pci video_fb
+scsi:
+hello: extcmd
+normal: terminal gfxterm crypto extcmd boot
+linux16: boot video relocator mmap
+cat: extcmd
+ufs1:
+mdraid09: raid
+lvm:
+chain: boot video
+ufs2:
+setpci: extcmd pci
+search_label:
+gptsync:
+setjmp:
+multiboot2: vbe boot video relocator mmap lsapm acpi
+gcry_rfc2268: crypto
+mdraid1x: raid
+legacycfg: linux crypto password gcry_md5 normal
+play:
+part_amiga:
+minix:
+echo: extcmd
+gcry_serpent: crypto
+gcry_md4: crypto
+gcry_md5: crypto
+part_msdos:
+gcry_camellia: crypto
+at_keyboard: keylayouts boot
Index: boot/grub.pc/i386-pc/partmap.lst
===================================================================
--- boot/grub.pc/i386-pc/partmap.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.pc/i386-pc/partmap.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,8 @@
+part_acorn
+part_amiga
+part_apple
+part_bsd
+part_gpt
+part_msdos
+part_sun
+part_sunpc
Index: boot/grub.pc/i386-pc/parttool.lst
===================================================================
--- boot/grub.pc/i386-pc/parttool.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.pc/i386-pc/parttool.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,1 @@
+msdos: msdospart
Index: boot/grub.pc/i386-pc/terminal.lst
===================================================================
--- boot/grub.pc/i386-pc/terminal.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.pc/i386-pc/terminal.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,7 @@
+iat_keyboard: at_keyboard
+iserial: serial
+iserial_*: serial
+ogfxterm: gfxterm
+oserial: serial
+oserial_*: serial
+ovga_text: vga_text
Index: boot/grub.pc/i386-pc/video.lst
===================================================================
--- boot/grub.pc/i386-pc/video.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ boot/grub.pc/i386-pc/video.lst	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,4 @@
+vbe
+vga
+video_bochs
+video_cirrus
Index: ot/grub/COPYING
===================================================================
--- boot/grub/COPYING	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ 	(revision )
@@ -1,345 +1,0 @@
-		    GNU GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-			    Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-
-		    GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-			    NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-		     END OF TERMS AND CONDITIONS
-
-
-	    How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year  name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.
Index: ot/grub/README
===================================================================
--- boot/grub/README	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ 	(revision )
@@ -1,5 +1,0 @@
-For licensing terms of GRUB boot loader see the file COPYING contained
-in this directory. Full version of GRUB, including its source code,
-can be downloaded from GRUB's project page:
-
-http://www.gnu.org/software/grub/
Index: contrib/conf/net-qe.sh
===================================================================
--- contrib/conf/net-qe.sh	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ contrib/conf/net-qe.sh	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,12 +1,14 @@
 #!/bin/sh
 
-# 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.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
+case "$1" in
+	ne2k)
+		shift
+		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
+		;;
+	e1k)
+		shift
+		qemu $@ -device e1000,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
+		;;
+	*)
+		echo "Usage: $0 {ne2k|e1k}"
+esac
Index: defaults/amd64/Makefile.config
===================================================================
--- defaults/amd64/Makefile.config	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ defaults/amd64/Makefile.config	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -54,8 +54,8 @@
 
 # Default framebuffer mode
-CONFIG_VESA_MODE = 800x600
+CONFIG_BFB_MODE = 800x600
 
 # Default framebuffer depth
-CONFIG_VESA_BPP = 16
+CONFIG_BFB_BPP = 16
 
 # Load disk drivers on startup
@@ -67,2 +67,5 @@
 # OHCI root hub power switch, ganged is enough
 OHCI_POWER_SWITCH = ganged
+
+# GRUB boot loader architecture
+GRUB_ARCH = pc
Index: defaults/ia32/Makefile.config
===================================================================
--- defaults/ia32/Makefile.config	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ defaults/ia32/Makefile.config	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -60,8 +60,8 @@
 
 # Default framebuffer mode
-CONFIG_VESA_MODE = 800x600
+CONFIG_BFB_MODE = 800x600
 
 # Default framebuffer depth
-CONFIG_VESA_BPP = 16
+CONFIG_BFB_BPP = 16
 
 # Load disk drivers on startup
@@ -73,2 +73,5 @@
 # OHCI root hub power switch, ganged is enough
 OHCI_POWER_SWITCH = ganged
+
+# GRUB boot loader architecture
+GRUB_ARCH = pc
Index: kernel/arch/abs32le/src/abs32le.c
===================================================================
--- kernel/arch/abs32le/src/abs32le.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/abs32le/src/abs32le.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -86,5 +86,5 @@
 }
 
-sysarg_t sys_tls_set(sysarg_t addr)
+sysarg_t sys_tls_set(uintptr_t addr)
 {
 	return EOK;
Index: kernel/arch/amd64/Makefile.inc
===================================================================
--- kernel/arch/amd64/Makefile.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/amd64/Makefile.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -72,5 +72,6 @@
 ARCH_SOURCES = \
 	arch/$(KARCH)/src/fpu_context.c \
-	arch/$(KARCH)/src/boot/boot.S \
+	arch/$(KARCH)/src/boot/multiboot.S \
+	arch/$(KARCH)/src/boot/multiboot2.S \
 	arch/$(KARCH)/src/boot/memmap.c \
 	arch/$(KARCH)/src/debug/stacktrace.c \
@@ -79,5 +80,4 @@
 	arch/$(KARCH)/src/context.S \
 	arch/$(KARCH)/src/ddi/ddi.c \
-	arch/$(KARCH)/src/drivers/vesa.c \
 	arch/$(KARCH)/src/drivers/i8254.c \
 	arch/$(KARCH)/src/drivers/i8259.c \
Index: kernel/arch/amd64/include/arch.h
===================================================================
--- kernel/arch/amd64/include/arch.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/amd64/include/arch.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -38,5 +38,5 @@
 #include <genarch/multiboot/multiboot.h>
 
-extern void arch_pre_main(uint32_t, const multiboot_info_t *);
+extern void arch_pre_main(uint32_t, void *);
 
 #endif
Index: kernel/arch/amd64/include/boot/boot.h
===================================================================
--- kernel/arch/amd64/include/boot/boot.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/amd64/include/boot/boot.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -40,7 +40,4 @@
 #define BOOT_STACK_SIZE  0x000400
 
-#define MULTIBOOT_HEADER_MAGIC  0x1BADB002
-#define MULTIBOOT_HEADER_FLAGS  0x00010003
-
 #ifndef __ASM__
 
Index: kernel/arch/amd64/src/amd64.c
===================================================================
--- kernel/arch/amd64/src/amd64.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/amd64/src/amd64.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -34,38 +34,29 @@
 
 #include <arch.h>
-
 #include <typedefs.h>
-
-#include <config.h>
-
-#include <proc/thread.h>
-#include <genarch/multiboot/multiboot.h>
-#include <genarch/drivers/legacy/ia32/io.h>
-#include <genarch/drivers/ega/ega.h>
-#include <arch/drivers/vesa.h>
-#include <genarch/drivers/i8042/i8042.h>
-#include <genarch/kbrd/kbrd.h>
+#include <errno.h>
+#include <memstr.h>
+#include <interrupt.h>
+#include <console/console.h>
+#include <syscall/syscall.h>
+#include <sysinfo/sysinfo.h>
+#include <arch/bios/bios.h>
+#include <arch/boot/boot.h>
+#include <arch/debugger.h>
 #include <arch/drivers/i8254.h>
 #include <arch/drivers/i8259.h>
-#include <arch/boot/boot.h>
+#include <arch/syscall.h>
+#include <genarch/acpi/acpi.h>
+#include <genarch/drivers/ega/ega.h>
+#include <genarch/drivers/i8042/i8042.h>
+#include <genarch/drivers/legacy/ia32/io.h>
+#include <genarch/fb/bfb.h>
+#include <genarch/kbrd/kbrd.h>
+#include <genarch/multiboot/multiboot.h>
+#include <genarch/multiboot/multiboot2.h>
 
 #ifdef CONFIG_SMP
 #include <arch/smp/apic.h>
 #endif
-
-#include <arch/bios/bios.h>
-#include <arch/cpu.h>
-#include <print.h>
-#include <arch/cpuid.h>
-#include <genarch/acpi/acpi.h>
-#include <panic.h>
-#include <interrupt.h>
-#include <arch/syscall.h>
-#include <arch/debugger.h>
-#include <syscall/syscall.h>
-#include <console/console.h>
-#include <ddi/irq.h>
-#include <sysinfo/sysinfo.h>
-#include <memstr.h>
 
 /** Disable I/O on non-privileged levels
@@ -101,11 +92,13 @@
 /** Perform amd64-specific initialization before main_bsp() is called.
  *
- * @param signature Should contain the multiboot signature.
- * @param mi        Pointer to the multiboot information structure.
- */
-void arch_pre_main(uint32_t signature, const multiboot_info_t *mi)
+ * @param signature Multiboot signature.
+ * @param info      Multiboot information structure.
+ *
+ */
+void arch_pre_main(uint32_t signature, void *info)
 {
 	/* Parse multiboot information obtained from the bootloader. */
-	multiboot_info_parse(signature, mi);
+	multiboot_info_parse(signature, (multiboot_info_t *) info);
+	multiboot2_info_parse(signature, (multiboot2_info_t *) info);
 	
 #ifdef CONFIG_SMP
@@ -153,13 +146,13 @@
 		
 #if (defined(CONFIG_FB) || defined(CONFIG_EGA))
-		bool vesa = false;
+		bool bfb = false;
 #endif
 		
 #ifdef CONFIG_FB
-		vesa = vesa_init();
+		bfb = bfb_init();
 #endif
 		
 #ifdef CONFIG_EGA
-		if (!vesa) {
+		if (!bfb) {
 			outdev_t *egadev = ega_init(EGA_BASE, EGA_VIDEORAM);
 			if (egadev)
@@ -261,10 +254,10 @@
  * we need not to go to CPL0 to read it.
  */
-sysarg_t sys_tls_set(sysarg_t addr)
+sysarg_t sys_tls_set(uintptr_t addr)
 {
 	THREAD->arch.tls = addr;
 	write_msr(AMD_MSR_FS, addr);
 	
-	return 0;
+	return EOK;
 }
 
Index: rnel/arch/amd64/src/boot/boot.S
===================================================================
--- kernel/arch/amd64/src/boot/boot.S	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ 	(revision )
@@ -1,681 +1,0 @@
-/*
- * Copyright (c) 2005 Ondrej Palkovsky
- * Copyright (c) 2006 Martin Decky
- * Copyright (c) 2008 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.
- */
-
-#include <arch/boot/boot.h>
-#include <arch/boot/memmap.h>
-#include <arch/mm/page.h>
-#include <arch/mm/ptl.h>
-#include <arch/pm.h>
-#include <arch/cpu.h>
-#include <arch/cpuid.h>
-
-#define START_STACK  (BOOT_OFFSET - BOOT_STACK_SIZE)
-
-.section K_TEXT_START, "ax"
-
-.code32
-
-.macro pm_error msg
-	movl \msg, %esi
-	jmp pm_error_halt
-.endm
-
-.macro pm_status msg
-#ifdef CONFIG_EGA
-	pushl %esi
-	movl \msg, %esi
-	call pm_early_puts
-	popl %esi
-#endif
-.endm
-
-.macro pm2_status msg
-#ifndef CONFIG_FB
-	pm_status \msg
-#endif
-.endm
-
-.align 4
-.global multiboot_image_start
-multiboot_header:
-	.long MULTIBOOT_HEADER_MAGIC
-	.long MULTIBOOT_HEADER_FLAGS
-	.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)  /* checksum */
-	.long multiboot_header
-	.long unmapped_ktext_start
-	.long 0
-	.long 0
-	.long multiboot_image_start
-
-multiboot_image_start:
-	cld
-	
-	/* Initialize stack pointer */
-	movl $START_STACK, %esp
-	
-	/* Initialize Global Descriptor Table register */
-	lgdtl bootstrap_gdtr
-	
-	/* Kernel data + stack */
-	movw $GDT_SELECTOR(KDATA_DES), %cx
-	movw %cx, %es
-	movw %cx, %ds
-	movw %cx, %ss
-	
-	/*
-	 * Simics seems to remove hidden part of GS on entering user mode
-	 * when _visible_ part of GS does not point to user-mode segment.
-	 */
-	movw $GDT_SELECTOR(UDATA_DES), %cx
-	movw %cx, %fs
-	movw %cx, %gs
-	
-	jmpl $GDT_SELECTOR(KTEXT32_DES), $multiboot_meeting_point
-	multiboot_meeting_point:
-	
-	/* Save GRUB arguments */
-	movl %eax, grub_eax
-	movl %ebx, grub_ebx
-	
-	pm_status $status_prot
-	
-	movl $(INTEL_CPUID_EXTENDED), %eax
-	cpuid
-	cmp $(INTEL_CPUID_EXTENDED), %eax
-	ja extended_cpuid_supported
-	
-		pm_error $err_extended_cpuid
-	
-	extended_cpuid_supported:
-	
-	movl $(AMD_CPUID_EXTENDED), %eax
-	cpuid
-	bt $(AMD_EXT_LONG_MODE), %edx
-	jc long_mode_supported
-	
-		pm_error $err_long_mode
-	
-	long_mode_supported:
-	
-	bt $(AMD_EXT_NOEXECUTE), %edx
-	jc noexecute_supported
-	
-		pm_error $err_noexecute
-	
-	noexecute_supported:
-	
-	movl $(INTEL_CPUID_STANDARD), %eax
-	cpuid
-	bt $(INTEL_FXSAVE), %edx
-	jc fx_supported
-	
-		pm_error $err_fx
-	
-	fx_supported:
-	
-	bt $(INTEL_SSE2), %edx
-	jc sse2_supported
-	
-		pm_error $err_sse2
-	
-	sse2_supported:
-	
-#include "vesa_prot.inc"
-	
-	/*
-	 * Protected 32-bit. We want to reuse the code-seg descriptor,
-	 * the Default operand size must not be 1 when entering long mode.
-	 */
-	
-	pm2_status $status_prot2
-	
-	/*
-	 * Enable 64-bit page translation entries - CR4.PAE = 1.
-	 * Paging is not enabled until after long mode is enabled.
-	 */
-	
-	movl %cr4, %eax
-	btsl $5, %eax
-	movl %eax, %cr4
-	
-	/* Set up paging tables */
-	leal ptl_0, %eax
-	movl %eax, %cr3
-	
-	/* Enable long mode */
-	movl $EFER_MSR_NUM, %ecx
-	rdmsr                     /* read EFER */
-	btsl $AMD_LME_FLAG, %eax  /* set LME = 1 */
-	wrmsr
-	
-	/* Enable paging to activate long mode (set CR0.PG = 1) */
-	movl %cr0, %eax
-	btsl $31, %eax
-	movl %eax, %cr0
-	
-	/* At this point we are in compatibility mode */
-	jmpl $GDT_SELECTOR(KTEXT_DES), $start64
-
-/** Print string to EGA display (in light red) and halt.
- *
- * Should be executed from 32 bit protected mode with paging
- * turned off. Stack is not required. This routine is used even
- * if CONFIG_EGA is not enabled. Since we are going to halt the
- * CPU anyway, it is always better to at least try to print
- * some hints.
- *
- * @param %esi Pointer to the NULL-terminated string
- *             to be print.
- *
- */
-pm_error_halt:
-	movl $0xb8000, %edi  /* base of EGA text mode memory */
-	xorl %eax, %eax
-	
-	/* Read bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	shl $8, %ax
-	
-	/* Read bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	
-	/* Sanity check for the cursor on screen */
-	cmp $2000, %ax
-	jb err_cursor_ok
-	
-		movw $1998, %ax
-	
-	err_cursor_ok:
-	
-	movw %ax, %bx
-	shl $1, %eax
-	addl %eax, %edi
-	
-	err_ploop:
-		lodsb
-		
-		cmp $0, %al
-		je err_ploop_end
-		
-		movb $0x0c, %ah  /* black background, light red foreground */
-		stosw
-		
-		/* Sanity check for the cursor on the last line */
-		inc %bx
-		cmp $2000, %bx
-		jb err_ploop
-		
-		/* Scroll the screen (24 rows) */
-		movl %esi, %edx
-		movl $0xb80a0, %esi
-		movl $0xb8000, %edi
-		movl $960, %ecx
-		rep movsl
-		
-		/* Clear the 24th row */
-		xorl %eax, %eax
-		movl $40, %ecx
-		rep stosl
-		
-		/* Go to row 24 */
-		movl %edx, %esi
-		movl $0xb8f00, %edi
-		movw $1920, %bx
-		
-		jmp err_ploop
-	err_ploop_end:
-	
-	/* Write bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bh, %al
-	outb %al, %dx
-	
-	/* Write bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bl, %al
-	outb %al, %dx
-	
-	cli
-	hlt1:
-		hlt
-		jmp hlt1
-
-/** Print string to EGA display (in light green).
- *
- * Should be called from 32 bit protected mode with paging
- * turned off. A stack space of at least 24 bytes is required,
- * but the function does not establish a stack frame.
- *
- * Macros such as pm_status and pm2_status take care that
- * this function is used only when CONFIG_EGA is enabled
- * and CONFIG_FB is disabled.
- *
- * @param %esi Pointer to the NULL-terminated string
- *             to be print.
- *
- */
-pm_early_puts:
-	pushl %eax
-	pushl %ebx
-	pushl %ecx
-	pushl %edx
-	pushl %edi
-	
-	movl $0xb8000, %edi  /* base of EGA text mode memory */
-	xorl %eax, %eax
-	
-	/* Read bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	shl $8, %ax
-	
-	/* Read bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	
-	/* Sanity check for the cursor on screen */
-	cmp $2000, %ax
-	jb pm_puts_cursor_ok
-	
-		movw $1998, %ax
-	
-	pm_puts_cursor_ok:
-	
-	movw %ax, %bx
-	shl $1, %eax
-	addl %eax, %edi
-	
-	pm_puts_ploop:
-		lodsb
-		
-		cmp $0, %al
-		je pm_puts_ploop_end
-		
-		movb $0x0a, %ah  /* black background, light green foreground */
-		stosw
-		
-		/* Sanity check for the cursor on the last line */
-		inc %bx
-		cmp $2000, %bx
-		jb pm_puts_ploop
-		
-		/* Scroll the screen (24 rows) */
-		movl %esi, %edx
-		movl $0xb80a0, %esi
-		movl $0xb8000, %edi
-		movl $960, %ecx
-		rep movsl
-		
-		/* Clear the 24th row */
-		xorl %eax, %eax
-		movl $40, %ecx
-		rep stosl
-		
-		/* Go to row 24 */
-		movl %edx, %esi
-		movl $0xb8f00, %edi
-		movw $1920, %bx
-		
-		jmp pm_puts_ploop
-	pm_puts_ploop_end:
-	
-	/* Write bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bh, %al
-	outb %al, %dx
-	
-	/* Write bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bl, %al
-	outb %al, %dx
-	
-	popl %edi
-	popl %edx
-	popl %ecx
-	popl %ebx
-	popl %eax
-	
-	ret
-
-.code64
-
-.macro long_status msg
-	pushq %rdi
-	movq \msg, %rdi
-	call early_puts
-	popq %rdi
-.endm
-
-start64:
-	
-	/*
-	 * Long mode.
-	 */
-	
-	movq $(PA2KA(START_STACK)), %rsp
-	
-	/* Create the first stack frame */
-	pushq $0
-	movq %rsp, %rbp
-	
-	long_status $status_long
-	
-	/* Call arch_pre_main(grub_eax, grub_ebx) */
-	xorq %rdi, %rdi
-	movl grub_eax, %edi
-	xorq %rsi, %rsi
-	movl grub_ebx, %esi
-	
-	movabsq $arch_pre_main, %rax
-	callq *%rax
-	
-	long_status $status_main
-	
-	/* Call main_bsp() */
-	movabsq $main_bsp, %rax
-	call *%rax
-	
-	/* Not reached */
-	cli
-	hlt0:
-		hlt
-		jmp hlt0
-
-/** Print string to EGA display.
- *
- * Should be called from long mode (with paging enabled
- * and stack established). This function is ABI compliant
- * (without red-zone).
- *
- * If CONFIG_EGA is undefined or CONFIG_FB is defined
- * then this function does nothing.
- *
- * @param %rdi Pointer to the NULL-terminated string
- *             to be printed.
- *
- */
-early_puts:
-	
-#if ((defined(CONFIG_EGA)) && (!defined(CONFIG_FB)))
-	
-	/* Prologue, save preserved registers */
-	pushq %rbp
-	movq %rsp, %rbp
-	pushq %rbx
-	
-	movq %rdi, %rsi
-	movq $(PA2KA(0xb8000)), %rdi  /* base of EGA text mode memory */
-	xorq %rax, %rax
-	
-	/* Read bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	shl $8, %ax
-	
-	/* Read bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	
-	/* Sanity check for the cursor on screen */
-	cmp $2000, %ax
-	jb early_puts_cursor_ok
-	
-		movw $1998, %ax
-	
-	early_puts_cursor_ok:
-	
-	movw %ax, %bx
-	shl $1, %rax
-	addq %rax, %rdi
-	
-	early_puts_ploop:
-		lodsb
-		
-		cmp $0, %al
-		je early_puts_ploop_end
-		
-		movb $0x0e, %ah  /* black background, yellow foreground */
-		stosw
-		
-		/* Sanity check for the cursor on the last line */
-		inc %bx
-		cmp $2000, %bx
-		jb early_puts_ploop
-		
-		/* Scroll the screen (24 rows) */
-		movq %rsi, %rdx
-		movq $(PA2KA(0xb80a0)), %rsi
-		movq $(PA2KA(0xb8000)), %rdi
-		movl $480, %ecx
-		rep movsq
-		
-		/* Clear the 24th row */
-		xorl %eax, %eax
-		movl $20, %ecx
-		rep stosq
-		
-		/* Go to row 24 */
-		movq %rdx, %rsi
-		movq $(PA2KA(0xb8f00)), %rdi
-		movw $1920, %bx
-		
-		jmp early_puts_ploop
-	early_puts_ploop_end:
-	
-	/* Write bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bh, %al
-	outb %al, %dx
-	
-	/* Write bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bl, %al
-	outb %al, %dx
-	
-	/* Epilogue, restore preserved registers */
-	popq %rbx
-	leave
-	
-#endif
-	
-	ret
-
-#include "vesa_real.inc"
-
-.section K_INI_PTLS, "aw", @progbits
-
-/** Generate initial page table contents.
- *
- * @param cnt Number of entries to generate. Must be multiple of 8.
- * @param g   Number of GB that will be added to the mapping.
- *
- */
-.macro ptl2gen cnt g
-	.if \cnt
-		ptl2gen "\cnt - 8" \g
-		.quad ((\cnt - 8) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
-		.quad ((\cnt - 7) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
-		.quad ((\cnt - 6) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
-		.quad ((\cnt - 5) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
-		.quad ((\cnt - 4) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
-		.quad ((\cnt - 3) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
-		.quad ((\cnt - 2) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
-		.quad ((\cnt - 1) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
-	.endif
-.endm
-
-/* Page table for pages in the 1st gigabyte. */
-.align 4096
-ptl_2_0g:
-	ptl2gen 512 0
-
-/* Page table for pages in the 2nd gigabyte. */
-.align 4096
-ptl_2_1g:
-	ptl2gen 512 1
-
-/* Page table for pages in the 3rd gigabyte. */
-.align 4096
-ptl_2_2g:
-	ptl2gen 512 2
-
-/* Page table for pages in the 4th gigabyte. */
-.align 4096
-ptl_2_3g:
-	ptl2gen 512 3
-
-/* Page table for pages in the 5th gigabyte. */
-.align 4096
-ptl_2_4g:
-	ptl2gen 512 4
-
-/* Page table for pages in the 6th gigabyte. */
-.align 4096
-ptl_2_5g:
-	ptl2gen 512 5
-
-/* Page table for pages in the 7th gigabyte. */
-.align 4096
-ptl_2_6g:
-	ptl2gen 512 6
-
-/* Page table for pages in the 8th gigabyte. */
-.align 4096
-ptl_2_7g:
-	ptl2gen 512 7
-
-.align 4096
-ptl_1:
-	/* Identity mapping for [0; 8G) */
-	.quad ptl_2_0g + (PTL_WRITABLE | PTL_PRESENT)
-	.quad ptl_2_1g + (PTL_WRITABLE | PTL_PRESENT)
-	.quad ptl_2_2g + (PTL_WRITABLE | PTL_PRESENT)
-	.quad ptl_2_3g + (PTL_WRITABLE | PTL_PRESENT)
-	.quad ptl_2_4g + (PTL_WRITABLE | PTL_PRESENT)
-	.quad ptl_2_5g + (PTL_WRITABLE | PTL_PRESENT)
-	.quad ptl_2_6g + (PTL_WRITABLE | PTL_PRESENT)
-	.quad ptl_2_7g + (PTL_WRITABLE | PTL_PRESENT)
-	.fill 504, 8, 0
-
-.align 4096
-.global ptl_0
-ptl_0:
-	.quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
-	.fill 255, 8, 0
-	.quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
-	.fill 255, 8, 0
-
-.section K_DATA_START, "aw", @progbits
-
-bootstrap_gdtr:
-	.word GDT_SELECTOR(GDT_ITEMS)
-	.long KA2PA(gdt)
-
-grub_eax:
-	.long 0
-
-grub_ebx:
-	.long 0
-
-err_extended_cpuid:
-	.asciz "Error: Extended CPUID not supported -- CPU is not 64-bit. System halted."
-err_long_mode:
-	.asciz "Error: 64-bit long mode not supported. System halted."
-err_noexecute:
-	.asciz "Error: No-execute pages not supported. System halted."
-err_fx:
-	.asciz "Error: FXSAVE/FXRESTORE instructions not supported. System halted."
-err_sse2:
-	.asciz "Error: SSE2 instructions not supported. System halted."
-
-status_prot:
-	.asciz "[prot] "
-status_vesa_copy:
-	.asciz "[vesa_copy] "
-status_grub_cmdline:
-	.asciz "[grub_cmdline] "
-status_vesa_real:
-	.asciz "[vesa_real] "
-status_prot2:
-	.asciz "[prot2] "
-status_long:
-	.asciz "[long] "
-status_main:
-	.asciz "[main] "
Index: kernel/arch/amd64/src/boot/memmap.c
===================================================================
--- kernel/arch/amd64/src/boot/memmap.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/amd64/src/boot/memmap.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -35,5 +35,5 @@
 #include <arch/boot/memmap.h>
 
-uint8_t e820counter = 0xffU;
+uint8_t e820counter = 0;
 e820memmap_t e820table[MEMMAP_E820_MAX_RECORDS];
 
Index: kernel/arch/amd64/src/boot/multiboot.S
===================================================================
--- kernel/arch/amd64/src/boot/multiboot.S	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ kernel/arch/amd64/src/boot/multiboot.S	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,684 @@
+/*
+ * Copyright (c) 2005 Ondrej Palkovsky
+ * Copyright (c) 2006 Martin Decky
+ * Copyright (c) 2008 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.
+ */
+
+#include <arch/boot/boot.h>
+#include <arch/mm/page.h>
+#include <arch/mm/ptl.h>
+#include <arch/pm.h>
+#include <genarch/multiboot/multiboot.h>
+#include <arch/cpuid.h>
+#include <arch/cpu.h>
+
+#define START_STACK  (BOOT_OFFSET - BOOT_STACK_SIZE)
+
+.section K_TEXT_START, "ax"
+
+.code32
+
+.macro pm_error msg
+	movl \msg, %esi
+	jmp pm_error_halt
+.endm
+
+.macro pm_status msg
+#ifdef CONFIG_EGA
+	pushl %esi
+	movl \msg, %esi
+	call pm_early_puts
+	popl %esi
+#endif
+.endm
+
+.macro pm2_status msg
+#ifndef CONFIG_FB
+	pm_status \msg
+#endif
+.endm
+
+.align 4
+.global multiboot_image_start
+multiboot_header:
+	.long MULTIBOOT_HEADER_MAGIC
+	.long MULTIBOOT_HEADER_FLAGS
+	.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)  /* checksum */
+	.long multiboot_header
+	.long unmapped_ktext_start
+	.long 0
+	.long 0
+	.long multiboot_image_start
+
+multiboot_image_start:
+	cld
+	
+	/* Initialize stack pointer */
+	movl $START_STACK, %esp
+	
+	/* Initialize Global Descriptor Table register */
+	lgdtl bootstrap_gdtr
+	
+	/* Kernel data + stack */
+	movw $GDT_SELECTOR(KDATA_DES), %cx
+	movw %cx, %es
+	movw %cx, %ds
+	movw %cx, %ss
+	
+	/*
+	 * Simics seems to remove hidden part of GS on entering user mode
+	 * when _visible_ part of GS does not point to user-mode segment.
+	 */
+	movw $GDT_SELECTOR(UDATA_DES), %cx
+	movw %cx, %fs
+	movw %cx, %gs
+	
+	jmpl $GDT_SELECTOR(KTEXT32_DES), $multiboot_meeting_point
+	multiboot_meeting_point:
+	
+	/*
+	 * Protected 32-bit. We want to reuse the code-seg descriptor,
+	 * the Default operand size must not be 1 when entering long mode.
+	 */
+	
+	/* Save multiboot arguments */
+	movl %eax, multiboot_eax
+	movl %ebx, multiboot_ebx
+	
+	pm_status $status_prot
+	
+	movl $(INTEL_CPUID_EXTENDED), %eax
+	cpuid
+	cmp $(INTEL_CPUID_EXTENDED), %eax
+	ja extended_cpuid_supported
+	
+		pm_error $err_extended_cpuid
+	
+	extended_cpuid_supported:
+	
+	movl $(AMD_CPUID_EXTENDED), %eax
+	cpuid
+	bt $(AMD_EXT_LONG_MODE), %edx
+	jc long_mode_supported
+	
+		pm_error $err_long_mode
+	
+	long_mode_supported:
+	
+	bt $(AMD_EXT_NOEXECUTE), %edx
+	jc noexecute_supported
+	
+		pm_error $err_noexecute
+	
+	noexecute_supported:
+	
+	movl $(INTEL_CPUID_STANDARD), %eax
+	cpuid
+	bt $(INTEL_FXSAVE), %edx
+	jc fx_supported
+	
+		pm_error $err_fx
+	
+	fx_supported:
+	
+	bt $(INTEL_SSE2), %edx
+	jc sse2_supported
+	
+		pm_error $err_sse2
+	
+	sse2_supported:
+	
+#include "vesa_prot.inc"
+	
+	pm2_status $status_prot2
+	
+	/*
+	 * Enable 64-bit page translation entries - CR4.PAE = 1.
+	 * Paging is not enabled until after long mode is enabled.
+	 */
+	
+	movl %cr4, %eax
+	btsl $5, %eax
+	movl %eax, %cr4
+	
+	/* Set up paging tables */
+	leal ptl_0, %eax
+	movl %eax, %cr3
+	
+	/* Enable long mode */
+	movl $EFER_MSR_NUM, %ecx
+	rdmsr                     /* read EFER */
+	btsl $AMD_LME_FLAG, %eax  /* set LME = 1 */
+	wrmsr
+	
+	/* Enable paging to activate long mode (set CR0.PG = 1) */
+	movl %cr0, %eax
+	btsl $31, %eax
+	movl %eax, %cr0
+	
+	/* At this point we are in compatibility mode */
+	jmpl $GDT_SELECTOR(KTEXT_DES), $start64
+
+/** Print string to EGA display (in light red) and halt.
+ *
+ * Should be executed from 32 bit protected mode with paging
+ * turned off. Stack is not required. This routine is used even
+ * if CONFIG_EGA is not enabled. Since we are going to halt the
+ * CPU anyway, it is always better to at least try to print
+ * some hints.
+ *
+ * @param %esi Pointer to the NULL-terminated string
+ *             to be print.
+ *
+ */
+pm_error_halt:
+	movl $0xb8000, %edi  /* base of EGA text mode memory */
+	xorl %eax, %eax
+	
+	/* Read bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	shl $8, %ax
+	
+	/* Read bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	
+	/* Sanity check for the cursor on screen */
+	cmp $2000, %ax
+	jb err_cursor_ok
+	
+		movw $1998, %ax
+	
+	err_cursor_ok:
+	
+	movw %ax, %bx
+	shl $1, %eax
+	addl %eax, %edi
+	
+	err_ploop:
+		lodsb
+		
+		cmp $0, %al
+		je err_ploop_end
+		
+		movb $0x0c, %ah  /* black background, light red foreground */
+		stosw
+		
+		/* Sanity check for the cursor on the last line */
+		inc %bx
+		cmp $2000, %bx
+		jb err_ploop
+		
+		/* Scroll the screen (24 rows) */
+		movl %esi, %edx
+		movl $0xb80a0, %esi
+		movl $0xb8000, %edi
+		movl $960, %ecx
+		rep movsl
+		
+		/* Clear the 24th row */
+		xorl %eax, %eax
+		movl $40, %ecx
+		rep stosl
+		
+		/* Go to row 24 */
+		movl %edx, %esi
+		movl $0xb8f00, %edi
+		movw $1920, %bx
+		
+		jmp err_ploop
+	err_ploop_end:
+	
+	/* Write bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bh, %al
+	outb %al, %dx
+	
+	/* Write bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bl, %al
+	outb %al, %dx
+	
+	cli
+	hlt1:
+		hlt
+		jmp hlt1
+
+/** Print string to EGA display (in light green).
+ *
+ * Should be called from 32 bit protected mode with paging
+ * turned off. A stack space of at least 24 bytes is required,
+ * but the function does not establish a stack frame.
+ *
+ * Macros such as pm_status and pm2_status take care that
+ * this function is used only when CONFIG_EGA is enabled
+ * and CONFIG_FB is disabled.
+ *
+ * @param %esi Pointer to the NULL-terminated string
+ *             to be print.
+ *
+ */
+pm_early_puts:
+	pushl %eax
+	pushl %ebx
+	pushl %ecx
+	pushl %edx
+	pushl %edi
+	
+	movl $0xb8000, %edi  /* base of EGA text mode memory */
+	xorl %eax, %eax
+	
+	/* Read bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	shl $8, %ax
+	
+	/* Read bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	
+	/* Sanity check for the cursor on screen */
+	cmp $2000, %ax
+	jb pm_puts_cursor_ok
+	
+		movw $1998, %ax
+	
+	pm_puts_cursor_ok:
+	
+	movw %ax, %bx
+	shl $1, %eax
+	addl %eax, %edi
+	
+	pm_puts_ploop:
+		lodsb
+		
+		cmp $0, %al
+		je pm_puts_ploop_end
+		
+		movb $0x0a, %ah  /* black background, light green foreground */
+		stosw
+		
+		/* Sanity check for the cursor on the last line */
+		inc %bx
+		cmp $2000, %bx
+		jb pm_puts_ploop
+		
+		/* Scroll the screen (24 rows) */
+		movl %esi, %edx
+		movl $0xb80a0, %esi
+		movl $0xb8000, %edi
+		movl $960, %ecx
+		rep movsl
+		
+		/* Clear the 24th row */
+		xorl %eax, %eax
+		movl $40, %ecx
+		rep stosl
+		
+		/* Go to row 24 */
+		movl %edx, %esi
+		movl $0xb8f00, %edi
+		movw $1920, %bx
+		
+		jmp pm_puts_ploop
+	pm_puts_ploop_end:
+	
+	/* Write bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bh, %al
+	outb %al, %dx
+	
+	/* Write bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bl, %al
+	outb %al, %dx
+	
+	popl %edi
+	popl %edx
+	popl %ecx
+	popl %ebx
+	popl %eax
+	
+	ret
+
+.code64
+
+.macro long_status msg
+	pushq %rdi
+	movq \msg, %rdi
+	call early_puts
+	popq %rdi
+.endm
+
+start64:
+	
+	/*
+	 * Long mode.
+	 */
+	
+	movq $(PA2KA(START_STACK)), %rsp
+	
+	/* Create the first stack frame */
+	pushq $0
+	movq %rsp, %rbp
+	
+	long_status $status_long
+	
+	/* Call arch_pre_main(multiboot_eax, multiboot_ebx) */
+	xorq %rdi, %rdi
+	movl multiboot_eax, %edi
+	xorq %rsi, %rsi
+	movl multiboot_ebx, %esi
+	
+	movabsq $arch_pre_main, %rax
+	callq *%rax
+	
+	long_status $status_main
+	
+	/* Call main_bsp() */
+	movabsq $main_bsp, %rax
+	call *%rax
+	
+	/* Not reached */
+	cli
+	hlt0:
+		hlt
+		jmp hlt0
+
+/** Print string to EGA display.
+ *
+ * Should be called from long mode (with paging enabled
+ * and stack established). This function is ABI compliant
+ * (without red-zone).
+ *
+ * If CONFIG_EGA is undefined or CONFIG_FB is defined
+ * then this function does nothing.
+ *
+ * @param %rdi Pointer to the NULL-terminated string
+ *             to be printed.
+ *
+ */
+early_puts:
+	
+#if ((defined(CONFIG_EGA)) && (!defined(CONFIG_FB)))
+	
+	/* Prologue, save preserved registers */
+	pushq %rbp
+	movq %rsp, %rbp
+	pushq %rbx
+	
+	movq %rdi, %rsi
+	movq $(PA2KA(0xb8000)), %rdi  /* base of EGA text mode memory */
+	xorq %rax, %rax
+	
+	/* Read bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	shl $8, %ax
+	
+	/* Read bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	
+	/* Sanity check for the cursor on screen */
+	cmp $2000, %ax
+	jb early_puts_cursor_ok
+	
+		movw $1998, %ax
+	
+	early_puts_cursor_ok:
+	
+	movw %ax, %bx
+	shl $1, %rax
+	addq %rax, %rdi
+	
+	early_puts_ploop:
+		lodsb
+		
+		cmp $0, %al
+		je early_puts_ploop_end
+		
+		movb $0x0e, %ah  /* black background, yellow foreground */
+		stosw
+		
+		/* Sanity check for the cursor on the last line */
+		inc %bx
+		cmp $2000, %bx
+		jb early_puts_ploop
+		
+		/* Scroll the screen (24 rows) */
+		movq %rsi, %rdx
+		movq $(PA2KA(0xb80a0)), %rsi
+		movq $(PA2KA(0xb8000)), %rdi
+		movl $480, %ecx
+		rep movsq
+		
+		/* Clear the 24th row */
+		xorl %eax, %eax
+		movl $20, %ecx
+		rep stosq
+		
+		/* Go to row 24 */
+		movq %rdx, %rsi
+		movq $(PA2KA(0xb8f00)), %rdi
+		movw $1920, %bx
+		
+		jmp early_puts_ploop
+	early_puts_ploop_end:
+	
+	/* Write bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bh, %al
+	outb %al, %dx
+	
+	/* Write bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bl, %al
+	outb %al, %dx
+	
+	/* Epilogue, restore preserved registers */
+	popq %rbx
+	leave
+	
+#endif
+	
+	ret
+
+#include "vesa_real.inc"
+
+.section K_INI_PTLS, "aw", @progbits
+
+/** Generate initial page table contents.
+ *
+ * @param cnt Number of entries to generate. Must be multiple of 8.
+ * @param g   Number of GB that will be added to the mapping.
+ *
+ */
+.macro ptl2gen cnt g
+	.if \cnt
+		ptl2gen "\cnt - 8" \g
+		.quad ((\cnt - 8) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
+		.quad ((\cnt - 7) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
+		.quad ((\cnt - 6) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
+		.quad ((\cnt - 5) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
+		.quad ((\cnt - 4) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
+		.quad ((\cnt - 3) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
+		.quad ((\cnt - 2) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
+		.quad ((\cnt - 1) * 0x200000) + (\g * 1024 * 1024 * 1024) | (PTL_WRITABLE | PTL_PRESENT | PTL_2MB_PAGE)
+	.endif
+.endm
+
+/* Page table for pages in the 1st gigabyte. */
+.align 4096
+ptl_2_0g:
+	ptl2gen 512 0
+
+/* Page table for pages in the 2nd gigabyte. */
+.align 4096
+ptl_2_1g:
+	ptl2gen 512 1
+
+/* Page table for pages in the 3rd gigabyte. */
+.align 4096
+ptl_2_2g:
+	ptl2gen 512 2
+
+/* Page table for pages in the 4th gigabyte. */
+.align 4096
+ptl_2_3g:
+	ptl2gen 512 3
+
+/* Page table for pages in the 5th gigabyte. */
+.align 4096
+ptl_2_4g:
+	ptl2gen 512 4
+
+/* Page table for pages in the 6th gigabyte. */
+.align 4096
+ptl_2_5g:
+	ptl2gen 512 5
+
+/* Page table for pages in the 7th gigabyte. */
+.align 4096
+ptl_2_6g:
+	ptl2gen 512 6
+
+/* Page table for pages in the 8th gigabyte. */
+.align 4096
+ptl_2_7g:
+	ptl2gen 512 7
+
+.align 4096
+ptl_1:
+	/* Identity mapping for [0; 8G) */
+	.quad ptl_2_0g + (PTL_WRITABLE | PTL_PRESENT)
+	.quad ptl_2_1g + (PTL_WRITABLE | PTL_PRESENT)
+	.quad ptl_2_2g + (PTL_WRITABLE | PTL_PRESENT)
+	.quad ptl_2_3g + (PTL_WRITABLE | PTL_PRESENT)
+	.quad ptl_2_4g + (PTL_WRITABLE | PTL_PRESENT)
+	.quad ptl_2_5g + (PTL_WRITABLE | PTL_PRESENT)
+	.quad ptl_2_6g + (PTL_WRITABLE | PTL_PRESENT)
+	.quad ptl_2_7g + (PTL_WRITABLE | PTL_PRESENT)
+	.fill 504, 8, 0
+
+.align 4096
+.global ptl_0
+ptl_0:
+	.quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
+	.fill 255, 8, 0
+	.quad ptl_1 + (PTL_WRITABLE | PTL_PRESENT)
+	.fill 255, 8, 0
+
+.section K_DATA_START, "aw", @progbits
+
+.global bootstrap_gdtr
+bootstrap_gdtr:
+	.word GDT_SELECTOR(GDT_ITEMS)
+	.long KA2PA(gdt)
+
+.global multiboot_eax
+multiboot_eax:
+	.long 0
+
+.global multiboot_ebx
+multiboot_ebx:
+	.long 0
+
+err_extended_cpuid:
+	.asciz "Error: Extended CPUID not supported -- CPU is not 64-bit. System halted."
+err_long_mode:
+	.asciz "Error: 64-bit long mode not supported. System halted."
+err_noexecute:
+	.asciz "Error: No-execute pages not supported. System halted."
+err_fx:
+	.asciz "Error: FXSAVE/FXRESTORE instructions not supported. System halted."
+err_sse2:
+	.asciz "Error: SSE2 instructions not supported. System halted."
+
+status_prot:
+	.asciz "[prot] "
+status_vesa_copy:
+	.asciz "[vesa_copy] "
+status_multiboot_cmdline:
+	.asciz "[multiboot_cmdline] "
+status_vesa_real:
+	.asciz "[vesa_real] "
+status_prot2:
+	.asciz "[prot2] "
+status_long:
+	.asciz "[long] "
+status_main:
+	.asciz "[main] "
Index: kernel/arch/amd64/src/boot/multiboot2.S
===================================================================
--- kernel/arch/amd64/src/boot/multiboot2.S	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ kernel/arch/amd64/src/boot/multiboot2.S	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,257 @@
+/*
+ * 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 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 <arch/boot/boot.h>
+#include <arch/mm/page.h>
+#include <arch/pm.h>
+#include <arch/cpuid.h>
+#include <arch/cpu.h>
+#include <genarch/multiboot/multiboot2.h>
+
+#define START_STACK  (BOOT_OFFSET - BOOT_STACK_SIZE)
+
+.section K_TEXT_START, "ax"
+
+.code32
+
+.align 8
+.global multiboot2_image_start
+multiboot2_header_start:
+	.long MULTIBOOT2_HEADER_MAGIC
+	.long MULTIBOOT2_HEADER_ARCH_I386
+	.long multiboot2_header_end - multiboot2_header_start
+	.long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_HEADER_ARCH_I386 + (multiboot2_header_end - multiboot2_header_start))
+	
+	/* Information request tag */
+	tag_info_req_start:
+		.word MULTIBOOT2_TAG_INFO_REQ
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_info_req_end - tag_info_req_start
+		.long MULTIBOOT2_TAG_MODULE
+		.long MULTIBOOT2_TAG_MEMMAP
+#ifdef CONFIG_FB
+		.long MULTIBOOT2_TAG_FBINFO
+#endif
+	tag_info_req_end:
+	
+	/* Address tag */
+	tag_address_start:
+		.word MULTIBOOT2_TAG_ADDRESS
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_address_end - tag_address_start
+		.long multiboot2_header_start
+		.long unmapped_ktext_start
+		.long 0
+		.long 0
+	tag_address_end:
+	
+	/* Entry address tag */
+	tag_entry_address_start:
+		.word MULTIBOOT2_TAG_ENTRY_ADDRESS
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_entry_address_end - tag_entry_address_start
+		.long multiboot2_image_start
+	tag_entry_address_end:
+	
+	/* Flags tag */
+	tag_flags_start:
+		.word MULTIBOOT2_TAG_FLAGS
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_flags_end - tag_flags_start
+		.long MULTIBOOT2_FLAGS_CONSOLE
+	tag_flags_end:
+	
+#ifdef CONFIG_FB
+	/* Framebuffer tag */
+	tag_framebuffer_start:
+		.word MULTIBOOT2_TAG_FRAMEBUFFER
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_framebuffer_end - tag_framebuffer_start
+		.long CONFIG_BFB_WIDTH
+		.long CONFIG_BFB_HEIGHT
+		.long CONFIG_BFB_BPP
+	tag_framebuffer_end:
+#endif
+	
+	/* Module alignment tag */
+	tag_module_align_start:
+		.word MULTIBOOT2_TAG_MODULE_ALIGN
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_module_align_end - tag_module_align_start
+		.long 0
+	tag_module_align_end:
+	
+	/* Tag terminator */
+	tag_terminator_start:
+		.word MULTIBOOT2_TAG_TERMINATOR
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_terminator_end - tag_terminator_start
+	tag_terminator_end:
+multiboot2_header_end:
+
+multiboot2_image_start:
+	cld
+	
+	/* Initialize stack pointer */
+	movl $START_STACK, %esp
+	
+	/* Initialize Global Descriptor Table register */
+	lgdtl bootstrap_gdtr
+	
+	/* Kernel data + stack */
+	movw $GDT_SELECTOR(KDATA_DES), %cx
+	movw %cx, %es
+	movw %cx, %ds
+	movw %cx, %ss
+	
+	/*
+	 * Simics seems to remove hidden part of GS on entering user mode
+	 * when _visible_ part of GS does not point to user-mode segment.
+	 */
+	movw $GDT_SELECTOR(UDATA_DES), %cx
+	movw %cx, %fs
+	movw %cx, %gs
+	
+	jmpl $GDT_SELECTOR(KTEXT32_DES), $multiboot2_meeting_point
+	multiboot2_meeting_point:
+	
+	/*
+	 * Protected 32-bit. We want to reuse the code-seg descriptor,
+	 * the Default operand size must not be 1 when entering long mode.
+	 */
+	
+	/* Save multiboot arguments */
+	movl %eax, multiboot_eax
+	movl %ebx, multiboot_ebx
+	
+	movl $(INTEL_CPUID_EXTENDED), %eax
+	cpuid
+	cmp $(INTEL_CPUID_EXTENDED), %eax
+	ja extended_cpuid_supported
+	
+		jmp pm_error_halt
+	
+	extended_cpuid_supported:
+	
+	movl $(AMD_CPUID_EXTENDED), %eax
+	cpuid
+	bt $(AMD_EXT_LONG_MODE), %edx
+	jc long_mode_supported
+	
+		jmp pm_error_halt
+	
+	long_mode_supported:
+	
+	bt $(AMD_EXT_NOEXECUTE), %edx
+	jc noexecute_supported
+	
+		jmp pm_error_halt
+	
+	noexecute_supported:
+	
+	movl $(INTEL_CPUID_STANDARD), %eax
+	cpuid
+	bt $(INTEL_FXSAVE), %edx
+	jc fx_supported
+	
+		jmp pm_error_halt
+	
+	fx_supported:
+	
+	bt $(INTEL_SSE2), %edx
+	jc sse2_supported
+	
+		jmp pm_error_halt
+	
+	sse2_supported:
+	
+	/*
+	 * Enable 64-bit page translation entries - CR4.PAE = 1.
+	 * Paging is not enabled until after long mode is enabled.
+	 */
+	
+	movl %cr4, %eax
+	btsl $5, %eax
+	movl %eax, %cr4
+	
+	/* Set up paging tables */
+	leal ptl_0, %eax
+	movl %eax, %cr3
+	
+	/* Enable long mode */
+	movl $EFER_MSR_NUM, %ecx
+	rdmsr                     /* read EFER */
+	btsl $AMD_LME_FLAG, %eax  /* set LME = 1 */
+	wrmsr
+	
+	/* Enable paging to activate long mode (set CR0.PG = 1) */
+	movl %cr0, %eax
+	btsl $31, %eax
+	movl %eax, %cr0
+	
+	/* At this point we are in compatibility mode */
+	jmpl $GDT_SELECTOR(KTEXT_DES), $start64
+
+pm_error_halt:
+	cli
+	hlt1:
+		hlt
+		jmp hlt1
+
+.code64
+
+start64:
+	
+	/*
+	 * Long mode.
+	 */
+	
+	movq $(PA2KA(START_STACK)), %rsp
+	
+	/* Create the first stack frame */
+	pushq $0
+	movq %rsp, %rbp
+	
+	/* Call arch_pre_main(multiboot_eax, multiboot_ebx) */
+	xorq %rdi, %rdi
+	movl multiboot_eax, %edi
+	xorq %rsi, %rsi
+	movl multiboot_ebx, %esi
+	
+	movabsq $arch_pre_main, %rax
+	callq *%rax
+	
+	/* Call main_bsp() */
+	movabsq $main_bsp, %rax
+	call *%rax
+	
+	/* Not reached */
+	cli
+	hlt0:
+		hlt
+		jmp hlt0
Index: kernel/arch/ia32/Makefile.inc
===================================================================
--- kernel/arch/ia32/Makefile.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/ia32/Makefile.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -107,6 +107,6 @@
 	arch/$(KARCH)/src/drivers/i8254.c \
 	arch/$(KARCH)/src/drivers/i8259.c \
-	arch/$(KARCH)/src/drivers/vesa.c \
-	arch/$(KARCH)/src/boot/boot.S \
+	arch/$(KARCH)/src/boot/multiboot.S \
+	arch/$(KARCH)/src/boot/multiboot2.S \
 	arch/$(KARCH)/src/boot/memmap.c \
 	arch/$(KARCH)/src/fpu_context.c \
Index: kernel/arch/ia32/include/arch.h
===================================================================
--- kernel/arch/ia32/include/arch.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/ia32/include/arch.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -36,7 +36,7 @@
 #define KERN_ia32_ARCH_H_
 
-#include <genarch/multiboot/multiboot.h>
+#include <typedefs.h>
 
-extern void arch_pre_main(uint32_t, const multiboot_info_t *);
+extern void arch_pre_main(uint32_t, void *);
 
 #endif
Index: kernel/arch/ia32/include/boot/boot.h
===================================================================
--- kernel/arch/ia32/include/boot/boot.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/ia32/include/boot/boot.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -40,9 +40,4 @@
 #define BOOT_STACK_SIZE  0x0400
 
-#define MULTIBOOT_HEADER_MAGIC  0x1BADB002
-#define MULTIBOOT_HEADER_FLAGS  0x00010003
-
-#define MULTIBOOT_LOADER_MAGIC  0x2BADB002
-
 #ifndef __ASM__
 
Index: rnel/arch/ia32/include/drivers/vesa.h
===================================================================
--- kernel/arch/ia32/include/drivers/vesa.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/*
- * Copyright (c) 2006 Jakub Vana
- * 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 ia32
- * @{
- */
-/** @file
- */
-
-#ifndef KERN_ia32_VESA_H_
-#define KERN_ia32_VESA_H_
-
-#include <typedefs.h>
-
-extern bool vesa_init(void);
-
-#endif
-
-/** @}
- */
Index: rnel/arch/ia32/src/boot/boot.S
===================================================================
--- kernel/arch/ia32/src/boot/boot.S	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ 	(revision )
@@ -1,736 +1,0 @@
-/*
- * Copyright (c) 2001 Jakub Jermar
- * Copyright (c) 2005 Martin Decky
- * Copyright (c) 2011 Martin Sucha
- * 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 <arch/boot/boot.h>
-#include <arch/boot/memmap.h>
-#include <arch/mm/page.h>
-#include <arch/pm.h>
-#include <arch/cpuid.h>
-
-#define START_STACK  (BOOT_OFFSET - BOOT_STACK_SIZE)
-
-.section K_TEXT_START, "ax"
-
-.code32
-
-.macro pm_error msg
-	movl \msg, %esi
-	jmp pm_error_halt
-.endm
-
-.macro pm_status msg
-#ifdef CONFIG_EGA
-	pushl %esi
-	movl \msg, %esi
-	call pm_early_puts
-	popl %esi
-#endif
-.endm
-
-.macro pm2_status msg
-	pushl \msg
-	call early_puts
-.endm
-
-.align 4
-.global multiboot_image_start
-multiboot_header:
-	.long MULTIBOOT_HEADER_MAGIC
-	.long MULTIBOOT_HEADER_FLAGS
-	.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)  /* checksum */
-	.long multiboot_header
-	.long unmapped_ktext_start
-	.long 0
-	.long 0
-	.long multiboot_image_start
-
-multiboot_image_start:
-	cld
-	
-	/* Initialize stack pointer */
-	movl $START_STACK, %esp
-	
-	/* Initialize Global Descriptor Table register */
-	lgdtl bootstrap_gdtr
-	
-	/* Kernel data + stack */
-	movw $GDT_SELECTOR(KDATA_DES), %cx
-	movw %cx, %es
-	movw %cx, %fs
-	movw %cx, %gs
-	movw %cx, %ds
-	movw %cx, %ss
-	
-	jmpl $GDT_SELECTOR(KTEXT_DES), $multiboot_meeting_point
-	multiboot_meeting_point:
-	
-	/* Save GRUB arguments */
-	movl %eax, grub_eax
-	movl %ebx, grub_ebx
-	
-	pm_status $status_prot
-	
-#include "vesa_prot.inc"
-	
-#ifndef PROCESSOR_i486
-	
-	pm_status $status_prot2
-	
-	movl $(INTEL_CPUID_LEVEL), %eax
-	cpuid
-	cmp $0x0, %eax  /* any function > 0? */
-	jbe pse_unsupported
-	
-	movl $(INTEL_CPUID_STANDARD), %eax
-	cpuid
-	bt $(INTEL_PSE), %edx
-	jnc pse_unsupported
-		
-		/* Map kernel and turn paging on */
-		pm_status $status_pse
-		call map_kernel_pse
-		jmp stack_init
-	
-#endif /* PROCESSOR_i486 */
-	
-	pse_unsupported:
-		
-		/* Map kernel and turn paging on */
-		pm_status $status_non_pse
-		call map_kernel_non_pse
-	
-	stack_init:
-	
-	/* Create the first stack frame */
-	pushl $0
-	movl %esp, %ebp
-	
-	pm2_status $status_prot3
-	
-	/* Call arch_pre_main(grub_eax, grub_ebx) */
-	pushl grub_ebx
-	pushl grub_eax
-	call arch_pre_main
-	
-	pm2_status $status_main
-	
-	/* Call main_bsp() */
-	call main_bsp
-	
-	/* Not reached */
-	cli
-	hlt0:
-		hlt
-		jmp hlt0
-
-/** Setup mapping for the kernel (PSE variant)
- *
- * Setup mapping for both the unmapped and mapped sections
- * of the kernel. For simplicity, we map the entire 4G space.
- *
- */
-.global map_kernel_pse
-map_kernel_pse:
-	/* Paging features */
-	movl %cr4, %ecx
-	orl $(1 << 4), %ecx      /* PSE on */
-	andl $(~(1 << 5)), %ecx  /* PAE off */
-	movl %ecx, %cr4
-	
-	movl $(page_directory + 0), %esi
-	movl $(page_directory + 2048), %edi
-	xorl %ecx, %ecx
-	xorl %ebx, %ebx
-	
-	floop_pse:
-		movl $((1 << 7) | (1 << 1) | (1 << 0)), %eax
-		orl %ebx, %eax
-		/* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
-		movl %eax, (%esi, %ecx, 4)
-		/* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
-		movl %eax, (%edi, %ecx, 4)
-		addl $(4 * 1024 * 1024), %ebx
-		
-		incl %ecx
-		cmpl $512, %ecx
-		jl floop_pse
-	
-	movl %esi, %cr3
-	
-	movl %cr0, %ebx
-	orl $(1 << 31), %ebx  /* paging on */
-	movl %ebx, %cr0
-	ret
-
-/** Setup mapping for the kernel (non-PSE variant).
- *
- * Setup mapping for both the unmapped and mapped sections
- * of the kernel. For simplicity, we map the entire 4G space.
- *
- */
-map_kernel_non_pse:
-	/* Paging features */
-	movl %cr4, %ecx
-	andl $(~(1 << 5)), %ecx  /* PAE off */
-	movl %ecx, %cr4
-	
-	call calc_kernel_end
-	call find_mem_for_pt
-	
-	mov kernel_end, %esi
-	mov free_area, %ecx
-	
-	cmpl %esi, %ecx
-	jbe use_kernel_end
-		
-		mov %ecx, %esi
-		
-		/* Align address down to 4k */
-		andl $(~4095), %esi
-		
-	use_kernel_end:
-		
-		/* Align address to 4k */
-		addl $4095, %esi
-		andl $(~4095), %esi
-		
-		/* Allocate space for page tables */
-		movl %esi, pt_loc
-		movl $ballocs, %edi
-		andl $0x7fffffff, %edi
-		
-		movl %esi, (%edi)
-		addl $4, %edi
-		movl $(2 * 1024 * 1024), (%edi)
-		
-		/* Fill page tables */
-		xorl %ecx, %ecx
-		xorl %ebx, %ebx
-		
-		floop_pt:
-			movl $((1 << 1) | (1 << 0)), %eax
-			orl %ebx, %eax
-			movl %eax, (%esi, %ecx, 4)
-			addl $(4 * 1024), %ebx
-			
-			incl %ecx
-			cmpl $(512 * 1024), %ecx
-			
-			jl floop_pt
-		
-		/* Fill page directory */
-		movl $(page_directory + 0), %esi
-		movl $(page_directory + 2048), %edi
-		xorl %ecx, %ecx
-		movl pt_loc, %ebx
-		
-		floop:
-			movl $((1 << 1) | (1 << 0)), %eax
-			orl %ebx, %eax
-			
-			/* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
-			movl %eax, (%esi, %ecx, 4)
-			
-			/* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
-			movl %eax, (%edi, %ecx, 4)
-			addl $(4 * 1024), %ebx
-			
-			incl %ecx
-			cmpl $512, %ecx
-			
-			jl floop
-		
-		movl %esi, %cr3
-		
-		movl %cr0, %ebx
-		orl $(1 << 31), %ebx  /* paging on */
-		movl %ebx, %cr0
-		
-		ret
-
-/** Calculate unmapped address of the end of the kernel. */
-calc_kernel_end:
-	movl $hardcoded_load_address, %edi
-	andl $0x7fffffff, %edi
-	movl (%edi), %esi
-	andl $0x7fffffff, %esi
-	
-	movl $hardcoded_ktext_size, %edi
-	andl $0x7fffffff, %edi
-	addl (%edi), %esi
-	andl $0x7fffffff, %esi
-	
-	movl $hardcoded_kdata_size, %edi
-	andl $0x7fffffff, %edi
-	addl (%edi), %esi
-	andl $0x7fffffff, %esi
-	movl %esi, kernel_end
-	
-	ret
-
-/** Find free 2M (+4k for alignment) region where to store page tables */
-find_mem_for_pt:
-	/* Check if multiboot info is present */
-	cmpl $MULTIBOOT_LOADER_MAGIC, grub_eax
-	je check_multiboot_map
-		
-		ret
-	
-	check_multiboot_map:
-		
-		/* Copy address of the multiboot info to ebx */
-		movl grub_ebx, %ebx
-		
-		/* Check if memory map flag is present */
-		movl (%ebx), %edx
-		andl $(1 << 6), %edx
-		jnz use_multiboot_map
-			
-			ret
-		
-	use_multiboot_map:
-		
-		/* Copy address of the memory map to edx */
-		movl 48(%ebx), %edx
-		movl %edx, %ecx
-		
-		addl 44(%ebx), %ecx
-		
-		/* Find a free region at least 2M in size */
-		check_memmap_loop:
-			
-			/* Is this a free region? */
-			cmp $1, 20(%edx)
-			jnz next_region
-			
-			/* Check size */
-			cmp $0, 16(%edx)
-			jnz next_region
-			
-			cmpl $(2 * 1024 * 1024 + 4 * 1024), 12(%edx)
-			jbe next_region
-			
-			cmp $0, 8(%edx)
-			jz found_region
-		
-		next_region:
-			
-			cmp %ecx, %edx
-			jbe next_region_do
-			
-				ret
-		
-		next_region_do:
-			
-			addl (%edx), %edx
-			addl $4, %edx
-			jmp check_memmap_loop
-			
-		found_region:
-			
-			/* Use end of the found region */
-			mov 4(%edx), %ecx
-			add 12(%edx), %ecx
-			sub $(2 * 1024 * 1024), %ecx
-			mov %ecx, free_area
-			
-			ret
-
-/** Print string to EGA display (in light red) and halt.
- *
- * Should be executed from 32 bit protected mode with paging
- * turned off. Stack is not required. This routine is used even
- * if CONFIG_EGA is not enabled. Since we are going to halt the
- * CPU anyway, it is always better to at least try to print
- * some hints.
- *
- * @param %esi NULL-terminated string to print.
- *
- */
-pm_error_halt:
-	movl $0xb8000, %edi  /* base of EGA text mode memory */
-	xorl %eax, %eax
-	
-	/* Read bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	shl $8, %ax
-	
-	/* Read bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	
-	/* Sanity check for the cursor on screen */
-	cmp $2000, %ax
-	jb err_cursor_ok
-	
-		movw $1998, %ax
-	
-	err_cursor_ok:
-	
-	movw %ax, %bx
-	shl $1, %eax
-	addl %eax, %edi
-	
-	err_ploop:
-		lodsb
-		
-		cmp $0, %al
-		je err_ploop_end
-		
-		movb $0x0c, %ah  /* black background, light red foreground */
-		stosw
-		
-		/* Sanity check for the cursor on the last line */
-		inc %bx
-		cmp $2000, %bx
-		jb err_ploop
-		
-		/* Scroll the screen (24 rows) */
-		movl %esi, %edx
-		movl $0xb80a0, %esi
-		movl $0xb8000, %edi
-		movl $960, %ecx
-		rep movsl
-		
-		/* Clear the 24th row */
-		xorl %eax, %eax
-		movl $40, %ecx
-		rep stosl
-		
-		/* Go to row 24 */
-		movl %edx, %esi
-		movl $0xb8f00, %edi
-		movw $1920, %bx
-		
-		jmp err_ploop
-	err_ploop_end:
-	
-	/* Write bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bh, %al
-	outb %al, %dx
-	
-	/* Write bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bl, %al
-	outb %al, %dx
-	
-	cli
-	hlt1:
-		hlt
-		jmp hlt1
-
-/** Print string to EGA display (in light green).
- *
- * Should be called from 32 bit protected mode with paging
- * turned off. A stack space of at least 24 bytes is required,
- * but the function does not establish a stack frame.
- *
- * Macros such as pm_status take care that this function
- * is used only when CONFIG_EGA is enabled.
- *
- * @param %esi NULL-terminated string to print.
- *
- */
-pm_early_puts:
-	pushl %eax
-	pushl %ebx
-	pushl %ecx
-	pushl %edx
-	pushl %edi
-	
-	movl $0xb8000, %edi  /* base of EGA text mode memory */
-	xorl %eax, %eax
-	
-	/* Read bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	shl $8, %ax
-	
-	/* Read bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	
-	/* Sanity check for the cursor on screen */
-	cmp $2000, %ax
-	jb pm_puts_cursor_ok
-	
-		movw $1998, %ax
-	
-	pm_puts_cursor_ok:
-	
-	movw %ax, %bx
-	shl $1, %eax
-	addl %eax, %edi
-	
-	pm_puts_ploop:
-		lodsb
-		
-		cmp $0, %al
-		je pm_puts_ploop_end
-		
-		movb $0x0a, %ah  /* black background, light green foreground */
-		stosw
-		
-		/* Sanity check for the cursor on the last line */
-		inc %bx
-		cmp $2000, %bx
-		jb pm_puts_ploop
-		
-		/* Scroll the screen (24 rows) */
-		movl %esi, %edx
-		movl $0xb80a0, %esi
-		movl $0xb8000, %edi
-		movl $960, %ecx
-		rep movsl
-		
-		/* Clear the 24th row */
-		xorl %eax, %eax
-		movl $40, %ecx
-		rep stosl
-		
-		/* Go to row 24 */
-		movl %edx, %esi
-		movl $0xb8f00, %edi
-		movw $1920, %bx
-		
-		jmp pm_puts_ploop
-	pm_puts_ploop_end:
-	
-	/* Write bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bh, %al
-	outb %al, %dx
-	
-	/* Write bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bl, %al
-	outb %al, %dx
-	
-	popl %edi
-	popl %edx
-	popl %ecx
-	popl %ebx
-	popl %eax
-	
-	ret
-
-/** Print string to EGA display.
- *
- * Should be called from 32 bit protected mode (with paging
- * enabled and stack established). This function is ABI compliant.
- *
- * If CONFIG_EGA is undefined or CONFIG_FB is defined
- * then this function does nothing.
- *
- * @param %ebp+0x08 NULL-terminated string to print.
- *
- */
-early_puts:
-	
-#if ((defined(CONFIG_EGA)) && (!defined(CONFIG_FB)))
-	
-	/* Prologue, save preserved registers */
-	pushl %ebp
-	movl %esp, %ebp
-	pushl %ebx
-	pushl %esi
-	pushl %edi
-	
-	movl 0x08(%ebp), %esi
-	movl $(PA2KA(0xb8000)), %edi  /* base of EGA text mode memory */
-	xorl %eax, %eax
-	
-	/* Read bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	shl $8, %ax
-	
-	/* Read bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	inb %dx, %al
-	
-	/* Sanity check for the cursor on screen */
-	cmp $2000, %ax
-	jb early_puts_cursor_ok
-	
-		movw $1998, %ax
-	
-	early_puts_cursor_ok:
-	
-	movw %ax, %bx
-	shl $1, %eax
-	addl %eax, %edi
-	
-	early_puts_ploop:
-		lodsb
-		
-		cmp $0, %al
-		je early_puts_ploop_end
-		
-		movb $0x0e, %ah  /* black background, yellow foreground */
-		stosw
-		
-		/* Sanity check for the cursor on the last line */
-		inc %bx
-		cmp $2000, %bx
-		jb early_puts_ploop
-		
-		/* Scroll the screen (24 rows) */
-		movl %esi, %edx
-		movl $(PA2KA(0xb80a0)), %esi
-		movl $(PA2KA(0xb8000)), %edi
-		movl $960, %ecx
-		rep movsl
-		
-		/* Clear the 24th row */
-		xorl %eax, %eax
-		movl $40, %ecx
-		rep stosl
-		
-		/* Go to row 24 */
-		movl %edx, %esi
-		movl $(PA2KA(0xb8f00)), %edi
-		movw $1920, %bx
-		
-		jmp early_puts_ploop
-	early_puts_ploop_end:
-	
-	/* Write bits 8 - 15 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xe, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bh, %al
-	outb %al, %dx
-	
-	/* Write bits 0 - 7 of the cursor address */
-	movw $0x3d4, %dx
-	movb $0xf, %al
-	outb %al, %dx
-	
-	movw $0x3d5, %dx
-	movb %bl, %al
-	outb %al, %dx
-	
-	/* Epilogue, restore preserved registers */
-	popl %edi
-	popl %esi
-	popl %ebx
-	leave
-	
-#endif
-	
-	ret
-
-#include "vesa_real.inc"
-
-.section K_DATA_START, "aw", @progbits
-
-.align 4096
-page_directory:
-	.space 4096, 0
-
-bootstrap_gdtr:
-	.word GDT_SELECTOR(GDT_ITEMS)
-	.long KA2PA(gdt)
-
-grub_eax:
-	.long 0
-grub_ebx:
-	.long 0
-
-pt_loc:
-	.long 0
-kernel_end:
-	.long 0
-free_area:
-	.long 0
-
-status_prot:
-	.asciz "[prot] "
-status_pse:
-	.asciz "[pse] "
-status_non_pse:
-	.asciz "[non_pse] "
-status_vesa_copy:
-	.asciz "[vesa_copy] "
-status_grub_cmdline:
-	.asciz "[grub_cmdline] "
-status_vesa_real:
-	.asciz "[vesa_real] "
-status_prot2:
-	.asciz "[prot2] "
-status_prot3:
-	.asciz "[prot3] "
-status_main:
-	.asciz "[main] "
Index: kernel/arch/ia32/src/boot/memmap.c
===================================================================
--- kernel/arch/ia32/src/boot/memmap.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/ia32/src/boot/memmap.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -35,5 +35,5 @@
 #include <arch/boot/memmap.h>
 
-uint8_t e820counter = 0xffU;
+uint8_t e820counter = 0;
 e820memmap_t e820table[MEMMAP_E820_MAX_RECORDS];
 
Index: kernel/arch/ia32/src/boot/multiboot.S
===================================================================
--- kernel/arch/ia32/src/boot/multiboot.S	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ kernel/arch/ia32/src/boot/multiboot.S	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,741 @@
+/*
+ * Copyright (c) 2001 Jakub Jermar
+ * Copyright (c) 2005 Martin Decky
+ * Copyright (c) 2011 Martin Sucha
+ * 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 <arch/boot/boot.h>
+#include <arch/mm/page.h>
+#include <arch/pm.h>
+#include <genarch/multiboot/multiboot.h>
+#include <arch/cpuid.h>
+
+#define START_STACK  (BOOT_OFFSET - BOOT_STACK_SIZE)
+
+.section K_TEXT_START, "ax"
+
+.code32
+
+.macro pm_error msg
+	movl \msg, %esi
+	jmp pm_error_halt
+.endm
+
+.macro pm_status msg
+#ifdef CONFIG_EGA
+	pushl %esi
+	movl \msg, %esi
+	call pm_early_puts
+	popl %esi
+#endif
+.endm
+
+.macro pm2_status msg
+	pushl \msg
+	call early_puts
+.endm
+
+.align 4
+.global multiboot_image_start
+multiboot_header:
+	.long MULTIBOOT_HEADER_MAGIC
+	.long MULTIBOOT_HEADER_FLAGS
+	.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)  /* checksum */
+	.long multiboot_header
+	.long unmapped_ktext_start
+	.long 0
+	.long 0
+	.long multiboot_image_start
+
+multiboot_image_start:
+	cld
+	
+	/* Initialize stack pointer */
+	movl $START_STACK, %esp
+	
+	/* Initialize Global Descriptor Table register */
+	lgdtl bootstrap_gdtr
+	
+	/* Kernel data + stack */
+	movw $GDT_SELECTOR(KDATA_DES), %cx
+	movw %cx, %es
+	movw %cx, %fs
+	movw %cx, %gs
+	movw %cx, %ds
+	movw %cx, %ss
+	
+	jmpl $GDT_SELECTOR(KTEXT_DES), $multiboot_meeting_point
+	multiboot_meeting_point:
+	
+	/* Save multiboot arguments */
+	movl %eax, multiboot_eax
+	movl %ebx, multiboot_ebx
+	
+	pm_status $status_prot
+	
+#include "vesa_prot.inc"
+	
+#ifndef PROCESSOR_i486
+	
+	pm_status $status_prot2
+	
+	movl $(INTEL_CPUID_LEVEL), %eax
+	cpuid
+	cmp $0x0, %eax  /* any function > 0? */
+	jbe pse_unsupported
+	
+	movl $(INTEL_CPUID_STANDARD), %eax
+	cpuid
+	bt $(INTEL_PSE), %edx
+	jnc pse_unsupported
+		
+		/* Map kernel and turn paging on */
+		pm_status $status_pse
+		call map_kernel_pse
+		jmp stack_init
+	
+#endif /* PROCESSOR_i486 */
+	
+	pse_unsupported:
+		
+		/* Map kernel and turn paging on */
+		pm_status $status_non_pse
+		call map_kernel_non_pse
+	
+	stack_init:
+	
+	/* Create the first stack frame */
+	pushl $0
+	movl %esp, %ebp
+	
+	pm2_status $status_prot3
+	
+	/* Call arch_pre_main(multiboot_eax, multiboot_ebx) */
+	pushl multiboot_ebx
+	pushl multiboot_eax
+	call arch_pre_main
+	
+	pm2_status $status_main
+	
+	/* Call main_bsp() */
+	call main_bsp
+	
+	/* Not reached */
+	cli
+	hlt0:
+		hlt
+		jmp hlt0
+
+/** Setup mapping for the kernel (PSE variant)
+ *
+ * Setup mapping for both the unmapped and mapped sections
+ * of the kernel. For simplicity, we map the entire 4G space.
+ *
+ */
+.global map_kernel_pse
+map_kernel_pse:
+	/* Paging features */
+	movl %cr4, %ecx
+	orl $(1 << 4), %ecx      /* PSE on */
+	andl $(~(1 << 5)), %ecx  /* PAE off */
+	movl %ecx, %cr4
+	
+	movl $(page_directory + 0), %esi
+	movl $(page_directory + 2048), %edi
+	xorl %ecx, %ecx
+	xorl %ebx, %ebx
+	
+	floop_pse:
+		movl $((1 << 7) | (1 << 1) | (1 << 0)), %eax
+		orl %ebx, %eax
+		/* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
+		movl %eax, (%esi, %ecx, 4)
+		/* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
+		movl %eax, (%edi, %ecx, 4)
+		addl $(4 * 1024 * 1024), %ebx
+		
+		incl %ecx
+		cmpl $512, %ecx
+		jl floop_pse
+	
+	movl %esi, %cr3
+	
+	movl %cr0, %ebx
+	orl $(1 << 31), %ebx  /* paging on */
+	movl %ebx, %cr0
+	ret
+
+/** Setup mapping for the kernel (non-PSE variant).
+ *
+ * Setup mapping for both the unmapped and mapped sections
+ * of the kernel. For simplicity, we map the entire 4G space.
+ *
+ */
+.global map_kernel_non_pse
+map_kernel_non_pse:
+	/* Paging features */
+	movl %cr4, %ecx
+	andl $(~(1 << 5)), %ecx  /* PAE off */
+	movl %ecx, %cr4
+	
+	call calc_kernel_end
+	call find_mem_for_pt
+	
+	mov kernel_end, %esi
+	mov free_area, %ecx
+	
+	cmpl %esi, %ecx
+	jbe use_kernel_end
+		
+		mov %ecx, %esi
+		
+		/* Align address down to 4k */
+		andl $(~4095), %esi
+		
+	use_kernel_end:
+		
+		/* Align address to 4k */
+		addl $4095, %esi
+		andl $(~4095), %esi
+		
+		/* Allocate space for page tables */
+		movl %esi, pt_loc
+		movl $ballocs, %edi
+		andl $0x7fffffff, %edi
+		
+		movl %esi, (%edi)
+		addl $4, %edi
+		movl $(2 * 1024 * 1024), (%edi)
+		
+		/* Fill page tables */
+		xorl %ecx, %ecx
+		xorl %ebx, %ebx
+		
+		floop_pt:
+			movl $((1 << 1) | (1 << 0)), %eax
+			orl %ebx, %eax
+			movl %eax, (%esi, %ecx, 4)
+			addl $(4 * 1024), %ebx
+			
+			incl %ecx
+			cmpl $(512 * 1024), %ecx
+			
+			jl floop_pt
+		
+		/* Fill page directory */
+		movl $(page_directory + 0), %esi
+		movl $(page_directory + 2048), %edi
+		xorl %ecx, %ecx
+		movl pt_loc, %ebx
+		
+		floop:
+			movl $((1 << 1) | (1 << 0)), %eax
+			orl %ebx, %eax
+			
+			/* Mapping 0x00000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
+			movl %eax, (%esi, %ecx, 4)
+			
+			/* Mapping 0x80000000 + %ecx * 4M => 0x00000000 + %ecx * 4M */
+			movl %eax, (%edi, %ecx, 4)
+			addl $(4 * 1024), %ebx
+			
+			incl %ecx
+			cmpl $512, %ecx
+			
+			jl floop
+		
+		movl %esi, %cr3
+		
+		movl %cr0, %ebx
+		orl $(1 << 31), %ebx  /* paging on */
+		movl %ebx, %cr0
+		
+		ret
+
+/** Calculate unmapped address of the end of the kernel. */
+calc_kernel_end:
+	movl $hardcoded_load_address, %edi
+	andl $0x7fffffff, %edi
+	movl (%edi), %esi
+	andl $0x7fffffff, %esi
+	
+	movl $hardcoded_ktext_size, %edi
+	andl $0x7fffffff, %edi
+	addl (%edi), %esi
+	andl $0x7fffffff, %esi
+	
+	movl $hardcoded_kdata_size, %edi
+	andl $0x7fffffff, %edi
+	addl (%edi), %esi
+	andl $0x7fffffff, %esi
+	movl %esi, kernel_end
+	
+	ret
+
+/** Find free 2M (+4k for alignment) region where to store page tables */
+find_mem_for_pt:
+	/* Check if multiboot info is present */
+	cmpl $MULTIBOOT_LOADER_MAGIC, multiboot_eax
+	je check_multiboot_map
+		
+		ret
+	
+	check_multiboot_map:
+		
+		/* Copy address of the multiboot info to ebx */
+		movl multiboot_ebx, %ebx
+		
+		/* Check if memory map flag is present */
+		movl (%ebx), %edx
+		andl $(1 << 6), %edx
+		jnz use_multiboot_map
+			
+			ret
+		
+	use_multiboot_map:
+		
+		/* Copy address of the memory map to edx */
+		movl 48(%ebx), %edx
+		movl %edx, %ecx
+		
+		addl 44(%ebx), %ecx
+		
+		/* Find a free region at least 2M in size */
+		check_memmap_loop:
+			
+			/* Is this a free region? */
+			cmp $1, 20(%edx)
+			jnz next_region
+			
+			/* Check size */
+			cmp $0, 16(%edx)
+			jnz next_region
+			
+			cmpl $(2 * 1024 * 1024 + 4 * 1024), 12(%edx)
+			jbe next_region
+			
+			cmp $0, 8(%edx)
+			jz found_region
+		
+		next_region:
+			
+			cmp %ecx, %edx
+			jbe next_region_do
+			
+				ret
+		
+		next_region_do:
+			
+			addl (%edx), %edx
+			addl $4, %edx
+			jmp check_memmap_loop
+			
+		found_region:
+			
+			/* Use end of the found region */
+			mov 4(%edx), %ecx
+			add 12(%edx), %ecx
+			sub $(2 * 1024 * 1024), %ecx
+			mov %ecx, free_area
+			
+			ret
+
+/** Print string to EGA display (in light red) and halt.
+ *
+ * Should be executed from 32 bit protected mode with paging
+ * turned off. Stack is not required. This routine is used even
+ * if CONFIG_EGA is not enabled. Since we are going to halt the
+ * CPU anyway, it is always better to at least try to print
+ * some hints.
+ *
+ * @param %esi NULL-terminated string to print.
+ *
+ */
+pm_error_halt:
+	movl $0xb8000, %edi  /* base of EGA text mode memory */
+	xorl %eax, %eax
+	
+	/* Read bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	shl $8, %ax
+	
+	/* Read bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	
+	/* Sanity check for the cursor on screen */
+	cmp $2000, %ax
+	jb err_cursor_ok
+	
+		movw $1998, %ax
+	
+	err_cursor_ok:
+	
+	movw %ax, %bx
+	shl $1, %eax
+	addl %eax, %edi
+	
+	err_ploop:
+		lodsb
+		
+		cmp $0, %al
+		je err_ploop_end
+		
+		movb $0x0c, %ah  /* black background, light red foreground */
+		stosw
+		
+		/* Sanity check for the cursor on the last line */
+		inc %bx
+		cmp $2000, %bx
+		jb err_ploop
+		
+		/* Scroll the screen (24 rows) */
+		movl %esi, %edx
+		movl $0xb80a0, %esi
+		movl $0xb8000, %edi
+		movl $960, %ecx
+		rep movsl
+		
+		/* Clear the 24th row */
+		xorl %eax, %eax
+		movl $40, %ecx
+		rep stosl
+		
+		/* Go to row 24 */
+		movl %edx, %esi
+		movl $0xb8f00, %edi
+		movw $1920, %bx
+		
+		jmp err_ploop
+	err_ploop_end:
+	
+	/* Write bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bh, %al
+	outb %al, %dx
+	
+	/* Write bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bl, %al
+	outb %al, %dx
+	
+	cli
+	hlt1:
+		hlt
+		jmp hlt1
+
+/** Print string to EGA display (in light green).
+ *
+ * Should be called from 32 bit protected mode with paging
+ * turned off. A stack space of at least 24 bytes is required,
+ * but the function does not establish a stack frame.
+ *
+ * Macros such as pm_status take care that this function
+ * is used only when CONFIG_EGA is enabled.
+ *
+ * @param %esi NULL-terminated string to print.
+ *
+ */
+pm_early_puts:
+	pushl %eax
+	pushl %ebx
+	pushl %ecx
+	pushl %edx
+	pushl %edi
+	
+	movl $0xb8000, %edi  /* base of EGA text mode memory */
+	xorl %eax, %eax
+	
+	/* Read bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	shl $8, %ax
+	
+	/* Read bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	
+	/* Sanity check for the cursor on screen */
+	cmp $2000, %ax
+	jb pm_puts_cursor_ok
+	
+		movw $1998, %ax
+	
+	pm_puts_cursor_ok:
+	
+	movw %ax, %bx
+	shl $1, %eax
+	addl %eax, %edi
+	
+	pm_puts_ploop:
+		lodsb
+		
+		cmp $0, %al
+		je pm_puts_ploop_end
+		
+		movb $0x0a, %ah  /* black background, light green foreground */
+		stosw
+		
+		/* Sanity check for the cursor on the last line */
+		inc %bx
+		cmp $2000, %bx
+		jb pm_puts_ploop
+		
+		/* Scroll the screen (24 rows) */
+		movl %esi, %edx
+		movl $0xb80a0, %esi
+		movl $0xb8000, %edi
+		movl $960, %ecx
+		rep movsl
+		
+		/* Clear the 24th row */
+		xorl %eax, %eax
+		movl $40, %ecx
+		rep stosl
+		
+		/* Go to row 24 */
+		movl %edx, %esi
+		movl $0xb8f00, %edi
+		movw $1920, %bx
+		
+		jmp pm_puts_ploop
+	pm_puts_ploop_end:
+	
+	/* Write bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bh, %al
+	outb %al, %dx
+	
+	/* Write bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bl, %al
+	outb %al, %dx
+	
+	popl %edi
+	popl %edx
+	popl %ecx
+	popl %ebx
+	popl %eax
+	
+	ret
+
+/** Print string to EGA display.
+ *
+ * Should be called from 32 bit protected mode (with paging
+ * enabled and stack established). This function is ABI compliant.
+ *
+ * If CONFIG_EGA is undefined or CONFIG_FB is defined
+ * then this function does nothing.
+ *
+ * @param %ebp+0x08 NULL-terminated string to print.
+ *
+ */
+early_puts:
+	
+#if ((defined(CONFIG_EGA)) && (!defined(CONFIG_FB)))
+	
+	/* Prologue, save preserved registers */
+	pushl %ebp
+	movl %esp, %ebp
+	pushl %ebx
+	pushl %esi
+	pushl %edi
+	
+	movl 0x08(%ebp), %esi
+	movl $(PA2KA(0xb8000)), %edi  /* base of EGA text mode memory */
+	xorl %eax, %eax
+	
+	/* Read bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	shl $8, %ax
+	
+	/* Read bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	inb %dx, %al
+	
+	/* Sanity check for the cursor on screen */
+	cmp $2000, %ax
+	jb early_puts_cursor_ok
+	
+		movw $1998, %ax
+	
+	early_puts_cursor_ok:
+	
+	movw %ax, %bx
+	shl $1, %eax
+	addl %eax, %edi
+	
+	early_puts_ploop:
+		lodsb
+		
+		cmp $0, %al
+		je early_puts_ploop_end
+		
+		movb $0x0e, %ah  /* black background, yellow foreground */
+		stosw
+		
+		/* Sanity check for the cursor on the last line */
+		inc %bx
+		cmp $2000, %bx
+		jb early_puts_ploop
+		
+		/* Scroll the screen (24 rows) */
+		movl %esi, %edx
+		movl $(PA2KA(0xb80a0)), %esi
+		movl $(PA2KA(0xb8000)), %edi
+		movl $960, %ecx
+		rep movsl
+		
+		/* Clear the 24th row */
+		xorl %eax, %eax
+		movl $40, %ecx
+		rep stosl
+		
+		/* Go to row 24 */
+		movl %edx, %esi
+		movl $(PA2KA(0xb8f00)), %edi
+		movw $1920, %bx
+		
+		jmp early_puts_ploop
+	early_puts_ploop_end:
+	
+	/* Write bits 8 - 15 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xe, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bh, %al
+	outb %al, %dx
+	
+	/* Write bits 0 - 7 of the cursor address */
+	movw $0x3d4, %dx
+	movb $0xf, %al
+	outb %al, %dx
+	
+	movw $0x3d5, %dx
+	movb %bl, %al
+	outb %al, %dx
+	
+	/* Epilogue, restore preserved registers */
+	popl %edi
+	popl %esi
+	popl %ebx
+	leave
+	
+#endif
+	
+	ret
+
+#include "vesa_real.inc"
+
+.section K_DATA_START, "aw", @progbits
+
+.align 4096
+page_directory:
+	.space 4096, 0
+
+.global bootstrap_gdtr
+bootstrap_gdtr:
+	.word GDT_SELECTOR(GDT_ITEMS)
+	.long KA2PA(gdt)
+
+.global multiboot_eax
+multiboot_eax:
+	.long 0
+
+.global multiboot_ebx
+multiboot_ebx:
+	.long 0
+
+pt_loc:
+	.long 0
+kernel_end:
+	.long 0
+free_area:
+	.long 0
+
+status_prot:
+	.asciz "[prot] "
+status_pse:
+	.asciz "[pse] "
+status_non_pse:
+	.asciz "[non_pse] "
+status_vesa_copy:
+	.asciz "[vesa_copy] "
+status_multiboot_cmdline:
+	.asciz "[multiboot_cmdline] "
+status_vesa_real:
+	.asciz "[vesa_real] "
+status_prot2:
+	.asciz "[prot2] "
+status_prot3:
+	.asciz "[prot3] "
+status_main:
+	.asciz "[main] "
Index: kernel/arch/ia32/src/boot/multiboot2.S
===================================================================
--- kernel/arch/ia32/src/boot/multiboot2.S	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ kernel/arch/ia32/src/boot/multiboot2.S	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,180 @@
+/*
+ * 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 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 <arch/boot/boot.h>
+#include <arch/pm.h>
+#include <arch/cpuid.h>
+#include <genarch/multiboot/multiboot2.h>
+
+#define START_STACK  (BOOT_OFFSET - BOOT_STACK_SIZE)
+
+.section K_TEXT_START, "ax"
+
+.code32
+
+.align 8
+.global multiboot2_image_start
+multiboot2_header_start:
+	.long MULTIBOOT2_HEADER_MAGIC
+	.long MULTIBOOT2_HEADER_ARCH_I386
+	.long multiboot2_header_end - multiboot2_header_start
+	.long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_HEADER_ARCH_I386 + (multiboot2_header_end - multiboot2_header_start))
+	
+	/* Information request tag */
+	tag_info_req_start:
+		.word MULTIBOOT2_TAG_INFO_REQ
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_info_req_end - tag_info_req_start
+		.long MULTIBOOT2_TAG_MODULE
+		.long MULTIBOOT2_TAG_MEMMAP
+#ifdef CONFIG_FB
+		.long MULTIBOOT2_TAG_FBINFO
+#endif
+	tag_info_req_end:
+	
+	/* Address tag */
+	tag_address_start:
+		.word MULTIBOOT2_TAG_ADDRESS
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_address_end - tag_address_start
+		.long multiboot2_header_start
+		.long unmapped_ktext_start
+		.long 0
+		.long 0
+	tag_address_end:
+	
+	/* Entry address tag */
+	tag_entry_address_start:
+		.word MULTIBOOT2_TAG_ENTRY_ADDRESS
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_entry_address_end - tag_entry_address_start
+		.long multiboot2_image_start
+	tag_entry_address_end:
+	
+	/* Flags tag */
+	tag_flags_start:
+		.word MULTIBOOT2_TAG_FLAGS
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_flags_end - tag_flags_start
+		.long MULTIBOOT2_FLAGS_CONSOLE
+	tag_flags_end:
+	
+#ifdef CONFIG_FB
+	/* Framebuffer tag */
+	tag_framebuffer_start:
+		.word MULTIBOOT2_TAG_FRAMEBUFFER
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_framebuffer_end - tag_framebuffer_start
+		.long CONFIG_BFB_WIDTH
+		.long CONFIG_BFB_HEIGHT
+		.long CONFIG_BFB_BPP
+	tag_framebuffer_end:
+#endif
+	
+	/* Module alignment tag */
+	tag_module_align_start:
+		.word MULTIBOOT2_TAG_MODULE_ALIGN
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_module_align_end - tag_module_align_start
+		.long 0
+	tag_module_align_end:
+	
+	/* Tag terminator */
+	tag_terminator_start:
+		.word MULTIBOOT2_TAG_TERMINATOR
+		.word MULTIBOOT2_FLAGS_REQUIRED
+		.long tag_terminator_end - tag_terminator_start
+	tag_terminator_end:
+multiboot2_header_end:
+
+multiboot2_image_start:
+	cld
+	
+	/* Initialize stack pointer */
+	movl $START_STACK, %esp
+	
+	/* Initialize Global Descriptor Table register */
+	lgdtl bootstrap_gdtr
+	
+	/* Kernel data + stack */
+	movw $GDT_SELECTOR(KDATA_DES), %cx
+	movw %cx, %es
+	movw %cx, %fs
+	movw %cx, %gs
+	movw %cx, %ds
+	movw %cx, %ss
+	
+	jmpl $GDT_SELECTOR(KTEXT_DES), $multiboot2_meeting_point
+	multiboot2_meeting_point:
+	
+	/* Save multiboot arguments */
+	movl %eax, multiboot_eax
+	movl %ebx, multiboot_ebx
+	
+#ifndef PROCESSOR_i486
+	
+	movl $(INTEL_CPUID_LEVEL), %eax
+	cpuid
+	cmp $0x0, %eax  /* any function > 0? */
+	jbe pse_unsupported
+	
+	movl $(INTEL_CPUID_STANDARD), %eax
+	cpuid
+	bt $(INTEL_PSE), %edx
+	jnc pse_unsupported
+		
+		/* Map kernel and turn paging on */
+		call map_kernel_pse
+		jmp stack_init
+	
+#endif /* PROCESSOR_i486 */
+	
+	pse_unsupported:
+		
+		/* Map kernel and turn paging on */
+		call map_kernel_non_pse
+	
+	stack_init:
+	
+	/* Create the first stack frame */
+	pushl $0
+	movl %esp, %ebp
+	
+	/* Call arch_pre_main(multiboot_eax, multiboot_ebx) */
+	pushl multiboot_ebx
+	pushl multiboot_eax
+	call arch_pre_main
+	
+	/* Call main_bsp() */
+	call main_bsp
+	
+	/* Not reached */
+	cli
+	hlt0:
+		hlt
+		jmp hlt0
Index: kernel/arch/ia32/src/boot/vesa_prot.inc
===================================================================
--- kernel/arch/ia32/src/boot/vesa_prot.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/ia32/src/boot/vesa_prot.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,5 +1,4 @@
 #ifdef CONFIG_FB
 
-#define MULTIBOOT_LOADER_MAGIC  0x2BADB002
 #define MBINFO_BIT_CMDLINE      2
 #define MBINFO_OFFSET_CMDLINE   16
@@ -14,13 +13,13 @@
 	rep movsb
 	
-	/* Check for GRUB command line */
+	/* Check for multiboot command line */
 	
-	pm_status $status_grub_cmdline
+	pm_status $status_multiboot_cmdline
 	
-	mov grub_eax, %eax
+	mov multiboot_eax, %eax
 	cmp $MULTIBOOT_LOADER_MAGIC, %eax
 	jne no_cmdline
 	
-	mov grub_ebx, %ebx
+	mov multiboot_ebx, %ebx
 	mov (%ebx), %eax
 	bt $MBINFO_BIT_CMDLINE, %eax
@@ -89,25 +88,33 @@
 		/* Returned back to protected mode */
 		
-		mov %ax, KA2PA(vesa_scanline)
+		movzx %ax, %ecx
+		mov %ecx, KA2PA(bfb_scanline)
+		
 		shr $16, %eax
-		mov %ax, KA2PA(vesa_bpp)
+		mov %ax, KA2PA(bfb_bpp)
 		
-		mov %bx, KA2PA(vesa_height)
+		movzx %bx, %ecx
+		mov %ecx, KA2PA(bfb_height)
+		
 		shr $16, %ebx
-		mov %bx, KA2PA(vesa_width)
+		mov %ebx, KA2PA(bfb_width)
 		
-		mov %dl, KA2PA(vesa_green_pos)
+		mov %dl, KA2PA(bfb_green_pos)
+		
 		shr $8, %edx
-		mov %dl, KA2PA(vesa_green_mask)
+		mov %dl, KA2PA(bfb_green_size)
+		
 		shr $8, %edx
-		mov %dl, KA2PA(vesa_red_pos)
+		mov %dl, KA2PA(bfb_red_pos)
+		
 		shr $8, %edx
-		mov %dl, KA2PA(vesa_red_mask)
+		mov %dl, KA2PA(bfb_red_size)
 		
 		mov %esi, %edx
-		mov %dl, KA2PA(vesa_blue_pos)
+		mov %dl, KA2PA(bfb_blue_pos)
+		
 		shr $8, %edx
-		mov %dl, KA2PA(vesa_blue_mask)
+		mov %dl, KA2PA(bfb_blue_size)
 		
-		mov %edi, KA2PA(vesa_ph_addr)
+		mov %edi, KA2PA(bfb_addr)
 #endif
Index: kernel/arch/ia32/src/boot/vesa_real.inc
===================================================================
--- kernel/arch/ia32/src/boot/vesa_real.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/ia32/src/boot/vesa_real.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -304,5 +304,5 @@
 		/*
 		 * Store mode parameters:
-		 *  eax = bpp[8] scanline[16]
+		 *  eax = bpp[16] scanline[16]
 		 *  ebx = width[16]  height[16]
 		 *  edx = red_mask[8] red_pos[8] green_mask[8] green_pos[8]
@@ -328,4 +328,5 @@
 		shl $8, %edx
 		mov VESA_MODE_RED_POS_OFFSET(%di), %dl
+		
 		shl $8, %edx
 		mov VESA_MODE_GREEN_MASK_OFFSET(%di), %dl
@@ -369,6 +370,10 @@
 		mov $0x0003, %ax
 		int $0x10
-		mov $0xffffffff, %edi
-		xor %ax, %ax
+		
+		xor %eax, %eax
+		xor %ebx, %ebx
+		xor %edx, %edx
+		xor %edi, %edi
+		
 		jz vesa_leave_real  /* force relative jump */
 
@@ -386,7 +391,7 @@
 
 default_mode:
-	.ascii STRING(CONFIG_VESA_MODE)
+	.ascii STRING(CONFIG_BFB_MODE)
 	.ascii "-"
-	.asciz STRING(CONFIG_VESA_BPP)
+	.asciz STRING(CONFIG_BFB_BPP)
 	.fill 24
 
Index: rnel/arch/ia32/src/drivers/vesa.c
===================================================================
--- kernel/arch/ia32/src/drivers/vesa.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ 	(revision )
@@ -1,119 +1,0 @@
-/*
- * Copyright (c) 2006 Jakub Vana
- * 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 ia32
- * @{
- */
-/**
- * @file
- * @brief VESA frame buffer driver.
- */
-
-#ifdef CONFIG_FB
-
-#include <genarch/fb/fb.h>
-#include <arch/drivers/vesa.h>
-#include <console/chardev.h>
-#include <console/console.h>
-#include <putchar.h>
-#include <mm/page.h>
-#include <mm/frame.h>
-#include <mm/as.h>
-#include <arch/mm/page.h>
-#include <synch/spinlock.h>
-#include <arch/asm.h>
-#include <typedefs.h>
-#include <memstr.h>
-#include <bitops.h>
-
-uint32_t vesa_ph_addr;
-uint16_t vesa_width;
-uint16_t vesa_height;
-uint16_t vesa_bpp;
-uint16_t vesa_scanline;
-
-uint8_t vesa_red_mask;
-uint8_t vesa_red_pos;
-
-uint8_t vesa_green_mask;
-uint8_t vesa_green_pos;
-
-uint8_t vesa_blue_mask;
-uint8_t vesa_blue_pos;
-
-bool vesa_init(void)
-{
-	if ((vesa_width == 0xffffU) || (vesa_height == 0xffffU))
-		return false;
-	
-	visual_t visual;
-	
-	switch (vesa_bpp) {
-	case 8:
-		visual = VISUAL_INDIRECT_8;
-		break;
-	case 16:
-		if ((vesa_red_mask == 5) && (vesa_red_pos == 10)
-		    && (vesa_green_mask == 5) && (vesa_green_pos == 5)
-		    && (vesa_blue_mask == 5) && (vesa_blue_pos == 0))
-			visual = VISUAL_RGB_5_5_5_LE;
-		else
-			visual = VISUAL_RGB_5_6_5_LE;
-		break;
-	case 24:
-		visual = VISUAL_BGR_8_8_8;
-		break;
-	case 32:
-		visual = VISUAL_BGR_8_8_8_0;
-		break;
-	default:
-		LOG("Unsupported bits per pixel.");
-		return false;
-	}
-	
-	fb_properties_t vesa_props = {
-		.addr = vesa_ph_addr,
-		.offset = 0,
-		.x = vesa_width,
-		.y = vesa_height,
-		.scan = vesa_scanline,
-		.visual = visual,
-	};
-	
-	outdev_t *fbdev = fb_init(&vesa_props);
-	if (!fbdev)
-		return false;
-	
-	stdout_wire(fbdev);
-	return true;
-}
-
-#endif
-
-/** @}
- */
Index: kernel/arch/ia32/src/ia32.c
===================================================================
--- kernel/arch/ia32/src/ia32.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/ia32/src/ia32.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -36,37 +36,24 @@
 
 #include <arch.h>
-
 #include <typedefs.h>
-
-#include <arch/pm.h>
-
-#include <genarch/multiboot/multiboot.h>
-#include <genarch/drivers/legacy/ia32/io.h>
-#include <genarch/drivers/ega/ega.h>
-#include <arch/drivers/vesa.h>
-#include <genarch/drivers/i8042/i8042.h>
-#include <genarch/kbrd/kbrd.h>
+#include <errno.h>
+#include <memstr.h>
+#include <interrupt.h>
+#include <console/console.h>
+#include <syscall/syscall.h>
+#include <sysinfo/sysinfo.h>
+#include <arch/bios/bios.h>
+#include <arch/boot/boot.h>
+#include <arch/debugger.h>
 #include <arch/drivers/i8254.h>
 #include <arch/drivers/i8259.h>
-
-#include <arch/context.h>
-
-#include <config.h>
-
-#include <arch/interrupt.h>
-#include <arch/asm.h>
 #include <genarch/acpi/acpi.h>
-
-#include <arch/bios/bios.h>
-
-#include <interrupt.h>
-#include <ddi/irq.h>
-#include <arch/debugger.h>
-#include <proc/thread.h>
-#include <syscall/syscall.h>
-#include <console/console.h>
-#include <sysinfo/sysinfo.h>
-#include <arch/boot/boot.h>
-#include <memstr.h>
+#include <genarch/drivers/ega/ega.h>
+#include <genarch/drivers/i8042/i8042.h>
+#include <genarch/drivers/legacy/ia32/io.h>
+#include <genarch/fb/bfb.h>
+#include <genarch/kbrd/kbrd.h>
+#include <genarch/multiboot/multiboot.h>
+#include <genarch/multiboot/multiboot2.h>
 
 #ifdef CONFIG_SMP
@@ -76,11 +63,13 @@
 /** Perform ia32-specific initialization before main_bsp() is called.
  *
- * @param signature Should contain the multiboot signature.
- * @param mi        Pointer to the multiboot information structure.
- */
-void arch_pre_main(uint32_t signature, const multiboot_info_t *mi)
+ * @param signature Multiboot signature.
+ * @param info      Multiboot information structure.
+ *
+ */
+void arch_pre_main(uint32_t signature, void *info)
 {
 	/* Parse multiboot information obtained from the bootloader. */
-	multiboot_info_parse(signature, mi);
+	multiboot_info_parse(signature, (multiboot_info_t *) info);
+	multiboot2_info_parse(signature, (multiboot2_info_t *) info);
 	
 #ifdef CONFIG_SMP
@@ -114,13 +103,13 @@
 		
 #if (defined(CONFIG_FB) || defined(CONFIG_EGA))
-		bool vesa = false;
+		bool bfb = false;
 #endif
 		
 #ifdef CONFIG_FB
-		vesa = vesa_init();
+		bfb = bfb_init();
 #endif
 		
 #ifdef CONFIG_EGA
-		if (!vesa) {
+		if (!bfb) {
 			outdev_t *egadev = ega_init(EGA_BASE, EGA_VIDEORAM);
 			if (egadev)
@@ -216,10 +205,10 @@
  * selector, and the descriptor->base is the correct address.
  */
-sysarg_t sys_tls_set(sysarg_t addr)
+sysarg_t sys_tls_set(uintptr_t addr)
 {
 	THREAD->arch.tls = addr;
 	set_tls_desc(addr);
 	
-	return 0;
+	return EOK;
 }
 
Index: kernel/arch/ia64/include/asm.h
===================================================================
--- kernel/arch/ia64/include/asm.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/ia64/include/asm.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -38,5 +38,4 @@
 #include <config.h>
 #include <typedefs.h>
-#include <typedefs.h>
 #include <arch/register.h>
 #include <trace.h>
Index: kernel/arch/ia64/src/ia64.c
===================================================================
--- kernel/arch/ia64/src/ia64.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/ia64/src/ia64.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -34,38 +34,21 @@
 
 #include <arch.h>
-#include <arch/drivers/ski.h>
-#include <arch/drivers/it.h>
-#include <arch/interrupt.h>
-#include <arch/barrier.h>
-#include <arch/asm.h>
-#include <arch/register.h>
 #include <typedefs.h>
-#include <arch/context.h>
-#include <arch/stack.h>
-#include <arch/mm/page.h>
+#include <errno.h>
 #include <interrupt.h>
-#include <mm/as.h>
-#include <config.h>
 #include <macros.h>
+#include <str.h>
 #include <userspace.h>
 #include <console/console.h>
-#include <abi/proc/uarg.h>
 #include <syscall/syscall.h>
-#include <ddi/irq.h>
-#include <arch/bootinfo.h>
+#include <sysinfo/sysinfo.h>
+#include <arch/drivers/it.h>
+#include <arch/drivers/kbd.h>
+#include <genarch/drivers/ega/ega.h>
+#include <genarch/drivers/i8042/i8042.h>
+#include <genarch/drivers/ns16550/ns16550.h>
 #include <genarch/drivers/legacy/ia32/io.h>
-#include <genarch/drivers/ega/ega.h>
 #include <genarch/kbrd/kbrd.h>
 #include <genarch/srln/srln.h>
-#include <genarch/drivers/i8042/i8042.h>
-#include <genarch/drivers/ns16550/ns16550.h>
-#include <arch/drivers/kbd.h>
-#include <smp/smp.h>
-#include <smp/ipi.h>
-#include <arch/atomic.h>
-#include <panic.h>
-#include <print.h>
-#include <sysinfo/sysinfo.h>
-#include <str.h>
 
 /* NS16550 as a COM 1 */
@@ -262,7 +245,7 @@
  * We use r13 (a.k.a. tp) for this purpose.
  */
-sysarg_t sys_tls_set(sysarg_t addr)
-{
-	return 0;
+sysarg_t sys_tls_set(uintptr_t addr)
+{
+	return EOK;
 }
 
@@ -270,6 +253,5 @@
 {
 	pio_write_8((ioport8_t *)0x64, 0xfe);
-	while (1)
-		;
+	while (1);
 }
 
Index: kernel/arch/ia64/src/start.S
===================================================================
--- kernel/arch/ia64/src/start.S	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/ia64/src/start.S	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -174,5 +174,5 @@
 	mov ar.bspstore = r8
 	loadrs
-
+	
 	#
 	# Initialize memory stack to some sane value and allocate a scratch area
@@ -196,5 +196,5 @@
 	srlz.i
 	srlz.d ;;
-
+	
 	br.call.sptk.many b0 = arch_pre_main
 0:
Index: kernel/arch/mips32/src/mips32.c
===================================================================
--- kernel/arch/mips32/src/mips32.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/mips32/src/mips32.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -34,31 +34,21 @@
 
 #include <arch.h>
-#include <arch/cp0.h>
-#include <arch/exception.h>
-#include <arch/debug.h>
-#include <mm/as.h>
+#include <typedefs.h>
+#include <errno.h>
+#include <interrupt.h>
+#include <macros.h>
+#include <str.h>
+#include <memstr.h>
 #include <userspace.h>
-#include <memstr.h>
-#include <proc/thread.h>
-#include <abi/proc/uarg.h>
-#include <print.h>
 #include <console/console.h>
 #include <syscall/syscall.h>
 #include <sysinfo/sysinfo.h>
-#include <arch/interrupt.h>
-#include <interrupt.h>
-#include <console/chardev.h>
-#include <arch/barrier.h>
+#include <arch/debug.h>
 #include <arch/debugger.h>
+#include <arch/drivers/msim.h>
 #include <genarch/fb/fb.h>
-#include <abi/fb/visuals.h>
 #include <genarch/drivers/dsrln/dsrlnin.h>
 #include <genarch/drivers/dsrln/dsrlnout.h>
 #include <genarch/srln/srln.h>
-#include <macros.h>
-#include <config.h>
-#include <str.h>
-#include <arch/drivers/msim.h>
-#include <arch/asm/regname.h>
 
 /* Size of the code jumping to the exception handler code
@@ -248,7 +238,7 @@
  * possible to have it separately in the future.
  */
-sysarg_t sys_tls_set(sysarg_t addr)
-{
-	return 0;
+sysarg_t sys_tls_set(uintptr_t addr)
+{
+	return EOK;
 }
 
Index: kernel/arch/mips64/src/mips64.c
===================================================================
--- kernel/arch/mips64/src/mips64.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/arch/mips64/src/mips64.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -34,31 +34,21 @@
 
 #include <arch.h>
-#include <arch/cp0.h>
-#include <arch/exception.h>
-#include <arch/debug.h>
-#include <mm/as.h>
+#include <typedefs.h>
+#include <errno.h>
+#include <interrupt.h>
+#include <macros.h>
+#include <str.h>
+#include <memstr.h>
 #include <userspace.h>
-#include <memstr.h>
-#include <proc/thread.h>
-#include <abi/proc/uarg.h>
-#include <print.h>
 #include <console/console.h>
 #include <syscall/syscall.h>
 #include <sysinfo/sysinfo.h>
-#include <arch/interrupt.h>
-#include <interrupt.h>
-#include <console/chardev.h>
-#include <arch/barrier.h>
+#include <arch/debug.h>
 #include <arch/debugger.h>
+#include <arch/drivers/msim.h>
 #include <genarch/fb/fb.h>
-#include <abi/fb/visuals.h>
 #include <genarch/drivers/dsrln/dsrlnin.h>
 #include <genarch/drivers/dsrln/dsrlnout.h>
 #include <genarch/srln/srln.h>
-#include <macros.h>
-#include <config.h>
-#include <str.h>
-#include <arch/drivers/msim.h>
-#include <arch/asm/regname.h>
 
 /* Size of the code jumping to the exception handler code
@@ -226,7 +216,7 @@
  * possible to have it separately in the future.
  */
-sysarg_t sys_tls_set(sysarg_t addr)
-{
-	return 0;
+sysarg_t sys_tls_set(uintptr_t addr)
+{
+	return EOK;
 }
 
Index: kernel/genarch/Makefile.inc
===================================================================
--- kernel/genarch/Makefile.inc	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/genarch/Makefile.inc	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -67,5 +67,6 @@
 		genarch/src/fb/font-8x16.c \
 		genarch/src/fb/logo-196x66.c \
-		genarch/src/fb/fb.c
+		genarch/src/fb/fb.c \
+		genarch/src/fb/bfb.c
 endif
 
@@ -143,5 +144,6 @@
 ifeq ($(CONFIG_MULTIBOOT), y)
 	GENARCH_SOURCES += \
-		genarch/src/multiboot/multiboot.c
+		genarch/src/multiboot/multiboot.c \
+		genarch/src/multiboot/multiboot2.c
 endif
 
Index: kernel/genarch/include/fb/bfb.h
===================================================================
--- kernel/genarch/include/fb/bfb.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ kernel/genarch/include/fb/bfb.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2006 Jakub Vana
+ * 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 genarch
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_BFB_H_
+#define KERN_BFB_H_
+
+#include <typedefs.h>
+
+extern uintptr_t bfb_addr;
+extern uint32_t bfb_width;
+extern uint32_t bfb_height;
+extern uint16_t bfb_bpp;
+extern uint32_t bfb_scanline;
+
+extern uint8_t bfb_red_pos;
+extern uint8_t bfb_red_size;
+
+extern uint8_t bfb_green_pos;
+extern uint8_t bfb_green_size;
+
+extern uint8_t bfb_blue_pos;
+extern uint8_t bfb_blue_size;
+
+extern bool bfb_init(void);
+
+#endif
+
+/** @}
+ */
Index: kernel/genarch/include/multiboot/multiboot.h
===================================================================
--- kernel/genarch/include/multiboot/multiboot.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/genarch/include/multiboot/multiboot.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -36,11 +36,21 @@
 #define KERN_MULTIBOOT_H_
 
+#define MULTIBOOT_HEADER_MAGIC  0x1badb002
+#define MULTIBOOT_HEADER_FLAGS  0x00010003
+
+#define MULTIBOOT_LOADER_MAGIC  0x2badb002
+
+#ifndef __ASM__
+
 #include <typedefs.h>
 #include <arch/boot/memmap.h>
+
+/** Convert 32-bit multiboot address to a pointer. */
+#define MULTIBOOT_PTR(mba)  ((void *) (uintptr_t) (mba))
 
 /** Multiboot 32-bit address. */
 typedef uint32_t mbaddr_t;
 
-/** Multiboot mod structure */
+/** Multiboot module structure */
 typedef struct {
 	mbaddr_t start;
@@ -48,5 +58,5 @@
 	mbaddr_t string;
 	uint32_t reserved;
-} __attribute__ ((packed)) multiboot_mod_t;
+} __attribute__((packed)) multiboot_module_t;
 
 /** Multiboot mmap structure */
@@ -54,5 +64,5 @@
 	uint32_t size;
 	e820memmap_t mm_info;
-} __attribute__ ((packed)) multiboot_mmap_t;
+} __attribute__((packed)) multiboot_memmap_t;
 
 /** Multiboot information structure */
@@ -74,24 +84,22 @@
 	
 	/* ... */
-} __attribute__ ((packed)) multiboot_info_t;
+} __attribute__((packed)) multiboot_info_t;
 
 enum multiboot_info_flags {
-	MBINFO_FLAGS_MEM     = 0x01,
-	MBINFO_FLAGS_BOOT    = 0x02,
-	MBINFO_FLAGS_CMDLINE = 0x04,
-	MBINFO_FLAGS_MODS    = 0x08,
-	MBINFO_FLAGS_SYMS1   = 0x10,
-	MBINFO_FLAGS_SYMS2   = 0x20,
-	MBINFO_FLAGS_MMAP    = 0x40
+	MULTIBOOT_INFO_FLAGS_MEM     = 0x01,
+	MULTIBOOT_INFO_FLAGS_BOOT    = 0x02,
+	MULTIBOOT_INFO_FLAGS_CMDLINE = 0x04,
+	MULTIBOOT_INFO_FLAGS_MODS    = 0x08,
+	MULTIBOOT_INFO_FLAGS_SYMS1   = 0x10,
+	MULTIBOOT_INFO_FLAGS_SYMS2   = 0x20,
+	MULTIBOOT_INFO_FLAGS_MMAP    = 0x40
 	
 	/* ... */
 };
 
-#define MULTIBOOT_LOADER_MAGIC  0x2BADB002
+extern void multiboot_extract_command(char *, size_t, const char *);
+extern void multiboot_info_parse(uint32_t, const multiboot_info_t *);
 
-/** Convert 32-bit multiboot address to a pointer. */
-#define MULTIBOOT_PTR(mba) ((void *)(uintptr_t) (mba))
-
-extern void multiboot_info_parse(uint32_t, const multiboot_info_t *);
+#endif /* __ASM__ */
 
 #endif
Index: kernel/genarch/include/multiboot/multiboot2.h
===================================================================
--- kernel/genarch/include/multiboot/multiboot2.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ kernel/genarch/include/multiboot/multiboot2.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,153 @@
+/*
+ * 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 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 genarch
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_MULTIBOOT2_H_
+#define KERN_MULTIBOOT2_H_
+
+#define MULTIBOOT2_HEADER_MAGIC      0xe85250d6
+#define MULTIBOOT2_HEADER_ARCH_I386  0
+
+#define MULTIBOOT2_LOADER_MAGIC  0x36d76289
+
+#define MULTIBOOT2_FLAGS_REQUIRED  0
+#define MULTIBOOT2_FLAGS_CONSOLE   0x03
+
+#define MULTIBOOT2_TAG_TERMINATOR     0
+#define MULTIBOOT2_TAG_INFO_REQ       1
+#define MULTIBOOT2_TAG_ADDRESS        2
+#define MULTIBOOT2_TAG_ENTRY_ADDRESS  3
+#define MULTIBOOT2_TAG_FLAGS          4
+#define MULTIBOOT2_TAG_FRAMEBUFFER    5
+#define MULTIBOOT2_TAG_MODULE_ALIGN   6
+
+#define MULTIBOOT2_TAG_MODULE  3
+#define MULTIBOOT2_TAG_MEMMAP  6
+#define MULTIBOOT2_TAG_FBINFO  8
+
+#define MULTIBOOT2_VISUAL_INDEXED  0
+#define MULTIBOOT2_VISUAL_RGB      1
+#define MULTIBOOT2_VISUAL_EGA      2
+
+#ifndef __ASM__
+
+#include <typedefs.h>
+#include <arch/boot/memmap.h>
+
+/** Multiboot2 32-bit address. */
+typedef uint32_t mb2addr_t;
+
+/** Multiboot2 information structure */
+typedef struct {
+	uint32_t size;
+	uint32_t reserved;
+} __attribute__((packed)) multiboot2_info_t;
+
+/** Multiboot2 modules structure */
+typedef struct {
+	mb2addr_t start;
+	mb2addr_t end;
+	char string[];
+} __attribute__((packed)) multiboot2_module_t;
+
+/** Multiboot2 memmap structure */
+typedef struct {
+	uint32_t entry_size;
+	uint32_t entry_version;
+} __attribute__ ((packed)) multiboot2_memmap_t;
+
+/** Multiboot2 memmap entry structure */
+typedef struct {
+	uint64_t base_address;
+	uint64_t size;
+	uint32_t type;
+	uint32_t reserved;
+} __attribute__((packed)) multiboot2_memmap_entry_t;
+
+/** Multiboot2 palette structure */
+typedef struct {
+	uint8_t red;
+	uint8_t green;
+	uint8_t blue;
+} __attribute__((packed)) multiboot2_colorinfo_palette_t;
+
+/** Multiboot2 indexed color information structure */
+typedef struct {
+	uint32_t colors;
+	multiboot2_colorinfo_palette_t palette[];
+} __attribute__((packed)) multiboot2_colorinfo_indexed_t;
+
+/** Multiboot2 RGB color information structure */
+typedef struct {
+	uint8_t red_pos;
+	uint8_t red_size;
+	uint8_t green_pos;
+	uint8_t green_size;
+	uint8_t blue_pos;
+	uint8_t blue_size;
+} __attribute__((packed)) multiboot2_colorinfo_rgb_t;
+
+/** Multiboot2 framebuffer information structure */
+typedef struct {
+	uint64_t addr;
+	uint32_t scanline;
+	uint32_t width;
+	uint32_t height;
+	uint8_t bpp;
+	uint8_t visual;
+	uint8_t reserved;
+	union {
+		multiboot2_colorinfo_indexed_t indexed;
+		multiboot2_colorinfo_rgb_t rgb;
+	};
+} __attribute__((packed)) multiboot2_fbinfo_t;
+
+/** Generic multiboot2 tag */
+typedef struct {
+	uint32_t type;
+	uint32_t size;
+	union {
+		multiboot2_module_t module;
+		multiboot2_memmap_t memmap;
+		multiboot2_fbinfo_t fbinfo;
+	};
+} __attribute__((packed)) multiboot2_tag_t;
+
+extern void multiboot2_info_parse(uint32_t, const multiboot2_info_t *);
+
+#endif /* __ASM__ */
+
+#endif
+
+/** @}
+ */
Index: kernel/genarch/src/drivers/i8042/i8042.c
===================================================================
--- kernel/genarch/src/drivers/i8042/i8042.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/genarch/src/drivers/i8042/i8042.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -44,4 +44,5 @@
 #include <mm/slab.h>
 #include <ddi/device.h>
+#include <time/delay.h>
 
 #define i8042_SET_COMMAND  0x60
@@ -51,4 +52,6 @@
 #define i8042_BUFFER_FULL_MASK  0x01
 #define i8042_WAIT_MASK         0x02
+
+#define i8042_TIMEOUT  65536
 
 static irq_ownership_t i8042_claim(irq_t *irq)
@@ -77,6 +80,24 @@
 static void i8042_clear_buffer(i8042_t *dev)
 {
-	while (pio_read_8(&dev->status) & i8042_BUFFER_FULL_MASK)
+	for (uint32_t i = 0; i < i8042_TIMEOUT; i++) {
+		if ((pio_read_8(&dev->status) & i8042_BUFFER_FULL_MASK) == 0)
+			break;
+		
 		(void) pio_read_8(&dev->data);
+		delay(50);  /* 50 us think time */
+	}
+}
+
+static void i8042_send_command(i8042_t *dev, uint8_t cmd)
+{
+	for (uint32_t i = 0; i < i8042_TIMEOUT; i++) {
+		if ((pio_read_8(&dev->status) & i8042_WAIT_MASK) == 0)
+			break;
+		
+		delay(50);  /* 50 us think time */
+	}
+	
+	pio_write_8(&dev->status, cmd);
+	delay(10000);  /* 10 ms think time */
 }
 
@@ -84,6 +105,6 @@
 i8042_instance_t *i8042_init(i8042_t *dev, inr_t inr)
 {
-	i8042_instance_t *instance
-	    = malloc(sizeof(i8042_instance_t), FRAME_ATOMIC);
+	i8042_instance_t *instance =
+	    malloc(sizeof(i8042_instance_t), FRAME_ATOMIC);
 	if (instance) {
 		instance->i8042 = dev;
@@ -96,5 +117,4 @@
 		instance->irq.handler = i8042_irq_handler;
 		instance->irq.instance = instance;
-		
 	}
 	
@@ -107,7 +127,8 @@
 	ASSERT(kbrdin);
 	
+	i8042_clear_buffer(instance->i8042);
+	
 	instance->kbrdin = kbrdin;
 	irq_register(&instance->irq);
-	i8042_clear_buffer(instance->i8042);
 }
 
@@ -116,9 +137,6 @@
 {
 	interrupts_disable();
-	
 	i8042_clear_buffer(dev);
-	
-	/* Reset CPU */
-	pio_write_8(&dev->status, i8042_CPU_RESET);
+	i8042_send_command(dev, i8042_CPU_RESET);
 }
 
Index: kernel/genarch/src/fb/bfb.c
===================================================================
--- kernel/genarch/src/fb/bfb.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ kernel/genarch/src/fb/bfb.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2006 Jakub Vana
+ * 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 genarch
+ * @{
+ */
+/**
+ * @file
+ * @brief Boot framebuffer driver.
+ */
+
+#include <typedefs.h>
+#include <genarch/fb/fb.h>
+#include <genarch/fb/bfb.h>
+#include <console/console.h>
+
+uintptr_t bfb_addr = 0;
+uint32_t bfb_width = 0;
+uint32_t bfb_height = 0;
+uint16_t bfb_bpp = 0;
+uint32_t bfb_scanline = 0;
+
+uint8_t bfb_red_pos = 0;
+uint8_t bfb_red_size = 0;
+
+uint8_t bfb_green_pos = 0;
+uint8_t bfb_green_size = 0;
+
+uint8_t bfb_blue_pos = 0;
+uint8_t bfb_blue_size = 0;
+
+bool bfb_init(void)
+{
+	if ((bfb_addr == 0) || (bfb_width == 0) || (bfb_height == 0) ||
+	    (bfb_bpp == 0) || (bfb_scanline == 0))
+		return false;
+	
+	fb_properties_t bfb_props = {
+		.addr = bfb_addr,
+		.offset = 0,
+		.x = bfb_width,
+		.y = bfb_height,
+		.scan = bfb_scanline
+	};
+	
+	switch (bfb_bpp) {
+	case 8:
+		bfb_props.visual = VISUAL_INDIRECT_8;
+		break;
+	case 16:
+		if ((bfb_red_pos == 10) && (bfb_red_size == 5) &&
+		    (bfb_green_pos == 5) && (bfb_green_size == 5) &&
+		    (bfb_blue_pos == 0) && (bfb_blue_size == 5))
+			bfb_props.visual = VISUAL_RGB_5_5_5_LE;
+		else
+			bfb_props.visual = VISUAL_RGB_5_6_5_LE;
+		break;
+	case 24:
+		bfb_props.visual = VISUAL_BGR_8_8_8;
+		break;
+	case 32:
+		bfb_props.visual = VISUAL_BGR_8_8_8_0;
+		break;
+	default:
+		LOG("Unsupported bits per pixel.");
+		return false;
+	}
+	
+	outdev_t *fbdev = fb_init(&bfb_props);
+	if (!fbdev)
+		return false;
+	
+	stdout_wire(fbdev);
+	return true;
+}
+
+/** @}
+ */
Index: kernel/genarch/src/multiboot/multiboot.c
===================================================================
--- kernel/genarch/src/multiboot/multiboot.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/genarch/src/multiboot/multiboot.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -33,18 +33,17 @@
  */
 
+#include <typedefs.h>
 #include <genarch/multiboot/multiboot.h>
-#include <typedefs.h>
 #include <config.h>
 #include <str.h>
-#include <macros.h>
 
 /** Extract command name from the multiboot module command line.
  *
- * @param buf      Destination buffer (will always NULL-terminate).
- * @param sz       Size of destination buffer (in bytes).
+ * @param buf      Destination buffer (will be always NULL-terminated).
+ * @param size     Size of destination buffer (in bytes).
  * @param cmd_line Input string (the command line).
  *
  */
-static void extract_command(char *buf, size_t sz, const char *cmd_line)
+void multiboot_extract_command(char *buf, size_t size, const char *cmd_line)
 {
 	/* Find the first space. */
@@ -69,5 +68,41 @@
 	
 	/* Copy the command. */
-	str_ncpy(buf, sz, start, (size_t) (end - start));
+	str_ncpy(buf, size, start, (size_t) (end - start));
+}
+
+static void multiboot_modules(uint32_t count, multiboot_module_t *mods)
+{
+	for (uint32_t i = 0; i < count; i++) {
+		if (init.cnt >= CONFIG_INIT_TASKS)
+			break;
+		
+		init.tasks[init.cnt].addr = PA2KA(mods[i].start);
+		init.tasks[init.cnt].size = mods[i].end - mods[i].start;
+		
+		/* Copy command line, if available. */
+		if (mods[i].string) {
+			multiboot_extract_command(init.tasks[init.cnt].name,
+			    CONFIG_TASK_NAME_BUFLEN, MULTIBOOT_PTR(mods[i].string));
+		} else
+			init.tasks[init.cnt].name[0] = 0;
+		
+		init.cnt++;
+	}
+}
+
+static void multiboot_memmap(uint32_t length, multiboot_memmap_t *memmap)
+{
+	uint32_t pos = 0;
+	
+	while ((pos < length) && (e820counter < MEMMAP_E820_MAX_RECORDS)) {
+		e820table[e820counter] = memmap->mm_info;
+		
+		/* Compute address of next structure. */
+		uint32_t size = sizeof(memmap->size) + memmap->size;
+		memmap = (multiboot_memmap_t *) ((uintptr_t) memmap + size);
+		pos += size;
+		
+		e820counter++;
+	}
 }
 
@@ -78,59 +113,21 @@
  *
  * @param signature Should contain the multiboot signature.
- * @param mi        Pointer to the multiboot information structure.
+ * @param info      Multiboot information structure.
+ *
  */
-void multiboot_info_parse(uint32_t signature, const multiboot_info_t *mi)
+void multiboot_info_parse(uint32_t signature, const multiboot_info_t *info)
 {
-	uint32_t flags;
+	if (signature != MULTIBOOT_LOADER_MAGIC)
+		return;
 	
-	if (signature == MULTIBOOT_LOADER_MAGIC)
-		flags = mi->flags;
-	else {
-		/* No multiboot info available. */
-		flags = 0;
-	}
-	
-	/* Copy module information. */
-	uint32_t i;
-	if ((flags & MBINFO_FLAGS_MODS) != 0) {
-		init.cnt = min(mi->mods_count, CONFIG_INIT_TASKS);
-		multiboot_mod_t *mods
-		    = (multiboot_mod_t *) MULTIBOOT_PTR(mi->mods_addr);
-		
-		for (i = 0; i < init.cnt; i++) {
-			init.tasks[i].addr = PA2KA(mods[i].start);
-			init.tasks[i].size = mods[i].end - mods[i].start;
-			
-			/* Copy command line, if available. */
-			if (mods[i].string) {
-				extract_command(init.tasks[i].name,
-				    CONFIG_TASK_NAME_BUFLEN,
-				    MULTIBOOT_PTR(mods[i].string));
-			} else
-				init.tasks[i].name[0] = 0;
-		}
-	} else
-		init.cnt = 0;
+	/* Copy modules information. */
+	if ((info->flags & MULTIBOOT_INFO_FLAGS_MODS) != 0)
+		multiboot_modules(info->mods_count,
+		    (multiboot_module_t *) MULTIBOOT_PTR(info->mods_addr));
 	
 	/* Copy memory map. */
-	
-	if ((flags & MBINFO_FLAGS_MMAP) != 0) {
-		int32_t mmap_length = mi->mmap_length;
-		multiboot_mmap_t *mme = MULTIBOOT_PTR(mi->mmap_addr);
-		e820counter = 0;
-		
-		i = 0;
-		while ((mmap_length > 0) && (i < MEMMAP_E820_MAX_RECORDS)) {
-			e820table[i++] = mme->mm_info;
-			
-			/* Compute address of next structure. */
-			uint32_t size = sizeof(mme->size) + mme->size;
-			mme = ((void *) mme) + size;
-			mmap_length -= size;
-		}
-		
-		e820counter = i;
-	} else
-		e820counter = 0;
+	if ((info->flags & MULTIBOOT_INFO_FLAGS_MMAP) != 0)
+		multiboot_memmap(info->mmap_length,
+		    (multiboot_memmap_t *) MULTIBOOT_PTR(info->mmap_addr));
 }
 
Index: kernel/genarch/src/multiboot/multiboot2.c
===================================================================
--- kernel/genarch/src/multiboot/multiboot2.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ kernel/genarch/src/multiboot/multiboot2.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,134 @@
+/*
+ * 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 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 genarch
+ * @{
+ */
+/** @file
+ */
+
+#include <typedefs.h>
+#include <genarch/multiboot/multiboot.h>
+#include <genarch/multiboot/multiboot2.h>
+#include <genarch/fb/bfb.h>
+#include <config.h>
+#include <align.h>
+
+#define MULTIBOOT2_TAG_ALIGN  8
+
+static void multiboot2_module(const multiboot2_module_t *module)
+{
+	if (init.cnt < CONFIG_INIT_TASKS) {
+		init.tasks[init.cnt].addr = PA2KA(module->start);
+		init.tasks[init.cnt].size = module->end - module->start;
+		multiboot_extract_command(init.tasks[init.cnt].name,
+		    CONFIG_TASK_NAME_BUFLEN, module->string);
+		
+		init.cnt++;
+	}
+}
+
+static void multiboot2_memmap(uint32_t length, const multiboot2_memmap_t *memmap)
+{
+	multiboot2_memmap_entry_t *entry = (multiboot2_memmap_entry_t *)
+	    ((uintptr_t) memmap + sizeof(*memmap));
+	uint32_t pos = sizeof(*memmap);
+	
+	while ((pos < length) && (e820counter < MEMMAP_E820_MAX_RECORDS)) {
+		e820table[e820counter].base_address = entry->base_address;
+		e820table[e820counter].size = entry->size;
+		e820table[e820counter].type = entry->type;
+		
+		/* Compute address of next entry. */
+		entry = (multiboot2_memmap_entry_t *)
+		    ((uintptr_t) entry + memmap->entry_size);
+		pos += memmap->entry_size;
+		
+		e820counter++;
+	}
+}
+
+static void multiboot2_fbinfo(const multiboot2_fbinfo_t *fbinfo)
+{
+#ifdef CONFIG_FB
+	if (fbinfo->visual == MULTIBOOT2_VISUAL_RGB) {
+		bfb_addr = fbinfo->addr;
+		bfb_width = fbinfo->width;
+		bfb_height = fbinfo->height;
+		bfb_bpp = fbinfo->bpp;
+		bfb_scanline = fbinfo->scanline;
+		
+		bfb_red_pos = fbinfo->rgb.red_pos;
+		bfb_red_size = fbinfo->rgb.red_size;
+		
+		bfb_green_pos = fbinfo->rgb.green_pos;
+		bfb_green_size = fbinfo->rgb.green_size;
+		
+		bfb_blue_pos = fbinfo->rgb.blue_pos;
+		bfb_blue_size = fbinfo->rgb.blue_size;
+	}
+#endif
+}
+
+/** Parse multiboot2 information structure.
+ *
+ * If @a signature does not contain a valid multiboot2 signature,
+ * assumes no multiboot2 information is available.
+ *
+ * @param signature Should contain the multiboot2 signature.
+ * @param info      Multiboot2 information structure.
+ *
+ */
+void multiboot2_info_parse(uint32_t signature, const multiboot2_info_t *info)
+{
+	if (signature != MULTIBOOT2_LOADER_MAGIC)
+		return;
+	
+	const multiboot2_tag_t *tag = (const multiboot2_tag_t *)
+	    ALIGN_UP((uintptr_t) info + sizeof(*info), MULTIBOOT2_TAG_ALIGN);
+	
+	while (tag->type != MULTIBOOT2_TAG_TERMINATOR) {
+		switch (tag->type) {
+		case MULTIBOOT2_TAG_MODULE:
+			multiboot2_module(&tag->module);
+			break;
+		case MULTIBOOT2_TAG_MEMMAP:
+			multiboot2_memmap(tag->size, &tag->memmap);
+			break;
+		case MULTIBOOT2_TAG_FBINFO:
+			multiboot2_fbinfo(&tag->fbinfo);
+			break;
+		}
+		
+		tag = (const multiboot2_tag_t *)
+		    ALIGN_UP((uintptr_t) tag + tag->size, MULTIBOOT2_TAG_ALIGN);
+	}
+}
+
+/** @}
+ */
Index: kernel/generic/include/ddi/ddi.h
===================================================================
--- kernel/generic/include/ddi/ddi.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/include/ddi/ddi.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -55,5 +55,10 @@
 extern void ddi_parea_register(parea_t *);
 
-extern sysarg_t sys_physmem_map(sysarg_t, sysarg_t, sysarg_t, sysarg_t);
+extern sysarg_t sys_physmem_map(uintptr_t, uintptr_t, size_t, unsigned int);
+
+extern sysarg_t sys_dmamem_map(uintptr_t, size_t, unsigned int, unsigned int,
+    void *);
+extern sysarg_t sys_dmamem_unmap(uintptr_t, size_t, unsigned int);
+
 extern sysarg_t sys_iospace_enable(ddi_ioarg_t *);
 
Index: kernel/generic/include/lib/rd.h
===================================================================
--- kernel/generic/include/lib/rd.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/include/lib/rd.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -38,44 +38,5 @@
 #include <typedefs.h>
 
-/**
- * RAM disk version
- */
-#define RD_VERSION	1
-
-/**
- * RAM disk magic number
- */
-#define RD_MAGIC_SIZE	4
-#define RD_MAG0			'H'
-#define RD_MAG1			'O'
-#define RD_MAG2			'R'
-#define RD_MAG3			'D'
-
-/**
- * RAM disk data encoding types
- */
-#define RD_DATA_NONE	0
-#define RD_DATA_LSB		1		/* Least significant byte first (little endian) */
-#define RD_DATA_MSB		2		/* Most signigicant byte first (big endian) */
-
-/**
- * RAM disk error return codes
- */
-#define RE_OK			0	/* No error */
-#define RE_INVALID		1	/* Invalid RAM disk image */
-#define RE_UNSUPPORTED		2	/* Non-supported image (e.g. wrong version) */
-
-/** RAM disk header */
-struct rd_header {
-	uint8_t magic[RD_MAGIC_SIZE];
-	uint8_t version;
-	uint8_t data_type;
-	uint32_t header_size;
-	uint64_t data_size;
-} __attribute__ ((packed));
-
-typedef struct rd_header rd_header_t;
-
-extern int init_rd(rd_header_t *addr, size_t size);
+extern void init_rd(void *, size_t);
 
 #endif
Index: kernel/generic/include/mm/page.h
===================================================================
--- kernel/generic/include/mm/page.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/include/mm/page.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -66,5 +66,6 @@
 extern uintptr_t hw_map(uintptr_t, size_t);
 
-extern sysarg_t sys_page_find_mapping(uintptr_t, uintptr_t *);
+extern int page_find_mapping(uintptr_t, void **);
+extern sysarg_t sys_page_find_mapping(uintptr_t, void *);
 
 #endif
Index: kernel/generic/include/synch/smc.h
===================================================================
--- kernel/generic/include/synch/smc.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/include/synch/smc.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -36,5 +36,5 @@
 #define KERN_SMC_H_
 
-extern sysarg_t sys_smc_coherence(uintptr_t va, size_t size);
+extern sysarg_t sys_smc_coherence(uintptr_t, size_t);
 
 #endif
Index: kernel/generic/include/syscall/syscall.h
===================================================================
--- kernel/generic/include/syscall/syscall.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/include/syscall/syscall.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -45,5 +45,5 @@
 extern sysarg_t syscall_handler(sysarg_t, sysarg_t, sysarg_t, sysarg_t,
     sysarg_t, sysarg_t, sysarg_t);
-extern sysarg_t sys_tls_set(sysarg_t);
+extern sysarg_t sys_tls_set(uintptr_t);
 
 #endif
Index: kernel/generic/src/ddi/ddi.c
===================================================================
--- kernel/generic/src/ddi/ddi.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/src/ddi/ddi.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -45,4 +45,5 @@
 #include <mm/frame.h>
 #include <mm/as.h>
+#include <mm/page.h>
 #include <synch/mutex.h>
 #include <syscall/copy.h>
@@ -52,4 +53,5 @@
 #include <errno.h>
 #include <trace.h>
+#include <bitops.h>
 
 /** This lock protects the parea_btree. */
@@ -87,25 +89,26 @@
 /** Map piece of physical memory into virtual address space of current task.
  *
- * @param pf    Physical address of the starting frame.
- * @param vp    Virtual address of the starting page.
+ * @param phys  Physical address of the starting frame.
+ * @param virt  Virtual address of the starting page.
  * @param pages Number of pages to map.
  * @param flags Address space area flags for the mapping.
  *
- * @return 0 on success, EPERM if the caller lacks capabilities to use this
- *         syscall, EBADMEM if pf or vf is not page aligned, ENOENT if there
- *         is no task matching the specified ID or the physical address space
- *         is not enabled for mapping and ENOMEM if there was a problem in
- *         creating address space area.
- *
- */
-NO_TRACE static int ddi_physmem_map(uintptr_t pf, uintptr_t vp, size_t pages,
+ * @return EOK on success.
+ * @return EPERM if the caller lacks capabilities to use this syscall.
+ * @return EBADMEM if phys or virt is not page aligned.
+ * @return ENOENT if there is no task matching the specified ID or
+ *         the physical address space is not enabled for mapping.
+ * @return ENOMEM if there was a problem in creating address space area.
+ *
+ */
+NO_TRACE static int ddi_physmem_map(uintptr_t phys, uintptr_t virt, size_t pages,
     unsigned int flags)
 {
 	ASSERT(TASK);
 	
-	if ((pf % FRAME_SIZE) != 0)
+	if ((phys % FRAME_SIZE) != 0)
 		return EBADMEM;
 	
-	if ((vp % PAGE_SIZE) != 0)
+	if ((virt % PAGE_SIZE) != 0)
 		return EBADMEM;
 	
@@ -118,5 +121,5 @@
 	
 	mem_backend_data_t backend_data;
-	backend_data.base = pf;
+	backend_data.base = phys;
 	backend_data.frames = pages;
 	
@@ -129,5 +132,5 @@
 	btree_node_t *nodep;
 	parea_t *parea = (parea_t *) btree_search(&parea_btree,
-	    (btree_key_t) pf, &nodep);
+	    (btree_key_t) phys, &nodep);
 	
 	if ((parea != NULL) && (parea->frames >= pages)) {
@@ -149,5 +152,5 @@
 	
 	irq_spinlock_lock(&zones.lock, true);
-	size_t znum = find_zone(ADDR2PFN(pf), pages, 0);
+	size_t znum = find_zone(ADDR2PFN(phys), pages, 0);
 	
 	if (znum == (size_t) -1) {
@@ -182,5 +185,5 @@
 	
 map:
-	if (!as_area_create(TASK->as, flags, pages * PAGE_SIZE, vp,
+	if (!as_area_create(TASK->as, flags, FRAMES2SIZE(pages), virt,
 	    AS_AREA_ATTR_NONE, &phys_backend, &backend_data)) {
 		/*
@@ -253,6 +256,6 @@
 /** Wrapper for SYS_PHYSMEM_MAP syscall.
  *
- * @param phys_base Physical base address to map
- * @param virt_base Destination virtual address
+ * @param phys  Physical base address to map
+ * @param virt  Destination virtual address
  * @param pages Number of pages
  * @param flags Flags of newly mapped pages
@@ -261,10 +264,10 @@
  *
  */
-sysarg_t sys_physmem_map(sysarg_t phys_base, sysarg_t virt_base,
-    sysarg_t pages, sysarg_t flags)
-{
-	return (sysarg_t) ddi_physmem_map(ALIGN_DOWN((uintptr_t) phys_base,
-	    FRAME_SIZE), ALIGN_DOWN((uintptr_t) virt_base, PAGE_SIZE),
-	    (size_t) pages, (int) flags);
+sysarg_t sys_physmem_map(uintptr_t phys, uintptr_t virt,
+    size_t pages, unsigned int flags)
+{
+	return (sysarg_t)
+	    ddi_physmem_map(ALIGN_DOWN(phys, FRAME_SIZE),
+	    ALIGN_DOWN(virt, PAGE_SIZE), pages, flags);
 }
 
@@ -287,4 +290,74 @@
 }
 
+NO_TRACE static int dmamem_map(uintptr_t virt, size_t size,
+    unsigned int map_flags, unsigned int flags, void **phys)
+{
+	ASSERT(TASK);
+	
+	if ((flags & DMAMEM_FLAGS_ANONYMOUS) == 0) {
+		// TODO: implement locking of non-anonymous mapping
+		return page_find_mapping(virt, phys);
+	} else {
+		// TODO: implement locking
+		
+		if ((virt % PAGE_SIZE) != 0)
+			return EBADMEM;
+		
+		size_t pages = SIZE2FRAMES(size);
+		uint8_t order;
+		
+		/* We need the 2^order >= pages */
+		if (pages == 1)
+			order = 0;
+		else
+			order = fnzb(pages - 1) + 1;
+		
+		*phys = frame_alloc_noreserve(order, 0);
+		if (*phys == NULL)
+			return ENOMEM;
+		
+		mem_backend_data_t backend_data;
+		backend_data.base = (uintptr_t) *phys;
+		backend_data.frames = pages;
+		
+		if (!as_area_create(TASK->as, map_flags, size, virt,
+		    AS_AREA_ATTR_NONE, &phys_backend, &backend_data)) {
+			frame_free_noreserve((uintptr_t) *phys);
+			return ENOMEM;
+		}
+		
+		return EOK;
+	}
+}
+
+NO_TRACE static int dmamem_unmap(uintptr_t virt, size_t size,
+    unsigned int flags)
+{
+	// TODO: implement unlocking & unmap
+	return EOK;
+}
+
+sysarg_t sys_dmamem_map(uintptr_t virt, size_t size, unsigned int map_flags,
+    unsigned int flags, void *phys_ptr)
+{
+	void *phys;
+	int rc = dmamem_map(virt, size, map_flags, flags, &phys);
+	if (rc != EOK)
+		return rc;
+	
+	rc = copy_to_uspace(phys_ptr, &phys, sizeof(phys));
+	if (rc != EOK) {
+		dmamem_unmap(virt, size, flags);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+sysarg_t sys_dmamem_unmap(uintptr_t virt, size_t size, unsigned int flags)
+{
+	return dmamem_unmap(virt, size, flags);
+}
+
 /** @}
  */
Index: kernel/generic/src/ipc/irq.c
===================================================================
--- kernel/generic/src/ipc/irq.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/src/ipc/irq.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -365,26 +365,15 @@
 		return IRQ_DECLINE;
 	
-#define CMD_MEM_READ(target) \
-do { \
-	void *va = code->cmds[i].addr; \
-	if (AS != irq->driver_as) \
-		as_switch(AS, irq->driver_as); \
-	memcpy_from_uspace(&target, va, (sizeof(target))); \
-	if (dstarg) \
-		scratch[dstarg] = target; \
-} while(0)
-
-#define CMD_MEM_WRITE(val) \
-do { \
-	void *va = code->cmds[i].addr; \
-	if (AS != irq->driver_as) \
-		as_switch(AS, irq->driver_as); \
-	memcpy_to_uspace(va, &val, sizeof(val)); \
-} while (0)
-
 	as_t *current_as = AS;
-	size_t i;
-	for (i = 0; i < code->cmdcount; i++) {
+	if (current_as != irq->driver_as)
+		as_switch(AS, irq->driver_as);
+	
+	for (size_t i = 0; i < code->cmdcount; i++) {
 		uint32_t dstval;
+		void *va;
+		uint8_t val8;
+		uint16_t val16;
+		uint32_t val32;
+		
 		uintptr_t srcarg = code->cmds[i].srcarg;
 		uintptr_t dstarg = code->cmds[i].dstarg;
@@ -442,50 +431,56 @@
 			}
 			break;
-		case CMD_MEM_READ_8: {
-			uint8_t val;
-			CMD_MEM_READ(val);
-			break;
-			}
-		case CMD_MEM_READ_16: {
-			uint16_t val;
-			CMD_MEM_READ(val);
-			break;
-			}
-		case CMD_MEM_READ_32: {
-			uint32_t val;
-			CMD_MEM_READ(val);
-			break;
-			}
-		case CMD_MEM_WRITE_8: {
-			uint8_t val = code->cmds[i].value;
-			CMD_MEM_WRITE(val);
-			break;
-			}
-		case CMD_MEM_WRITE_16: {
-			uint16_t val = code->cmds[i].value;
-			CMD_MEM_WRITE(val);
-			break;
-			}
-		case CMD_MEM_WRITE_32: {
-			uint32_t val = code->cmds[i].value;
-			CMD_MEM_WRITE(val);
-			break;
-			}
+		case CMD_MEM_READ_8:
+			va = code->cmds[i].addr;
+			memcpy_from_uspace(&val8, va, sizeof(val8));
+			if (dstarg)
+				scratch[dstarg] = val8;
+			break;
+		case CMD_MEM_READ_16:
+			va = code->cmds[i].addr;
+			memcpy_from_uspace(&val16, va, sizeof(val16));
+			if (dstarg)
+				scratch[dstarg] = val16;
+			break;
+		case CMD_MEM_READ_32:
+			va = code->cmds[i].addr;
+			memcpy_from_uspace(&val32, va, sizeof(val32));
+			if (dstarg)
+				scratch[dstarg] = val32;
+			break;
+		case CMD_MEM_WRITE_8:
+			val8 = code->cmds[i].value;
+			va = code->cmds[i].addr;
+			memcpy_to_uspace(va, &val8, sizeof(val8));
+			break;
+		case CMD_MEM_WRITE_16:
+			val16 = code->cmds[i].value;
+			va = code->cmds[i].addr;
+			memcpy_to_uspace(va, &val16, sizeof(val16));
+			break;
+		case CMD_MEM_WRITE_32:
+			val32 = code->cmds[i].value;
+			va = code->cmds[i].addr;
+			memcpy_to_uspace(va, &val32, sizeof(val32));
+			break;
 		case CMD_MEM_WRITE_A_8:
 			if (srcarg) {
-				uint8_t val = scratch[srcarg];
-				CMD_MEM_WRITE(val);
+				val8 = scratch[srcarg];
+				va = code->cmds[i].addr;
+				memcpy_to_uspace(va, &val8, sizeof(val8));
 			}
 			break;
 		case CMD_MEM_WRITE_A_16:
 			if (srcarg) {
-				uint16_t val = scratch[srcarg];
-				CMD_MEM_WRITE(val);
+				val16 = scratch[srcarg];
+				va = code->cmds[i].addr;
+				memcpy_to_uspace(va, &val16, sizeof(val16));
 			}
 			break;
 		case CMD_MEM_WRITE_A_32:
 			if (srcarg) {
-				uint32_t val = scratch[srcarg];
-				CMD_MEM_WRITE(val);
+				val32 = scratch[srcarg];
+				va = code->cmds[i].addr;
+				memcpy_to_uspace(va, &val32, sizeof(val32));
 			}
 			break;
@@ -513,4 +508,5 @@
 		}
 	}
+	
 	if (AS != current_as)
 		as_switch(AS, current_as);
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/src/ipc/sysipc.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -278,5 +278,5 @@
 		}
 	} else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_IN) {
-		if (!IPC_GET_RETVAL(answer->data)) { 
+		if (!IPC_GET_RETVAL(answer->data)) {
 			irq_spinlock_lock(&answer->sender->lock, true);
 			as_t *as = answer->sender->as;
Index: kernel/generic/src/lib/rd.c
===================================================================
--- kernel/generic/src/lib/rd.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/src/lib/rd.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -33,5 +33,5 @@
 /**
  * @file
- * @brief	RAM disk support.
+ * @brief RAM disk support.
  *
  * Support for RAM disk images.
@@ -39,66 +39,31 @@
 
 #include <lib/rd.h>
-#include <byteorder.h>
 #include <mm/frame.h>
 #include <sysinfo/sysinfo.h>
 #include <ddi/ddi.h>
-#include <align.h>
 
-static parea_t rd_parea;		/**< Physical memory area for rd. */
+/** Physical memory area for RAM disk. */
+static parea_t rd_parea;
 
-/**
- * RAM disk initialization routine. At this point, the RAM disk memory is shared
- * and information about the share is provided as sysinfo values to the
- * userspace tasks.
- */  
-int init_rd(rd_header_t *header, size_t size)
+/** RAM disk initialization routine
+ *
+ * The information about the RAM disk is provided as sysinfo
+ * values to the uspace tasks.
+ *
+ */
+void init_rd(void *data, size_t size)
 {
-	/* Identify RAM disk */
-	if ((header->magic[0] != RD_MAG0) || (header->magic[1] != RD_MAG1) ||
-	    (header->magic[2] != RD_MAG2) || (header->magic[3] != RD_MAG3))
-		return RE_INVALID;
+	uintptr_t base = KA2PA((uintptr_t) data);
+	ASSERT((base % FRAME_SIZE) == 0);
 	
-	/* Identify version */	
-	if (header->version != RD_VERSION)
-		return RE_UNSUPPORTED;
-	
-	uint32_t hsize;
-	uint64_t dsize;
-	switch (header->data_type) {
-	case RD_DATA_LSB:
-		hsize = uint32_t_le2host(header->header_size);
-		dsize = uint64_t_le2host(header->data_size);
-		break;
-	case RD_DATA_MSB:
-		hsize = uint32_t_be2host(header->header_size);
-		dsize = uint64_t_be2host(header->data_size);
-		break;
-	default:
-		return RE_UNSUPPORTED;
-	}
-	
-	if ((hsize % FRAME_SIZE) || (dsize % FRAME_SIZE))
-		return RE_UNSUPPORTED;
-		
-	if (hsize > size)
-		return RE_INVALID;
-	
-	if ((uint64_t) hsize + dsize > size)
-		dsize = size - hsize;
-	
-	rd_parea.pbase = ALIGN_DOWN((uintptr_t) KA2PA((void *) header + hsize),
-	    FRAME_SIZE);
-	rd_parea.frames = SIZE2FRAMES(dsize);
+	rd_parea.pbase = base;
+	rd_parea.frames = SIZE2FRAMES(size);
 	rd_parea.unpriv = false;
 	rd_parea.mapped = false;
 	ddi_parea_register(&rd_parea);
-
+	
 	sysinfo_set_item_val("rd", NULL, true);
-	sysinfo_set_item_val("rd.header_size", NULL, hsize);	
-	sysinfo_set_item_val("rd.size", NULL, dsize);
-	sysinfo_set_item_val("rd.address.physical", NULL,
-	    (sysarg_t) KA2PA((void *) header + hsize));
-
-	return RE_OK;
+	sysinfo_set_item_val("rd.size", NULL, size);
+	sysinfo_set_item_val("rd.address.physical", NULL, (sysarg_t) base);
 }
 
Index: kernel/generic/src/main/kinit.c
===================================================================
--- kernel/generic/src/main/kinit.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/src/main/kinit.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -179,5 +179,5 @@
 	for (i = 0; i < init.cnt; i++) {
 		if (init.tasks[i].addr % FRAME_SIZE) {
-			printf("init[%zu].addr is not frame aligned\n", i);
+			printf("init[%zu]: Address is not frame aligned\n", i);
 			programs[i].task = NULL;
 			continue;
@@ -203,22 +203,28 @@
 		    namebuf, &programs[i]);
 		
-		if ((rc == 0) && (programs[i].task != NULL)) {
+		if (rc == 0) {
+			if (programs[i].task != NULL) {
+				/*
+				 * Set capabilities to init userspace tasks.
+				 */
+				cap_set(programs[i].task, CAP_CAP | CAP_MEM_MANAGER |
+				    CAP_IO_MANAGER | CAP_IRQ_REG);
+				
+				if (!ipc_phone_0)
+					ipc_phone_0 = &programs[i].task->answerbox;
+			}
+			
 			/*
-			 * Set capabilities to init userspace tasks.
+			 * If programs[i].task == NULL then it is
+			 * the program loader and it was registered
+			 * successfully.
 			 */
-			cap_set(programs[i].task, CAP_CAP | CAP_MEM_MANAGER |
-			    CAP_IO_MANAGER | CAP_IRQ_REG);
-			
-			if (!ipc_phone_0)
-				ipc_phone_0 = &programs[i].task->answerbox;
-		} else if (rc == 0) {
-			/* It was the program loader and was registered */
-		} else {
-			/* RAM disk image */
-			int rd = init_rd((rd_header_t *) init.tasks[i].addr, init.tasks[i].size);
-			
-			if (rd != RE_OK)
-				printf("Init binary %zu not used (error %d)\n", i, rd);
-		}
+		} else if (i == init.cnt - 1) {
+			/*
+			 * Assume the last task is the RAM disk.
+			 */
+			init_rd((void *) init.tasks[i].addr, init.tasks[i].size);
+		} else
+			printf("init[%zu]: Init binary load failed (error %d)\n", i, rc);
 	}
 	
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/src/main/main.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -268,6 +268,6 @@
 	 * Create the first thread.
 	 */
-	thread_t *kinit_thread
-		= thread_create(kinit, NULL, kernel, 0, "kinit", true);
+	thread_t *kinit_thread =
+	    thread_create(kinit, NULL, kernel, 0, "kinit", true);
 	if (!kinit_thread)
 		panic("Cannot create kinit thread.");
Index: kernel/generic/src/mm/page.c
===================================================================
--- kernel/generic/src/mm/page.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/src/mm/page.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -53,5 +53,5 @@
  * We assume that the other processors are either not using the mapping yet
  * (i.e. during the bootstrap) or are executing the TLB shootdown code.  While
- * we don't care much about the former case, the processors in the latter case 
+ * we don't care much about the former case, the processors in the latter case
  * will do an implicit serialization by virtue of running the TLB shootdown
  * interrupt handler.
@@ -198,34 +198,37 @@
 }
 
+int page_find_mapping(uintptr_t virt, void **phys)
+{
+	mutex_lock(&AS->lock);
+	
+	pte_t *pte = page_mapping_find(AS, virt, false);
+	if ((!PTE_VALID(pte)) || (!PTE_PRESENT(pte))) {
+		mutex_unlock(&AS->lock);
+		return ENOENT;
+	}
+	
+	*phys = (void *) PTE_GET_FRAME(pte) +
+	    (virt - ALIGN_DOWN(virt, PAGE_SIZE));
+	
+	mutex_unlock(&AS->lock);
+	
+	return EOK;
+}
 
 /** Syscall wrapper for getting mapping of a virtual page.
- * 
- * @retval EOK Everything went find, @p uspace_frame and @p uspace_node
- *             contains correct values.
- * @retval ENOENT Virtual address has no mapping.
- */
-sysarg_t sys_page_find_mapping(uintptr_t virt_address,
-    uintptr_t *uspace_frame)
-{
-	mutex_lock(&AS->lock);
-	
-	pte_t *pte = page_mapping_find(AS, virt_address, false);
-	if (!PTE_VALID(pte) || !PTE_PRESENT(pte)) {
-		mutex_unlock(&AS->lock);
-		
-		return (sysarg_t) ENOENT;
-	}
-	
-	uintptr_t phys_address = PTE_GET_FRAME(pte);
-	
-	mutex_unlock(&AS->lock);
-	
-	int rc = copy_to_uspace(uspace_frame,
-	    &phys_address, sizeof(phys_address));
-	if (rc != EOK) {
-		return (sysarg_t) rc;
-	}
-	
-	return EOK;
+ *
+ * @return EOK on success.
+ * @return ENOENT if no virtual address mapping found.
+ *
+ */
+sysarg_t sys_page_find_mapping(uintptr_t virt, void *phys_ptr)
+{
+	void *phys;
+	int rc = page_find_mapping(virt, &phys);
+	if (rc != EOK)
+		return rc;
+	
+	rc = copy_to_uspace(phys_ptr, &phys, sizeof(phys));
+	return (sysarg_t) rc;
 }
 
Index: kernel/generic/src/syscall/syscall.c
===================================================================
--- kernel/generic/src/syscall/syscall.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ kernel/generic/src/syscall/syscall.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -176,4 +176,6 @@
 	(syshandler_t) sys_device_assign_devno,
 	(syshandler_t) sys_physmem_map,
+	(syshandler_t) sys_dmamem_map,
+	(syshandler_t) sys_dmamem_unmap,
 	(syshandler_t) sys_iospace_enable,
 	(syshandler_t) sys_register_irq,
Index: tools/config.py
===================================================================
--- tools/config.py	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ tools/config.py	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -85,4 +85,5 @@
 	if ctype == 'cnf':
 		return True
+	
 	return False
 
@@ -242,5 +243,5 @@
 		
 		default = get_default_rule(rule)
-
+		
 		#
 		# If we don't have a value but we do have
@@ -344,4 +345,20 @@
 	return True
 
+def preprocess_config(config, rules):
+	"Preprocess configuration"
+	
+	varname_mode = 'CONFIG_BFB_MODE'
+	varname_width = 'CONFIG_BFB_WIDTH'
+	varname_height = 'CONFIG_BFB_HEIGHT'
+	
+	if varname_mode in config:
+		mode = config[varname_mode].partition('x')
+		
+		config[varname_width] = mode[0]
+		rules.append((varname_width, 'choice', 'Default framebuffer width', None, None))
+		
+		config[varname_height] = mode[2]
+		rules.append((varname_height, 'choice', 'Default framebuffer height', None, None))
+
 def create_output(mkname, mcname, config, rules):
 	"Create output configuration"
@@ -504,4 +521,5 @@
 	if (len(sys.argv) >= 3) and (sys.argv[2] == 'default'):
 		if (infer_verify_choices(config, rules)):
+			preprocess_config(config, rules)
 			create_output(MAKEFILE, MACROS, config, rules)
 			return 0
@@ -517,4 +535,5 @@
 		
 		if (infer_verify_choices(config, rules)):
+			preprocess_config(config, rules)
 			create_output(MAKEFILE, MACROS, config, rules)
 			return 0
@@ -564,5 +583,5 @@
 				
 				default = get_default_rule(rule)
-
+				
 				#
 				# If we don't have a value but we do have
@@ -626,4 +645,5 @@
 		xtui.screen_done(screen)
 	
+	preprocess_config(config, rules)
 	create_output(MAKEFILE, MACROS, config, rules)
 	return 0
Index: ols/mkhord.py
===================================================================
--- tools/mkhord.py	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ 	(revision )
@@ -1,105 +1,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2008 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.
-#
-
-"""
-HORD encapsulator
-"""
-
-import sys
-import os
-import xstruct
-
-HEADER = """little:
-	char tag[4]            /* 'HORD' */
-	uint8_t version        /* version */
-	uint8_t encoding       /* encoding */
-	uint32_t header_size   /* header size */
-	uint64_t payload_size  /* payload size */
-"""
-
-HORD_LSB = 1
-
-def align_up(size, alignment):
-	"Align upwards to a given alignment"
-	return (((size) + ((alignment) - 1)) & ~((alignment) - 1))
-
-def usage(prname):
-	"Print usage syntax"
-	print(prname + " <ALIGNMENT> <FS_IMAGE> <HORD_IMAGE>")
-
-def main():
-	if (len(sys.argv) < 4):
-		usage(sys.argv[0])
-		return
-	
-	if (not sys.argv[1].isdigit()):
-		print("<ALIGNMENT> must be a number")
-		return
-	
-	align = int(sys.argv[1], 0)
-	if (align <= 0):
-		print("<ALIGNMENT> must be positive")
-		return
-	
-	fs_image = os.path.abspath(sys.argv[2])
-	if (not os.path.isfile(fs_image)):
-		print("<FS_IMAGE> must be a file")
-		return
-	
-	inf = open(fs_image, "rb")
-	outf = open(sys.argv[3], "wb")
-	
-	header = xstruct.create(HEADER)
-	
-	header_size = header.size()
-	payload_size = os.path.getsize(fs_image)
-	
-	header_size_aligned = align_up(header_size, align)
-	payload_size_aligned = align_up(payload_size, align)
-	
-	header.tag = b"HORD"
-	header.version = 1
-	header.encoding = HORD_LSB
-	header.header_size = header_size_aligned
-	header.payload_size = payload_size_aligned
-	
-	outf.write(header.pack())
-	outf.write(xstruct.create("little: padding[%d]" % (header_size_aligned - header_size)).pack())
-	
-	outf.write(inf.read())
-	
-	padding = payload_size_aligned - payload_size
-	if (padding > 0):
-		outf.write(xstruct.create("little: padding[%d]" % padding).pack())
-	
-	inf.close()
-	outf.close()
-
-if __name__ == '__main__':
-	main()
Index: tools/toolchain.sh
===================================================================
--- tools/toolchain.sh	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ tools/toolchain.sh	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -55,5 +55,5 @@
 BINUTILS_VERSION="2.21.1"
 BINUTILS_RELEASE="a"
-GCC_VERSION="4.6.1"
+GCC_VERSION="4.6.2"
 GDB_VERSION="7.3.1"
 
@@ -275,7 +275,7 @@
 	
 	download_fetch "${BINUTILS_SOURCE}" "${BINUTILS}" "bde820eac53fa3a8d8696667418557ad"
-	download_fetch "${GCC_SOURCE}" "${GCC_CORE}" "0c0e7e35d2215e19de9c97efba507553"
-	download_fetch "${GCC_SOURCE}" "${GCC_OBJC}" "cbf0d4b701827922cf37ba6a4ace0079"
-	download_fetch "${GCC_SOURCE}" "${GCC_CPP}" "0d75ca7ca35b1e7f252223f9d23a6ad1"
+	download_fetch "${GCC_SOURCE}" "${GCC_CORE}" "780f614ab18c7a9066dec6387d7490b2"
+	download_fetch "${GCC_SOURCE}" "${GCC_OBJC}" "94043cc0d08394eddebed73f30ecad89"
+	download_fetch "${GCC_SOURCE}" "${GCC_CPP}" "87ecd60431e41096419dd8a10f76e46b"
 	download_fetch "${GDB_SOURCE}" "${GDB}" "b89a5fac359c618dda97b88645ceab47"
 }
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -64,4 +64,5 @@
 	app/nettest1 \
 	app/nettest2 \
+	app/nettest3 \
 	app/ping \
 	app/websrv \
@@ -118,5 +119,6 @@
 	drv/bus/usb/vhc \
 	drv/nic/lo \
-	drv/nic/ne2k
+	drv/nic/ne2k \
+	drv/nic/e1k
 
 ifeq ($(CONFIG_PCC),y)
Index: uspace/app/bdsh/cmds/modules/mount/mount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -27,4 +27,5 @@
  */
 
+#include <loc.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -67,7 +68,9 @@
 {
 	LIST_INITIALIZE(mtab_list);
+	mtab_ent_t *old_ent = NULL;
+	char *svc_name;
+	int rc;
+
 	get_mtab_list(&mtab_list);
-
-	mtab_ent_t *old_ent = NULL;
 
 	list_foreach(mtab_list, cur) {
@@ -83,10 +86,19 @@
 		if (mtab_ent->instance)
 			printf("/%d", mtab_ent->instance);
-		printf(" on %s ", mtab_ent->mp);
+
+		printf(" %s", mtab_ent->mp);
+
+		rc = loc_service_get_name(mtab_ent->service_id, &svc_name);
+		if (rc == EOK) {
+			printf(" %s", svc_name);
+			free(svc_name);
+		} else {
+			printf(" (%" PRIun ")", mtab_ent->service_id);
+		}
 
 		if (str_size(mtab_ent->opts) > 0)
-			printf("opts=%s ", mtab_ent->opts);
+			printf(" (%s)", mtab_ent->opts);
 
-		printf("(service=%" PRIun ")\n", mtab_ent->service_id);
+		putchar('\n');
 	}
 
Index: uspace/app/locinfo/locinfo.c
===================================================================
--- uspace/app/locinfo/locinfo.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/app/locinfo/locinfo.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -89,4 +89,5 @@
 			}
 			printf("\t%s (%" PRIun ")\n", svc_name, svc_ids[j]);
+			free(svc_name);
 		}
 
Index: uspace/app/netecho/netecho.c
===================================================================
--- uspace/app/netecho/netecho.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/app/netecho/netecho.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -241,4 +241,6 @@
 		/* Accept a socket if a stream socket is used */
 		addrlen = sizeof(address_buf);
+		if (verbose)
+			printf("accept()\n");
             	socket_id = accept(listening_id, (void *) address_buf, &addrlen);
 		if (socket_id <= 0) {
@@ -258,4 +260,6 @@
 
 		/* Receive a message to echo */
+		if (verbose)
+			printf("recvfrom()\n");
 		rcv_size = recvfrom(socket_id, data, size, 0, address,
 		    &addrlen);
@@ -297,7 +301,17 @@
 
 			/* 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");
+			if (type == SOCK_STREAM) {
+				if (verbose)
+					printf("send()\n");
+				rc = send(socket_id, reply ? reply : data, reply ? reply_length : length, 0);
+				if (rc != EOK)
+					socket_print_error(stderr, rc, "Socket send: ", "\n");
+			} else {
+				if (verbose)
+					printf("sendto()\n");
+				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");
+			}
 		}
 
Index: uspace/app/nettest3/Makefile
===================================================================
--- uspace/app/nettest3/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/app/nettest3/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2011 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 = nettest3
+
+SOURCES = \
+	nettest3.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/nettest3/nettest3.c
===================================================================
--- uspace/app/nettest3/nettest3.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/app/nettest3/nettest3.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2011 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 nettest
+ * @{
+ */
+
+/** @file
+ * Networking test 3.
+ */
+
+#include <async.h>
+#include <stdio.h>
+#include <str.h>
+
+#include <net/in.h>
+#include <net/in6.h>
+#include <net/inet.h>
+#include <net/socket.h>
+
+#define BUF_SIZE 32
+
+static char *data;
+static size_t size;
+
+static char buf[BUF_SIZE];
+
+static struct sockaddr_in addr;
+
+static uint16_t port;
+
+int main(int argc, char *argv[])
+{
+	int rc;
+	int fd;
+	char *endptr;
+
+	port = 7;
+
+	data = (char *)"Hello World!";
+	size = str_size(data);
+
+	/* Connect to local IP address by default */
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	addr.sin_addr.s_addr = htonl(0x7f000001);
+
+	if (argc >= 2) {
+		printf("parsing address '%s'\n", argv[1]);
+		rc = inet_pton(AF_INET, argv[1], (uint8_t *)&addr.sin_addr.s_addr);
+		if (rc != EOK) {
+			fprintf(stderr, "Error parsing address\n");
+			return 1;
+		}
+		printf("result: rc=%d, family=%d, addr=%x\n", rc,
+		    addr.sin_family, addr.sin_addr.s_addr);
+	}
+
+	if (argc >= 3) {
+		printf("parsing port '%s'\n", argv[2]);
+		addr.sin_port = htons(strtoul(argv[2], &endptr, 10));
+		if (*endptr != '\0') {
+			fprintf(stderr, "Error parsing port\n");
+			return 1;
+		}
+	}
+
+	printf("socket()\n");
+	fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+	printf(" -> %d\n", fd);
+	if (fd < 0)
+		return 1;
+
+	printf("connect()\n");
+	rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+	printf(" -> %d\n", rc);
+	if (rc != 0)
+		return 1;
+
+	printf("send()\n");
+	rc = send(fd, data, size, 0);
+	printf(" -> %d\n", rc);
+	if (rc < 0)
+		return 1;
+
+	do {
+		printf("recv()\n");
+		rc = recv(fd, buf, BUF_SIZE, 0);
+		printf(" -> %d\n", rc);
+	} while (rc > 0);
+
+	async_usleep(1000*1000);
+
+	printf("closesocket()\n");
+	rc = closesocket(fd);
+	printf(" -> %d\n", rc);
+
+	return 0;
+}
+
+
+/** @}
+ */
Index: uspace/app/tester/mm/mapping1.c
===================================================================
--- uspace/app/tester/mm/mapping1.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/app/tester/mm/mapping1.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -71,5 +71,5 @@
 	int i;
 	for (i = 0; i < page_count; i++) {
-		void *page_start = ((char *)area) + PAGE_SIZE * i;
+		void *page_start = ((char *) area) + PAGE_SIZE * i;
 		int rc = as_get_physical_mapping(page_start, NULL);
 		if (rc != expected_rc) {
Index: uspace/app/websrv/websrv.c
===================================================================
--- uspace/app/websrv/websrv.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/app/websrv/websrv.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -31,8 +31,14 @@
  */
 /**
- * @file (Less-than-skeleton) web server.
+ * @file Skeletal web server.
  */
 
+#include <bool.h>
+#include <errno.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <fcntl.h>
 
 #include <net/in.h>
@@ -44,13 +50,194 @@
 #define PORT_NUMBER 8080
 
+#define WEB_ROOT "/data/web"
+
 /** Buffer for receiving the request. */
 #define BUFFER_SIZE 1024
-static char buf[BUFFER_SIZE];
+static char rbuf[BUFFER_SIZE];
+static size_t rbuf_out, rbuf_in;
+
+static char lbuf[BUFFER_SIZE + 1];
+static size_t lbuf_used;
+
+static char fbuf[BUFFER_SIZE];
 
 /** Response to send to client. */
-static const char *response_msg =
+static const char *ok_msg =
     "HTTP/1.0 200 OK\r\n"
-    "\r\n"
-    "<h1>Hello from HelenOS!</h1>\r\n";
+    "\r\n";
+
+/** Receive one character (with buffering) */
+static int recv_char(int fd, char *c)
+{
+	ssize_t rc;
+
+	if (rbuf_out == rbuf_in) {
+		rbuf_out = 0;
+		rbuf_in = 0;
+
+		rc = recv(fd, rbuf, BUFFER_SIZE, 0);
+		if (rc <= 0) {
+			printf("recv() failed (%zd)\n", rc);
+			return rc;
+		}
+
+		rbuf_in = rc;
+	}
+
+	*c = rbuf[rbuf_out++];
+	return EOK;
+}
+
+/** Receive one line with length limit. */
+static int recv_line(int fd)
+{
+	char c, prev;
+	int rc;
+	char *bp;
+
+	bp = lbuf; c = '\0';
+	while (bp < lbuf + BUFFER_SIZE) {
+		prev = c;
+		rc = recv_char(fd, &c);
+		if (rc != EOK)
+			return rc;
+
+		*bp++ = c;
+		if (prev == '\r' && c == '\n')
+			break;
+	}
+
+	lbuf_used = bp - lbuf;
+	*bp = '\0';
+
+	if (bp == lbuf + BUFFER_SIZE)
+		return ELIMIT;
+
+	return EOK;
+}
+
+static bool uri_is_valid(char *uri)
+{
+	char *cp;
+	char c;
+
+	if (uri[0] != '/')
+		return false;
+	if (uri[1] == '.')
+		return false;
+
+	cp = uri + 1;
+	while (*cp != '\0') {
+		c = *cp++;
+		if (c == '/')
+			return false;
+	}
+
+	return true;
+}
+
+static int send_response(int conn_sd, const char *msg)
+{
+	size_t response_size;
+	ssize_t rc;
+
+	response_size = str_size(msg);
+
+	/* Send a canned response. */
+        printf("Send response...\n");
+	rc = send(conn_sd, (void *) msg, response_size, 0);
+	if (rc < 0) {
+		printf("send() failed.\n");
+		return rc;
+	}
+
+	return EOK;
+}
+
+static int uri_get(const char *uri, int conn_sd)
+{
+	int rc;
+	char *fname;
+	int fd;
+	ssize_t nr;
+
+	if (str_cmp(uri, "/") == 0)
+		uri = "/index.htm";
+
+	rc = asprintf(&fname, "%s%s", WEB_ROOT, uri);
+	if (rc < 0)
+		return ENOMEM;
+
+	fd = open(fname, O_RDONLY);
+	if (fd < 0) {
+		printf("File '%s' not found.\n", fname);
+		free(fname);
+		return ENOENT;
+	}
+
+	free(fname);
+
+	rc = send_response(conn_sd, ok_msg);
+	if (rc != EOK)
+		return rc;
+
+	while (true) {
+		nr = read(fd, fbuf, BUFFER_SIZE);
+		if (nr == 0)
+			break;
+
+		if (nr < 0) {
+			close(fd);
+			return EIO;
+		}
+
+		rc = send(conn_sd, fbuf, nr, 0);
+		if (rc < 0) {
+			printf("send() failed\n");
+			close(fd);
+			return rc;
+		}
+	}
+
+	close(fd);
+
+	return EOK;
+}
+
+static int req_process(int conn_sd)
+{
+	int rc;
+	char *uri, *end_uri;
+
+	rc = recv_line(conn_sd);
+	if (rc != EOK) {
+		printf("recv_line() failed\n");
+		return rc;
+	}
+
+	printf("%s", lbuf);
+
+	if (str_lcmp(lbuf, "GET ", 4) != 0) {
+		printf("Invalid HTTP method.\n");
+		return EINVAL;
+	}
+
+	uri = lbuf + 4;
+	end_uri = str_chr(uri, ' ');
+	if (end_uri == NULL) {
+		end_uri = lbuf + lbuf_used - 2;
+		assert(*end_uri == '\r');
+	}
+
+	*end_uri = '\0';
+	printf("Requested URI '%s'.\n", uri);
+
+	if (!uri_is_valid(uri)) {
+		printf("Invalid request URI.\n");
+		return EINVAL;
+	}
+
+	return uri_get(uri, conn_sd);
+}
 
 int main(int argc, char *argv[])
@@ -64,5 +251,4 @@
 	int rc;
 
-	size_t response_size;
 
 	addr.sin_family = AF_INET;
@@ -94,6 +280,4 @@
 		return 1;
 	}
-
-	response_size = str_size(response_msg);
 
 	printf("Listening for connections at port number %u.\n", PORT_NUMBER);
@@ -105,5 +289,5 @@
 		if (conn_sd < 0) {
 			printf("accept() failed.\n");
-			return 1;
+			continue;
 		}
 
@@ -111,19 +295,9 @@
 
 		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;
-		}
+		rbuf_out = rbuf_in = 0;
+
+		rc = req_process(conn_sd);
+		if (rc != EOK) 
+			printf("Error processing request.\n");
 
 		rc = closesocket(conn_sd);
Index: uspace/dist/data/web/bar.htm
===================================================================
--- uspace/dist/data/web/bar.htm	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/dist/data/web/bar.htm	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,10 @@
+<html>
+    <head>
+	<title>Bar!</title>
+    </head>
+    <body>
+	<h1>Bar!</h1>
+
+	<a href="/">Back to top</a>
+    </body>
+</html>
Index: uspace/dist/data/web/foo.htm
===================================================================
--- uspace/dist/data/web/foo.htm	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/dist/data/web/foo.htm	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,10 @@
+<html>
+    <head>
+	<title>Foo!</title>
+    </head>
+    <body>
+	<h1>Foo!</h1>
+
+	<a href="/">Back to top</a>
+    </body>
+</html>
Index: uspace/dist/data/web/index.htm
===================================================================
--- uspace/dist/data/web/index.htm	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/dist/data/web/index.htm	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,18 @@
+<html>
+    <head>
+        <title>
+    	    Hello from HelenOS!
+        </title>
+    </head>
+    <body>
+        <h1>Hello from HelenOS!</h1>
+        <p>
+            This web page is brought to you by courtesy of HelenOS web server
+    	    and TCP/IP stack.
+        </p>
+	<p>
+    	    Now <a href="foo.htm">go to page foo</a> or <a href="bar.htm">go
+    	    to bar</a>.
+        </p>
+    </body>
+</html>
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/isa/isa.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -108,5 +108,5 @@
 static ddf_dev_ops_t isa_fun_ops;
 
-static int isa_add_device(ddf_dev_t *dev);
+static int isa_dev_add(ddf_dev_t *dev);
 static int isa_dev_remove(ddf_dev_t *dev);
 static int isa_fun_online(ddf_fun_t *fun);
@@ -115,5 +115,5 @@
 /** The isa device driver's standard operations */
 static driver_ops_t isa_ops = {
-	.add_device = &isa_add_device,
+	.dev_add = &isa_dev_add,
 	.dev_remove = &isa_dev_remove,
 	.fun_online = &isa_fun_online,
@@ -494,9 +494,9 @@
 }
 
-static int isa_add_device(ddf_dev_t *dev)
+static int isa_dev_add(ddf_dev_t *dev)
 {
 	isa_bus_t *isa;
 
-	ddf_msg(LVL_DEBUG, "isa_add_device, device handle = %d",
+	ddf_msg(LVL_DEBUG, "isa_dev_add, device handle = %d",
 	    (int) dev->handle);
 
Index: uspace/drv/bus/isa/isa.dev
===================================================================
--- uspace/drv/bus/isa/isa.dev	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/isa/isa.dev	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -13,3 +13,7 @@
 	irq 1
 	io_range 060 10
-	
+
+ne2k:
+	match 100 isa/ne2k
+	irq 5
+	io_range 300 20
Index: uspace/drv/bus/isa/isa.ma
===================================================================
--- uspace/drv/bus/isa/isa.ma	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/isa/isa.ma	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,1 +1,1 @@
-9 	pci/ven=8086&dev=7000
+9 pci/ven=8086&dev=7000
Index: uspace/drv/bus/pci/pciintel/pci.c
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -205,5 +205,5 @@
 };
 
-static int pci_add_device(ddf_dev_t *);
+static int pci_dev_add(ddf_dev_t *);
 static int pci_fun_online(ddf_fun_t *);
 static int pci_fun_offline(ddf_fun_t *);
@@ -211,5 +211,5 @@
 /** PCI bus driver standard operations */
 static driver_ops_t pci_ops = {
-	.add_device = &pci_add_device,
+	.dev_add = &pci_dev_add,
 	.fun_online = &pci_fun_online,
 	.fun_offline = &pci_fun_offline,
@@ -610,5 +610,5 @@
 }
 
-static int pci_add_device(ddf_dev_t *dnode)
+static int pci_dev_add(ddf_dev_t *dnode)
 {
 	pci_bus_t *bus = NULL;
@@ -617,10 +617,10 @@
 	int rc;
 	
-	ddf_msg(LVL_DEBUG, "pci_add_device");
+	ddf_msg(LVL_DEBUG, "pci_dev_add");
 	dnode->parent_sess = NULL;
 	
 	bus = ddf_dev_data_alloc(dnode, sizeof(pci_bus_t));
 	if (bus == NULL) {
-		ddf_msg(LVL_ERROR, "pci_add_device allocation failed.");
+		ddf_msg(LVL_ERROR, "pci_dev_add allocation failed.");
 		rc = ENOMEM;
 		goto fail;
@@ -634,5 +634,5 @@
 	    dnode->handle, IPC_FLAG_BLOCKING);
 	if (!dnode->parent_sess) {
-		ddf_msg(LVL_ERROR, "pci_add_device failed to connect to the "
+		ddf_msg(LVL_ERROR, "pci_dev_add failed to connect to the "
 		    "parent driver.");
 		rc = ENOENT;
@@ -644,5 +644,5 @@
 	rc = hw_res_get_resource_list(dnode->parent_sess, &hw_resources);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "pci_add_device failed to get hw resources "
+		ddf_msg(LVL_ERROR, "pci_dev_add failed to get hw resources "
 		    "for the device.");
 		goto fail;
Index: uspace/drv/bus/pci/pciintel/pci.h
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/pci/pciintel/pci.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
Index: uspace/drv/bus/usb/ehci/Makefile
===================================================================
--- uspace/drv/bus/usb/ehci/Makefile	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/ehci/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -42,5 +42,4 @@
 
 SOURCES = \
-	hc_iface.c \
 	main.c \
 	pci.c
Index: pace/drv/bus/usb/ehci/ehci.h
===================================================================
--- uspace/drv/bus/usb/ehci/ehci.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ 	(revision )
@@ -1,48 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbehci
- * @{
- */
-/** @file
- * Common EHCI definitions.
- */
-#ifndef DRV_EHCI_EHCI_H
-#define DRV_EHCI_EHCI_H
-
-#include <usbhc_iface.h>
-
-#define NAME "ehci"
-
-extern usbhc_iface_t ehci_hc_iface;
-
-#endif
-/**
- * @}
- */
-
Index: uspace/drv/bus/usb/ehci/ehci.ma
===================================================================
--- uspace/drv/bus/usb/ehci/ehci.ma	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/ehci/ehci.ma	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,39 +1,1 @@
-10 pci/ven=1002&dev=4345
-10 pci/ven=1002&dev=4386
-10 pci/ven=1002&dev=4396
-10 pci/ven=1002&dev=4373
-10 pci/ven=1022&dev=7463
-10 pci/ven=1022&dev=7808
-10 pci/ven=102f&dev=01b5
-10 pci/ven=10cf&dev=1415
-10 pci/ven=10de&dev=00e8
-10 pci/ven=10de&dev=055f
-10 pci/ven=10de&dev=056a
-10 pci/ven=10de&dev=077c
-10 pci/ven=10de&dev=077e
-10 pci/ven=10de&dev=0aa6
-10 pci/ven=10de&dev=0aa9
-10 pci/ven=10de&dev=0aaa
-10 pci/ven=10de&dev=0d9d
-10 pci/ven=1166&dev=0414
-10 pci/ven=1166&dev=0416
-10 pci/ven=1414&dev=5805
-10 pci/ven=1414&dev=5807
-10 pci/ven=15ad&dev=0770
-10 pci/ven=17a0&dev=8084
-10 pci/ven=8086&dev=24cd
-10 pci/ven=8086&dev=24dd
-10 pci/ven=8086&dev=265c
-10 pci/ven=8086&dev=268c
-10 pci/ven=8086&dev=27cc
-10 pci/ven=8086&dev=2836
-10 pci/ven=8086&dev=283a
-10 pci/ven=8086&dev=293a
-10 pci/ven=8086&dev=293c
-10 pci/ven=8086&dev=3a3a
-10 pci/ven=8086&dev=3a3c
-10 pci/ven=8086&dev=3a6a
-10 pci/ven=8086&dev=3a6c
-10 pci/ven=8086&dev=8117
-10 pci/ven=8086&dev=8807
-10 pci/ven=8086&dev=880f
+10 pci/class=0c&subclass=03&progif=20
Index: pace/drv/bus/usb/ehci/hc_iface.c
===================================================================
--- uspace/drv/bus/usb/ehci/hc_iface.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ 	(revision )
@@ -1,160 +1,0 @@
-/*
- * Copyright (c) 2011 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/** @addtogroup drvusbehci
- * @{
- */
-/** @file
- * USB-HC interface implementation.
- */
-#include <ddf/driver.h>
-#include <ddf/interrupt.h>
-#include <device/hw_res.h>
-#include <errno.h>
-#include <str_error.h>
-
-#include <usb_iface.h>
-#include <usb/ddfiface.h>
-#include <usb/debug.h>
-
-#include "ehci.h"
-
-#define UNSUPPORTED(methodname) \
-	usb_log_debug("Client called unsupported interface method " \
-	    "`%s()' in %s:%d.\n", \
-	    methodname, __FILE__, __LINE__)
-
-/** Found free USB address.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] speed Speed of the device that will get this address.
- * @param[out] address Non-null pointer where to store the free address.
- * @return Error code.
- */
-static int request_address(ddf_fun_t *fun, usb_speed_t speed,
-    usb_address_t *address)
-{
-	UNSUPPORTED("request_address");
-
-	return ENOTSUP;
-}
-
-/** Bind USB address with device devman handle.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] address USB address of the device.
- * @param[in] handle Devman handle of the device.
- * @return Error code.
- */
-static int bind_address(ddf_fun_t *fun,
-    usb_address_t address, devman_handle_t handle)
-{
-	UNSUPPORTED("bind_address");
-
-	return ENOTSUP;
-}
-
-/** Find device handle by USB address.
- *
- * @param[in] fun DDF function that was called.
- * @param[in] address Address in question.
- * @param[out] handle Where to store device handle if found.
- * @return Error code.
- */
-static int find_by_address(ddf_fun_t *fun, usb_address_t address,
-    devman_handle_t *handle)
-{
-	UNSUPPORTED("find_by_address");
-
-	return ENOTSUP;
-}
-
-/** Release previously requested address.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] address USB address to be released.
- * @return Error code.
- */
-static int release_address(ddf_fun_t *fun, usb_address_t address)
-{
-	UNSUPPORTED("release_address");
-
-	return ENOTSUP;
-}
-
-/** Register endpoint for bandwidth reservation.
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] address USB address of the device.
- * @param[in] speed Endpoint speed (invalid means to use device one).
- * @param[in] endpoint Endpoint number.
- * @param[in] transfer_type USB transfer type.
- * @param[in] direction Endpoint data direction.
- * @param[in] max_packet_size Max packet size of the endpoint.
- * @param[in] interval Polling interval.
- * @return Error code.
- */
-static int register_endpoint(ddf_fun_t *fun,
-    usb_address_t address, usb_speed_t speed, usb_endpoint_t endpoint,
-    usb_transfer_type_t transfer_type, usb_direction_t direction,
-    size_t max_packet_size, unsigned int interval)
-{
-	UNSUPPORTED("register_endpoint");
-
-	return ENOTSUP;
-}
-
-/** Unregister endpoint (free some bandwidth reservation).
- *
- * @param[in] fun Device function the action was invoked on.
- * @param[in] address USB address of the device.
- * @param[in] endpoint Endpoint number.
- * @param[in] direction Endpoint data direction.
- * @return Error code.
- */
-static int unregister_endpoint(ddf_fun_t *fun, usb_address_t address,
-    usb_endpoint_t endpoint, usb_direction_t direction)
-{
-	UNSUPPORTED("unregister_endpoint");
-
-	return ENOTSUP;
-}
-
-/** Host controller interface implementation for EHCI. */
-usbhc_iface_t ehci_hc_iface = {
-	.request_address = request_address,
-	.bind_address = bind_address,
-	.find_by_address = find_by_address,
-	.release_address = release_address,
-
-	.register_endpoint = register_endpoint,
-	.unregister_endpoint = unregister_endpoint,
-};
-
-/**
- * @}
- */
Index: uspace/drv/bus/usb/ehci/main.c
===================================================================
--- uspace/drv/bus/usb/ehci/main.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/ehci/main.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -42,12 +42,14 @@
 #include <usb/ddfiface.h>
 #include <usb/debug.h>
+#include <usb/host/hcd.h>
 
 #include "pci.h"
-#include "ehci.h"
 
-static int ehci_add_device(ddf_dev_t *device);
+#define NAME "ehci"
+
+static int ehci_dev_add(ddf_dev_t *device);
 /*----------------------------------------------------------------------------*/
 static driver_ops_t ehci_driver_ops = {
-	.add_device = ehci_add_device,
+	.dev_add = ehci_dev_add,
 };
 /*----------------------------------------------------------------------------*/
@@ -57,5 +59,5 @@
 };
 static ddf_dev_ops_t hc_ops = {
-	.interfaces[USBHC_DEV_IFACE] = &ehci_hc_iface,
+	.interfaces[USBHC_DEV_IFACE] = &hcd_iface,
 };
 
@@ -66,5 +68,5 @@
  * @return Error code.
  */
-static int ehci_add_device(ddf_dev_t *device)
+static int ehci_dev_add(ddf_dev_t *device)
 {
 	assert(device);
@@ -95,4 +97,11 @@
 		return ENOMEM;
 	}
+	hcd_t *ehci_hc = ddf_fun_data_alloc(hc_fun, sizeof(hcd_t));
+	if (ehci_hc == NULL) {
+		usb_log_error("Failed to alloc generic HC driver.\n");
+		return ENOMEM;
+	}
+	/* High Speed, no bandwidth */
+	hcd_init(ehci_hc, USB_SPEED_HIGH, 0, NULL);
 	hc_fun->ops = &hc_ops;
 
Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -127,15 +127,16 @@
 	assert(hub_fun);
 
-	const usb_address_t hub_address =
-	    usb_device_manager_get_free_address(
-	        &instance->generic.dev_manager, USB_SPEED_FULL);
-	if (hub_address <= 0) {
+	/* Try to get address 1 for root hub. */
+	instance->rh.address = 1;
+	int ret = usb_device_manager_request_address(
+	    &instance->generic.dev_manager, &instance->rh.address, false,
+	    USB_SPEED_FULL);
+	if (ret != EOK) {
 		usb_log_error("Failed to get OHCI root hub address: %s\n",
-		    str_error(hub_address));
-		return hub_address;
-	}
-	instance->rh.address = hub_address;
-	usb_device_manager_bind(
-	    &instance->generic.dev_manager, hub_address, hub_fun->handle);
+		    str_error(ret));
+		return ret;
+	}
+	usb_device_manager_bind_address(&instance->generic.dev_manager,
+	    instance->rh.address, hub_fun->handle);
 
 #define CHECK_RET_UNREG_RETURN(ret, message...) \
@@ -143,13 +144,14 @@
 	usb_log_error(message); \
 	usb_endpoint_manager_remove_ep( \
-	    &instance->generic.ep_manager, hub_address, 0, USB_DIRECTION_BOTH, \
-	    NULL, NULL);\
-	usb_device_manager_release( \
-	    &instance->generic.dev_manager, hub_address); \
+	    &instance->generic.ep_manager, instance->rh.address, 0, \
+	    USB_DIRECTION_BOTH, NULL, NULL); \
+	usb_device_manager_release_address( \
+	    &instance->generic.dev_manager, instance->rh.address); \
 	return ret; \
 } else (void)0
-	int ret = usb_endpoint_manager_add_ep(
-	    &instance->generic.ep_manager, hub_address, 0, USB_DIRECTION_BOTH,
-	    USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64, 0, NULL, NULL);
+	ret = usb_endpoint_manager_add_ep(
+	    &instance->generic.ep_manager, instance->rh.address, 0,
+	    USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64,
+	    0, NULL, NULL);
 	CHECK_RET_UNREG_RETURN(ret,
 	    "Failed to register root hub control endpoint: %s.\n",
@@ -193,6 +195,6 @@
 	list_initialize(&instance->pending_batches);
 
-	hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
-	    bandwidth_count_usb11);
+	hcd_init(&instance->generic, USB_SPEED_FULL,
+	    BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
 	instance->generic.private_data = instance;
 	instance->generic.schedule = hc_schedule;
Index: uspace/drv/bus/usb/ohci/main.c
===================================================================
--- uspace/drv/bus/usb/ohci/main.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/ohci/main.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -48,7 +48,7 @@
  * @return Error code.
  */
-static int ohci_add_device(ddf_dev_t *device)
+static int ohci_dev_add(ddf_dev_t *device)
 {
-	usb_log_debug("ohci_add_device() called\n");
+	usb_log_debug("ohci_dev_add() called\n");
 	assert(device);
 
@@ -65,5 +65,5 @@
 /*----------------------------------------------------------------------------*/
 static driver_ops_t ohci_driver_ops = {
-	.add_device = ohci_add_device,
+	.dev_add = ohci_dev_add,
 };
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/ohci/ohci.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/ohci/ohci.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -76,25 +76,16 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Get address of the device identified by handle.
- *
- * @param[in] dev DDF instance of the device to use.
- * @param[in] iid (Unused).
- * @param[in] call Pointer to the call that represents interrupt.
- */
-static int usb_iface_get_address(
-    ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address)
+/** Get USB address assigned to root hub.
+ *
+ * @param[in] fun Root hub function.
+ * @param[out] address Store the address here.
+ * @return Error code.
+ */
+static int rh_get_my_address(ddf_fun_t *fun, usb_address_t *address)
 {
 	assert(fun);
-	usb_device_manager_t *manager =
-	    &dev_to_ohci(fun->dev)->hc.generic.dev_manager;
-
-	const usb_address_t addr =
-	    usb_device_manager_find_address(manager, handle);
-	if (addr < 0) {
-		return addr;
-	}
 
 	if (address != NULL) {
-		*address = addr;
+		*address = dev_to_ohci(fun->dev)->hc.rh.address;
 	}
 
@@ -108,5 +99,5 @@
  * @return Error code.
  */
-static int usb_iface_get_hc_handle(
+static int rh_get_hc_handle(
     ddf_fun_t *fun, devman_handle_t *handle)
 {
@@ -122,6 +113,6 @@
 /** Root hub USB interface */
 static usb_iface_t usb_iface = {
-	.get_hc_handle = usb_iface_get_hc_handle,
-	.get_address = usb_iface_get_address
+	.get_hc_handle = rh_get_hc_handle,
+	.get_my_address = rh_get_my_address,
 };
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/ohci/ohci.ma
===================================================================
--- uspace/drv/bus/usb/ohci/ohci.ma	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/ohci/ohci.ma	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,15 +1,1 @@
-10 pci/ven=106b&dev=0026
-10 pci/ven=106b&dev=003f
-10 pci/ven=10de&dev=0aa5
-
-10 pci/ven=1002&dev=4374
-10 pci/ven=1002&dev=4375
-
-10 pci/ven=1002&dev=4387
-10 pci/ven=1002&dev=4388
-10 pci/ven=1002&dev=4389
-10 pci/ven=1002&dev=438a
-10 pci/ven=1002&dev=438b
-10 pci/ven=1002&dev=4397
-10 pci/ven=1002&dev=4398
-10 pci/ven=1002&dev=4399
+10 pci/class=0c&subclass=03&progif=10
Index: uspace/drv/bus/usb/ohci/utils/malloc32.h
===================================================================
--- uspace/drv/bus/usb/ohci/utils/malloc32.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/ohci/utils/malloc32.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -56,8 +56,9 @@
 	uintptr_t result;
 	int ret = as_get_physical_mapping(addr, &result);
-
+	
 	if (ret != EOK)
 		return 0;
-	return (result | ((uintptr_t)addr & 0xfff));
+	
+	return result;
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -199,6 +199,6 @@
 #undef CHECK_RET_RETURN
 
-	hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
-	    bandwidth_count_usb11);
+	hcd_init(&instance->generic, USB_SPEED_FULL,
+	    BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
 
 	instance->generic.private_data = instance;
Index: uspace/drv/bus/usb/uhci/main.c
===================================================================
--- uspace/drv/bus/usb/uhci/main.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/uhci/main.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -43,8 +43,8 @@
 #define NAME "uhci"
 
-static int uhci_add_device(ddf_dev_t *device);
+static int uhci_dev_add(ddf_dev_t *device);
 /*----------------------------------------------------------------------------*/
 static driver_ops_t uhci_driver_ops = {
-	.add_device = uhci_add_device,
+	.dev_add = uhci_dev_add,
 };
 /*----------------------------------------------------------------------------*/
@@ -59,7 +59,7 @@
  * @return Error code.
  */
-int uhci_add_device(ddf_dev_t *device)
+int uhci_dev_add(ddf_dev_t *device)
 {
-	usb_log_debug2("uhci_add_device() called\n");
+	usb_log_debug2("uhci_dev_add() called\n");
 	assert(device);
 
Index: uspace/drv/bus/usb/uhci/uhci.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/uhci/uhci.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -89,30 +89,4 @@
 };
 /*----------------------------------------------------------------------------*/
-/** Get address of the device identified by handle.
- *
- * @param[in] fun DDF instance of the function to use.
- * @param[in] handle DDF handle of the driver seeking its USB address.
- * @param[out] address Found address.
- */
-static int usb_iface_get_address(
-    ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address)
-{
-	assert(fun);
-	usb_device_manager_t *manager =
-	    &dev_to_uhci(fun->dev)->hc.generic.dev_manager;
-	const usb_address_t addr =
-	    usb_device_manager_find_address(manager, handle);
-
-	if (addr < 0) {
-		return addr;
-	}
-
-	if (address != NULL) {
-		*address = addr;
-	}
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
 /** Gets handle of the respective hc.
  *
@@ -135,5 +109,4 @@
 static usb_iface_t usb_iface = {
 	.get_hc_handle = usb_iface_get_hc_handle,
-	.get_address = usb_iface_get_address
 };
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/uhci/uhci.ma
===================================================================
--- uspace/drv/bus/usb/uhci/uhci.ma	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/uhci/uhci.ma	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,29 +1,1 @@
-10 pci/ven=8086&dev=7020
-10 pci/ven=8086&dev=7112
-
-10 pci/ven=8086&dev=27c8
-10 pci/ven=8086&dev=27c9
-10 pci/ven=8086&dev=27ca
-10 pci/ven=8086&dev=27cb
-
-10 pci/ven=8086&dev=2830
-10 pci/ven=8086&dev=2831
-10 pci/ven=8086&dev=2832
-10 pci/ven=8086&dev=2834
-10 pci/ven=8086&dev=2835
-
-10 pci/ven=8086&dev=2934
-10 pci/ven=8086&dev=2935
-10 pci/ven=8086&dev=2936
-10 pci/ven=8086&dev=2937
-10 pci/ven=8086&dev=2938
-10 pci/ven=8086&dev=2939
-
-10 pci/ven=8086&dev=24c2
-10 pci/ven=8086&dev=24c4
-10 pci/ven=8086&dev=24c7
-
-10 pci/ven=8086&dev=2688
-10 pci/ven=8086&dev=2689
-10 pci/ven=8086&dev=268a
-10 pci/ven=8086&dev=268b
+10 pci/class=0c&subclass=03&progif=00
Index: uspace/drv/bus/usb/uhci/utils/malloc32.h
===================================================================
--- uspace/drv/bus/usb/uhci/utils/malloc32.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/uhci/utils/malloc32.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -54,10 +54,11 @@
 	if (addr == NULL)
 		return 0;
-
+	
 	uintptr_t result;
 	const int ret = as_get_physical_mapping(addr, &result);
 	if (ret != EOK)
 		return 0;
-	return (result | ((uintptr_t)addr & 0xfff));
+	
+	return result;
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/uhcirh/main.c
===================================================================
--- uspace/drv/bus/usb/uhcirh/main.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/uhcirh/main.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -51,8 +51,8 @@
     uintptr_t *io_reg_address, size_t *io_reg_size);
 
-static int uhci_rh_add_device(ddf_dev_t *device);
+static int uhci_rh_dev_add(ddf_dev_t *device);
 
 static driver_ops_t uhci_rh_driver_ops = {
-	.add_device = uhci_rh_add_device,
+	.dev_add = uhci_rh_dev_add,
 };
 
@@ -82,10 +82,10 @@
  * @return Error code.
  */
-static int uhci_rh_add_device(ddf_dev_t *device)
+static int uhci_rh_dev_add(ddf_dev_t *device)
 {
 	if (!device)
 		return EINVAL;
 
-	usb_log_debug2("uhci_rh_add_device(handle=%" PRIun ")\n",
+	usb_log_debug2("uhci_rh_dev_add(handle=%" PRIun ")\n",
 	    device->handle);
 
Index: uspace/drv/bus/usb/usbflbk/main.c
===================================================================
--- uspace/drv/bus/usb/usbflbk/main.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbflbk/main.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -74,14 +74,4 @@
 }
 
-/** Callback when new device is about to be removed.
- *
- * @param dev Representation of a generic DDF device.
- * @return Error code.
- */
-static int usbfallback_device_remove(usb_device_t *dev)
-{
-	return EOK;
-}
-
 /** Callback when new device is removed and recognized as gone by DDF.
  *
@@ -107,5 +97,5 @@
 static const usb_driver_ops_t usbfallback_driver_ops = {
 	.device_add = usbfallback_device_add,
-	.device_rem = usbfallback_device_remove,
+	.device_rem = usbfallback_device_gone,
 	.device_gone = usbfallback_device_gone,
 };
Index: uspace/drv/bus/usb/usbhid/generic/hiddev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/generic/hiddev.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhid/generic/hiddev.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -61,19 +61,12 @@
 
 /*----------------------------------------------------------------------------*/
-
 static size_t usb_generic_hid_get_event_length(ddf_fun_t *fun);
-
-static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer, 
+static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer,
     size_t size, size_t *act_size, int *event_nr, unsigned int flags);
-
 static int usb_generic_hid_client_connected(ddf_fun_t *fun);
-
 static size_t usb_generic_get_report_descriptor_length(ddf_fun_t *fun);
-
-static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc, 
+static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc,
     size_t size, size_t *actual_size);
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static usbhid_iface_t usb_generic_iface = {
 	.get_event = usb_generic_hid_get_event,
@@ -82,12 +75,10 @@
 	.get_report_descriptor = usb_generic_get_report_descriptor
 };
-
+/*----------------------------------------------------------------------------*/
 static ddf_dev_ops_t usb_generic_hid_ops = {
 	.interfaces[USBHID_DEV_IFACE] = &usb_generic_iface,
 	.open = usb_generic_hid_client_connected
 };
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static size_t usb_generic_hid_get_event_length(ddf_fun_t *fun)
 {
@@ -99,5 +90,5 @@
 	}
 
-	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
+	const usb_hid_dev_t *hid_dev = fun->driver_data;
 
 	usb_log_debug2("hid_dev: %p, Max input report size (%zu).\n",
@@ -106,8 +97,6 @@
 	return hid_dev->max_input_report_size;
 }
-
-/*----------------------------------------------------------------------------*/
-
-static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer, 
+/*----------------------------------------------------------------------------*/
+static int usb_generic_hid_get_event(ddf_fun_t *fun, uint8_t *buffer,
     size_t size, size_t *act_size, int *event_nr, unsigned int flags)
 {
@@ -120,8 +109,8 @@
 	}
 
-	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
+	const usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
 
 	if (hid_dev->input_report_size > size) {
-		usb_log_debug("input_report_size > size (%zu, %zu)\n", 
+		usb_log_debug("input_report_size > size (%zu, %zu)\n",
 		    hid_dev->input_report_size, size);
 		return EINVAL;	// TODO: other error code
@@ -129,5 +118,5 @@
 
 	/*! @todo This should probably be somehow atomic. */
-	memcpy(buffer, hid_dev->input_report, 
+	memcpy(buffer, hid_dev->input_report,
 	    hid_dev->input_report_size);
 	*act_size = hid_dev->input_report_size;
@@ -138,7 +127,5 @@
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static size_t usb_generic_get_report_descriptor_length(ddf_fun_t *fun)
 {
@@ -150,15 +137,13 @@
 	}
 
-	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
-
-	usb_log_debug2("hid_dev->report_desc_size = %zu\n", 
+	const usb_hid_dev_t *hid_dev = fun->driver_data;
+
+	usb_log_debug2("hid_dev->report_desc_size = %zu\n",
 	    hid_dev->report_desc_size);
 
 	return hid_dev->report_desc_size;
 }
-
-/*----------------------------------------------------------------------------*/
-
-static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc, 
+/*----------------------------------------------------------------------------*/
+static int usb_generic_get_report_descriptor(ddf_fun_t *fun, uint8_t *desc,
     size_t size, size_t *actual_size)
 {
@@ -170,5 +155,5 @@
 	}
 
-	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
+	const usb_hid_dev_t *hid_dev = fun->driver_data;
 
 	if (hid_dev->report_desc_size > size) {
@@ -181,7 +166,5 @@
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int usb_generic_hid_client_connected(ddf_fun_t *fun)
 {
@@ -189,12 +172,12 @@
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 void usb_generic_hid_deinit(usb_hid_dev_t *hid_dev, void *data)
 {
 	ddf_fun_t *fun = data;
-	const int ret = ddf_fun_unbind(fun);
-	if (ret != EOK) {
+	if (fun == NULL)
+		return;
+
+	if (ddf_fun_unbind(fun) != EOK) {
 		usb_log_error("Failed to unbind generic hid fun.\n");
 		return;
@@ -206,7 +189,5 @@
 	ddf_fun_destroy(fun);
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 int usb_generic_hid_init(usb_hid_dev_t *hid_dev, void **data)
 {
@@ -216,5 +197,4 @@
 
 	/* Create the exposed function. */
-	/** @todo Generate numbers for the devices? */
 	usb_log_debug("Creating DDF function %s...\n", HID_GENERIC_FUN_NAME);
 	ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
@@ -225,4 +205,7 @@
 	}
 
+	/* This is nasty, both device and this function have the same
+	 * driver data, thus destruction causes to double free */
+	fun->driver_data = hid_dev;
 	fun->ops = &usb_generic_hid_ops;
 
@@ -231,10 +214,8 @@
 		usb_log_error("Could not bind DDF function: %s.\n",
 		    str_error(rc));
+		fun->driver_data = NULL;
 		ddf_fun_destroy(fun);
 		return rc;
 	}
-	/* This is nasty both device and this function have the same
-	 * driver data, thus destruction would lead to double free */
-	fun->driver_data = hid_dev;
 
 	usb_log_debug("HID function created. Handle: %" PRIun "\n", fun->handle);
@@ -243,12 +224,9 @@
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 bool usb_generic_hid_polling_callback(usb_hid_dev_t *hid_dev, void *data)
 {
 	return true;
 }
-
 /**
  * @}
Index: uspace/drv/bus/usb/usbhid/kbd/kbddev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbddev.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhid/kbd/kbddev.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -41,4 +41,5 @@
 #include <io/keycode.h>
 #include <io/console.h>
+#include <abi/ipc/methods.h>
 #include <ipc/kbdev.h>
 #include <async.h>
@@ -86,5 +87,4 @@
 
 /*----------------------------------------------------------------------------*/
-
 /** Keyboard polling endpoint description for boot protocol class. */
 const usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description = {
@@ -101,50 +101,40 @@
 
 static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev);
-
-/*----------------------------------------------------------------------------*/
-
-enum {
-	USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE = 63
+/*----------------------------------------------------------------------------*/
+static const uint8_t USB_KBD_BOOT_REPORT_DESCRIPTOR[] = {
+	0x05, 0x01,  /* Usage Page (Generic Desktop), */
+	0x09, 0x06,  /* Usage (Keyboard), */
+	0xA1, 0x01,  /* Collection (Application), */
+	0x75, 0x01,  /*   Report Size (1), */
+	0x95, 0x08,  /*   Report Count (8), */
+	0x05, 0x07,  /*   Usage Page (Key Codes); */
+	0x19, 0xE0,  /*   Usage Minimum (224), */
+	0x29, 0xE7,  /*   Usage Maximum (231), */
+	0x15, 0x00,  /*   Logical Minimum (0), */
+	0x25, 0x01,  /*   Logical Maximum (1), */
+	0x81, 0x02,  /*   Input (Data, Variable, Absolute),  ; Modifier byte */
+	0x95, 0x01,  /*   Report Count (1), */
+	0x75, 0x08,  /*   Report Size (8), */
+	0x81, 0x01,  /*   Input (Constant),                  ; Reserved byte */
+	0x95, 0x05,  /*   Report Count (5), */
+	0x75, 0x01,  /*   Report Size (1), */
+	0x05, 0x08,  /*   Usage Page (Page# for LEDs), */
+	0x19, 0x01,  /*   Usage Minimum (1), */
+	0x29, 0x05,  /*   Usage Maxmimum (5), */
+	0x91, 0x02,  /*   Output (Data, Variable, Absolute),  ; LED report */
+	0x95, 0x01,  /*   Report Count (1), */
+	0x75, 0x03,  /*   Report Size (3), */
+	0x91, 0x01,  /*   Output (Constant),            ; LED report padding */
+	0x95, 0x06,  /*   Report Count (6), */
+	0x75, 0x08,  /*   Report Size (8), */
+	0x15, 0x00,  /*   Logical Minimum (0), */
+	0x25, 0xff,  /*   Logical Maximum (255), */
+	0x05, 0x07,  /*   Usage Page (Key Codes), */
+	0x19, 0x00,  /*   Usage Minimum (0), */
+	0x29, 0xff,  /*   Usage Maximum (255), */
+	0x81, 0x00,  /*   Input (Data, Array),   ; Key arrays (6 bytes) */
+	0xC0         /* End Collection */
 };
-
-static const uint8_t USB_KBD_BOOT_REPORT_DESCRIPTOR[
-    USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE] = {
-        0x05, 0x01,  // Usage Page (Generic Desktop),
-        0x09, 0x06,  // Usage (Keyboard),
-        0xA1, 0x01,  // Collection (Application),
-        0x75, 0x01,  //   Report Size (1),
-        0x95, 0x08,  //   Report Count (8),       
-        0x05, 0x07,  //   Usage Page (Key Codes);
-        0x19, 0xE0,  //   Usage Minimum (224),
-        0x29, 0xE7,  //   Usage Maximum (231),
-        0x15, 0x00,  //   Logical Minimum (0),
-        0x25, 0x01,  //   Logical Maximum (1),
-        0x81, 0x02,  //   Input (Data, Variable, Absolute),   ; Modifier byte
-	0x95, 0x01,  //   Report Count (1),
-        0x75, 0x08,  //   Report Size (8),
-        0x81, 0x01,  //   Input (Constant),                   ; Reserved byte
-        0x95, 0x05,  //   Report Count (5),
-        0x75, 0x01,  //   Report Size (1),
-        0x05, 0x08,  //   Usage Page (Page# for LEDs),
-        0x19, 0x01,  //   Usage Minimum (1),
-        0x29, 0x05,  //   Usage Maxmimum (5),
-        0x91, 0x02,  //   Output (Data, Variable, Absolute),  ; LED report
-        0x95, 0x01,  //   Report Count (1),
-        0x75, 0x03,  //   Report Size (3),
-        0x91, 0x01,  //   Output (Constant),              ; LED report padding
-        0x95, 0x06,  //   Report Count (6),
-        0x75, 0x08,  //   Report Size (8),
-        0x15, 0x00,  //   Logical Minimum (0),
-        0x25, 0xff,  //   Logical Maximum (255),
-        0x05, 0x07,  //   Usage Page (Key Codes),
-        0x19, 0x00,  //   Usage Minimum (0),
-        0x29, 0xff,  //   Usage Maximum (255),
-        0x81, 0x00,  //   Input (Data, Array),            ; Key arrays (6 bytes)
-        0xC0           // End Collection
-
-};
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 typedef enum usb_kbd_flags {
 	USB_KBD_STATUS_UNINITIALIZED = 0,
@@ -152,17 +142,14 @@
 	USB_KBD_STATUS_TO_DESTROY = -1
 } usb_kbd_flags;
-
 /*----------------------------------------------------------------------------*/
 /* IPC method handler                                                         */
 /*----------------------------------------------------------------------------*/
-
-static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
-
 /**
  * Default handler for IPC methods not handled by DDF.
  *
- * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
- * assumes the caller is the console and thus it stores IPC session to it for
- * later use by the driver to notify about key events.
+ * Currently recognizes only two methods (IPC_M_CONNECT_TO_ME and KBDEV_SET_IND)
+ * IPC_M_CONNECT_TO_ME assumes the caller is the console and  stores IPC
+ * session to it for later use by the driver to notify about key events.
+ * KBDEV_SET_IND sets LED keyboard indicators.
  *
  * @param fun Device function handling the call.
@@ -173,41 +160,50 @@
     ipc_callid_t icallid, ipc_call_t *icall)
 {
-	sysarg_t method = IPC_GET_IMETHOD(*icall);
-
-	usb_kbd_t *kbd_dev = (usb_kbd_t *) fun->driver_data;
-	if (kbd_dev == NULL) {
-		usb_log_debug("default_connection_handler: "
-		    "Missing parameter.\n");
+	if (fun == NULL || fun->driver_data == NULL) {
+		usb_log_error("%s: Missing parameter.\n", __FUNCTION__);
 		async_answer_0(icallid, EINVAL);
 		return;
 	}
 
-	async_sess_t *sess =
-	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
-	if (sess != NULL) {
+	const sysarg_t method = IPC_GET_IMETHOD(*icall);
+	usb_kbd_t *kbd_dev = fun->driver_data;
+
+	switch (method) {
+	case KBDEV_SET_IND:
+		kbd_dev->mods = IPC_GET_ARG1(*icall);
+		usb_kbd_set_led(kbd_dev->hid_dev, kbd_dev);
+		async_answer_0(icallid, EOK);
+		break;
+	/* This might be ugly but async_callback_receive_start makes no
+	 * difference for incorrect call and malloc failure. */
+	case IPC_M_CONNECT_TO_ME: {
+		async_sess_t *sess =
+		    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
+		/* Probably ENOMEM error, try again. */
+		if (sess == NULL) {
+			usb_log_warning(
+			    "Failed to create start console session.\n");
+			async_answer_0(icallid, EAGAIN);
+			break;
+		}
 		if (kbd_dev->console_sess == NULL) {
 			kbd_dev->console_sess = sess;
-			usb_log_debug("default_connection_handler: OK\n");
+			usb_log_debug("%s: OK\n", __FUNCTION__);
 			async_answer_0(icallid, EOK);
 		} else {
-			usb_log_debug("default_connection_handler: "
-			    "console session already set\n");
+			usb_log_error("%s: console session already set\n",
+			   __FUNCTION__);
 			async_answer_0(icallid, ELIMIT);
 		}
-	} else {
-		switch (method) {
-		case KBDEV_SET_IND:
-			kbd_dev->mods = IPC_GET_ARG1(*icall);
-			usb_kbd_set_led(kbd_dev->hid_dev, kbd_dev);
-			async_answer_0(icallid, EOK);
-			break;
-		default:
-			usb_log_debug("default_connection_handler: Wrong function.\n");
+		break;
+	}
+	default:
+			usb_log_error("%s: Unknown method: %d.\n",
+			    __FUNCTION__, (int) method);
 			async_answer_0(icallid, EINVAL);
 			break;
-		}
-	}
-}
-
+	}
+
+}
 /*----------------------------------------------------------------------------*/
 /* Key processing functions                                                   */
@@ -226,5 +222,5 @@
  * @param kbd_dev Keyboard device structure.
  */
-static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev) 
+static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev)
 {
 	if (kbd_dev->output_size == 0) {
@@ -274,13 +270,15 @@
 	}
 
-	usb_log_debug("Output report buffer: %s\n", 
-	    usb_debug_str_buffer(kbd_dev->output_buffer, kbd_dev->output_size, 
+	usb_log_debug("Output report buffer: %s\n",
+	    usb_debug_str_buffer(kbd_dev->output_buffer, kbd_dev->output_size,
 	        0));
 
-	usbhid_req_set_report(&hid_dev->usb_dev->ctrl_pipe, 
-	    hid_dev->usb_dev->interface_no, USB_HID_REPORT_TYPE_OUTPUT, 
+	rc = usbhid_req_set_report(&hid_dev->usb_dev->ctrl_pipe,
+	    hid_dev->usb_dev->interface_no, USB_HID_REPORT_TYPE_OUTPUT,
 	    kbd_dev->output_buffer, kbd_dev->output_size);
-}
-
+	if (rc != EOK) {
+		usb_log_warning("Failed to set kbd indicators.\n");
+	}
+}
 /*----------------------------------------------------------------------------*/
 /** Send key event.
@@ -291,6 +289,5 @@
  * @param key Key code
  */
-void usb_kbd_push_ev(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev, int type, 
-    unsigned int key)
+void usb_kbd_push_ev(usb_kbd_t *kbd_dev, int type, unsigned key)
 {
 	usb_log_debug2("Sending kbdev event %d/%d to the console\n", type, key);
@@ -302,11 +299,13 @@
 
 	async_exch_t *exch = async_exchange_begin(kbd_dev->console_sess);
-	async_msg_2(exch, KBDEV_EVENT, type, key);
-	async_exchange_end(exch);
-}
-
-/*----------------------------------------------------------------------------*/
-
-static inline int usb_kbd_is_lock(unsigned int key_code) 
+	if (exch != NULL) {
+		async_msg_2(exch, KBDEV_EVENT, type, key);
+		async_exchange_end(exch);
+	} else {
+		usb_log_warning("Failed to send key to console.\n");
+	}
+}
+/*----------------------------------------------------------------------------*/
+static inline int usb_kbd_is_lock(unsigned int key_code)
 {
 	return (key_code == KC_NUM_LOCK
@@ -314,5 +313,5 @@
 	    || key_code == KC_CAPS_LOCK);
 }
-
+/*----------------------------------------------------------------------------*/
 static size_t find_in_array_int32(int32_t val, int32_t *arr, size_t arr_size)
 {
@@ -325,5 +324,4 @@
 	return (size_t) -1;
 }
-
 /*----------------------------------------------------------------------------*/
 /**
@@ -342,9 +340,7 @@
  * @sa usb_kbd_push_ev(), usb_kbd_repeat_start(), usb_kbd_repeat_stop()
  */
-static void usb_kbd_check_key_changes(usb_hid_dev_t *hid_dev, 
+static void usb_kbd_check_key_changes(usb_hid_dev_t *hid_dev,
     usb_kbd_t *kbd_dev)
 {
-	unsigned int key;
-	size_t i;
 
 	/*
@@ -356,8 +352,8 @@
 	 * whole input report.
 	 */
-	i = find_in_array_int32(ERROR_ROLLOVER, kbd_dev->keys,
+	size_t i = find_in_array_int32(ERROR_ROLLOVER, kbd_dev->keys,
 	    kbd_dev->key_count);
 	if (i != (size_t) -1) {
-		usb_log_debug("Detected phantom state.\n");
+		usb_log_error("Detected phantom state.\n");
 		return;
 	}
@@ -367,15 +363,15 @@
 	 */
 	for (i = 0; i < kbd_dev->key_count; i++) {
-		int32_t old_key = kbd_dev->keys_old[i];
+		const int32_t old_key = kbd_dev->keys_old[i];
 		/* Find the old key among currently pressed keys. */
-		size_t pos = find_in_array_int32(old_key, kbd_dev->keys,
+		const size_t pos = find_in_array_int32(old_key, kbd_dev->keys,
 		    kbd_dev->key_count);
 		/* If the key was not found, we need to signal release. */
 		if (pos == (size_t) -1) {
-			key = usbhid_parse_scancode(old_key);
+			const unsigned key = usbhid_parse_scancode(old_key);
 			if (!usb_kbd_is_lock(key)) {
 				usb_kbd_repeat_stop(kbd_dev, key);
 			}
-			usb_kbd_push_ev(hid_dev, kbd_dev, KEY_RELEASE, key);
+			usb_kbd_push_ev(kbd_dev, KEY_RELEASE, key);
 			usb_log_debug2("Key released: %u "
 			    "(USB code %" PRIu32 ")\n", key, old_key);
@@ -387,15 +383,15 @@
 	 */
 	for (i = 0; i < kbd_dev->key_count; ++i) {
-		int32_t new_key = kbd_dev->keys[i];
+		const int32_t new_key = kbd_dev->keys[i];
 		/* Find the new key among already pressed keys. */
-		size_t pos = find_in_array_int32(new_key, kbd_dev->keys_old,
-		    kbd_dev->key_count);
+		const size_t pos = find_in_array_int32(new_key,
+		    kbd_dev->keys_old, kbd_dev->key_count);
 		/* If the key was not found, we need to signal press. */
 		if (pos == (size_t) -1) {
-			key = usbhid_parse_scancode(kbd_dev->keys[i]);
+			unsigned key = usbhid_parse_scancode(kbd_dev->keys[i]);
 			if (!usb_kbd_is_lock(key)) {
 				usb_kbd_repeat_start(kbd_dev, key);
 			}
-			usb_kbd_push_ev(hid_dev, kbd_dev, KEY_PRESS, key);
+			usb_kbd_push_ev(kbd_dev, KEY_PRESS, key);
 			usb_log_debug2("Key pressed: %u "
 			    "(USB code %" PRIu32 ")\n", key, new_key);
@@ -405,4 +401,5 @@
 	memcpy(kbd_dev->keys_old, kbd_dev->keys, kbd_dev->key_count * 4);
 
+	// TODO Get rid of this
 	char key_buffer[512];
 	ddf_dump_buffer(key_buffer, 512,
@@ -410,5 +407,4 @@
 	usb_log_debug2("Stored keys %s.\n", key_buffer);
 }
-
 /*----------------------------------------------------------------------------*/
 /* General kbd functions                                                      */
@@ -436,10 +432,19 @@
 
 	usb_hid_report_path_t *path = usb_hid_report_path();
-	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
-
-	usb_hid_report_path_set_report_id (path, hid_dev->report_id);
-
-	// fill in the currently pressed keys
-
+	if (path == NULL) {
+		usb_log_error("Failed to create hid/kbd report path.\n");
+		return;
+	}
+
+	int ret =
+	   usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	if (ret != EOK) {
+		usb_log_error("Failed to append to hid/kbd report path.\n");
+		return;
+	}
+
+	usb_hid_report_path_set_report_id(path, hid_dev->report_id);
+
+	/* Fill in the currently pressed keys. */
 	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
 	    &hid_dev->report, NULL, path,
@@ -449,10 +454,10 @@
 
 	while (field != NULL) {
-		usb_log_debug2("FIELD (%p) - VALUE(%d) USAGE(%u)\n", 
+		usb_log_debug2("FIELD (%p) - VALUE(%d) USAGE(%u)\n",
 		    field, field->value, field->usage);
-		
+
 		assert(i < kbd_dev->key_count);
 
-		// save the key usage
+		/* Save the key usage. */
 		if (field->value != 0) {
 			kbd_dev->keys[i] = field->usage;
@@ -474,43 +479,7 @@
 	usb_kbd_check_key_changes(hid_dev, kbd_dev);
 }
-
 /*----------------------------------------------------------------------------*/
 /* HID/KBD structure manipulation                                             */
 /*----------------------------------------------------------------------------*/
-
-static void usb_kbd_mark_unusable(usb_kbd_t *kbd_dev)
-{
-	kbd_dev->initialized = USB_KBD_STATUS_TO_DESTROY;
-}
-
-/*----------------------------------------------------------------------------*/
-
-/**
- * Creates a new USB/HID keyboard structure.
- *
- * The structure returned by this function is not initialized. Use 
- * usb_kbd_init() to initialize it prior to polling.
- *
- * @return New uninitialized structure for representing a USB/HID keyboard or
- *         NULL if not successful (memory error).
- */
-static usb_kbd_t *usb_kbd_new(void)
-{
-	usb_kbd_t *kbd_dev = 
-	    (usb_kbd_t *)calloc(1, sizeof(usb_kbd_t));
-
-	if (kbd_dev == NULL) {
-		usb_log_error("No memory!\n");
-		return NULL;
-	}
-
-	kbd_dev->console_sess = NULL;
-	kbd_dev->initialized = USB_KBD_STATUS_UNINITIALIZED;
-
-	return kbd_dev;
-}
-
-/*----------------------------------------------------------------------------*/
-
 static int usb_kbd_create_function(usb_kbd_t *kbd_dev)
 {
@@ -528,8 +497,6 @@
 	}
 
-	/*
-	 * Store the initialized HID device and HID ops
-	 * to the DDF function.
-	 */
+	/* Store the initialized HID device and HID ops
+	 * to the DDF function. */
 	fun->ops = &kbd_dev->ops;
 	fun->driver_data = kbd_dev;
@@ -539,5 +506,5 @@
 		usb_log_error("Could not bind DDF function: %s.\n",
 		    str_error(rc));
-		fun->driver_data = NULL; /* We need this later */
+		fun->driver_data = NULL; /* We did not allocate this. */
 		ddf_fun_destroy(fun);
 		return rc;
@@ -547,5 +514,5 @@
 	    HID_KBD_FUN_NAME, fun->handle);
 
-	usb_log_debug("Adding DDF function to category %s...\n", 
+	usb_log_debug("Adding DDF function to category %s...\n",
 	    HID_KBD_CLASS_NAME);
 	rc = ddf_fun_add_to_category(fun, HID_KBD_CATEGORY_NAME);
@@ -554,6 +521,12 @@
 		    "Could not add DDF function to category %s: %s.\n",
 		    HID_KBD_CLASS_NAME, str_error(rc));
-		fun->driver_data = NULL; /* We need this later */
-		ddf_fun_destroy(fun);
+		if (ddf_fun_unbind(fun) == EOK) {
+			fun->driver_data = NULL; /* We did not allocate this. */
+			ddf_fun_destroy(fun);
+		} else {
+			usb_log_error(
+			    "Failed to unbind `%s', will not destroy.\n",
+			    fun->name);
+		}
 		return rc;
 	}
@@ -562,5 +535,4 @@
 	return EOK;
 }
-
 /*----------------------------------------------------------------------------*/
 /* API functions                                                              */
@@ -591,29 +563,52 @@
 
 	if (hid_dev == NULL) {
-		usb_log_error("Failed to init keyboard structure: no structure"
-		    " given.\n");
+		usb_log_error(
+		    "Failed to init keyboard structure: no structure given.\n");
 		return EINVAL;
 	}
 
-	usb_kbd_t *kbd_dev = usb_kbd_new();
+	usb_kbd_t *kbd_dev = calloc(1, sizeof(usb_kbd_t));
 	if (kbd_dev == NULL) {
-		usb_log_error("Error while creating USB/HID KBD device "
-		    "structure.\n");
-		return ENOMEM;  // TODO: some other code??
-	}
+		usb_log_error("Failed to allocate KBD device structure.\n");
+		return ENOMEM;
+	}
+	/* Default values */
+	fibril_mutex_initialize(&kbd_dev->repeat_mtx);
+	kbd_dev->initialized = USB_KBD_STATUS_UNINITIALIZED;
+	kbd_dev->ops.default_handler = default_connection_handler;
 
 	/* Store link to HID device */
 	kbd_dev->hid_dev = hid_dev;
 
-	/*
-	 * TODO: make more general
-	 */
+	/* Modifiers and locks */
+	kbd_dev->mods = DEFAULT_ACTIVE_MODS;
+
+	/* Autorepeat */
+	kbd_dev->repeat.delay_before = DEFAULT_DELAY_BEFORE_FIRST_REPEAT;
+	kbd_dev->repeat.delay_between = DEFAULT_REPEAT_DELAY;
+
+
+	// TODO: make more general
 	usb_hid_report_path_t *path = usb_hid_report_path();
-	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	if (path == NULL) {
+		usb_log_error("Failed to create kbd report path.\n");
+		usb_kbd_destroy(kbd_dev);
+		return ENOMEM;
+	}
+
+	int ret =
+	    usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
+	if (ret != EOK) {
+		usb_log_error("Failed to append item to kbd report path.\n");
+		usb_hid_report_path_free(path);
+		usb_kbd_destroy(kbd_dev);
+		return ret;
+	}
 
 	usb_hid_report_path_set_report_id(path, 0);
 
-	kbd_dev->key_count = usb_hid_report_size(
-	    &hid_dev->report, 0, USB_HID_REPORT_TYPE_INPUT);
+	kbd_dev->key_count =
+	    usb_hid_report_size(&hid_dev->report, 0, USB_HID_REPORT_TYPE_INPUT);
+
 	usb_hid_report_path_free(path);
 
@@ -621,30 +616,24 @@
 
 	kbd_dev->keys = calloc(kbd_dev->key_count, sizeof(int32_t));
-
 	if (kbd_dev->keys == NULL) {
-		usb_log_error("No memory!\n");
-		free(kbd_dev);
+		usb_log_error("Failed to allocate key buffer.\n");
+		usb_kbd_destroy(kbd_dev);
 		return ENOMEM;
 	}
 
-	kbd_dev->keys_old = 
-		(int32_t *)calloc(kbd_dev->key_count, sizeof(int32_t));
-
+	kbd_dev->keys_old = calloc(kbd_dev->key_count, sizeof(int32_t));
 	if (kbd_dev->keys_old == NULL) {
-		usb_log_error("No memory!\n");
-		free(kbd_dev->keys);
-		free(kbd_dev);
+		usb_log_error("Failed to allocate old_key buffer.\n");
+		usb_kbd_destroy(kbd_dev);
 		return ENOMEM;
 	}
 
-	/*
-	 * Output report
-	 */
+	/* Output report */
 	kbd_dev->output_size = 0;
 	kbd_dev->output_buffer = usb_hid_report_output(&hid_dev->report,
 	    &kbd_dev->output_size, 0);
 	if (kbd_dev->output_buffer == NULL) {
-		usb_log_warning("Error creating output report buffer.\n");
-		free(kbd_dev->keys);
+		usb_log_error("Error creating output report buffer.\n");
+		usb_kbd_destroy(kbd_dev);
 		return ENOMEM;
 	}
@@ -653,92 +642,71 @@
 
 	kbd_dev->led_path = usb_hid_report_path();
-	usb_hid_report_path_append_item(
+	if (kbd_dev->led_path == NULL) {
+		usb_log_error("Failed to create kbd led report path.\n");
+		usb_kbd_destroy(kbd_dev);
+		return ENOMEM;
+	}
+
+	ret = usb_hid_report_path_append_item(
 	    kbd_dev->led_path, USB_HIDUT_PAGE_LED, 0);
+	if (ret != EOK) {
+		usb_log_error("Failed to append to kbd/led report path.\n");
+		usb_kbd_destroy(kbd_dev);
+		return ret;
+	}
 
 	kbd_dev->led_output_size = usb_hid_report_size(
 	    &hid_dev->report, 0, USB_HID_REPORT_TYPE_OUTPUT);
 
-	usb_log_debug("Output report size (in items): %zu\n", 
+	usb_log_debug("Output report size (in items): %zu\n",
 	    kbd_dev->led_output_size);
 
-	kbd_dev->led_data = (int32_t *)calloc(
-	    kbd_dev->led_output_size, sizeof(int32_t));
-
+	kbd_dev->led_data = calloc(kbd_dev->led_output_size, sizeof(int32_t));
 	if (kbd_dev->led_data == NULL) {
-		usb_log_warning("Error creating buffer for LED output report."
-		    "\n");
-		free(kbd_dev->keys);
-		usb_hid_report_output_free(kbd_dev->output_buffer);
-		free(kbd_dev);
+		usb_log_error("Error creating buffer for LED output report.\n");
+		usb_kbd_destroy(kbd_dev);
 		return ENOMEM;
 	}
 
-	/*
-	 * Modifiers and locks
-	 */
-	kbd_dev->modifiers = 0;
-	kbd_dev->mods = DEFAULT_ACTIVE_MODS;
-	kbd_dev->lock_keys = 0;
-
-	/*
-	 * Autorepeat
-	 */
-	kbd_dev->repeat.key_new = 0;
-	kbd_dev->repeat.key_repeated = 0;
-	kbd_dev->repeat.delay_before = DEFAULT_DELAY_BEFORE_FIRST_REPEAT;
-	kbd_dev->repeat.delay_between = DEFAULT_REPEAT_DELAY;
-
-	fibril_mutex_initialize(&kbd_dev->repeat_mtx);
-
-	// save the KBD device structure into the HID device structure
+	/* Set LEDs according to initial setup.
+	 * Set Idle rate */
+	usb_kbd_set_led(hid_dev, kbd_dev);
+
+	usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe,
+	    hid_dev->usb_dev->interface_no, IDLE_RATE);
+
+	/* Save the KBD device structure into the HID device structure. */
 	*data = kbd_dev;
 
-	// set handler for incoming calls
-	kbd_dev->ops.default_handler = default_connection_handler;
-
-	/*
-	 * Set LEDs according to initial setup.
-	 * Set Idle rate
-	 */
-	usb_kbd_set_led(hid_dev, kbd_dev);
-
-	usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 
-	    hid_dev->usb_dev->interface_no, IDLE_RATE);
-
-	/*
-	 * Create new fibril for auto-repeat
-	 */
+	kbd_dev->initialized = USB_KBD_STATUS_INITIALIZED;
+	usb_log_debug("HID/KBD device structure initialized.\n");
+
+	usb_log_debug("Creating KBD function...\n");
+	ret = usb_kbd_create_function(kbd_dev);
+	if (ret != EOK) {
+		usb_kbd_destroy(kbd_dev);
+		return ret;
+	}
+
+	/* Create new fibril for auto-repeat. */
 	fid_t fid = fibril_create(usb_kbd_repeat_fibril, kbd_dev);
 	if (fid == 0) {
 		usb_log_error("Failed to start fibril for KBD auto-repeat");
+		usb_kbd_destroy(kbd_dev);
 		return ENOMEM;
 	}
 	fibril_add_ready(fid);
 
-	kbd_dev->initialized = USB_KBD_STATUS_INITIALIZED;
-	usb_log_debug("HID/KBD device structure initialized.\n");
-
-	usb_log_debug("Creating KBD function...\n");
-	int rc = usb_kbd_create_function(kbd_dev);
-	if (rc != EOK) {
-		usb_kbd_destroy(kbd_dev);
-		return rc;
-	}
-
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 bool usb_kbd_polling_callback(usb_hid_dev_t *hid_dev, void *data)
 {
-	if (hid_dev == NULL/* || buffer == NULL*/ || data == NULL) {
-		// do not continue polling (???)
+	if (hid_dev == NULL || data == NULL) {
+		/* This means something serious */
 		return false;
 	}
 
-	usb_kbd_t *kbd_dev = (usb_kbd_t *)data;
-	assert(kbd_dev != NULL);
-
+	usb_kbd_t *kbd_dev = data;
 	// TODO: add return value from this function
 	usb_kbd_process_data(hid_dev, kbd_dev);
@@ -746,19 +714,14 @@
 	return true;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev)
 {
 	return (kbd_dev->initialized == USB_KBD_STATUS_INITIALIZED);
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev)
 {
 	return (kbd_dev->initialized == USB_KBD_STATUS_TO_DESTROY);
 }
-
 /*----------------------------------------------------------------------------*/
 /**
@@ -773,6 +736,7 @@
 	}
 
-	// hangup session to the console
-	async_hangup(kbd_dev->console_sess);
+	/* Hangup session to the console. */
+	if (kbd_dev->console_sess)
+		async_hangup(kbd_dev->console_sess);
 
 	//assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
@@ -781,51 +745,44 @@
 	while (fibril_mutex_is_locked(&kbd_dev->repeat_mtx)) {}
 
-	// free all buffers
+	/* Free all buffers. */
 	free(kbd_dev->keys);
 	free(kbd_dev->keys_old);
 	free(kbd_dev->led_data);
 
-	if (kbd_dev->led_path != NULL) {
-		usb_hid_report_path_free(kbd_dev->led_path);
-	}
-	if (kbd_dev->output_buffer != NULL) {
-		usb_hid_report_output_free(kbd_dev->output_buffer);
-	}
-
-	if (ddf_fun_unbind(kbd_dev->fun) != EOK) {
-		usb_log_warning("Failed to unbind kbd function.\n");
-	} else {
-		usb_log_debug2("%s unbound.\n", kbd_dev->fun->name);
-		kbd_dev->fun->driver_data = NULL;
-		ddf_fun_destroy(kbd_dev->fun);
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
+	usb_hid_report_path_free(kbd_dev->led_path);
+	usb_hid_report_output_free(kbd_dev->output_buffer);
+
+	if (kbd_dev->fun) {
+		if (ddf_fun_unbind(kbd_dev->fun) != EOK) {
+			usb_log_warning("Failed to unbind %s.\n",
+			    kbd_dev->fun->name);
+		} else {
+			usb_log_debug2("%s unbound.\n", kbd_dev->fun->name);
+			kbd_dev->fun->driver_data = NULL;
+			ddf_fun_destroy(kbd_dev->fun);
+		}
+	}
+	free(kbd_dev);
+}
+/*----------------------------------------------------------------------------*/
 void usb_kbd_deinit(usb_hid_dev_t *hid_dev, void *data)
 {
-	if (hid_dev == NULL) {
-		return;
-	}
-
 	if (data != NULL) {
 		usb_kbd_t *kbd_dev = data;
 		if (usb_kbd_is_initialized(kbd_dev)) {
-			usb_kbd_mark_unusable(kbd_dev);
-			/* wait for autorepeat */
+			kbd_dev->initialized = USB_KBD_STATUS_TO_DESTROY;
+			/* Wait for autorepeat */
 			async_usleep(CHECK_DELAY);
-			usb_kbd_destroy(kbd_dev);
-		}
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
+		}
+		usb_kbd_destroy(kbd_dev);
+	}
+}
+/*----------------------------------------------------------------------------*/
 int usb_kbd_set_boot_protocol(usb_hid_dev_t *hid_dev)
 {
+	assert(hid_dev);
 	int rc = usb_hid_parse_report_descriptor(
 	    &hid_dev->report, USB_KBD_BOOT_REPORT_DESCRIPTOR,
-	    USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE);
+	    sizeof(USB_KBD_BOOT_REPORT_DESCRIPTOR));
 
 	if (rc != EOK) {
@@ -846,5 +803,4 @@
 	return EOK;
 }
-
 /**
  * @}
Index: uspace/drv/bus/usb/usbhid/kbd/kbddev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbddev.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhid/kbd/kbddev.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -135,5 +135,5 @@
 void usb_kbd_destroy(usb_kbd_t *kbd_dev);
 
-void usb_kbd_push_ev(struct usb_hid_dev *hid_dev, usb_kbd_t *kbd_dev,
+void usb_kbd_push_ev(usb_kbd_t *kbd_dev,
     int type, unsigned int key);
 
Index: uspace/drv/bus/usb/usbhid/kbd/kbdrepeat.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbdrepeat.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhid/kbd/kbdrepeat.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -45,7 +45,4 @@
 #include "kbddev.h"
 
-
-
-/*----------------------------------------------------------------------------*/
 /**
  * Main loop handling the auto-repeat of keys.
@@ -58,12 +55,12 @@
  * If the same key is still pressed, it uses the delay between repeats stored
  * in the keyboard structure to wait until the key should be repeated.
- * 
+ *
  * If the currently repeated key is not pressed any more (
- * usb_kbd_repeat_stop() was called), it stops repeating it and starts 
+ * usb_kbd_repeat_stop() was called), it stops repeating it and starts
  * checking again.
  *
  * @note For accessing the keyboard device auto-repeat information a fibril
  *       mutex (repeat_mtx) from the @a kbd structure is used.
- * 
+ *
  * @param kbd Keyboard device structure.
  */
@@ -75,18 +72,17 @@
 
 	while (true) {
-		// check if the kbd structure is usable
+		/* Check if the kbd structure is usable. */
 		if (!usb_kbd_is_initialized(kbd)) {
 			usb_log_warning("kbd not ready, exiting autorepeat.\n");
 			return;
 		}
-		
+
 		fibril_mutex_lock(&kbd->repeat_mtx);
 
 		if (kbd->repeat.key_new > 0) {
 			if (kbd->repeat.key_new == kbd->repeat.key_repeated) {
-				usb_log_debug2("Repeating key: %u.\n", 
+				usb_log_debug2("Repeating key: %u.\n",
 				    kbd->repeat.key_repeated);
-				// ugly hack with the NULL
-				usb_kbd_push_ev(NULL, kbd, KEY_PRESS, 
+				usb_kbd_push_ev(kbd, KEY_PRESS,
 				    kbd->repeat.key_repeated);
 				delay = kbd->repeat.delay_between;
@@ -106,9 +102,7 @@
 		}
 		fibril_mutex_unlock(&kbd->repeat_mtx);
-		
 		async_usleep(delay);
 	}
 }
-
 /*----------------------------------------------------------------------------*/
 /**
@@ -116,5 +110,5 @@
  *
  * Starts the loop for checking changes in auto-repeat.
- * 
+ *
  * @param arg User-specified argument. Expects pointer to the keyboard device
  *            structure representing the keyboard.
@@ -132,5 +126,5 @@
 	}
 
-	usb_kbd_t *kbd = (usb_kbd_t *)arg;
+	usb_kbd_t *kbd = arg;
 
 	usb_kbd_repeat_loop(kbd);
@@ -138,5 +132,4 @@
 	return EOK;
 }
-
 /*----------------------------------------------------------------------------*/
 /**
@@ -156,5 +149,4 @@
 	fibril_mutex_unlock(&kbd->repeat_mtx);
 }
-
 /*----------------------------------------------------------------------------*/
 /**
@@ -162,5 +154,5 @@
  *
  * @note Only one key is repeated at any time, but this function may be called
- *       even with key that is not currently repeated (in that case nothing 
+ *       even with key that is not currently repeated (in that case nothing
  *       happens).
  *
@@ -176,5 +168,4 @@
 	fibril_mutex_unlock(&kbd->repeat_mtx);
 }
-
 /**
  * @}
Index: uspace/drv/bus/usb/usbhid/main.c
===================================================================
--- uspace/drv/bus/usb/usbhid/main.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhid/main.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -49,39 +49,33 @@
 
 /**
- * Function for adding a new device of type USB/HID/keyboard.
+ * Callback for passing a new device to the driver.
  *
- * This functions initializes required structures from the device's descriptors
- * and starts new fibril for polling the keyboard for events and another one for
- * handling auto-repeat of keys.
+ * @note Currently, only boot-protocol keyboards are supported by this driver.
  *
- * During initialization, the keyboard is switched into boot protocol, the idle
- * rate is set to 0 (infinity), resulting in the keyboard only reporting event
- * when a key is pressed or released. Finally, the LED lights are turned on 
- * according to the default setup of lock keys.
- *
- * @note By default, the keyboards is initialized with Num Lock turned on and 
- *       other locks turned off.
- * @note Currently supports only boot-protocol keyboards.
- *
- * @param dev Device to add.
+ * @param dev Structure representing the new device.
  * @return Error code.
  */
-static int usb_hid_try_add_device(usb_device_t *dev)
+static int usb_hid_device_add(usb_device_t *dev)
 {
-	assert(dev != NULL);
+	usb_log_debug("%s\n", __FUNCTION__);
 
-	/* Initialize device (get and process descriptors, get address, etc.) */
-	usb_log_debug("Initializing USB/HID device...\n");
+	if (dev == NULL) {
+		usb_log_error("Wrong parameter given for add_device().\n");
+		return EINVAL;
+	}
 
+	if (dev->interface_no < 0) {
+		usb_log_error("Failed to add HID device: endpoints not found."
+		    "\n");
+		return ENOTSUP;
+	}
 	usb_hid_dev_t *hid_dev =
 	    usb_device_data_alloc(dev, sizeof(usb_hid_dev_t));
 	if (hid_dev == NULL) {
-		usb_log_error("Error while creating USB/HID device "
-		    "structure.\n");
+		usb_log_error("Failed to create USB/HID device structure.\n");
 		return ENOMEM;
 	}
 
 	int rc = usb_hid_init(hid_dev, dev);
-
 	if (rc != EOK) {
 		usb_log_error("Failed to initialize USB/HID device.\n");
@@ -92,19 +86,7 @@
 	usb_log_debug("USB/HID device structure initialized.\n");
 
-	/*
-	 * 1) subdriver vytvori vlastnu ddf_fun, vlastne ddf_dev_ops, ktore da
-	 *    do nej.
-	 * 2) do tych ops do .interfaces[DEV_IFACE_USBHID (asi)] priradi 
-	 *    vyplnenu strukturu usbhid_iface_t.
-	 * 3) klientska aplikacia - musi si rucne vytvorit telefon
-	 *    (devman_device_connect() - cesta k zariadeniu (/hw/pci0/...) az 
-	 *    k tej fcii.
-	 *    pouzit usb/classes/hid/iface.h - prvy int je telefon
-	 */
-
 	/* Start automated polling function.
 	 * This will create a separate fibril that will query the device
-	 * for the data continuously 
-	 */
+	 * for the data continuously. */
        rc = usb_device_auto_poll(dev,
 	   /* Index of the polling pipe. */
@@ -113,5 +95,5 @@
 	   usb_hid_polling_callback,
 	   /* How much data to request. */
-	   dev->pipes[hid_dev->poll_pipe_index].pipe->max_packet_size,
+	   dev->pipes[hid_dev->poll_pipe_index].pipe.max_packet_size,
 	   /* Callback when the polling ends. */
 	   usb_hid_polling_ended_callback,
@@ -126,43 +108,4 @@
 	}
 	hid_dev->running = true;
-
-	/*
-	 * Hurrah, device is initialized.
-	 */
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/**
- * Callback for passing a new device to the driver.
- *
- * @note Currently, only boot-protocol keyboards are supported by this driver.
- *
- * @param dev Structure representing the new device.
- * @return Error code.
- */
-static int usb_hid_device_add(usb_device_t *dev)
-{
-	usb_log_debug("usb_hid_device_add()\n");
-
-	if (dev == NULL) {
-		usb_log_warning("Wrong parameter given for add_device().\n");
-		return EINVAL;
-	}
-
-	if (dev->interface_no < 0) {
-		usb_log_warning("Device is not a supported HID device.\n");
-		usb_log_error("Failed to add HID device: endpoints not found."
-		    "\n");
-		return ENOTSUP;
-	}
-
-	int rc = usb_hid_try_add_device(dev);
-
-	if (rc != EOK) {
-		usb_log_warning("Device is not a supported HID device.\n");
-		usb_log_error("Failed to add HID device: %s.\n",
-		    str_error(rc));
-		return rc;
-	}
 
 	usb_log_info("HID device `%s' ready to use.\n", dev->ddf_dev->name);
@@ -179,5 +122,7 @@
 static int usb_hid_device_rem(usb_device_t *dev)
 {
-	return EOK;
+	// TODO: Stop device polling
+	// TODO: Call deinit (stops autorepeat too)
+	return ENOTSUP;
 }
 /*----------------------------------------------------------------------------*/
@@ -190,15 +135,17 @@
 static int usb_hid_device_gone(usb_device_t *dev)
 {
+	assert(dev);
+	assert(dev->driver_data);
 	usb_hid_dev_t *hid_dev = dev->driver_data;
-	unsigned tries = 10;
-	while (hid_dev->running) {
+	unsigned tries = 100;
+	/* Wait for fail. */
+	while (hid_dev->running && tries--) {
 		async_usleep(100000);
-		if (!tries--) {
-			usb_log_error("Can't remove hub, still running.\n");
-			return EBUSY;
-		}
+	}
+	if (hid_dev->running) {
+		usb_log_error("Can't remove hid, still running.\n");
+		return EBUSY;
 	}
 
-	assert(!hid_dev->running);
 	usb_hid_deinit(hid_dev);
 	usb_log_debug2("%s destruction complete.\n", dev->ddf_dev->name);
Index: uspace/drv/bus/usb/usbhid/mouse/mousedev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -55,5 +55,5 @@
 #define ARROWS_PER_SINGLE_WHEEL 3
 
-#define NAME  "mouse"
+#define NAME "mouse"
 
 /*----------------------------------------------------------------------------*/
@@ -77,11 +77,5 @@
 
 /*----------------------------------------------------------------------------*/
-
-enum {
-	USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE = 63
-};
-
-static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[
-    USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE] = {
+static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[] = {
 	0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
 	0x09, 0x02,                    // USAGE (Mouse)
@@ -123,20 +117,17 @@
     ipc_callid_t icallid, ipc_call_t *icall)
 {
-	usb_mouse_t *mouse_dev = (usb_mouse_t *) fun->driver_data;
+	usb_mouse_t *mouse_dev = fun->driver_data;
 
 	if (mouse_dev == NULL) {
-		usb_log_debug("default_connection_handler: Missing "
-		    "parameters.\n");
+		usb_log_debug("%s: Missing parameters.\n", __FUNCTION__);
 		async_answer_0(icallid, EINVAL);
 		return;
 	}
 
-	usb_log_debug("default_connection_handler: fun->name: %s\n",
-	              fun->name);
-	usb_log_debug("default_connection_handler: mouse_sess: %p, "
-	    "wheel_sess: %p\n", mouse_dev->mouse_sess, mouse_dev->wheel_sess);
-
-	async_sess_t **sess_ptr =
-	    (str_cmp(fun->name, HID_MOUSE_FUN_NAME) == 0) ?
+	usb_log_debug("%s: fun->name: %s\n", __FUNCTION__, fun->name);
+	usb_log_debug("%s: mouse_sess: %p, wheel_sess: %p\n",
+	    __FUNCTION__, mouse_dev->mouse_sess, mouse_dev->wheel_sess);
+
+	async_sess_t **sess_ptr = (fun == mouse_dev->mouse_fun) ?
 	    &mouse_dev->mouse_sess : &mouse_dev->wheel_sess;
 
@@ -146,58 +137,15 @@
 		if (*sess_ptr == NULL) {
 			*sess_ptr = sess;
-			usb_log_debug("Console session to mouse set ok (%p).\n",
-			    sess);
+			usb_log_debug("Console session to %s set ok (%p).\n",
+			    fun->name, sess);
 			async_answer_0(icallid, EOK);
 		} else {
-			usb_log_debug("default_connection_handler: Console "
-			    "session to mouse already set.\n");
+			usb_log_error("Console session to %s already set.\n",
+			    fun->name);
 			async_answer_0(icallid, ELIMIT);
 		}
 	} else {
-		usb_log_debug("default_connection_handler: Invalid function.\n");
+		usb_log_debug("%s: Invalid function.\n", __FUNCTION__);
 		async_answer_0(icallid, EINVAL);
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
-static usb_mouse_t *usb_mouse_new(void)
-{
-	usb_mouse_t *mouse = calloc(1, sizeof(usb_mouse_t));
-	if (mouse == NULL) {
-		return NULL;
-	}
-	mouse->mouse_sess = NULL;
-	mouse->wheel_sess = NULL;
-
-	return mouse;
-}
-
-/*----------------------------------------------------------------------------*/
-
-static void usb_mouse_destroy(usb_mouse_t *mouse_dev)
-{
-	assert(mouse_dev != NULL);
-
-	// hangup session to the console
-	if (mouse_dev->mouse_sess != NULL)
-		async_hangup(mouse_dev->mouse_sess);
-
-	if (mouse_dev->wheel_sess != NULL)
-		async_hangup(mouse_dev->wheel_sess);
-	int ret = ddf_fun_unbind(mouse_dev->mouse_fun);
-	if (ret != EOK) {
-		usb_log_error("Failed to unbind mouse function.\n");
-	} else {
-		ddf_fun_destroy(mouse_dev->mouse_fun);
-		/* Prevent double free */
-		mouse_dev->wheel_fun->driver_data = NULL;
-	}
-
-	ret = ddf_fun_unbind(mouse_dev->wheel_fun);
-	if (ret != EOK) {
-		usb_log_error("Failed to unbind wheel function.\n");
-	} else {
-		ddf_fun_destroy(mouse_dev->wheel_fun);
 	}
 }
@@ -215,8 +163,7 @@
 	}
 
-	int count = ((wheel < 0) ? -wheel : wheel) * ARROWS_PER_SINGLE_WHEEL;
-	int i;
-
-	for (i = 0; i < count; i++) {
+	const unsigned count =
+	    ((wheel < 0) ? -wheel : wheel) * ARROWS_PER_SINGLE_WHEEL;
+	for (unsigned i = 0; i < count; i++) {
 		/* Send arrow press and release. */
 		usb_log_debug2("Sending key %d to the console\n", key);
@@ -267,9 +214,9 @@
 	}
 
-	int shift_x = get_mouse_axis_move_value(hid_dev->report_id,
+	const int shift_x = get_mouse_axis_move_value(hid_dev->report_id,
 	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_X);
-	int shift_y = get_mouse_axis_move_value(hid_dev->report_id,
+	const int shift_y = get_mouse_axis_move_value(hid_dev->report_id,
 	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_Y);
-	int wheel = get_mouse_axis_move_value(hid_dev->report_id,
+	const int wheel = get_mouse_axis_move_value(hid_dev->report_id,
 	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
 
@@ -277,6 +224,8 @@
 		async_exch_t *exch =
 		    async_exchange_begin(mouse_dev->mouse_sess);
-		async_req_2_0(exch, MOUSEEV_MOVE_EVENT, shift_x, shift_y);
-		async_exchange_end(exch);
+		if (exch != NULL) {
+			async_req_2_0(exch, MOUSEEV_MOVE_EVENT, shift_x, shift_y);
+			async_exchange_end(exch);
+		}
 	}
 
@@ -284,9 +233,17 @@
 		usb_mouse_send_wheel(mouse_dev, wheel);
 
-	/*
-	 * Buttons
-	 */
+	/* Buttons */
 	usb_hid_report_path_t *path = usb_hid_report_path();
-	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0);
+	if (path == NULL) {
+		usb_log_warning("Failed to create USB HID report path.\n");
+		return true;
+	}
+	int ret =
+	   usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0);
+	if (ret != EOK) {
+		usb_hid_report_path_free(path);
+		usb_log_warning("Failed to add buttons to report path.\n");
+		return true;
+	}
 	usb_hid_report_path_set_report_id(path, hid_dev->report_id);
 
@@ -298,23 +255,27 @@
 		usb_log_debug2(NAME " VALUE(%X) USAGE(%X)\n", field->value,
 		    field->usage);
-		
-		if (mouse_dev->buttons[field->usage - field->usage_minimum] == 0
-		    && field->value != 0) {
+		assert(field->usage > field->usage_minimum);
+		const unsigned index = field->usage - field->usage_minimum;
+		assert(index < mouse_dev->buttons_count);
+
+		if (mouse_dev->buttons[index] == 0 && field->value != 0) {
 			async_exch_t *exch =
 			    async_exchange_begin(mouse_dev->mouse_sess);
-			async_req_2_0(exch, MOUSEEV_BUTTON_EVENT, field->usage, 1);
-			async_exchange_end(exch);
-			
-			mouse_dev->buttons[field->usage - field->usage_minimum]
-			    = field->value;
-		} else if (mouse_dev->buttons[field->usage - field->usage_minimum] != 0
-		    && field->value == 0) {
+			if (exch != NULL) {
+				async_req_2_0(exch, MOUSEEV_BUTTON_EVENT,
+				    field->usage, 1);
+				async_exchange_end(exch);
+				mouse_dev->buttons[index] = field->value;
+			}
+
+		} else if (mouse_dev->buttons[index] != 0 && field->value == 0) {
 			async_exch_t *exch =
 			    async_exchange_begin(mouse_dev->mouse_sess);
-			async_req_2_0(exch, MOUSEEV_BUTTON_EVENT, field->usage, 0);
-			async_exchange_end(exch);
-
-			mouse_dev->buttons[field->usage - field->usage_minimum] =
-			   field->value;
+			if (exch != NULL) {
+				async_req_2_0(exch, MOUSEEV_BUTTON_EVENT,
+				    field->usage, 0);
+				async_exchange_end(exch);
+				mouse_dev->buttons[index] = field->value;
+			}
 		}
 
@@ -329,7 +290,16 @@
 	return true;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
+#define FUN_UNBIND_DESTROY(fun) \
+if (fun) { \
+	if (ddf_fun_unbind((fun)) == EOK) { \
+		(fun)->driver_data = NULL; \
+		ddf_fun_destroy((fun)); \
+	} else { \
+		usb_log_error("Could not unbind function `%s', it " \
+		    "will not be destroyed.\n", (fun)->name); \
+	} \
+} else (void)0
+/*----------------------------------------------------------------------------*/
 static int usb_mouse_create_function(usb_hid_dev_t *hid_dev, usb_mouse_t *mouse)
 {
@@ -339,8 +309,9 @@
 	/* Create the exposed function. */
 	usb_log_debug("Creating DDF function %s...\n", HID_MOUSE_FUN_NAME);
-	ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
+	ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
 	    HID_MOUSE_FUN_NAME);
 	if (fun == NULL) {
-		usb_log_error("Could not create DDF function node.\n");
+		usb_log_error("Could not create DDF function node `%s'.\n",
+		    HID_MOUSE_FUN_NAME);
 		return ENOMEM;
 	}
@@ -351,11 +322,13 @@
 	int rc = ddf_fun_bind(fun);
 	if (rc != EOK) {
-		usb_log_error("Could not bind DDF function: %s.\n",
-		    str_error(rc));
-		return rc;
-	}
-
-	usb_log_debug("Adding DDF function to category %s...\n", 
-	    HID_MOUSE_CATEGORY);
+		usb_log_error("Could not bind DDF function `%s': %s.\n",
+		    fun->name, str_error(rc));
+		fun->driver_data = NULL;
+		ddf_fun_destroy(fun);
+		return rc;
+	}
+
+	usb_log_debug("Adding DDF function `%s' to category %s...\n",
+	    fun->name, HID_MOUSE_CATEGORY);
 	rc = ddf_fun_add_to_category(fun, HID_MOUSE_CATEGORY);
 	if (rc != EOK) {
@@ -363,4 +336,5 @@
 		    "Could not add DDF function to category %s: %s.\n",
 		    HID_MOUSE_CATEGORY, str_error(rc));
+		FUN_UNBIND_DESTROY(fun);
 		return rc;
 	}
@@ -370,10 +344,13 @@
 	 * Special function for acting as keyboard (wheel)
 	 */
-	usb_log_debug("Creating DDF function %s...\n", 
+	usb_log_debug("Creating DDF function %s...\n",
 	              HID_MOUSE_WHEEL_FUN_NAME);
-	fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
+	fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
 	    HID_MOUSE_WHEEL_FUN_NAME);
 	if (fun == NULL) {
-		usb_log_error("Could not create DDF function node.\n");
+		usb_log_error("Could not create DDF function node `%s'.\n",
+		    HID_MOUSE_WHEEL_FUN_NAME);
+		FUN_UNBIND_DESTROY(mouse->mouse_fun);
+		mouse->mouse_fun = NULL;
 		return ENOMEM;
 	}
@@ -388,6 +365,11 @@
 	rc = ddf_fun_bind(fun);
 	if (rc != EOK) {
-		usb_log_error("Could not bind DDF function: %s.\n",
-		    str_error(rc));
+		usb_log_error("Could not bind DDF function `%s': %s.\n",
+		    fun->name, str_error(rc));
+		FUN_UNBIND_DESTROY(mouse->mouse_fun);
+		mouse->mouse_fun = NULL;
+
+		fun->driver_data = NULL;
+		ddf_fun_destroy(fun);
 		return rc;
 	}
@@ -400,4 +382,8 @@
 		    "Could not add DDF function to category %s: %s.\n",
 		    HID_MOUSE_WHEEL_CATEGORY, str_error(rc));
+
+		FUN_UNBIND_DESTROY(mouse->mouse_fun);
+		mouse->mouse_fun = NULL;
+		FUN_UNBIND_DESTROY(fun);
 		return rc;
 	}
@@ -448,7 +434,5 @@
 	return highest_button;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 int usb_mouse_init(usb_hid_dev_t *hid_dev, void **data)
 {
@@ -461,5 +445,5 @@
 	}
 
-	usb_mouse_t *mouse_dev = usb_mouse_new();
+	usb_mouse_t *mouse_dev = calloc(1, sizeof(usb_mouse_t));
 	if (mouse_dev == NULL) {
 		usb_log_error("Error while creating USB/HID Mouse device "
@@ -484,55 +468,71 @@
 	}
 
-
-	// save the Mouse device structure into the HID device structure
-	*data = mouse_dev;
-
 	// set handler for incoming calls
 	mouse_dev->ops.default_handler = default_connection_handler;
 
 	// TODO: how to know if the device supports the request???
-	usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 
+	usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe,
 	    hid_dev->usb_dev->interface_no, IDLE_RATE);
 
 	int rc = usb_mouse_create_function(hid_dev, mouse_dev);
 	if (rc != EOK) {
-		usb_mouse_destroy(mouse_dev);
-		return rc;
-	}
+		free(mouse_dev->buttons);
+		free(mouse_dev);
+		return rc;
+	}
+
+	/* Save the Mouse device structure into the HID device structure. */
+	*data = mouse_dev;
 
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 bool usb_mouse_polling_callback(usb_hid_dev_t *hid_dev, void *data)
 {
 	if (hid_dev == NULL || data == NULL) {
-		usb_log_error("Missing argument to the mouse polling callback."
-		    "\n");
+		usb_log_error(
+		    "Missing argument to the mouse polling callback.\n");
 		return false;
 	}
 
-	usb_mouse_t *mouse_dev = (usb_mouse_t *)data;
-		
+	usb_mouse_t *mouse_dev = data;
+
 	return usb_mouse_process_report(hid_dev, mouse_dev);
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 void usb_mouse_deinit(usb_hid_dev_t *hid_dev, void *data)
 {
-	if (data != NULL) {
-		usb_mouse_destroy(data);
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
+	if (data == NULL)
+		return;
+
+	usb_mouse_t *mouse_dev = data;
+
+	/* Hangup session to the console */
+	if (mouse_dev->mouse_sess != NULL) {
+		const int ret = async_hangup(mouse_dev->mouse_sess);
+		if (ret != EOK)
+			usb_log_warning("Failed to hang up mouse session: "
+			    "%p, %s.\n", mouse_dev->mouse_sess, str_error(ret));
+	}
+
+	if (mouse_dev->wheel_sess != NULL) {
+		const int ret = async_hangup(mouse_dev->wheel_sess);
+		if (ret != EOK)
+			usb_log_warning("Failed to hang up wheel session: "
+			    "%p, %s.\n", mouse_dev->wheel_sess, str_error(ret));
+	}
+
+	FUN_UNBIND_DESTROY(mouse_dev->mouse_fun);
+	FUN_UNBIND_DESTROY(mouse_dev->wheel_fun);
+
+	free(mouse_dev->buttons);
+	free(mouse_dev);
+}
+/*----------------------------------------------------------------------------*/
 int usb_mouse_set_boot_protocol(usb_hid_dev_t *hid_dev)
 {
 	int rc = usb_hid_parse_report_descriptor(
 	    &hid_dev->report, USB_MOUSE_BOOT_REPORT_DESCRIPTOR,
-	    USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE);
+	    sizeof(USB_MOUSE_BOOT_REPORT_DESCRIPTOR));
 
 	if (rc != EOK) {
Index: uspace/drv/bus/usb/usbhid/multimedia/multimedia.c
===================================================================
--- uspace/drv/bus/usb/usbhid/multimedia/multimedia.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhid/multimedia/multimedia.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -67,11 +67,9 @@
 	/** IPC session to the console device (for sending key events). */
 	async_sess_t *console_sess;
-	/** DDF function */
-	ddf_fun_t *fun;
 } usb_multimedia_t;
 
 
 /*----------------------------------------------------------------------------*/
-/** 
+/**
  * Default handler for IPC methods not handled by DDF.
  *
@@ -88,11 +86,10 @@
 {
 	usb_log_debug(NAME " default_connection_handler()\n");
-
-	usb_multimedia_t *multim_dev = (usb_multimedia_t *)fun->driver_data;
-
-	if (multim_dev == NULL) {
+	if (fun == NULL || fun->driver_data == NULL) {
 		async_answer_0(icallid, EINVAL);
 		return;
 	}
+
+	usb_multimedia_t *multim_dev = fun->driver_data;
 
 	async_sess_t *sess =
@@ -109,11 +106,8 @@
 		async_answer_0(icallid, EINVAL);
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static ddf_dev_ops_t multimedia_ops = {
 	.default_handler = default_connection_handler
 };
-
 /*----------------------------------------------------------------------------*/
 /**
@@ -127,23 +121,22 @@
  *       sends also these keys to application (otherwise it cannot use those
  *       keys at all).
- * 
- * @param hid_dev 
- * @param lgtch_dev 
- * @param type Type of the event (press / release). Recognized values: 
+ *
+ * @param hid_dev
+ * @param multim_dev
+ * @param type Type of the event (press / release). Recognized values:
  *             KEY_PRESS, KEY_RELEASE
  * @param key Key code of the key according to HID Usage Tables.
  */
-static void usb_multimedia_push_ev(usb_hid_dev_t *hid_dev, 
+static void usb_multimedia_push_ev(
     usb_multimedia_t *multim_dev, int type, unsigned int key)
 {
-	assert(hid_dev != NULL);
 	assert(multim_dev != NULL);
 
-	kbd_event_t ev;
-
-	ev.type = type;
-	ev.key = key;
-	ev.mods = 0;
-	ev.c = 0;
+	const kbd_event_t ev = {
+		.type = type,
+		.key = key,
+		.mods = 0,
+		.c = 0,
+	};
 
 	usb_log_debug2(NAME " Sending key %d to the console\n", ev.key);
@@ -155,14 +148,16 @@
 
 	async_exch_t *exch = async_exchange_begin(multim_dev->console_sess);
-	async_msg_4(exch, KBDEV_EVENT, ev.type, ev.key, ev.mods, ev.c);
-	async_exchange_end(exch);
-}
-
-/*----------------------------------------------------------------------------*/
-
+	if (exch != NULL) {
+		async_msg_4(exch, KBDEV_EVENT, ev.type, ev.key, ev.mods, ev.c);
+		async_exchange_end(exch);
+	} else {
+		usb_log_warning("Failed to send multimedia key.\n");
+	}
+}
+/*----------------------------------------------------------------------------*/
 int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data)
 {
 	if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
-		return EINVAL; /*! @todo Other return code? */
+		return EINVAL;
 	}
 
@@ -187,5 +182,4 @@
 
 	multim_dev->console_sess = NULL;
-	multim_dev->fun = fun;
 
 	//todo Autorepeat?
@@ -199,6 +193,6 @@
 	}
 
-	usb_log_debug("%s function created (handle: %" PRIun ").\n",
-	    NAME, fun->handle);
+	usb_log_debug(NAME " function created (handle: %" PRIun ").\n",
+	    fun->handle);
 
 	rc = ddf_fun_add_to_category(fun, "keyboard");
@@ -207,50 +201,63 @@
 		    "Could not add DDF function to category 'keyboard': %s.\n",
 		    str_error(rc));
-		ddf_fun_destroy(fun);
+		if (ddf_fun_unbind(fun) != EOK) {
+			usb_log_error("Failed to unbind %s, won't destroy.\n",
+			    fun->name);
+		} else {
+			ddf_fun_destroy(fun);
+		}
 		return rc;
 	}
 
 	/* Save the KBD device structure into the HID device structure. */
-	*data = multim_dev;
+	*data = fun;
 
 	usb_log_debug(NAME " HID/multimedia structure initialized.\n");
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data)
 {
-	if (hid_dev == NULL) {
-		return;
-	}
-
-	if (data != NULL) {
-		usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
-		// hangup session to the console
-		async_hangup(multim_dev->console_sess);
-		const int ret = ddf_fun_unbind(multim_dev->fun);
-		if (ret != EOK) {
-			usb_log_error("Failed to unbind multim function.\n");
+	ddf_fun_t *fun = data;
+	if (fun != NULL && fun->driver_data != NULL) {
+		usb_multimedia_t *multim_dev = fun->driver_data;
+		/* Hangup session to the console */
+		if (multim_dev->console_sess)
+			async_hangup(multim_dev->console_sess);
+		if (ddf_fun_unbind(fun) != EOK) {
+			usb_log_error("Failed to unbind %s, won't destroy.\n",
+			    fun->name);
 		} else {
-			usb_log_debug2("%s unbound.\n", multim_dev->fun->name);
-			ddf_fun_destroy(multim_dev->fun);
+			usb_log_debug2("%s unbound.\n", fun->name);
+			/* This frees multim_dev too as it was stored in
+			 * fun->data */
+			ddf_fun_destroy(fun);
 		}
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
+	} else {
+		usb_log_error(
+		    "Failed to deinit multimedia subdriver, data missing.\n");
+	}
+}
+/*----------------------------------------------------------------------------*/
 bool usb_multimedia_polling_callback(struct usb_hid_dev *hid_dev, void *data)
 {
 	// TODO: checks
-	if (hid_dev == NULL || data == NULL) {
+	ddf_fun_t *fun = data;
+	if (hid_dev == NULL || fun == NULL || fun->driver_data == NULL) {
 		return false;
 	}
 
-	usb_multimedia_t *multim_dev = (usb_multimedia_t *)data;
+	usb_multimedia_t *multim_dev = fun->driver_data;
 
 	usb_hid_report_path_t *path = usb_hid_report_path();
-	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
+	if (path == NULL)
+		return true; /* This might be a temporary failure. */
+
+	int ret =
+	    usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
+	if (ret != EOK) {
+		usb_hid_report_path_free(path);
+		return true; /* This might be a temporary failure. */
+	}
 
 	usb_hid_report_path_set_report_id(path, hid_dev->report_id);
@@ -261,23 +268,21 @@
 	    USB_HID_REPORT_TYPE_INPUT);
 
-	/*! @todo Is this iterating OK if done multiple times? 
-	 *  @todo The parsing is not OK
-	 */
+	//FIXME Is this iterating OK if done multiple times?
+	//FIXME The parsing is not OK. (what's wrong?)
 	while (field != NULL) {
-		if(field->value != 0) {
-			usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n", 
+		if (field->value != 0) {
+			usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n",
 			    field->value, field->usage);
-			unsigned int key = 
+			const unsigned key =
 			    usb_multimedia_map_usage(field->usage);
-			const char *key_str = 
+			const char *key_str =
 			    usbhid_multimedia_usage_to_str(field->usage);
 			usb_log_info("Pressed key: %s\n", key_str);
-			usb_multimedia_push_ev(hid_dev, multim_dev, KEY_PRESS, 
-			                       key);
+			usb_multimedia_push_ev(multim_dev, KEY_PRESS, key);
 		}
 
 		field = usb_hid_report_get_sibling(
 		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
-		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
 		    USB_HID_REPORT_TYPE_INPUT);
 	}
@@ -287,5 +292,4 @@
 	return true;
 }
-
 /**
  * @}
Index: uspace/drv/bus/usb/usbhid/subdrivers.c
===================================================================
--- uspace/drv/bus/usb/usbhid/subdrivers.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhid/subdrivers.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -98,8 +98,7 @@
 		}
 	},
-	{NULL, -1, 0, -1, -1, {NULL, NULL, NULL, NULL, NULL}}
 };
 
-const int USB_HID_MAX_SUBDRIVERS =
+const size_t USB_HID_MAX_SUBDRIVERS =
     sizeof(usb_hid_subdrivers) / sizeof(usb_hid_subdrivers[0]);
 
Index: uspace/drv/bus/usb/usbhid/subdrivers.h
===================================================================
--- uspace/drv/bus/usb/usbhid/subdrivers.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhid/subdrivers.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -84,5 +84,5 @@
 
 extern const usb_hid_subdriver_mapping_t usb_hid_subdrivers[];
-extern const int USB_HID_MAX_SUBDRIVERS;
+extern const size_t USB_HID_MAX_SUBDRIVERS;
 
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/usbhid/usbhid.c
===================================================================
--- uspace/drv/bus/usb/usbhid/usbhid.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhid/usbhid.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -51,6 +51,4 @@
 #include "subdrivers.h"
 
-/*----------------------------------------------------------------------------*/
-
 /* Array of endpoints expected on the device, NULL terminated. */
 const usb_endpoint_description_t *usb_hid_endpoints[] = {
@@ -60,7 +58,5 @@
 	NULL
 };
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev)
 {
@@ -78,7 +74,5 @@
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev)
 {
@@ -92,14 +86,13 @@
 	hid_dev->subdriver_count = 1;
 	// TODO 2 should be mouse, but find a better way
-	hid_dev->subdrivers[2] = usb_hid_subdrivers[0].subdriver;
+	hid_dev->subdrivers[0] = usb_hid_subdrivers[2].subdriver;
 
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int usb_hid_set_generic_hid_subdriver(usb_hid_dev_t *hid_dev)
 {
-	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
+	assert(hid_dev != NULL);
+	assert(hid_dev->subdriver_count == 0);
 
 	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
@@ -117,7 +110,5 @@
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static bool usb_hid_ids_match(const usb_hid_dev_t *hid_dev,
     const usb_hid_subdriver_mapping_t *mapping)
@@ -128,10 +119,8 @@
 	return (hid_dev->usb_dev->descriptors.device.vendor_id
 	    == mapping->vendor_id
-	    && hid_dev->usb_dev->descriptors.device.product_id 
+	    && hid_dev->usb_dev->descriptors.device.product_id
 	    == mapping->product_id);
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev,
     const usb_hid_subdriver_mapping_t *mapping)
@@ -145,7 +134,7 @@
 		return false;
 	}
-	int i = 0;
-	while (mapping->usage_path[i].usage != 0
-	    || mapping->usage_path[i].usage_page != 0) {
+
+	for (int i = 0; mapping->usage_path[i].usage != 0
+	    || mapping->usage_path[i].usage_page != 0; ++i) {
 		if (usb_hid_report_path_append_item(usage_path,
 		    mapping->usage_path[i].usage_page,
@@ -155,5 +144,4 @@
 			return false;
 		}
-		++i;
 	}
 
@@ -165,5 +153,4 @@
 	do {
 		usb_log_debug("Trying report id %u\n", report_id);
-
 		if (report_id != 0) {
 			usb_hid_report_path_set_report_id(usage_path,
@@ -171,7 +158,8 @@
 		}
 
-		usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-		    &hid_dev->report, NULL, usage_path, mapping->compare,
-		    USB_HID_REPORT_TYPE_INPUT);
+		const usb_hid_report_field_t *field =
+		    usb_hid_report_get_sibling(
+		        &hid_dev->report, NULL, usage_path, mapping->compare,
+		        USB_HID_REPORT_TYPE_INPUT);
 
 		usb_log_debug("Field: %p\n", field);
@@ -190,13 +178,12 @@
 	return matches;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev,
-    const usb_hid_subdriver_t **subdrivers, int count)
-{
-	int i;
-
-	if (count <= 0) {
+    const usb_hid_subdriver_t **subdrivers, unsigned count)
+{
+	assert(hid_dev);
+	assert(subdrivers);
+
+	if (count == 0) {
 		hid_dev->subdriver_count = 0;
 		hid_dev->subdrivers = NULL;
@@ -210,9 +197,6 @@
 	}
 
-	for (i = 0; i < count; ++i) {
-		hid_dev->subdrivers[i].init = subdrivers[i]->init;
-		hid_dev->subdrivers[i].deinit = subdrivers[i]->deinit;
-		hid_dev->subdrivers[i].poll = subdrivers[i]->poll;
-		hid_dev->subdrivers[i].poll_end = subdrivers[i]->poll_end;
+	for (unsigned i = 0; i < count; ++i) {
+		hid_dev->subdrivers[i] = *subdrivers[i];
 	}
 
@@ -227,7 +211,5 @@
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int usb_hid_find_subdrivers(usb_hid_dev_t *hid_dev)
 {
@@ -235,31 +217,23 @@
 
 	const usb_hid_subdriver_t *subdrivers[USB_HID_MAX_SUBDRIVERS];
-
-	int i = 0, count = 0;
-	const usb_hid_subdriver_mapping_t *mapping = &usb_hid_subdrivers[i];
-
-	bool ids_matched;
-	bool matched;
-
-	while (count < USB_HID_MAX_SUBDRIVERS &&
-	    (mapping->usage_path != NULL
-	    || mapping->vendor_id >= 0 || mapping->product_id >= 0)) {
-		// check the vendor & product ID
+	unsigned count = 0;
+
+	for (unsigned i = 0; i < USB_HID_MAX_SUBDRIVERS; ++i) {
+		const usb_hid_subdriver_mapping_t *mapping =
+		    &usb_hid_subdrivers[i];
+		/* Check the vendor & product ID. */
 		if (mapping->vendor_id >= 0 && mapping->product_id < 0) {
-			usb_log_warning("Missing Product ID for Vendor ID %d\n",
-			    mapping->vendor_id);
-			return EINVAL;
+			usb_log_warning("Mapping[%d]: Missing Product ID for "
+			    "Vendor ID %d\n", i, mapping->vendor_id);
 		}
 		if (mapping->product_id >= 0 && mapping->vendor_id < 0) {
-			usb_log_warning("Missing Vendor ID for Product ID %d\n",
-			    mapping->product_id);
-			return EINVAL;
-		}
-
-		ids_matched = false;
-		matched = false;
-
-		if (mapping->vendor_id >= 0) {
-			assert(mapping->product_id >= 0);
+			usb_log_warning("Mapping[%d]: Missing Vendor ID for "
+			    "Product ID %d\n", i, mapping->product_id);
+		}
+
+		bool matched = false;
+
+		/* Check ID match. */
+		if (mapping->vendor_id >= 0 && mapping->product_id >= 0) {
 			usb_log_debug("Comparing device against vendor ID %u"
 			    " and product ID %u.\n", mapping->vendor_id,
@@ -267,17 +241,15 @@
 			if (usb_hid_ids_match(hid_dev, mapping)) {
 				usb_log_debug("IDs matched.\n");
-				ids_matched = true;
+				matched = true;
 			}
 		}
 
+		/* Check usage match. */
 		if (mapping->usage_path != NULL) {
 			usb_log_debug("Comparing device against usage path.\n");
 			if (usb_hid_path_matches(hid_dev, mapping)) {
-				// does not matter if IDs were matched
+				/* Does not matter if IDs were matched. */
 				matched = true;
 			}
-		} else {
-			// matched only if IDs were matched and there is no path
-			matched = ids_matched;
 		}
 
@@ -286,16 +258,10 @@
 			subdrivers[count++] = &mapping->subdriver;
 		}
-
-		mapping = &usb_hid_subdrivers[++i];
 	}
 
 	/* We have all subdrivers determined, save them into the hid device */
-	// TODO Dowe really need this complicated stuff if there is
-	// max_subdrivers limitation?
 	return usb_hid_save_subdrivers(hid_dev, subdrivers, count);
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, const usb_device_t *dev)
 {
@@ -303,27 +269,26 @@
 	assert(dev);
 
-	if (dev->pipes[USB_HID_KBD_POLL_EP_NO].present) {
-		usb_log_debug("Found keyboard endpoint.\n");
-		// save the pipe index
-		hid_dev->poll_pipe_index = USB_HID_KBD_POLL_EP_NO;
-	} else if (dev->pipes[USB_HID_MOUSE_POLL_EP_NO].present) {
-		usb_log_debug("Found mouse endpoint.\n");
-		// save the pipe index
-		hid_dev->poll_pipe_index = USB_HID_MOUSE_POLL_EP_NO;
-	} else if (dev->pipes[USB_HID_GENERIC_POLL_EP_NO].present) {
-		usb_log_debug("Found generic HID endpoint.\n");
-		// save the pipe index
-		hid_dev->poll_pipe_index = USB_HID_GENERIC_POLL_EP_NO;
-	} else {
-		usb_log_error("None of supported endpoints found - probably"
-		    " not a supported device.\n");
-		return ENOTSUP;
-	}
-
-	return EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-
+	static const struct {
+		unsigned ep_number;
+		const char* description;
+	} endpoints[] = {
+		{USB_HID_KBD_POLL_EP_NO, "Keyboard endpoint"},
+		{USB_HID_MOUSE_POLL_EP_NO, "Mouse endpoint"},
+		{USB_HID_GENERIC_POLL_EP_NO, "Generic HID endpoint"},
+	};
+
+	for (unsigned i = 0; i < sizeof(endpoints)/sizeof(endpoints[0]); ++i) {
+		if (endpoints[i].ep_number >= dev->pipes_count) {
+			return EINVAL;
+		}
+		if (dev->pipes[endpoints[i].ep_number].present) {
+			usb_log_debug("Found: %s.\n", endpoints[i].description);
+			hid_dev->poll_pipe_index = endpoints[i].ep_number;
+			return EOK;
+		}
+	}
+	return ENOTSUP;
+}
+/*----------------------------------------------------------------------------*/
 static int usb_hid_init_report(usb_hid_dev_t *hid_dev)
 {
@@ -357,24 +322,28 @@
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
+/*
+ * This functions initializes required structures from the device's descriptors
+ * and starts new fibril for polling the keyboard for events and another one for
+ * handling auto-repeat of keys.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on 
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and 
+ *       other locks turned off.
+ *
+ * @param hid_dev Device to initialize, non-NULL.
+ * @param dev USB device, non-NULL.
+ * @return Error code.
+ */
 int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev)
 {
-	int rc, i;
+	assert(hid_dev);
+	assert(dev);
 
 	usb_log_debug("Initializing HID structure...\n");
-
-	if (hid_dev == NULL) {
-		usb_log_error("Failed to init HID structure: no structure given"
-		    ".\n");
-		return EINVAL;
-	}
-
-	if (dev == NULL) {
-		usb_log_error("Failed to init HID structure: no USB device"
-		    " given.\n");
-		return EINVAL;
-	}
 
 	usb_hid_report_init(&hid_dev->report);
@@ -384,5 +353,5 @@
 	hid_dev->poll_pipe_index = -1;
 
-	rc = usb_hid_check_pipes(hid_dev, dev);
+	int rc = usb_hid_check_pipes(hid_dev, dev);
 	if (rc != EOK) {
 		return rc;
@@ -390,28 +359,26 @@
 
 	/* Get the report descriptor and parse it. */
-	rc = usb_hid_process_report_descriptor(hid_dev->usb_dev,
-	    &hid_dev->report, &hid_dev->report_desc, &hid_dev->report_desc_size);
-
-	bool fallback = false;
-
+	rc = usb_hid_process_report_descriptor(
+	    hid_dev->usb_dev, &hid_dev->report, &hid_dev->report_desc,
+	    &hid_dev->report_desc_size);
+
+	/* If report parsing went well, find subdrivers. */
 	if (rc == EOK) {
-		// try to find subdrivers that may want to handle this device
-		rc = usb_hid_find_subdrivers(hid_dev);
-		if (rc != EOK || hid_dev->subdriver_count == 0) {
-			// try to fall back to the boot protocol if available
-			usb_log_info("No subdrivers found to handle this"
-			    " device.\n");
-			fallback = true;
-			assert(hid_dev->subdrivers == NULL);
-			assert(hid_dev->subdriver_count == 0);
-		}
+		usb_hid_find_subdrivers(hid_dev);
 	} else {
-		usb_log_error("Failed to parse Report descriptor.\n");
-		// try to fall back to the boot protocol if available
-		fallback = true;
-	}
-
-	if (fallback) {
-		// fall back to boot protocol
+		usb_log_error("Failed to parse report descriptor: fallback.\n");
+		hid_dev->subdrivers = NULL;
+		hid_dev->subdriver_count = 0;
+	}
+
+	usb_log_debug("Subdriver count(before trying boot protocol): %d\n",
+	    hid_dev->subdriver_count);
+
+	/* No subdrivers, fall back to the boot protocol if available. */
+	if (hid_dev->subdriver_count == 0) {
+		assert(hid_dev->subdrivers == NULL);
+		usb_log_info("No subdrivers found to handle device, trying "
+		    "boot protocol.\n");
+
 		switch (hid_dev->poll_pipe_index) {
 		case USB_HID_KBD_POLL_EP_NO:
@@ -419,5 +386,5 @@
 			rc = usb_kbd_set_boot_protocol(hid_dev);
 			if (rc == EOK) {
-				rc = usb_hid_set_boot_kbd_subdriver(hid_dev);
+				usb_hid_set_boot_kbd_subdriver(hid_dev);
 			}
 			break;
@@ -426,5 +393,5 @@
 			rc = usb_mouse_set_boot_protocol(hid_dev);
 			if (rc == EOK) {
-				rc = usb_hid_set_boot_mouse_subdriver(hid_dev);
+				usb_hid_set_boot_mouse_subdriver(hid_dev);
 			}
 			break;
@@ -432,44 +399,54 @@
 			assert(hid_dev->poll_pipe_index
 			    == USB_HID_GENERIC_POLL_EP_NO);
-
 			usb_log_info("Falling back to generic HID driver.\n");
-			rc = usb_hid_set_generic_hid_subdriver(hid_dev);
-		}
-	}
-
-	if (rc != EOK) {
-		usb_log_error("No subdriver for handling this device could be"
-		    " initialized: %s.\n", str_error(rc));
-		usb_log_debug("Subdriver count: %d\n",
-		    hid_dev->subdriver_count);
-	} else {
-		bool ok = false;
-
-		usb_log_debug("Subdriver count: %d\n",
-		    hid_dev->subdriver_count);
-
-		for (i = 0; i < hid_dev->subdriver_count; ++i) {
-			if (hid_dev->subdrivers[i].init != NULL) {
-				usb_log_debug("Initializing subdriver %d.\n",i);
-				rc = hid_dev->subdrivers[i].init(hid_dev,
-				    &hid_dev->subdrivers[i].data);
-				if (rc != EOK) {
-					usb_log_warning("Failed to initialize"
-					    " HID subdriver structure.\n");
-				} else {
-					// at least one subdriver initialized
-					ok = true;
-				}
+			usb_hid_set_generic_hid_subdriver(hid_dev);
+		}
+	}
+
+	usb_log_debug("Subdriver count(after trying boot protocol): %d\n",
+	    hid_dev->subdriver_count);
+
+	/* Still no subdrivers? */
+	if (hid_dev->subdriver_count == 0) {
+		assert(hid_dev->subdrivers == NULL);
+		usb_log_error(
+		    "No subdriver for handling this device could be found.\n");
+		return ENOTSUP;
+	}
+
+	/*
+	 * 1) subdriver vytvori vlastnu ddf_fun, vlastne ddf_dev_ops, ktore da
+	 *    do nej.
+	 * 2) do tych ops do .interfaces[DEV_IFACE_USBHID (asi)] priradi 
+	 *    vyplnenu strukturu usbhid_iface_t.
+	 * 3) klientska aplikacia - musi si rucne vytvorit telefon
+	 *    (devman_device_connect() - cesta k zariadeniu (/hw/pci0/...) az 
+	 *    k tej fcii.
+	 *    pouzit usb/classes/hid/iface.h - prvy int je telefon
+	 */
+	bool ok = false;
+	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
+		if (hid_dev->subdrivers[i].init != NULL) {
+			usb_log_debug("Initializing subdriver %d.\n",i);
+			const int pret = hid_dev->subdrivers[i].init(hid_dev,
+			    &hid_dev->subdrivers[i].data);
+			if (pret != EOK) {
+				usb_log_warning("Failed to initialize"
+				    " HID subdriver structure: %s.\n",
+				    str_error(pret));
+				rc = pret;
 			} else {
+				/* At least one subdriver initialized. */
 				ok = true;
 			}
-		}
-
-		rc = (ok) ? EOK : -1;	// what error to report
-	}
-
-
-	if (rc == EOK) {
-		// save max input report size and allocate space for the report
+		} else {
+			/* Does not need initialization. */
+			ok = true;
+		}
+	}
+
+	if (ok) {
+		/* Save max input report size and
+		 * allocate space for the report */
 		rc = usb_hid_init_report(hid_dev);
 		if (rc != EOK) {
@@ -481,7 +458,5 @@
 	return rc;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
     size_t buffer_size, void *arg)
@@ -516,5 +491,5 @@
 	bool cont = false;
 	/* Continue if at least one of the subdrivers want to continue */
-	for (int i = 0; i < hid_dev->subdriver_count; ++i) {
+	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
 		if (hid_dev->subdrivers[i].poll != NULL) {
 			cont = cont || hid_dev->subdrivers[i].poll(
@@ -525,7 +500,5 @@
 	return cont;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, void *arg)
 {
@@ -535,5 +508,5 @@
 	usb_hid_dev_t *hid_dev = arg;
 
-	for (int i = 0; i < hid_dev->subdriver_count; ++i) {
+	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
 		if (hid_dev->subdrivers[i].poll_end != NULL) {
 			hid_dev->subdrivers[i].poll_end(
@@ -544,21 +517,15 @@
 	hid_dev->running = false;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 void usb_hid_new_report(usb_hid_dev_t *hid_dev)
 {
 	++hid_dev->report_nr;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 int usb_hid_report_number(const usb_hid_dev_t *hid_dev)
 {
 	return hid_dev->report_nr;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 void usb_hid_deinit(usb_hid_dev_t *hid_dev)
 {
@@ -570,5 +537,5 @@
 	    hid_dev->subdrivers, hid_dev->subdriver_count);
 
-	for (int i = 0; i < hid_dev->subdriver_count; ++i) {
+	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
 		if (hid_dev->subdrivers[i].deinit != NULL) {
 			hid_dev->subdrivers[i].deinit(hid_dev,
Index: uspace/drv/bus/usb/usbhid/usbhid.h
===================================================================
--- uspace/drv/bus/usb/usbhid/usbhid.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhid/usbhid.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -104,5 +104,5 @@
 
 	/** Index of the polling pipe in usb_hid_endpoints array. */
-	int poll_pipe_index;
+	unsigned poll_pipe_index;
 
 	/** Subdrivers. */
@@ -110,5 +110,5 @@
 
 	/** Number of subdrivers. */
-	int subdriver_count;
+	unsigned subdriver_count;
 
 	/** Report descriptor. */
Index: uspace/drv/bus/usb/usbhub/port.c
===================================================================
--- uspace/drv/bus/usb/usbhub/port.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhub/port.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -401,4 +401,5 @@
 {
 	usb_hub_port_t *port = arg;
+	assert(port);
 	const int rc =
 	    usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET);
@@ -440,21 +441,20 @@
 	    data->port, &new_address, NULL, NULL, &child_fun);
 
-	if (rc != EOK) {
+	if (rc == EOK) {
+		fibril_mutex_lock(&data->port->mutex);
+		data->port->attached_device.fun = child_fun;
+		data->port->attached_device.address = new_address;
+		fibril_mutex_unlock(&data->port->mutex);
+
+		usb_log_info("Detected new device on `%s' (port %zu), "
+		    "address %d (handle %" PRIun ").\n",
+		    data->hub->usb_device->ddf_dev->name,
+		    data->port->port_number, new_address, child_fun->handle);
+	} else {
 		usb_log_error("Failed registering device on port %zu: %s.\n",
 		    data->port->port_number, str_error(rc));
-		goto leave;
-	}
-
-	fibril_mutex_lock(&data->port->mutex);
-	data->port->attached_device.fun = child_fun;
-	data->port->attached_device.address = new_address;
-	fibril_mutex_unlock(&data->port->mutex);
-
-	usb_log_info("Detected new device on `%s' (port %zu), "
-	    "address %d (handle %" PRIun ").\n",
-	    data->hub->usb_device->ddf_dev->name, data->port->port_number,
-	    new_address, child_fun->handle);
-
-leave:
+	}
+
+
 	fibril_mutex_lock(&data->hub->pending_ops_mutex);
 	assert(data->hub->pending_ops_count > 0);
Index: uspace/drv/bus/usb/usbhub/port.h
===================================================================
--- uspace/drv/bus/usb/usbhub/port.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhub/port.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -44,5 +44,5 @@
 /** Information about single port on a hub. */
 typedef struct {
-	/* Port number as reporteed in descriptors. */
+	/* Port number as reported in descriptors. */
 	size_t port_number;
 	/** Device communication pipe. */
Index: uspace/drv/bus/usb/usbhub/usbhub.c
===================================================================
--- uspace/drv/bus/usb/usbhub/usbhub.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbhub/usbhub.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -170,33 +170,5 @@
 int usb_hub_device_remove(usb_device_t *usb_dev)
 {
-	assert(usb_dev);
-	usb_hub_dev_t *hub_dev = usb_dev->driver_data;
-	assert(hub_dev);
-	//TODO: Cascade the call here.
-	//TODO: Enable after cascading is implemented.
 	return ENOTSUP;
-	if (!hub_dev->power_switched) {
-		/* That is all we can do. */
-		return EOK;
-	}
-	int ret = EOK;
-	usb_log_info("Hub is about to be removed, powering down all ports.\n");
-	for (size_t port = 0; port < hub_dev->port_count; ++port) {
-		usb_log_debug("Powering down port %zu.\n", port);
-		int pret = usb_hub_port_clear_feature(
-		    &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
-		if (pret != EOK) {
-			usb_log_error("Cannot power down port %zu: %s.\n",
-			    hub_dev->ports[port].port_number, str_error(pret));
-			ret = pret;
-		} else {
-			if (!hub_dev->per_port_power) {
-				usb_log_debug("Ganged power switching mode, "
-				   "one port is enough.\n");
-				break;
-			}
-		}
-	}
-	return ret;
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/usbmast/bo_trans.c
===================================================================
--- uspace/drv/bus/usb/usbmast/bo_trans.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbmast/bo_trans.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -67,6 +67,6 @@
 	int retval = EOK;
 	size_t act_size;
-	usb_pipe_t *bulk_in_pipe = mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe;
-	usb_pipe_t *bulk_out_pipe = mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe;
+	usb_pipe_t *bulk_in_pipe = &mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe;
+	usb_pipe_t *bulk_out_pipe = &mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe;
 	usb_direction_t ddir;
 	void *dbuf;
@@ -118,8 +118,8 @@
 		if (ddir == USB_DIRECTION_IN) {
 			usb_pipe_clear_halt(&mfun->mdev->usb_dev->ctrl_pipe,
-			    mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe);
+			    &mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe);
 		} else {
 			usb_pipe_clear_halt(&mfun->mdev->usb_dev->ctrl_pipe,
-			    mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
+			    &mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
 		}
         } else if (rc != EOK) {
@@ -216,7 +216,7 @@
 	usb_massstor_reset(mdev);
 	usb_pipe_clear_halt(&mdev->usb_dev->ctrl_pipe,
-	    mdev->usb_dev->pipes[BULK_IN_EP].pipe);
+	    &mdev->usb_dev->pipes[BULK_IN_EP].pipe);
 	usb_pipe_clear_halt(&mdev->usb_dev->ctrl_pipe,
-	    mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
+	    &mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
 }
 
Index: uspace/drv/bus/usb/usbmast/main.c
===================================================================
--- uspace/drv/bus/usb/usbmast/main.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbmast/main.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -114,4 +114,5 @@
 {
 	//TODO: flush buffers, or whatever.
+	//TODO: remove device
 	return ENOTSUP;
 }
@@ -139,10 +140,10 @@
 
 	usb_log_info("Initializing mass storage `%s'.\n", dev->ddf_dev->name);
-	usb_log_debug(" Bulk in endpoint: %d [%zuB].\n",
-	    dev->pipes[BULK_IN_EP].pipe->endpoint_no,
-	    (size_t) dev->pipes[BULK_IN_EP].descriptor->max_packet_size);
+	usb_log_debug("Bulk in endpoint: %d [%zuB].\n",
+	    dev->pipes[BULK_IN_EP].pipe.endpoint_no,
+	    dev->pipes[BULK_IN_EP].pipe.max_packet_size);
 	usb_log_debug("Bulk out endpoint: %d [%zuB].\n",
-	    dev->pipes[BULK_OUT_EP].pipe->endpoint_no,
-	    (size_t) dev->pipes[BULK_OUT_EP].descriptor->max_packet_size);
+	    dev->pipes[BULK_OUT_EP].pipe.endpoint_no,
+	    dev->pipes[BULK_OUT_EP].pipe.max_packet_size);
 
 	usb_log_debug("Get LUN count...\n");
Index: uspace/drv/bus/usb/usbmid/explore.c
===================================================================
--- uspace/drv/bus/usb/usbmid/explore.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbmid/explore.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -54,9 +54,8 @@
  * @return Interface @p interface_no is already present in the list.
  */
-static bool interface_in_list(list_t *list, int interface_no)
+static bool interface_in_list(const list_t *list, int interface_no)
 {
 	list_foreach(*list, l) {
-		usbmid_interface_t *iface
-		    = list_get_instance(l, usbmid_interface_t, link);
+		usbmid_interface_t *iface = usbmid_interface_from_link(l);
 		if (iface->interface_no == interface_no) {
 			return true;
@@ -82,47 +81,43 @@
 	};
 
-	usb_dp_parser_t parser = {
+	static const usb_dp_parser_t parser = {
 		.nesting = usb_dp_standard_descriptor_nesting
 	};
 
 	const uint8_t *interface_ptr =
-	    usb_dp_get_nested_descriptor(&parser, &data, data.data);
-	if (interface_ptr == NULL) {
-		return;
-	}
-
-	do {
-		if (interface_ptr[1] != USB_DESCTYPE_INTERFACE) {
-			goto next_descriptor;
-		}
-
-		usb_standard_interface_descriptor_t *interface
+	    usb_dp_get_nested_descriptor(&parser, &data, config_descriptor);
+
+	/* Walk all descriptors nested in the current configuration decriptor;
+	 * i.e. all interface descriptors. */
+	for (;interface_ptr != NULL;
+	    interface_ptr = usb_dp_get_sibling_descriptor(
+	        &parser, &data, config_descriptor, interface_ptr))
+	{
+		/* The second byte is DESCTYPE byte in all desriptors. */
+		if (interface_ptr[1] != USB_DESCTYPE_INTERFACE)
+			continue;
+
+		const usb_standard_interface_descriptor_t *interface
 		    = (usb_standard_interface_descriptor_t *) interface_ptr;
 
 		/* Skip alternate interfaces. */
-		if (!interface_in_list(list, interface->interface_number)) {
-			usbmid_interface_t *iface
-			    = malloc(sizeof(usbmid_interface_t));
-			if (iface == NULL) {
-				break;
-			}
-			link_initialize(&iface->link);
-			iface->fun = NULL;
-			iface->interface_no = interface->interface_number;
-			iface->interface = interface;
-
-			list_append(&iface->link, list);
-		}
-
-		/* TODO: add the alternatives and create match ids from them
-		 * as well.
-		 */
-
-next_descriptor:
-		interface_ptr = usb_dp_get_sibling_descriptor(&parser, &data,
-		    data.data, interface_ptr);
-
-	} while (interface_ptr != NULL);
-
+		if (interface_in_list(list, interface->interface_number)) {
+			/* TODO: add the alternatives and create match ids
+			 * for them. */
+			continue;
+		}
+		usbmid_interface_t *iface = malloc(sizeof(usbmid_interface_t));
+		if (iface == NULL) {
+			//TODO: Do something about that failure.
+			break;
+		}
+
+		link_initialize(&iface->link);
+		iface->fun = NULL;
+		iface->interface_no = interface->interface_number;
+		iface->interface = interface;
+
+		list_append(&iface->link, list);
+	}
 }
 
@@ -139,14 +134,15 @@
 	int rc;
 
-	int dev_class = dev->descriptors.device.device_class;
+	unsigned dev_class = dev->descriptors.device.device_class;
 	if (dev_class != USB_CLASS_USE_INTERFACE) {
 		usb_log_warning(
-		    "Device class: %d (%s), but expected class 0.\n",
-		    dev_class, usb_str_class(dev_class));
+		    "Device class: %u (%s), but expected class %u.\n",
+		    dev_class, usb_str_class(dev_class),
+		    USB_CLASS_USE_INTERFACE);
 		usb_log_error("Not multi interface device, refusing.\n");
 		return false;
 	}
 
-	/* Short cuts to save on typing ;-). */
+	/* Shortcuts to save on typing ;-). */
 	const void *config_descriptor_raw = dev->descriptors.configuration;
 	size_t config_descriptor_size = dev->descriptors.configuration_size;
@@ -163,4 +159,5 @@
 	}
 
+	/* Create driver soft-state. */
 	usb_mid_t *usb_mid = usb_device_data_alloc(dev, sizeof(usb_mid_t));
 	if (!usb_mid) {
@@ -169,5 +166,5 @@
 	}
 
-	/* Create control function */
+	/* Create control function. */
 	usb_mid->ctl_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, "ctl");
 	if (usb_mid->ctl_fun == NULL) {
@@ -175,7 +172,7 @@
 		return false;
 	}
-
 	usb_mid->ctl_fun->ops = &mid_device_ops;
 
+	/* Bind control function. */
 	rc = ddf_fun_bind(usb_mid->ctl_fun);
 	if (rc != EOK) {
@@ -192,10 +189,10 @@
 	    &usb_mid->interface_list);
 
+	/* Start child function for every interface. */
 	list_foreach(usb_mid->interface_list, link) {
-		usbmid_interface_t *iface = list_get_instance(link,
-		    usbmid_interface_t, link);
+		usbmid_interface_t *iface = usbmid_interface_from_link(link);
 
 		usb_log_info("Creating child for interface %d (%s).\n",
-		    (int) iface->interface_no,
+		    iface->interface_no,
 		    usb_str_class(iface->interface->interface_class));
 
Index: uspace/drv/bus/usb/usbmid/main.c
===================================================================
--- uspace/drv/bus/usb/usbmid/main.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbmid/main.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -68,5 +68,5 @@
 /** Callback when a MID device is about to be removed from the host.
  *
- * @param gen_dev Generic DDF device representing the removed device.
+ * @param dev USB device representing the removed device.
  * @return Error code.
  */
@@ -74,16 +74,46 @@
 {
 	assert(dev);
-	int ret = ENOTSUP;
 	usb_mid_t *usb_mid = dev->driver_data;
 	assert(usb_mid);
 
-	/* Signal all interface functions */
-	list_foreach(usb_mid->interface_list, item) {
+	/* Remove ctl function */
+	int ret = ddf_fun_unbind(usb_mid->ctl_fun);
+	if (ret != EOK) {
+		usb_log_error("Failed to unbind USB MID ctl function: %s.\n",
+		    str_error(ret));
+		return ret;
+	}
+	ddf_fun_destroy(usb_mid->ctl_fun);
+
+	/* Remove all children */
+	while (!list_empty(&usb_mid->interface_list)) {
+		link_t *item = list_first(&usb_mid->interface_list);
+		list_remove(item);
+
 		usbmid_interface_t *iface = usbmid_interface_from_link(item);
 
-		usb_log_info("Signaling remove to child for interface "
-		    "%d (%s).\n", iface->interface_no,
+		usb_log_info("Removing child for interface %d (%s).\n",
+		    iface->interface_no,
 		    usb_str_class(iface->interface->interface_class));
-		// TODO cascade the call.
+
+		/* Tell the child to go off-line. */
+		int pret = ddf_fun_offline(iface->fun);
+		if (pret != EOK) {
+			usb_log_warning("Failed to turn off child for interface"
+			    " %d (%s): %s\n", iface->interface_no,
+			    usb_str_class(iface->interface->interface_class),
+			    str_error(pret));
+			ret = pret;
+		}
+
+		/* Now remove the child. */
+		pret = usbmid_interface_destroy(iface);
+		if (pret != EOK) {
+			usb_log_error("Failed to destroy child for interface "
+			    "%d (%s): %s\n", iface->interface_no,
+			    usb_str_class(iface->interface->interface_class),
+			    str_error(pret));
+			ret = pret;
+		}
 	}
 	return ret;
@@ -92,5 +122,5 @@
 /** Callback when a MID device was removed from the host.
  *
- * @param gen_dev Generic DDF device representing the removed device.
+ * @param dev USB device representing the removed device.
  * @return Error code.
  */
@@ -98,8 +128,10 @@
 {
 	assert(dev);
+	usb_mid_t *usb_mid = dev->driver_data;
+	assert(usb_mid);
+
 	usb_log_info("USB MID gone: `%s'.\n", dev->ddf_dev->name);
 
 	/* Remove ctl function */
-	usb_mid_t *usb_mid = dev->driver_data;
 	int ret = ddf_fun_unbind(usb_mid->ctl_fun);
 	if (ret != EOK) {
@@ -117,5 +149,5 @@
 		usbmid_interface_t *iface = usbmid_interface_from_link(item);
 
-		usb_log_info("Removing child for interface %d (%s).\n",
+		usb_log_info("Child for interface %d (%s) gone.\n",
 		    iface->interface_no,
 		    usb_str_class(iface->interface->interface_class));
Index: uspace/drv/bus/usb/usbmid/usbmid.c
===================================================================
--- uspace/drv/bus/usb/usbmid/usbmid.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbmid/usbmid.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -45,6 +45,5 @@
 
 /** Callback for DDF USB interface. */
-static int usb_iface_get_interface_impl(ddf_fun_t *fun, devman_handle_t handle,
-    int *iface_no)
+static int usb_iface_get_interface_impl(ddf_fun_t *fun, int *iface_no)
 {
 	assert(fun);
@@ -62,7 +61,7 @@
 /** DDF interface of the child - interface function. */
 static usb_iface_t child_usb_iface = {
-	.get_hc_handle = usb_iface_get_hc_handle_hub_child_impl,
-	.get_address = usb_iface_get_address_hub_impl,
-	.get_interface = usb_iface_get_interface_impl
+	.get_hc_handle = usb_iface_get_hc_handle_device_impl,
+	.get_my_address = usb_iface_get_my_address_forward_impl,
+	.get_my_interface = usb_iface_get_interface_impl,
 };
 
@@ -110,7 +109,7 @@
 	 * class name something humanly understandable.
 	 */
-	rc = asprintf(&child_name, "%s%d",
+	rc = asprintf(&child_name, "%s%hhu",
 	    usb_str_class(interface_descriptor->interface_class),
-	    (int) interface_descriptor->interface_number);
+	    interface_descriptor->interface_number);
 	if (rc < 0) {
 		return ENOMEM;
@@ -123,9 +122,4 @@
 		return ENOMEM;
 	}
-
-	iface->fun = child;
-
-	child->driver_data = iface;
-	child->ops = &child_device_ops;
 
 	rc = usb_device_create_match_ids_from_interface(device_descriptor,
@@ -143,4 +137,8 @@
 	}
 
+	iface->fun = child;
+	child->driver_data = iface;
+	child->ops = &child_device_ops;
+
 	return EOK;
 }
Index: uspace/drv/bus/usb/usbmid/usbmid.h
===================================================================
--- uspace/drv/bus/usb/usbmid/usbmid.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/usbmid/usbmid.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -51,5 +51,5 @@
 	ddf_fun_t *fun;
 	/** Interface descriptor. */
-	usb_standard_interface_descriptor_t *interface;
+	const usb_standard_interface_descriptor_t *interface;
 	/** Interface number. */
 	int interface_no;
Index: uspace/drv/bus/usb/vhc/connhost.c
===================================================================
--- uspace/drv/bus/usb/vhc/connhost.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/vhc/connhost.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -57,20 +57,12 @@
  * @return Error code.
  */
-static int request_address(ddf_fun_t *fun, usb_speed_t speed,
-    usb_address_t *address)
-{
-	VHC_DATA(vhc, fun);
-
-	usb_address_t addr = usb_device_manager_get_free_address(
-	    &vhc->dev_manager, USB_SPEED_HIGH);
-	if (addr < 0) {
-		return addr;
-	}
-
-	if (address != NULL) {
-		*address = addr;
-	}
-
-	return EOK;
+static int request_address(ddf_fun_t *fun, usb_address_t *address, bool strict,
+    usb_speed_t speed)
+{
+	VHC_DATA(vhc, fun);
+
+	assert(address);
+	return usb_device_manager_request_address(
+	    &vhc->dev_manager, address, strict, speed);
 }
 
@@ -88,5 +80,5 @@
 	usb_log_debug("Binding handle %" PRIun " to address %d.\n",
 	    handle, address);
-	usb_device_manager_bind(&vhc->dev_manager, address, handle);
+	usb_device_manager_bind_address(&vhc->dev_manager, address, handle);
 
 	return EOK;
@@ -118,5 +110,5 @@
 	VHC_DATA(vhc, fun);
 	usb_log_debug("Releasing address %d...\n", address);
-	usb_device_manager_release(&vhc->dev_manager, address);
+	usb_device_manager_release_address(&vhc->dev_manager, address);
 
 	return ENOTSUP;
@@ -136,5 +128,5 @@
  */
 static int register_endpoint(ddf_fun_t *fun,
-    usb_address_t address, usb_speed_t speed, usb_endpoint_t endpoint,
+    usb_address_t address, usb_endpoint_t endpoint,
     usb_transfer_type_t transfer_type, usb_direction_t direction,
     size_t max_packet_size, unsigned int interval)
@@ -479,6 +471,5 @@
 }
 
-static int tell_address(ddf_fun_t *fun, devman_handle_t handle,
-    usb_address_t *address)
+static int tell_address(ddf_fun_t *fun, usb_address_t *address)
 {
 	UNSUPPORTED("tell_address");
@@ -497,12 +488,9 @@
 }
 
-static int tell_address_rh(ddf_fun_t *root_hub_fun, devman_handle_t handle,
-    usb_address_t *address)
+static int tell_address_rh(ddf_fun_t *root_hub_fun, usb_address_t *address)
 {
 	VHC_DATA(vhc, root_hub_fun);
 
-	if (handle == 0) {
-		handle = root_hub_fun->handle;
-	}
+	devman_handle_t handle = root_hub_fun->handle;
 
 	usb_log_debug("tell_address_rh(handle=%" PRIun ")\n", handle);
@@ -520,5 +508,5 @@
 	.request_address = request_address,
 	.bind_address = bind_address,
-	.find_by_address = find_by_address,
+	.get_handle = find_by_address,
 	.release_address = release_address,
 
@@ -532,10 +520,10 @@
 usb_iface_t vhc_usb_iface = {
 	.get_hc_handle = usb_iface_get_hc_handle_hc_impl,
-	.get_address = tell_address
+	.get_my_address = tell_address
 };
 
 usb_iface_t rh_usb_iface = {
 	.get_hc_handle = usb_iface_get_hc_handle_rh_impl,
-	.get_address = tell_address_rh
+	.get_my_address = tell_address_rh
 };
 
Index: uspace/drv/bus/usb/vhc/main.c
===================================================================
--- uspace/drv/bus/usb/vhc/main.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/vhc/main.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -58,5 +58,5 @@
 };
 
-static int vhc_add_device(ddf_dev_t *dev)
+static int vhc_dev_add(ddf_dev_t *dev)
 {
 	static int vhc_count = 0;
@@ -80,5 +80,5 @@
 		return rc;
 	}
-	usb_device_manager_init(&data->dev_manager);
+	usb_device_manager_init(&data->dev_manager, USB_SPEED_MAX);
 
 	ddf_fun_t *hc = ddf_fun_create(dev, fun_exposed, "hc");
@@ -131,5 +131,5 @@
 
 static driver_ops_t vhc_driver_ops = {
-	.add_device = vhc_add_device,
+	.dev_add = vhc_dev_add,
 };
 
Index: uspace/drv/bus/usb/vhc/vhc.ma
===================================================================
--- uspace/drv/bus/usb/vhc/vhc.ma	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/bus/usb/vhc/vhc.ma	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,2 +1,1 @@
 10 usb&hc=vhc
-
Index: uspace/drv/char/ns8250/ns8250.c
===================================================================
--- uspace/drv/char/ns8250/ns8250.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/char/ns8250/ns8250.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -223,10 +223,10 @@
 };
 
-static int ns8250_add_device(ddf_dev_t *dev);
+static int ns8250_dev_add(ddf_dev_t *dev);
 static int ns8250_dev_remove(ddf_dev_t *dev);
 
 /** The serial port device driver's standard operations. */
 static driver_ops_t ns8250_ops = {
-	.add_device = &ns8250_add_device,
+	.dev_add = &ns8250_dev_add,
 	.dev_remove = &ns8250_dev_remove
 };
@@ -717,5 +717,5 @@
 }
 
-/** The add_device callback method of the serial port driver.
+/** The dev_add callback method of the serial port driver.
  *
  * Probe and initialize the newly added device.
@@ -723,5 +723,5 @@
  * @param dev		The serial port device.
  */
-static int ns8250_add_device(ddf_dev_t *dev)
+static int ns8250_dev_add(ddf_dev_t *dev)
 {
 	ns8250_t *ns = NULL;
@@ -730,5 +730,5 @@
 	int rc;
 	
-	ddf_msg(LVL_DEBUG, "ns8250_add_device %s (handle = %d)",
+	ddf_msg(LVL_DEBUG, "ns8250_dev_add %s (handle = %d)",
 	    dev->name, (int) dev->handle);
 	
Index: uspace/drv/infrastructure/root/root.c
===================================================================
--- uspace/drv/infrastructure/root/root.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/infrastructure/root/root.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -66,5 +66,5 @@
 #define VIRTUAL_FUN_MATCH_SCORE 100
 
-static int root_add_device(ddf_dev_t *dev);
+static int root_dev_add(ddf_dev_t *dev);
 static int root_fun_online(ddf_fun_t *fun);
 static int root_fun_offline(ddf_fun_t *fun);
@@ -72,5 +72,5 @@
 /** The root device driver's standard operations. */
 static driver_ops_t root_ops = {
-	.add_device = &root_add_device,
+	.dev_add = &root_dev_add,
 	.fun_online = &root_fun_online,
 	.fun_offline = &root_fun_offline
@@ -198,7 +198,7 @@
  *			of HW and pseudo devices).
  */
-static int root_add_device(ddf_dev_t *dev)
-{
-	ddf_msg(LVL_DEBUG, "root_add_device, device handle=%" PRIun,
+static int root_dev_add(ddf_dev_t *dev)
+{
+	ddf_msg(LVL_DEBUG, "root_dev_add, device handle=%" PRIun,
 	    dev->handle);
 
Index: uspace/drv/infrastructure/rootmac/rootmac.c
===================================================================
--- uspace/drv/infrastructure/rootmac/rootmac.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/infrastructure/rootmac/rootmac.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -125,5 +125,5 @@
  *
  */
-static int rootmac_add_device(ddf_dev_t *dev)
+static int rootmac_dev_add(ddf_dev_t *dev)
 {
 	/* Register functions */
@@ -136,5 +136,5 @@
 /** The root device driver's standard operations. */
 static driver_ops_t rootmac_ops = {
-	.add_device = &rootmac_add_device
+	.dev_add = &rootmac_dev_add
 };
 
Index: uspace/drv/infrastructure/rootpc/rootpc.c
===================================================================
--- uspace/drv/infrastructure/rootpc/rootpc.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/infrastructure/rootpc/rootpc.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -63,10 +63,10 @@
 } rootpc_fun_t;
 
-static int rootpc_add_device(ddf_dev_t *dev);
+static int rootpc_dev_add(ddf_dev_t *dev);
 static void root_pc_init(void);
 
 /** The root device driver's standard operations. */
 static driver_ops_t rootpc_ops = {
-	.add_device = &rootpc_add_device
+	.dev_add = &rootpc_dev_add
 };
 
@@ -175,7 +175,7 @@
  * @return		Zero on success, negative error number otherwise.
  */
-static int rootpc_add_device(ddf_dev_t *dev)
-{
-	ddf_msg(LVL_DEBUG, "rootpc_add_device, device handle = %d",
+static int rootpc_dev_add(ddf_dev_t *dev)
+{
+	ddf_msg(LVL_DEBUG, "rootpc_dev_add, device handle = %d",
 	    (int)dev->handle);
 	
Index: uspace/drv/infrastructure/rootvirt/rootvirt.c
===================================================================
--- uspace/drv/infrastructure/rootvirt/rootvirt.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/infrastructure/rootvirt/rootvirt.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -62,5 +62,5 @@
 };
 
-static int rootvirt_add_device(ddf_dev_t *dev);
+static int rootvirt_dev_add(ddf_dev_t *dev);
 static int rootvirt_dev_remove(ddf_dev_t *dev);
 static int rootvirt_fun_online(ddf_fun_t *fun);
@@ -68,5 +68,5 @@
 
 static driver_ops_t rootvirt_ops = {
-	.add_device = &rootvirt_add_device,
+	.dev_add = &rootvirt_dev_add,
 	.dev_remove = &rootvirt_dev_remove,
 	.fun_online = &rootvirt_fun_online,
@@ -172,5 +172,5 @@
 
 
-static int rootvirt_add_device(ddf_dev_t *dev)
+static int rootvirt_dev_add(ddf_dev_t *dev)
 {
 	rootvirt_t *rootvirt;
@@ -183,5 +183,5 @@
 	}
 
-	ddf_msg(LVL_DEBUG, "add_device(handle=%d)", (int)dev->handle);
+	ddf_msg(LVL_DEBUG, "dev_add(handle=%d)", (int)dev->handle);
 
 	rootvirt = ddf_dev_data_alloc(dev, sizeof(rootvirt_t));
Index: uspace/drv/nic/e1k/Makefile
===================================================================
--- uspace/drv/nic/e1k/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/e1k/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2011 Radim Vansa
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBNET_PREFIX)/libnet.a $(LIBNIC_PREFIX)/libnic.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBNET_PREFIX)/include -I$(LIBNIC_PREFIX)/include
+BINARY = e1k
+
+SOURCES = \
+	e1k.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/nic/e1k/e1k.c
===================================================================
--- uspace/drv/nic/e1k/e1k.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/e1k/e1k.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,2231 @@
+/*
+ * Copyright (c) 2011 Zdenek Bouska
+ * 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 e1k.c
+ *
+ * Driver for Intel Pro/1000 8254x Family of Gigabit Ethernet Controllers
+ *
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <adt/list.h>
+#include <align.h>
+#include <byteorder.h>
+#include <sysinfo.h>
+#include <ipc/irc.h>
+#include <ipc/ns.h>
+#include <libarch/ddi.h>
+#include <as.h>
+#include <ddf/interrupt.h>
+#include <devman.h>
+#include <device/hw_res_parsed.h>
+#include <device/pci.h>
+#include <nic.h>
+#include <nil_remote.h>
+#include <ops/nic.h>
+#include <packet_client.h>
+#include <packet_remote.h>
+#include <net/packet_header.h>
+#include "e1k.h"
+
+#define NAME  "e1k"
+
+#define E1000_DEFAULT_INTERRUPT_INTERVAL_USEC  250
+
+/* Must be power of 8 */
+#define E1000_RX_PACKETS_COUNT  128
+#define E1000_TX_PACKETS_COUNT  128
+
+#define E1000_RECEIVE_ADDRESS  16
+
+/** Maximum receiving packet size */
+#define E1000_MAX_RECEIVE_PACKET_SIZE  2048
+
+/** nic_driver_data_t* -> e1000_t* cast */
+#define DRIVER_DATA_NIC(nic) \
+	((e1000_t *) nic_get_specific(nic))
+
+/** device_t* -> nic_driver_data_t* cast */
+#define NIC_DATA_DEV(dev) \
+	((nic_t *) ((dev)->driver_data))
+
+/** device_t* -> e1000_t* cast */
+#define DRIVER_DATA_DEV(dev) \
+	(DRIVER_DATA_NIC(NIC_DATA_DEV(dev)))
+
+/** Cast pointer to uint64_t
+ *
+ * @param ptr Pointer to cast
+ *
+ * @return The uint64_t pointer representation.
+ *
+ */
+#define PTR_TO_U64(ptr)  ((uint64_t) ((uintptr_t) (ptr)))
+
+/** Cast the memaddr part to the void*
+ *
+ * @param memaddr The memaddr value
+ *
+ */
+#define MEMADDR_TO_PTR(memaddr)  ((void *) ((size_t) (memaddr)))
+
+#define E1000_REG_BASE(e1000) \
+	((e1000)->reg_base_virt)
+
+#define E1000_REG_ADDR(e1000, reg) \
+	((uint32_t *) (E1000_REG_BASE(e1000) + reg))
+
+#define E1000_REG_READ(e1000, reg) \
+	(pio_read_32(E1000_REG_ADDR(e1000, reg)))
+
+#define E1000_REG_WRITE(e1000, reg, value) \
+	(pio_write_32(E1000_REG_ADDR(e1000, reg), value))
+
+/** E1000 device data */
+typedef struct {
+	/** Physical registers base address */
+	void *reg_base_phys;
+	/** Virtual registers base address */
+	void *reg_base_virt;
+	
+	/** Physical tx ring address */
+	void *tx_ring_phys;
+	/** Virtual tx ring address */
+	void *tx_ring_virt;
+	
+	/** Packets in tx ring  */
+	packet_t **tx_ring_packets;
+	
+	/** Physical rx ring address */
+	void *rx_ring_phys;
+	/** Virtual rx ring address */
+	void *rx_ring_virt;
+	
+	/** Packets in rx ring  */
+	packet_t **rx_ring_packets;
+	
+	/** VLAN tag */
+	uint16_t vlan_tag;
+	
+	/** Add VLAN tag to packet */
+	bool vlan_tag_add;
+	
+	/** Used unicast Receive Address count */
+	unsigned int unicast_ra_count;
+	
+	/** Used milticast Receive addrress count */
+	unsigned int multicast_ra_count;
+	
+	/** PCI device ID */
+	uint16_t device_id;
+	
+	/** The irq assigned */
+	int irq;
+	
+	/** Lock for CTRL register */
+	fibril_mutex_t ctrl_lock;
+	
+	/** Lock for receiver */
+	fibril_mutex_t rx_lock;
+	
+	/** Lock for transmitter */
+	fibril_mutex_t tx_lock;
+	
+	/** Lock for EEPROM access */
+	fibril_mutex_t eeprom_lock;
+} e1000_t;
+
+/** Global mutex for work with shared irq structure */
+FIBRIL_MUTEX_INITIALIZE(irq_reg_mutex);
+
+static int e1000_get_address(e1000_t *, nic_address_t *);
+static void e1000_eeprom_get_address(e1000_t *, nic_address_t *);
+static int e1000_set_addr(ddf_fun_t *, const nic_address_t *);
+
+static int e1000_defective_get_mode(ddf_fun_t *, uint32_t *);
+static int e1000_defective_set_mode(ddf_fun_t *, uint32_t);
+
+static int e1000_get_cable_state(ddf_fun_t *, nic_cable_state_t *);
+static int e1000_get_device_info(ddf_fun_t *, nic_device_info_t *);
+static int e1000_get_operation_mode(ddf_fun_t *, int *,
+    nic_channel_mode_t *, nic_role_t *);
+static int e1000_set_operation_mode(ddf_fun_t *, int,
+    nic_channel_mode_t, nic_role_t);
+static int e1000_autoneg_enable(ddf_fun_t *, uint32_t);
+static int e1000_autoneg_disable(ddf_fun_t *);
+static int e1000_autoneg_restart(ddf_fun_t *);
+
+static int e1000_vlan_set_tag(ddf_fun_t *, uint16_t, bool, bool);
+
+/** Network interface options for E1000 card driver */
+static nic_iface_t e1000_nic_iface;
+
+/** Network interface options for E1000 card driver */
+static nic_iface_t e1000_nic_iface = {
+	.set_address = &e1000_set_addr,
+	.get_device_info = &e1000_get_device_info,
+	.get_cable_state = &e1000_get_cable_state,
+	.get_operation_mode = &e1000_get_operation_mode,
+	.set_operation_mode = &e1000_set_operation_mode,
+	.autoneg_enable = &e1000_autoneg_enable,
+	.autoneg_disable = &e1000_autoneg_disable,
+	.autoneg_restart = &e1000_autoneg_restart,
+	.vlan_set_tag = &e1000_vlan_set_tag,
+	.defective_get_mode = &e1000_defective_get_mode,
+	.defective_set_mode = &e1000_defective_set_mode,
+};
+
+/** Basic device operations for E1000 driver */
+static ddf_dev_ops_t e1000_dev_ops;
+
+static int e1000_dev_add(ddf_dev_t *);
+
+/** Basic driver operations for E1000 driver */
+static driver_ops_t e1000_driver_ops = {
+	.dev_add = e1000_dev_add
+};
+
+/** Driver structure for E1000 driver */
+static driver_t e1000_driver = {
+	.name = NAME,
+	.driver_ops = &e1000_driver_ops
+};
+
+/* The default implementation callbacks */
+static int e1000_on_activating(nic_t *);
+static int e1000_on_stopping(nic_t *);
+static void e1000_write_packet(nic_t *, packet_t *);
+
+/** Commands to deal with interrupt
+ *
+ */
+irq_cmd_t e1000_irq_commands[] = {
+	{
+		/* Get the interrupt status */
+		.cmd = CMD_PIO_READ_32,
+		.addr = NULL,
+		.dstarg = 2
+	},
+	{
+		.cmd = CMD_PREDICATE,
+		.value = 2,
+		.srcarg = 2
+	},
+	{
+		/* Disable interrupts until interrupt routine is finished */
+		.cmd = CMD_PIO_WRITE_32,
+		.addr = NULL,
+		.value = 0xffffffff
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+/** Interrupt code definition */
+irq_code_t e1000_irq_code = {
+	.cmdcount = sizeof(e1000_irq_commands) / sizeof(irq_cmd_t),
+	.cmds = e1000_irq_commands
+};
+
+/** Get the device information
+ *
+ * @param dev  NIC device
+ * @param info Information to fill
+ *
+ * @return EOK
+ *
+ */
+static int e1000_get_device_info(ddf_fun_t *dev, nic_device_info_t *info)
+{
+	assert(dev);
+	assert(info);
+	
+	bzero(info, sizeof(nic_device_info_t));
+	
+	info->vendor_id = 0x8086;
+	str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH,
+	    "Intel Corporation");
+	str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH,
+	    "Intel Pro");
+	
+	info->ethernet_support[ETH_10M] = ETH_10BASE_T;
+	info->ethernet_support[ETH_100M] = ETH_100BASE_TX;
+	info->ethernet_support[ETH_1000M] = ETH_1000BASE_T;
+	
+	return EOK;
+}
+
+/** Check the cable state
+ *
+ * @param[in]  dev   device
+ * @param[out] state state to fill
+ *
+ * @return EOK
+ *
+ */
+static int e1000_get_cable_state(ddf_fun_t *dev, nic_cable_state_t *state)
+{
+	assert(dev);
+	assert(DRIVER_DATA_DEV(dev));
+	assert(state);
+	
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	if (E1000_REG_READ(e1000, E1000_STATUS) & (STATUS_LU))
+		*state = NIC_CS_PLUGGED;
+	else
+		*state = NIC_CS_UNPLUGGED;
+	
+	return EOK;
+}
+
+static uint16_t e1000_calculate_itr_interval_from_usecs(suseconds_t useconds)
+{
+	return useconds * 4;
+}
+
+/** Get operation mode of the device
+ *
+ */
+static int e1000_get_operation_mode(ddf_fun_t *dev, int *speed,
+    nic_channel_mode_t *duplex, nic_role_t *role)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	uint32_t status = E1000_REG_READ(e1000, E1000_STATUS);
+	
+	if (status & STATUS_FD)
+		*duplex = NIC_CM_FULL_DUPLEX;
+	else
+		*duplex = NIC_CM_HALF_DUPLEX;
+	
+	uint32_t speed_bits =
+	    (status >> STATUS_SPEED_SHIFT) & STATUS_SPEED_ALL;
+	
+	if (speed_bits == STATUS_SPEED_10)
+		*speed = 10;
+	else if (speed_bits == STATUS_SPEED_100)
+		*speed = 100;
+	else if ((speed_bits == STATUS_SPEED_1000A) ||
+	    (speed_bits == STATUS_SPEED_1000B))
+		*speed = 1000;
+	
+	*role = NIC_ROLE_UNKNOWN;
+	return EOK;
+}
+
+static void e1000_link_restart(e1000_t *e1000)
+{
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	
+	if (ctrl & CTRL_SLU) {
+		ctrl &= ~(CTRL_SLU);
+		fibril_mutex_unlock(&e1000->ctrl_lock);
+		usleep(10);
+		fibril_mutex_lock(&e1000->ctrl_lock);
+		ctrl |= CTRL_SLU;
+	}
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	
+	e1000_link_restart(e1000);
+}
+
+/** Set operation mode of the device
+ *
+ */
+static int e1000_set_operation_mode(ddf_fun_t *dev, int speed,
+    nic_channel_mode_t duplex, nic_role_t role)
+{
+	if ((speed != 10) && (speed != 100) && (speed != 1000))
+		return EINVAL;
+	
+	if ((duplex != NIC_CM_HALF_DUPLEX) && (duplex != NIC_CM_FULL_DUPLEX))
+		return EINVAL;
+	
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	
+	ctrl |= CTRL_FRCSPD;
+	ctrl |= CTRL_FRCDPLX;
+	ctrl &= ~(CTRL_ASDE);
+	
+	if (duplex == NIC_CM_FULL_DUPLEX)
+		ctrl |= CTRL_FD;
+	else
+		ctrl &= ~(CTRL_FD);
+	
+	ctrl &= ~(CTRL_SPEED_MASK);
+	if (speed == 1000)
+		ctrl |= CTRL_SPEED_1000 << CTRL_SPEED_SHIFT;
+	else if (speed == 100)
+		ctrl |= CTRL_SPEED_100 << CTRL_SPEED_SHIFT;
+	else
+		ctrl |= CTRL_SPEED_10 << CTRL_SPEED_SHIFT;
+	
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	
+	e1000_link_restart(e1000);
+	
+	return EOK;
+}
+
+/** Enable auto-negotiation
+ *
+ * @param dev           Device to update
+ * @param advertisement Ignored on E1000
+ *
+ * @return EOK if advertisement mode set successfully
+ *
+ */
+static int e1000_autoneg_enable(ddf_fun_t *dev, uint32_t advertisement)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	
+	ctrl &= ~(CTRL_FRCSPD);
+	ctrl &= ~(CTRL_FRCDPLX);
+	ctrl |= CTRL_ASDE;
+	
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	
+	e1000_link_restart(e1000);
+	
+	return EOK;
+}
+
+/** Disable auto-negotiation
+ *
+ * @param dev Device to update
+ *
+ * @return EOK
+ *
+ */
+static int e1000_autoneg_disable(ddf_fun_t *dev)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	
+	ctrl |= CTRL_FRCSPD;
+	ctrl |= CTRL_FRCDPLX;
+	ctrl &= ~(CTRL_ASDE);
+	
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	
+	e1000_link_restart(e1000);
+	
+	return EOK;
+}
+
+/** Restart auto-negotiation
+ *
+ * @param dev Device to update
+ *
+ * @return EOK if advertisement mode set successfully
+ *
+ */
+static int e1000_autoneg_restart(ddf_fun_t *dev)
+{
+	return e1000_autoneg_enable(dev, 0);
+}
+
+/** Get state of acceptance of weird packets
+ *
+ * @param      device Device to check
+ * @param[out] mode   Current mode
+ *
+ */
+static int e1000_defective_get_mode(ddf_fun_t *device, uint32_t *mode)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(device);
+	
+	*mode = 0;
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	if (rctl & RCTL_SBP)
+		*mode = NIC_DEFECTIVE_BAD_CRC | NIC_DEFECTIVE_SHORT;
+	
+	return EOK;
+};
+
+/** Set acceptance of weird packets
+ *
+ * @param device Device to update
+ * @param mode   Mode to set
+ *
+ * @return ENOTSUP if the mode is not supported
+ * @return EOK of mode was set
+ *
+ */
+static int e1000_defective_set_mode(ddf_fun_t *device, uint32_t mode)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(device);
+	int rc = EOK;
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	bool short_mode = (mode & NIC_DEFECTIVE_SHORT ? true : false);
+	bool bad_mode = (mode & NIC_DEFECTIVE_BAD_CRC ? true : false);
+	
+	if (short_mode && bad_mode)
+		rctl |= RCTL_SBP;
+	else if ((!short_mode) && (!bad_mode))
+		rctl &= ~RCTL_SBP;
+	else
+		rc = ENOTSUP;
+	
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return rc;
+};
+
+/** Write receive address to RA registr
+ *
+ * @param e1000      E1000 data structure
+ * @param position   RA register position
+ * @param address    Ethernet address
+ * @param set_av_bit Set the Addtess Valid bit
+ *
+ */
+static void e1000_write_receive_address(e1000_t *e1000, unsigned int position,
+    const nic_address_t * address, bool set_av_bit)
+{
+	uint8_t *mac0 = (uint8_t *) address->address;
+	uint8_t *mac1 = (uint8_t *) address->address + 1;
+	uint8_t *mac2 = (uint8_t *) address->address + 2;
+	uint8_t *mac3 = (uint8_t *) address->address + 3;
+	uint8_t *mac4 = (uint8_t *) address->address + 4;
+	uint8_t *mac5 = (uint8_t *) address->address + 5;
+	
+	uint32_t rah;
+	uint32_t ral;
+	
+	ral = ((*mac3) << 24) | ((*mac2) << 16) | ((*mac1) << 8) | (*mac0);
+	rah = ((*mac5) << 8) | ((*mac4));
+	
+	if (set_av_bit)
+		rah |= RAH_AV;
+	else
+		rah |= E1000_REG_READ(e1000, E1000_RAH_ARRAY(position)) & RAH_AV;
+	
+	E1000_REG_WRITE(e1000, E1000_RAH_ARRAY(position), rah);
+	E1000_REG_WRITE(e1000, E1000_RAL_ARRAY(position), ral);
+}
+
+/** Disable receive address in RA registr
+ *
+ *  Clear Address Valid bit
+ *
+ * @param e1000    E1000 data structure
+ * @param position RA register position
+ *
+ */
+static void e1000_disable_receive_address(e1000_t *e1000, unsigned int position)
+{
+	uint32_t rah = E1000_REG_READ(e1000, E1000_RAH_ARRAY(position));
+	rah = rah & ~RAH_AV;
+	E1000_REG_WRITE(e1000, E1000_RAH_ARRAY(position), rah);
+}
+
+/** Clear all unicast addresses from RA registers
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_clear_unicast_receive_addresses(e1000_t *e1000)
+{
+	for (unsigned int ra_num = 1;
+	    ra_num <= e1000->unicast_ra_count;
+	    ra_num++)
+		e1000_disable_receive_address(e1000, ra_num);
+	
+	e1000->unicast_ra_count = 0;
+}
+
+/** Clear all multicast addresses from RA registers
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_clear_multicast_receive_addresses(e1000_t *e1000)
+{
+	unsigned int first_multicast_ra_num =
+	    E1000_RECEIVE_ADDRESS - e1000->multicast_ra_count;
+	
+	for (unsigned int ra_num = E1000_RECEIVE_ADDRESS - 1;
+	    ra_num >= first_multicast_ra_num;
+	    ra_num--)
+		e1000_disable_receive_address(e1000, ra_num);
+	
+	e1000->multicast_ra_count = 0;
+}
+
+/** Return receive address filter positions count usable for unicast
+ *
+ * @param e1000 E1000 data structure
+ *
+ * @return receive address filter positions count usable for unicast
+ *
+ */
+static unsigned int get_free_unicast_address_count(e1000_t *e1000)
+{
+	return E1000_RECEIVE_ADDRESS - 1 - e1000->multicast_ra_count;
+}
+
+/** Return receive address filter positions count usable for multicast
+ *
+ * @param e1000 E1000 data structure
+ *
+ * @return receive address filter positions count usable for multicast
+ *
+ */
+static unsigned int get_free_multicast_address_count(e1000_t *e1000)
+{
+	return E1000_RECEIVE_ADDRESS - 1 - e1000->unicast_ra_count;
+}
+
+/** Write unicast receive addresses to receive address filter registers
+ *
+ * @param e1000    E1000 data structure
+ * @param addr     Pointer to address array
+ * @param addr_cnt Address array count
+ *
+ */
+static void e1000_add_unicast_receive_addresses(e1000_t *e1000,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	assert(addr_cnt <= get_free_unicast_address_count(e1000));
+	
+	nic_address_t *addr_iterator = (nic_address_t *) addr;
+	
+	/* ra_num = 0 is primary address */
+	for (unsigned int ra_num = 1;
+	    ra_num <= addr_cnt;
+	    ra_num++) {
+		e1000_write_receive_address(e1000, ra_num, addr_iterator, true);
+		addr_iterator++;
+	}
+}
+
+/** Write multicast receive addresses to receive address filter registers
+ *
+ * @param e1000    E1000 data structure
+ * @param addr     Pointer to address array
+ * @param addr_cnt Address array count
+ *
+ */
+static void e1000_add_multicast_receive_addresses(e1000_t *e1000,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	assert(addr_cnt <= get_free_multicast_address_count(e1000));
+	
+	nic_address_t *addr_iterator = (nic_address_t *) addr;
+	
+	unsigned int first_multicast_ra_num = E1000_RECEIVE_ADDRESS - addr_cnt;
+	for (unsigned int ra_num = E1000_RECEIVE_ADDRESS - 1;
+	    ra_num >= first_multicast_ra_num;
+	    ra_num--) {
+		e1000_write_receive_address(e1000, ra_num, addr_iterator, true);
+		addr_iterator++;
+	}
+}
+
+/** Disable receiving packets for default address
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void disable_ra0_address_filter(e1000_t *e1000)
+{
+	uint32_t rah0 = E1000_REG_READ(e1000, E1000_RAH_ARRAY(0));
+	rah0 = rah0 & ~RAH_AV;
+	E1000_REG_WRITE(e1000, E1000_RAH_ARRAY(0), rah0);
+}
+
+/** Enable receiving packets for default address
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void enable_ra0_address_filter(e1000_t *e1000)
+{
+	uint32_t rah0 = E1000_REG_READ(e1000, E1000_RAH_ARRAY(0));
+	rah0 = rah0 | RAH_AV;
+	E1000_REG_WRITE(e1000, E1000_RAH_ARRAY(0), rah0);
+}
+
+/** Disable unicast promiscuous mode
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_unicast_promisc(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl & ~RCTL_UPE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Enable unicast promiscuous mode
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_unicast_promisc(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl | RCTL_UPE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Disable multicast promiscuous mode
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_multicast_promisc(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl & ~RCTL_MPE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Enable multicast promiscuous mode
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_multicast_promisc(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl | RCTL_MPE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Enable accepting of broadcast packets
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_broadcast_accept(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl | RCTL_BAM;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Disable accepting of broadcast packets
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_broadcast_accept(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl & ~RCTL_BAM;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Enable VLAN filtering according to VFTA registers
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_vlan_filter(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl | RCTL_VFE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Disable VLAN filtering
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_vlan_filter(e1000_t *e1000)
+{
+	uint32_t rctl = E1000_REG_READ(e1000, E1000_RCTL);
+	rctl = rctl & ~RCTL_VFE;
+	E1000_REG_WRITE(e1000, E1000_RCTL, rctl);
+}
+
+/** Set multicast packets acceptance mode
+ *
+ * @param nic      NIC device to update
+ * @param mode     Mode to set
+ * @param addr     Address list (used in mode = NIC_MULTICAST_LIST)
+ * @param addr_cnt Length of address list (used in mode = NIC_MULTICAST_LIST)
+ *
+ * @return EOK
+ *
+ */
+static int e1000_on_multicast_mode_change(nic_t *nic, nic_multicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	int rc = EOK;
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	switch (mode) {
+	case NIC_MULTICAST_BLOCKED:
+		e1000_clear_multicast_receive_addresses(e1000);
+		e1000_disable_multicast_promisc(e1000);
+		nic_report_hw_filtering(nic, -1, 1, -1);
+		break;
+	case NIC_MULTICAST_LIST:
+		e1000_clear_multicast_receive_addresses(e1000);
+		if (addr_cnt > get_free_multicast_address_count(e1000)) {
+			/*
+			 * Future work: fill MTA table
+			 * Not strictly neccessary, it only saves some compares
+			 * in the NIC library.
+			 */
+			e1000_enable_multicast_promisc(e1000);
+			nic_report_hw_filtering(nic, -1, 0, -1);
+		} else {
+			e1000_disable_multicast_promisc(e1000);
+			e1000_add_multicast_receive_addresses(e1000, addr, addr_cnt);
+			nic_report_hw_filtering(nic, -1, 1, -1);
+		}
+		break;
+	case NIC_MULTICAST_PROMISC:
+		e1000_enable_multicast_promisc(e1000);
+		e1000_clear_multicast_receive_addresses(e1000);
+		nic_report_hw_filtering(nic, -1, 1, -1);
+		break;
+	default:
+		rc = ENOTSUP;
+		break;
+	}
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return rc;
+}
+
+/** Set unicast packets acceptance mode
+ *
+ * @param nic      NIC device to update
+ * @param mode     Mode to set
+ * @param addr     Address list (used in mode = NIC_MULTICAST_LIST)
+ * @param addr_cnt Length of address list (used in mode = NIC_MULTICAST_LIST)
+ *
+ * @return EOK
+ *
+ */
+static int e1000_on_unicast_mode_change(nic_t *nic, nic_unicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	int rc = EOK;
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	switch (mode) {
+	case NIC_UNICAST_BLOCKED:
+		disable_ra0_address_filter(e1000);
+		e1000_clear_unicast_receive_addresses(e1000);
+		e1000_disable_unicast_promisc(e1000);
+		nic_report_hw_filtering(nic, 1, -1, -1);
+		break;
+	case NIC_UNICAST_DEFAULT:
+		enable_ra0_address_filter(e1000);
+		e1000_clear_unicast_receive_addresses(e1000);
+		e1000_disable_unicast_promisc(e1000);
+		nic_report_hw_filtering(nic, 1, -1, -1);
+		break;
+	case NIC_UNICAST_LIST:
+		enable_ra0_address_filter(e1000);
+		e1000_clear_unicast_receive_addresses(e1000);
+		if (addr_cnt > get_free_unicast_address_count(e1000)) {
+			e1000_enable_unicast_promisc(e1000);
+			nic_report_hw_filtering(nic, 0, -1, -1);
+		} else {
+			e1000_disable_unicast_promisc(e1000);
+			e1000_add_unicast_receive_addresses(e1000, addr, addr_cnt);
+			nic_report_hw_filtering(nic, 1, -1, -1);
+		}
+		break;
+	case NIC_UNICAST_PROMISC:
+		e1000_enable_unicast_promisc(e1000);
+		enable_ra0_address_filter(e1000);
+		e1000_clear_unicast_receive_addresses(e1000);
+		nic_report_hw_filtering(nic, 1, -1, -1);
+		break;
+	default:
+		rc = ENOTSUP;
+		break;
+	}
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return rc;
+}
+
+/** Set broadcast packets acceptance mode
+ *
+ * @param nic  NIC device to update
+ * @param mode Mode to set
+ *
+ * @return EOK
+ *
+ */
+static int e1000_on_broadcast_mode_change(nic_t *nic, nic_broadcast_mode_t mode)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	int rc = EOK;
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	switch (mode) {
+	case NIC_BROADCAST_BLOCKED:
+		e1000_disable_broadcast_accept(e1000);
+		break;
+	case NIC_BROADCAST_ACCEPTED:
+		e1000_enable_broadcast_accept(e1000);
+		break;
+	default:
+		rc = ENOTSUP;
+		break;
+	}
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return rc;
+}
+
+/** Check if receiving is enabled
+ *
+ * @param e1000 E1000 data structure
+ *
+ * @return true if receiving is enabled
+ *
+ */
+static bool e1000_is_rx_enabled(e1000_t *e1000)
+{
+	if (E1000_REG_READ(e1000, E1000_RCTL) & (RCTL_EN))
+		return true;
+	
+	return false;
+}
+
+/** Enable receiving
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_rx(e1000_t *e1000)
+{
+	/* Set Receive Enable Bit */
+	E1000_REG_WRITE(e1000, E1000_RCTL,
+	    E1000_REG_READ(e1000, E1000_RCTL) | (RCTL_EN));
+}
+
+/** Disable receiving
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_rx(e1000_t *e1000)
+{
+	/* Clear Receive Enable Bit */
+	E1000_REG_WRITE(e1000, E1000_RCTL,
+	    E1000_REG_READ(e1000, E1000_RCTL) & ~(RCTL_EN));
+}
+
+/** Set VLAN mask
+ *
+ * @param nic       NIC device to update
+ * @param vlan_mask VLAN mask
+ *
+ */
+static void e1000_on_vlan_mask_change(nic_t *nic,
+    const nic_vlan_mask_t *vlan_mask)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	if (vlan_mask) {
+		/*
+		 * Disable receiving, so that packet matching
+		 * partially written VLAN is not received.
+		 */
+		bool rx_enabled = e1000_is_rx_enabled(e1000);
+		if (rx_enabled)
+			e1000_disable_rx(e1000);
+		
+		for (unsigned int i = 0; i < NIC_VLAN_BITMAP_SIZE; i += 4) {
+			uint32_t bitmap_part =
+			    ((uint32_t) vlan_mask->bitmap[i]) |
+			    (((uint32_t) vlan_mask->bitmap[i + 1]) << 8) |
+			    (((uint32_t) vlan_mask->bitmap[i + 2]) << 16) |
+			    (((uint32_t) vlan_mask->bitmap[i + 3]) << 24);
+			E1000_REG_WRITE(e1000, E1000_VFTA_ARRAY(i / 4), bitmap_part);
+		}
+		
+		e1000_enable_vlan_filter(e1000);
+		if (rx_enabled)
+			e1000_enable_rx(e1000);
+	} else
+		e1000_disable_vlan_filter(e1000);
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+}
+
+/** Set VLAN mask
+ *
+ * @param device E1000 device
+ * @param tag    VLAN tag
+ *
+ * @return EOK
+ * @return ENOTSUP
+ *
+ */
+static int e1000_vlan_set_tag(ddf_fun_t *device, uint16_t tag, bool add,
+    bool strip)
+{
+	/* VLAN CFI bit cannot be set */
+	if (tag & VLANTAG_CFI)
+		return ENOTSUP;
+	
+	/*
+	 * CTRL.VME is neccessary for both strip and add
+	 * but CTRL.VME means stripping tags on receive.
+	 */
+	if (!strip && add)
+		return ENOTSUP;
+	
+	e1000_t *e1000 = DRIVER_DATA_DEV(device);
+	
+	e1000->vlan_tag = tag;
+	e1000->vlan_tag_add = add;
+	
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	if (strip)
+		ctrl |= CTRL_VME;
+	else
+		ctrl &= ~CTRL_VME;
+	
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	return EOK;
+}
+
+/** Fill receive descriptor with new empty packet
+ *
+ * Store packet in e1000->rx_ring_packets
+ *
+ * @param nic    NIC data stricture
+ * @param offset Receive descriptor offset
+ *
+ */
+static void e1000_fill_new_rx_descriptor(nic_t *nic, size_t offset)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	packet_t *packet =
+	    nic_alloc_packet(nic, E1000_MAX_RECEIVE_PACKET_SIZE);
+	
+	assert(packet);
+	
+	*(e1000->rx_ring_packets + offset) = packet;
+	e1000_rx_descriptor_t *rx_descriptor = (e1000_rx_descriptor_t *)
+	    (e1000->rx_ring_virt + offset * sizeof(e1000_rx_descriptor_t));
+	
+	void *phys;
+	int rc =
+	    nic_dma_lock_packet(packet, E1000_MAX_RECEIVE_PACKET_SIZE, &phys);
+	
+	if (rc == EOK)
+		rx_descriptor->phys_addr = PTR_TO_U64(phys + packet->data_start);
+	else
+		rx_descriptor->phys_addr = 0;
+	
+	rx_descriptor->length = 0;
+	rx_descriptor->checksum = 0;
+	rx_descriptor->status = 0;
+	rx_descriptor->errors = 0;
+	rx_descriptor->special = 0;
+}
+
+/** Clear receive descriptor
+ *
+ * @param e1000  E1000 data
+ * @param offset Receive descriptor offset
+ *
+ */
+static void e1000_clear_rx_descriptor(e1000_t *e1000, unsigned int offset)
+{
+	e1000_rx_descriptor_t *rx_descriptor = (e1000_rx_descriptor_t *)
+	    (e1000->rx_ring_virt + offset * sizeof(e1000_rx_descriptor_t));
+	
+	rx_descriptor->length = 0;
+	rx_descriptor->checksum = 0;
+	rx_descriptor->status = 0;
+	rx_descriptor->errors = 0;
+	rx_descriptor->special = 0;
+}
+
+/** Clear receive descriptor
+ *
+ * @param nic    NIC data
+ * @param offset Receive descriptor offset
+ *
+ */
+static void e1000_clear_tx_descriptor(nic_t *nic, unsigned int offset)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	e1000_tx_descriptor_t *tx_descriptor = (e1000_tx_descriptor_t *)
+	    (e1000->tx_ring_virt + offset * sizeof(e1000_tx_descriptor_t));
+	
+	if (tx_descriptor->length) {
+		packet_t *old_packet = *(e1000->tx_ring_packets + offset);
+		if (old_packet)
+			nic_release_packet(nic, old_packet);
+	}
+	
+	tx_descriptor->phys_addr = 0;
+	tx_descriptor->length = 0;
+	tx_descriptor->checksum_offset = 0;
+	tx_descriptor->command = 0;
+	tx_descriptor->status = 0;
+	tx_descriptor->checksum_start_field = 0;
+	tx_descriptor->special = 0;
+}
+
+/** Increment tail pointer for receive or transmit ring
+ *
+ * @param tail              Old Tail
+ * @param descriptors_count Ring length
+ *
+ * @return New tail
+ *
+ */
+static uint32_t e1000_inc_tail(uint32_t tail, uint32_t descriptors_count)
+{
+	if (tail + 1 == descriptors_count)
+		return 0;
+	else
+		return tail + 1;
+}
+
+/** Receive packets
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_receive_packets(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	uint32_t *tail_addr = E1000_REG_ADDR(e1000, E1000_RDT);
+	uint32_t next_tail = e1000_inc_tail(*tail_addr, E1000_RX_PACKETS_COUNT);
+	
+	e1000_rx_descriptor_t *rx_descriptor = (e1000_rx_descriptor_t *)
+	    (e1000->rx_ring_virt + next_tail * sizeof(e1000_rx_descriptor_t));
+	
+	while (rx_descriptor->status & 0x01) {
+		uint32_t packet_size = rx_descriptor->length - E1000_CRC_SIZE;
+		
+		packet_t *packet = *(e1000->rx_ring_packets + next_tail);
+		packet_suffix(packet, packet_size);
+		
+		nic_dma_unlock_packet(packet, E1000_MAX_RECEIVE_PACKET_SIZE);
+		nic_received_packet(nic, packet);
+		
+		e1000_fill_new_rx_descriptor(nic, next_tail);
+		
+		*tail_addr = e1000_inc_tail(*tail_addr, E1000_RX_PACKETS_COUNT);
+		next_tail = e1000_inc_tail(*tail_addr, E1000_RX_PACKETS_COUNT);
+		
+		rx_descriptor = (e1000_rx_descriptor_t *)
+		    (e1000->rx_ring_virt + next_tail * sizeof(e1000_rx_descriptor_t));
+	}
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+}
+
+/** Enable E1000 interupts
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_enable_interrupts(e1000_t *e1000)
+{
+	E1000_REG_WRITE(e1000, E1000_IMS, ICR_RXT0);
+}
+
+/** Disable E1000 interupts
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_disable_interrupts(e1000_t *e1000)
+{
+	E1000_REG_WRITE(e1000, E1000_IMS, 0);
+}
+
+/** Interrupt handler implementation
+ *
+ * This function is called from e1000_interrupt_handler()
+ * and e1000_poll()
+ *
+ * @param nic NIC data
+ * @param icr ICR register value
+ *
+ */
+static void e1000_interrupt_handler_impl(nic_t *nic, uint32_t icr)
+{
+	if (icr & ICR_RXT0)
+		e1000_receive_packets(nic);
+}
+
+/** Handle device interrupt
+ *
+ * @param dev   E1000 device
+ * @param iid   IPC call id
+ * @param icall IPC call structure
+ *
+ */
+static void e1000_interrupt_handler(ddf_dev_t *dev, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	uint32_t icr = (uint32_t) IPC_GET_ARG2(*icall);
+	nic_t *nic = NIC_DATA_DEV(dev);
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	e1000_interrupt_handler_impl(nic, icr);
+	e1000_enable_interrupts(e1000);
+}
+
+/** Register interrupt handler for the card in the system
+ *
+ * Note: The global irq_reg_mutex is locked because of work with global
+ * structure.
+ *
+ * @param nic Driver data
+ *
+ * @return EOK if the handler was registered
+ * @return Negative error code otherwise
+ *
+ */
+inline static int e1000_register_int_handler(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	/* Lock the mutex in whole driver while working with global structure */
+	fibril_mutex_lock(&irq_reg_mutex);
+	
+	e1000_irq_code.cmds[0].addr = e1000->reg_base_virt + E1000_ICR;
+	e1000_irq_code.cmds[2].addr = e1000->reg_base_virt + E1000_IMC;
+	
+	int rc = register_interrupt_handler(nic_get_ddf_dev(nic),
+	    e1000->irq, e1000_interrupt_handler, &e1000_irq_code);
+	
+	fibril_mutex_unlock(&irq_reg_mutex);
+	return rc;
+}
+
+/** Force receiving all packets in the receive buffer
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_poll(nic_t *nic)
+{
+	assert(nic);
+	
+	e1000_t *e1000 = nic_get_specific(nic);
+	assert(e1000);
+	
+	uint32_t icr = E1000_REG_READ(e1000, E1000_ICR);
+	e1000_interrupt_handler_impl(nic, icr);
+}
+
+/** Calculates ITR register interrupt from timeval structure
+ *
+ * @param period Period
+ *
+ */
+static uint16_t e1000_calculate_itr_interval(const struct timeval *period)
+{
+	// TODO: use also tv_sec
+	return e1000_calculate_itr_interval_from_usecs(period->tv_usec);
+}
+
+/** Set polling mode
+ *
+ * @param device  Device to set
+ * @param mode    Mode to set
+ * @param period  Period for NIC_POLL_PERIODIC
+ *
+ * @return EOK if succeed
+ * @return ENOTSUP if the mode is not supported
+ *
+ */
+static int e1000_poll_mode_change(nic_t *nic, nic_poll_mode_t mode,
+    const struct timeval *period)
+{
+	assert(nic);
+	
+	e1000_t *e1000 = nic_get_specific(nic);
+	assert(e1000);
+	
+	switch (mode) {
+	case NIC_POLL_IMMEDIATE:
+		E1000_REG_WRITE(e1000, E1000_ITR, 0);
+		e1000_enable_interrupts(e1000);
+		break;
+	case NIC_POLL_ON_DEMAND:
+		e1000_disable_interrupts(e1000);
+		break;
+	case NIC_POLL_PERIODIC:
+		assert(period);
+		uint16_t itr_interval = e1000_calculate_itr_interval(period);
+		E1000_REG_WRITE(e1000, E1000_ITR, (uint32_t) itr_interval);
+		e1000_enable_interrupts(e1000);
+		break;
+	default:
+		return ENOTSUP;
+	}
+	
+	return EOK;
+}
+
+/** Initialize receive registers
+ *
+ * @param e1000 E1000 data structure
+ *
+ */
+static void e1000_initialize_rx_registers(e1000_t *e1000)
+{
+	E1000_REG_WRITE(e1000, E1000_RDLEN, E1000_RX_PACKETS_COUNT * 16);
+	E1000_REG_WRITE(e1000, E1000_RDH, 0);
+	
+	/* It is not posible to let HW use all descriptors */
+	E1000_REG_WRITE(e1000, E1000_RDT, E1000_RX_PACKETS_COUNT - 1);
+	
+	/* Set Broadcast Enable Bit */
+	E1000_REG_WRITE(e1000, E1000_RCTL, RCTL_BAM);
+}
+
+/** Initialize receive structure
+ *
+ * @param nic NIC data
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_initialize_rx_structure(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	int rc = dmamem_map_anonymous(
+	    E1000_RX_PACKETS_COUNT * sizeof(e1000_rx_descriptor_t),
+	    AS_AREA_READ | AS_AREA_WRITE, 0, &e1000->rx_ring_phys,
+	    &e1000->rx_ring_virt);
+	if (rc != EOK)
+		return rc;
+	
+	E1000_REG_WRITE(e1000, E1000_RDBAH,
+	    (uint32_t) (PTR_TO_U64(e1000->rx_ring_phys) >> 32));
+	E1000_REG_WRITE(e1000, E1000_RDBAL,
+	    (uint32_t) PTR_TO_U64(e1000->rx_ring_phys));
+	
+	e1000->rx_ring_packets =
+	    malloc(E1000_RX_PACKETS_COUNT * sizeof(packet_t *));
+	// FIXME: Check return value
+	
+	/* Write descriptor */
+	for (unsigned int offset = 0;
+	    offset < E1000_RX_PACKETS_COUNT;
+	    offset++)
+		e1000_fill_new_rx_descriptor(nic, offset);
+	
+	e1000_initialize_rx_registers(e1000);
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return EOK;
+}
+
+/** Uninitialize receive structure
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_uninitialize_rx_structure(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	/* Write descriptor */
+	for (unsigned int offset = 0;
+	    offset < E1000_RX_PACKETS_COUNT;
+	    offset++) {
+		packet_t *packet = *(e1000->rx_ring_packets + offset);
+		nic_dma_unlock_packet(packet, E1000_MAX_RECEIVE_PACKET_SIZE);
+		nic_release_packet(nic, packet);
+	}
+	
+	free(e1000->rx_ring_packets);
+	dmamem_unmap_anonymous(e1000->rx_ring_virt);
+}
+
+/** Clear receive descriptor ring
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_clear_rx_ring(e1000_t *e1000)
+{
+	/* Write descriptor */
+	for (unsigned int offset = 0;
+	    offset < E1000_RX_PACKETS_COUNT;
+	    offset++)
+		e1000_clear_rx_descriptor(e1000, offset);
+}
+
+/** Initialize filters
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_initialize_filters(e1000_t *e1000)
+{
+	/* Initialize address filter */
+	e1000->unicast_ra_count = 0;
+	e1000->multicast_ra_count = 0;
+	e1000_clear_unicast_receive_addresses(e1000);
+}
+
+/** Initialize VLAN
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_initialize_vlan(e1000_t *e1000)
+{
+	e1000->vlan_tag_add = false;
+}
+
+/** Fill MAC address from EEPROM to RA[0] register
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_fill_mac_from_eeprom(e1000_t *e1000)
+{
+	/* MAC address from eeprom to RA[0] */
+	nic_address_t address;
+	e1000_eeprom_get_address(e1000, &address);
+	e1000_write_receive_address(e1000, 0, &address, true);
+}
+
+/** Initialize other registers
+ *
+ * @param dev E1000 data.
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static void e1000_initialize_registers(e1000_t *e1000)
+{
+	E1000_REG_WRITE(e1000, E1000_ITR,
+	    e1000_calculate_itr_interval_from_usecs(
+	    E1000_DEFAULT_INTERRUPT_INTERVAL_USEC));
+	E1000_REG_WRITE(e1000, E1000_FCAH, 0);
+	E1000_REG_WRITE(e1000, E1000_FCAL, 0);
+	E1000_REG_WRITE(e1000, E1000_FCT, 0);
+	E1000_REG_WRITE(e1000, E1000_FCTTV, 0);
+	E1000_REG_WRITE(e1000, E1000_VET, VET_VALUE);
+	E1000_REG_WRITE(e1000, E1000_CTRL, CTRL_ASDE);
+}
+
+/** Initialize transmit registers
+ *
+ * @param e1000 E1000 data.
+ *
+ */
+static void e1000_initialize_tx_registers(e1000_t *e1000)
+{
+	E1000_REG_WRITE(e1000, E1000_TDLEN, E1000_TX_PACKETS_COUNT * 16);
+	E1000_REG_WRITE(e1000, E1000_TDH, 0);
+	E1000_REG_WRITE(e1000, E1000_TDT, 0);
+	
+	E1000_REG_WRITE(e1000, E1000_TIPG,
+	    10 << TIPG_IPGT_SHIFT |
+	    8 << TIPG_IPGR1_SHIFT |
+	    6 << TIPG_IPGR2_SHIFT);
+	
+	E1000_REG_WRITE(e1000, E1000_TCTL,
+	    0x0F << TCTL_CT_SHIFT /* Collision Threshold */ |
+	    0x40 << TCTL_COLD_SHIFT /* Collision Distance */ |
+	    TCTL_PSP /* Pad Short Packets */);
+}
+
+/** Initialize transmit structure
+ *
+ * @param e1000 E1000 data.
+ *
+ */
+static int e1000_initialize_tx_structure(e1000_t *e1000)
+{
+	fibril_mutex_lock(&e1000->tx_lock);
+	
+	int rc = dmamem_map_anonymous(
+	    E1000_TX_PACKETS_COUNT * sizeof(e1000_tx_descriptor_t),
+	    AS_AREA_READ | AS_AREA_WRITE, 0, &e1000->tx_ring_phys,
+	    &e1000->tx_ring_virt);
+	if (rc != EOK)
+		return rc;
+	
+	bzero(e1000->tx_ring_virt,
+	    E1000_TX_PACKETS_COUNT * sizeof(e1000_tx_descriptor_t));
+	
+	E1000_REG_WRITE(e1000, E1000_TDBAH,
+	    (uint32_t) (PTR_TO_U64(e1000->tx_ring_phys) >> 32));
+	E1000_REG_WRITE(e1000, E1000_TDBAL,
+	    (uint32_t) PTR_TO_U64(e1000->tx_ring_phys));
+	
+	e1000->tx_ring_packets =
+	    malloc(E1000_TX_PACKETS_COUNT * sizeof(packet_t *));
+	// FIXME: Check return value
+	
+	e1000_initialize_tx_registers(e1000);
+	
+	fibril_mutex_unlock(&e1000->tx_lock);
+	return EOK;
+}
+
+/** Uninitialize transmit structure
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_uninitialize_tx_structure(e1000_t *e1000)
+{
+	free(e1000->tx_ring_packets);
+	dmamem_unmap_anonymous(e1000->tx_ring_virt);
+}
+
+/** Clear transmit descriptor ring
+ *
+ * @param nic NIC data
+ *
+ */
+static void e1000_clear_tx_ring(nic_t *nic)
+{
+	/* Write descriptor */
+	for (unsigned int offset = 0;
+	    offset < E1000_TX_PACKETS_COUNT;
+	    offset++)
+		e1000_clear_tx_descriptor(nic, offset);
+}
+
+/** Enable transmit
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_enable_tx(e1000_t *e1000)
+{
+	/* Set Transmit Enable Bit */
+	E1000_REG_WRITE(e1000, E1000_TCTL,
+	    E1000_REG_READ(e1000, E1000_TCTL) | (TCTL_EN));
+}
+
+/** Disable transmit
+ *
+ * @param e1000 E1000 data
+ *
+ */
+static void e1000_disable_tx(e1000_t *e1000)
+{
+	/* Clear Transmit Enable Bit */
+	E1000_REG_WRITE(e1000, E1000_TCTL,
+	    E1000_REG_READ(e1000, E1000_TCTL) & ~(TCTL_EN));
+}
+
+/** Reset E1000 device
+ *
+ * @param e1000 The E1000 data
+ *
+ */
+static int e1000_reset(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	E1000_REG_WRITE(e1000, E1000_CTRL, CTRL_RST);
+	
+	/* Wait for the reset */
+	usleep(20);
+	
+	/* check if RST_BIT cleared */
+	if (E1000_REG_READ(e1000, E1000_CTRL) & (CTRL_RST))
+		return EINVAL;
+	
+	e1000_initialize_registers(e1000);
+	e1000_initialize_rx_registers(e1000);
+	e1000_initialize_tx_registers(e1000);
+	e1000_fill_mac_from_eeprom(e1000);
+	e1000_initialize_filters(e1000);
+	e1000_initialize_vlan(e1000);
+	
+	return EOK;
+}
+
+/** Activate the device to receive and transmit packets
+ *
+ * @param nic NIC driver data
+ *
+ * @return EOK if activated successfully
+ * @return Error code otherwise
+ *
+ */
+static int e1000_on_activating(nic_t *nic)
+{
+	assert(nic);
+	
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	fibril_mutex_lock(&e1000->tx_lock);
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	e1000_enable_interrupts(e1000);
+	
+	nic_enable_interrupt(nic, e1000->irq);
+	
+	e1000_clear_rx_ring(e1000);
+	e1000_enable_rx(e1000);
+	
+	e1000_clear_tx_ring(nic);
+	e1000_enable_tx(e1000);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	ctrl |= CTRL_SLU;
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	fibril_mutex_unlock(&e1000->tx_lock);
+	fibril_mutex_unlock(&e1000->rx_lock);
+	
+	return EOK;
+}
+
+/** Callback for NIC_STATE_DOWN change
+ *
+ * @param nic NIC driver data
+ *
+ * @return EOK if succeed
+ * @return Error code otherwise
+ *
+ */
+static int e1000_on_down_unlocked(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	uint32_t ctrl = E1000_REG_READ(e1000, E1000_CTRL);
+	ctrl &= ~CTRL_SLU;
+	E1000_REG_WRITE(e1000, E1000_CTRL, ctrl);
+	
+	e1000_disable_tx(e1000);
+	e1000_disable_rx(e1000);
+	
+	nic_disable_interrupt(nic, e1000->irq);
+	e1000_disable_interrupts(e1000);
+	
+	/*
+	 * Wait for the for the end of all data
+	 * transfers to descriptors.
+	 */
+	usleep(100);
+	
+	return EOK;
+}
+
+/** Callback for NIC_STATE_DOWN change
+ *
+ * @param nic NIC driver data
+ *
+ * @return EOK if succeed
+ * @return Error code otherwise
+ *
+ */
+static int e1000_on_down(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	fibril_mutex_lock(&e1000->tx_lock);
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	int rc = e1000_on_down_unlocked(nic);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	fibril_mutex_unlock(&e1000->tx_lock);
+	fibril_mutex_unlock(&e1000->rx_lock);
+	
+	return rc;
+}
+
+/** Callback for NIC_STATE_STOPPED change
+ *
+ * @param nic NIC driver data
+ *
+ * @return EOK if succeed
+ * @return Error code otherwise
+ *
+ */
+static int e1000_on_stopping(nic_t *nic)
+{
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	fibril_mutex_lock(&e1000->tx_lock);
+	fibril_mutex_lock(&e1000->ctrl_lock);
+	
+	int rc = e1000_on_down_unlocked(nic);
+	if (rc == EOK)
+		rc = e1000_reset(nic);
+	
+	fibril_mutex_unlock(&e1000->ctrl_lock);
+	fibril_mutex_unlock(&e1000->tx_lock);
+	fibril_mutex_unlock(&e1000->rx_lock);
+	
+	return rc;
+}
+
+/** Create driver data structure
+ *
+ * @return Intialized device data structure or NULL
+ *
+ */
+static e1000_t *e1000_create_dev_data(ddf_dev_t *dev)
+{
+	assert(dev);
+	assert(!dev->driver_data);
+	
+	nic_t *nic = nic_create_and_bind(dev);
+	if (!nic)
+		return NULL;
+	
+	e1000_t *e1000 = malloc(sizeof(e1000_t));
+	if (!e1000) {
+		nic_unbind_and_destroy(dev);
+		return NULL;
+	}
+	
+	bzero(e1000, sizeof(e1000_t));
+	
+	nic_set_specific(nic, e1000);
+	nic_set_write_packet_handler(nic, e1000_write_packet);
+	nic_set_state_change_handlers(nic, e1000_on_activating,
+	    e1000_on_down, e1000_on_stopping);
+	nic_set_filtering_change_handlers(nic,
+	    e1000_on_unicast_mode_change, e1000_on_multicast_mode_change,
+	    e1000_on_broadcast_mode_change, NULL, e1000_on_vlan_mask_change);
+	nic_set_poll_handlers(nic, e1000_poll_mode_change, e1000_poll);
+	
+	fibril_mutex_initialize(&e1000->ctrl_lock);
+	fibril_mutex_initialize(&e1000->rx_lock);
+	fibril_mutex_initialize(&e1000->tx_lock);
+	fibril_mutex_initialize(&e1000->eeprom_lock);
+	
+	return e1000;
+}
+
+/** Delete driver data structure
+ *
+ * @param data E1000 device data structure
+ *
+ */
+inline static void e1000_delete_dev_data(ddf_dev_t *dev)
+{
+	assert(dev);
+	
+	if (dev->driver_data != NULL)
+		nic_unbind_and_destroy(dev);
+}
+
+/** Clean up the E1000 device structure.
+ *
+ * @param dev Device structure.
+ *
+ */
+static void e1000_dev_cleanup(ddf_dev_t *dev)
+{
+	assert(dev);
+	
+	e1000_delete_dev_data(dev);
+	
+	if (dev->parent_sess != NULL) {
+		async_hangup(dev->parent_sess);
+		dev->parent_sess = NULL;
+	}
+}
+
+/** Fill the irq and io_addr part of device data structure
+ *
+ * The hw_resources must be obtained before calling this function
+ *
+ * @param dev          Device structure
+ * @param hw_resources Hardware resources obtained from the parent device
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_fill_resource_info(ddf_dev_t *dev,
+    const hw_res_list_parsed_t *hw_resources)
+{
+	assert(dev != NULL);
+	assert(hw_resources != NULL);
+	assert(dev->driver_data != NULL);
+	
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	
+	if (hw_resources->irqs.count != 1)
+		return EINVAL;
+	
+	e1000->irq = hw_resources->irqs.irqs[0];
+	e1000->reg_base_phys =
+	    MEMADDR_TO_PTR(hw_resources->mem_ranges.ranges[0].address);
+	
+	return EOK;
+}
+
+/** Obtain information about hardware resources of the device
+ *
+ * The device must be connected to the parent
+ *
+ * @param dev Device structure
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_get_resource_info(ddf_dev_t *dev)
+{
+	assert(dev != NULL);
+	assert(NIC_DATA_DEV(dev) != NULL);
+	
+	hw_res_list_parsed_t hw_res_parsed;
+	hw_res_list_parsed_init(&hw_res_parsed);
+	
+	/* Get hw resources form parent driver */
+	int rc = nic_get_resources(NIC_DATA_DEV(dev), &hw_res_parsed);
+	if (rc != EOK)
+		return rc;
+	
+	/* Fill resources information to the device */
+	rc = e1000_fill_resource_info(dev, &hw_res_parsed);
+	hw_res_list_parsed_clean(&hw_res_parsed);
+	
+	return rc;
+}
+
+/** Initialize the E1000 device structure
+ *
+ * @param dev Device information
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_device_initialize(ddf_dev_t *dev)
+{
+	/* Allocate driver data for the device. */
+	e1000_t *e1000 = e1000_create_dev_data(dev);
+	if (e1000 == NULL)
+		return ENOMEM;
+	
+	/* Obtain and fill hardware resources info */
+	int rc = e1000_get_resource_info(dev);
+	if (rc != EOK) {
+		e1000_dev_cleanup(dev);
+		return rc;
+	}
+	
+	rc = pci_config_space_read_16(dev->parent_sess, PCI_DEVICE_ID,
+	    &e1000->device_id);
+	if (rc != EOK) {
+		e1000_dev_cleanup(dev);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/** Enable the I/O ports of the device.
+ *
+ * @param dev E1000 device.
+ *
+ * @return EOK if successed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_pio_enable(ddf_dev_t *dev)
+{
+	e1000_t *e1000 = DRIVER_DATA_DEV(dev);
+	
+	int rc = pio_enable(e1000->reg_base_phys, 8 * PAGE_SIZE,
+	    &e1000->reg_base_virt);
+	if (rc != EOK)
+		return EADDRNOTAVAIL;
+	
+	return EOK;
+}
+
+/** Probe and initialize the newly added device.
+ *
+ * @param dev E1000 device.
+ *
+ */
+int e1000_dev_add(ddf_dev_t *dev)
+{
+	assert(dev);
+	
+	/* Initialize device structure for E1000 */
+	int rc = e1000_device_initialize(dev);
+	if (rc != EOK)
+		return rc;
+	
+	/* Device initialization */
+	nic_t *nic = dev->driver_data;
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	/* Map registers */
+	rc = e1000_pio_enable(dev);
+	if (rc != EOK)
+		goto err_destroy;
+	
+	e1000_initialize_registers(e1000);
+	rc = e1000_initialize_tx_structure(e1000);
+	if (rc != EOK)
+		goto err_pio;
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	e1000_fill_mac_from_eeprom(e1000);
+	e1000_initialize_filters(e1000);
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	
+	e1000_initialize_vlan(e1000);
+	
+	rc = nic_register_as_ddf_fun(nic, &e1000_dev_ops);
+	if (rc != EOK)
+		goto err_tx_structure;
+	
+	rc = e1000_register_int_handler(nic);
+	if (rc != EOK)
+		goto err_tx_structure;
+	
+	rc = nic_connect_to_services(nic);
+	if (rc != EOK)
+		goto err_irq;
+	
+	rc = e1000_initialize_rx_structure(nic);
+	if (rc != EOK)
+		goto err_irq;
+	
+	nic_address_t e1000_address;
+	e1000_get_address(e1000, &e1000_address);
+	rc = nic_report_address(nic, &e1000_address);
+	if (rc != EOK)
+		goto err_rx_structure;
+	
+	struct timeval period;
+	period.tv_sec = 0;
+	period.tv_usec = E1000_DEFAULT_INTERRUPT_INTERVAL_USEC;
+	rc = nic_report_poll_mode(nic, NIC_POLL_PERIODIC, &period);
+	if (rc != EOK)
+		goto err_rx_structure;
+	
+	return EOK;
+	
+err_rx_structure:
+	e1000_uninitialize_rx_structure(nic);
+err_irq:
+	unregister_interrupt_handler(dev, DRIVER_DATA_DEV(dev)->irq);
+err_tx_structure:
+	e1000_uninitialize_tx_structure(e1000);
+err_pio:
+	// TODO: e1000_pio_disable(dev);
+err_destroy:
+	e1000_dev_cleanup(dev);
+	return rc;
+}
+
+/** Read 16-bit value from EEPROM of E1000 adapter
+ *
+ * Read using the EERD register.
+ *
+ * @param device         E1000 device
+ * @param eeprom_address 8-bit EEPROM address
+ *
+ * @return 16-bit value from EEPROM
+ *
+ */
+static uint16_t e1000_eeprom_read(e1000_t *e1000, uint8_t eeprom_address)
+{
+	fibril_mutex_lock(&e1000->eeprom_lock);
+	
+	uint32_t eerd_done;
+	uint32_t eerd_address_offset;
+	
+	switch (e1000->device_id) {
+	case 0x107c:
+	case 0x1013:
+	case 0x1018:
+	case 0x1019:
+	case 0x101A:
+	case 0x1076:
+	case 0x1077:
+	case 0x1078:
+	case 0x10b9:
+		/* 82541xx and 82547GI/EI */
+		eerd_done = EERD_DONE_82541XX_82547GI_EI;
+		eerd_address_offset = EERD_ADDRESS_OFFSET_82541XX_82547GI_EI;
+		break;
+	default:
+		eerd_done = EERD_DONE;
+		eerd_address_offset = EERD_ADDRESS_OFFSET;
+		break;
+	}
+	
+	/* Write address and START bit to EERD register */
+	uint32_t write_data = EERD_START |
+	    (((uint32_t) eeprom_address) << eerd_address_offset);
+	E1000_REG_WRITE(e1000, E1000_EERD, write_data);
+	
+	uint32_t eerd = E1000_REG_READ(e1000, E1000_EERD);
+	while ((eerd & eerd_done) == 0) {
+		usleep(1);
+		eerd = E1000_REG_READ(e1000, E1000_EERD);
+	}
+	
+	fibril_mutex_unlock(&e1000->eeprom_lock);
+	
+	return (uint16_t) (eerd >> EERD_DATA_OFFSET);
+}
+
+/** Get MAC address of the E1000 adapter
+ *
+ * @param device  E1000 device
+ * @param address Place to store the address
+ * @param max_len Maximal addresss length to store
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ *
+ */
+static int e1000_get_address(e1000_t *e1000, nic_address_t *address)
+{
+	fibril_mutex_lock(&e1000->rx_lock);
+	
+	uint8_t *mac0_dest = (uint8_t *) address->address;
+	uint8_t *mac1_dest = (uint8_t *) address->address + 1;
+	uint8_t *mac2_dest = (uint8_t *) address->address + 2;
+	uint8_t *mac3_dest = (uint8_t *) address->address + 3;
+	uint8_t *mac4_dest = (uint8_t *) address->address + 4;
+	uint8_t *mac5_dest = (uint8_t *) address->address + 5;
+	
+	uint32_t rah = E1000_REG_READ(e1000, E1000_RAH_ARRAY(0));
+	uint32_t ral = E1000_REG_READ(e1000, E1000_RAL_ARRAY(0));
+	
+	*mac0_dest = (uint8_t) ral;
+	*mac1_dest = (uint8_t) (ral >> 8);
+	*mac2_dest = (uint8_t) (ral >> 16);
+	*mac3_dest = (uint8_t) (ral >> 24);
+	*mac4_dest = (uint8_t) rah;
+	*mac5_dest = (uint8_t) (rah >> 8);
+	
+	fibril_mutex_unlock(&e1000->rx_lock);
+	return EOK;
+};
+
+/** Set card MAC address
+ *
+ * @param device  E1000 device
+ * @param address Address
+ *
+ * @return EOK if succeed
+ * @return Negative error code otherwise
+ */
+static int e1000_set_addr(ddf_fun_t *dev, const nic_address_t *addr)
+{
+	nic_t *nic = NIC_DATA_DEV(dev);
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	
+	fibril_mutex_lock(&e1000->rx_lock);
+	fibril_mutex_lock(&e1000->tx_lock);
+	
+	int rc = nic_report_address(nic, addr);
+	if (rc == EOK)
+		e1000_write_receive_address(e1000, 0, addr, false);
+	
+	fibril_mutex_unlock(&e1000->tx_lock);
+	fibril_mutex_unlock(&e1000->rx_lock);
+	
+	return rc;
+}
+
+static void e1000_eeprom_get_address(e1000_t *e1000,
+    nic_address_t *address)
+{
+	uint16_t *mac0_dest = (uint16_t *) address->address;
+	uint16_t *mac2_dest = (uint16_t *) (address->address + 2);
+	uint16_t *mac4_dest = (uint16_t *) (address->address + 4);
+	
+	*mac0_dest = e1000_eeprom_read(e1000, 0);
+	*mac2_dest = e1000_eeprom_read(e1000, 1);
+	*mac4_dest = e1000_eeprom_read(e1000, 2);
+}
+
+/** Send packet
+ *
+ * @param nic    NIC driver data structure
+ * @param packet Packet to send
+ *
+ * @return EOK if succeed
+ * @return Error code in the case of error
+ *
+ */
+static void e1000_write_packet(nic_t *nic, packet_t *packet)
+{
+	assert(nic);
+	
+	e1000_t *e1000 = DRIVER_DATA_NIC(nic);
+	fibril_mutex_lock(&e1000->tx_lock);
+	
+	uint32_t tdt = E1000_REG_READ(e1000, E1000_TDT);
+	e1000_tx_descriptor_t *tx_descriptor_addr = (e1000_tx_descriptor_t *)
+	    (e1000->tx_ring_virt + tdt * sizeof(e1000_tx_descriptor_t));
+	
+	bool descriptor_available = false;
+	
+	/* Descriptor never used */
+	if (tx_descriptor_addr->length == 0)
+		descriptor_available = true;
+	
+	/* Descriptor done */
+	if (tx_descriptor_addr->status & TXDESCRIPTOR_STATUS_DD) {
+		descriptor_available = true;
+		packet_t *old_packet = *(e1000->tx_ring_packets + tdt);
+		if (old_packet) {
+			size_t old_packet_size = packet_get_data_length(old_packet);
+			nic_dma_unlock_packet(old_packet, old_packet_size);
+			nic_release_packet(nic, old_packet);
+		}
+	}
+	
+	if (!descriptor_available) {
+		/* Packet lost */
+		fibril_mutex_unlock(&e1000->tx_lock);
+		return;
+	}
+	
+	size_t packet_size = packet_get_data_length(packet);
+	
+	void *phys;
+	int rc = nic_dma_lock_packet(packet, packet_size, &phys);
+	if (rc != EOK) {
+		fibril_mutex_unlock(&e1000->tx_lock);
+		return;
+	}
+	
+	*(e1000->tx_ring_packets + tdt) = packet;
+	
+	tx_descriptor_addr->phys_addr =
+	    PTR_TO_U64(phys + packet->data_start);
+	tx_descriptor_addr->length = packet_size;
+	
+	/*
+	 * Report status to STATUS.DD (descriptor done),
+	 * add ethernet CRC, end of packet.
+	 */
+	tx_descriptor_addr->command = TXDESCRIPTOR_COMMAND_RS |
+	    TXDESCRIPTOR_COMMAND_IFCS |
+	    TXDESCRIPTOR_COMMAND_EOP;
+	
+	tx_descriptor_addr->checksum_offset = 0;
+	tx_descriptor_addr->status = 0;
+	if (e1000->vlan_tag_add) {
+		tx_descriptor_addr->special = e1000->vlan_tag;
+		tx_descriptor_addr->command |= TXDESCRIPTOR_COMMAND_VLE;
+	} else
+		tx_descriptor_addr->special = 0;
+	
+	tx_descriptor_addr->checksum_start_field = 0;
+	
+	tdt++;
+	if (tdt == E1000_TX_PACKETS_COUNT)
+		tdt = 0;
+	
+	E1000_REG_WRITE(e1000, E1000_TDT, tdt);
+	
+	fibril_mutex_unlock(&e1000->tx_lock);
+}
+
+int main(void)
+{
+	int rc = nic_driver_init(NAME);
+	if (rc != EOK)
+		return rc;
+	
+	nic_driver_implement(&e1000_driver_ops, &e1000_dev_ops,
+	    &e1000_nic_iface);
+	return ddf_driver_main(&e1000_driver);
+}
Index: uspace/drv/nic/e1k/e1k.h
===================================================================
--- uspace/drv/nic/e1k/e1k.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/e1k/e1k.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2011 Zdenek Bouska
+ * 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 e1k.h
+ *
+ * Registers, bit positions and masks definition of the E1000 network family
+ * cards
+ *
+ */
+
+#ifndef E1K_H_
+#define E1K_H_
+
+#include <stdint.h>
+
+/** Ethernet CRC size after packet received in rx_descriptor */
+#define E1000_CRC_SIZE  4
+
+#define VET_VALUE  0x8100
+
+#define E1000_RAL_ARRAY(n)   (E1000_RAL + ((n) * 8))
+#define E1000_RAH_ARRAY(n)   (E1000_RAH + ((n) * 8))
+#define E1000_VFTA_ARRAY(n)  (E1000_VFTA + (0x04 * (n)))
+
+/** Receive descriptior */
+typedef struct {
+	/** Buffer Address - physical */
+	uint64_t phys_addr;
+	/** Length is per segment */
+	uint16_t length;
+	/** Checksum - not all types, on some reseved  */
+	uint16_t checksum;
+	/** Status field */
+	uint8_t status;
+	/** Errors field */
+	uint8_t errors;
+	/** Special Field - not all types, on some reseved  */
+	uint16_t special;
+} e1000_rx_descriptor_t;
+
+/** Legacy transmit descriptior */
+typedef struct {
+	/** Buffer Address - physical */
+	uint64_t phys_addr;
+	/** Length is per segment */
+	uint16_t length;
+	/** Checksum Offset */
+	uint8_t checksum_offset;
+	/** Command field */
+	uint8_t command;
+	/** Status field, upper bits are reserved */
+	uint8_t status;
+	/** Checksum Start Field */
+	uint8_t checksum_start_field;
+	/** Special Field */
+	uint16_t special;
+} e1000_tx_descriptor_t;
+
+/** VLAN tag bits */
+enum e1000_vlantag {
+	VLANTAG_CFI = (1 << 12),  /**< Canonical Form Indicator */
+};
+
+/** Transmit descriptor COMMAND field bits */
+enum e1000_txdescriptor_command {
+	TXDESCRIPTOR_COMMAND_VLE = (1 << 6),   /**< VLAN Packet Enable */
+	TXDESCRIPTOR_COMMAND_RS = (1 << 3),    /**< Report Status */
+	TXDESCRIPTOR_COMMAND_IFCS = (1 << 1),  /**< Insert FCS */
+	TXDESCRIPTOR_COMMAND_EOP = (1 << 0)    /**< End Of Packet */
+};
+
+/** Transmit descriptor STATUS field bits */
+enum e1000_txdescriptor_status {
+	TXDESCRIPTOR_STATUS_DD = (1 << 0)  /**< Descriptor Done */
+};
+
+/** E1000 Registers */
+enum e1000_registers {
+	E1000_CTRL = 0x0,      /**< Device Control Register */
+	E1000_STATUS = 0x8,    /**< Device Status Register */
+	E1000_EERD = 0x14,     /**< EEPROM Read Register */
+	E1000_TCTL = 0x400,    /**< Transmit Control Register */
+	E1000_TIPG = 0x410,    /**< Transmit IPG Register */
+	E1000_TDBAL = 0x3800,  /**< Transmit Descriptor Base Address Low */
+	E1000_TDBAH = 0x3804,  /**< Transmit Descriptor Base Address High */
+	E1000_TDLEN = 0x3808,  /**< Transmit Descriptor Length */
+	E1000_TDH = 0x3810,    /**< Transmit Descriptor Head */
+	E1000_TDT = 0x3818,    /**< Transmit Descriptor Tail */
+	E1000_RCTL = 0x100,    /**< Receive Control Register */
+	E1000_RDBAL = 0x2800,  /**< Receive Descriptor Base Address Low */
+	E1000_RDBAH = 0x2804,  /**< Receive Descriptor Base Address High */
+	E1000_RDLEN = 0x2808,  /**< Receive Descriptor Length */
+	E1000_RDH = 0x2810,    /**< Receive Descriptor Head */
+	E1000_RDT = 0x2818,    /**< Receive Descriptor Tail */
+	E1000_RAL = 0x5400,    /**< Receive Address Low */
+	E1000_RAH = 0x5404,    /**< Receive Address High */
+	E1000_VFTA = 0x5600,   /**< VLAN Filter Table Array */
+	E1000_VET = 0x38,      /**< VLAN Ether Type */
+	E1000_FCAL = 0x28,     /**< Flow Control Address Low */
+	E1000_FCAH = 0x2C,     /**< Flow Control Address High */
+	E1000_FCTTV = 0x170,   /**< Flow Control Transmit Timer Value */
+	E1000_FCT = 0x30,      /**< Flow Control Type */
+	E1000_ICR = 0xC0,      /**< Interrupt Cause Read Register */
+	E1000_ITR = 0xC4,      /**< Interrupt Throttling Register */
+	E1000_IMS = 0xD0,      /**< Interrupt Mask Set/Read Register */
+	E1000_IMC = 0xD8       /**< Interrupt Mask Clear Register */
+};
+
+/** EEPROM Read Register fields */
+enum e1000_eerd {
+	/** Start Read */
+	EERD_START = (1 << 0),
+	/** Read Done */
+	EERD_DONE = (1 << 4),
+	/** Read Done for 82541xx and 82547GI/EI */
+	EERD_DONE_82541XX_82547GI_EI = (1 << 1),
+	/** Read Address offset */
+	EERD_ADDRESS_OFFSET = 8,
+	/** Read Address offset for 82541xx and 82547GI/EI */
+	EERD_ADDRESS_OFFSET_82541XX_82547GI_EI = 2,
+	/** Read Data */
+	EERD_DATA_OFFSET = 16
+};
+
+/** Device Control Register fields */
+enum e1000_ctrl {
+	CTRL_FD = (1 << 0),    /**< Full-Duplex */
+	CTRL_LRST = (1 << 3),  /**< Link Reset */
+	CTRL_ASDE = (1 << 5),  /**< Auto-Speed Detection Enable */
+	CTRL_SLU = (1 << 6),   /**< Set Link Up */
+	CTRL_ILOS = (1 << 7),  /**< Invert Loss-of-Signal */
+	
+	/** Speed selection shift */
+	CTRL_SPEED_SHIFT = 8,
+	/** Speed selection size */
+	CTRL_SPEED_SIZE = 2,
+	/** Speed selection all bit set value */
+	CTRL_SPEED_ALL = ((1 << CTRL_SPEED_SIZE) - 1),
+	/** Speed selection shift */
+	CTRL_SPEED_MASK = CTRL_SPEED_ALL << CTRL_SPEED_SHIFT,
+	/** Speed selection 10 Mb/s value */
+	CTRL_SPEED_10 = 0,
+	/** Speed selection 10 Mb/s value */
+	CTRL_SPEED_100 = 1,
+	/** Speed selection 10 Mb/s value */
+	CTRL_SPEED_1000 = 2,
+	
+	CTRL_FRCSPD = (1 << 11),   /**< Force Speed */
+	CTRL_FRCDPLX = (1 << 12),  /**< Force Duplex */
+	CTRL_RST = (1 << 26),      /**< Device Reset */
+	CTRL_VME = (1 << 30),      /**< VLAN Mode Enable */
+	CTRL_PHY_RST = (1 << 31)   /**< PHY Reset */
+};
+
+/** Device Status Register fields */
+enum e1000_status {
+	STATUS_FD = (1 << 0),  /**< Link Full Duplex configuration Indication */
+	STATUS_LU = (1 << 1),  /**< Link Up Indication */
+	
+	/** Link speed setting shift */
+	STATUS_SPEED_SHIFT = 6,
+	/** Link speed setting size */
+	STATUS_SPEED_SIZE = 2,
+	/** Link speed setting all bits set */
+	STATUS_SPEED_ALL = ((1 << STATUS_SPEED_SIZE) - 1),
+	/** Link speed setting 10 Mb/s value */
+	STATUS_SPEED_10 = 0,
+	/** Link speed setting 100 Mb/s value */
+	STATUS_SPEED_100 = 1,
+	/** Link speed setting 1000 Mb/s value variant A */
+	STATUS_SPEED_1000A = 2,
+	/** Link speed setting 1000 Mb/s value variant B */
+	STATUS_SPEED_1000B = 3,
+};
+
+/** Transmit IPG Register fields
+ *
+ * IPG = Inter Packet Gap
+ *
+ */
+enum e1000_tipg {
+	TIPG_IPGT_SHIFT = 0,    /**< IPG Transmit Time shift */
+	TIPG_IPGR1_SHIFT = 10,  /**< IPG Receive Time 1 */
+	TIPG_IPGR2_SHIFT = 20   /**< IPG Receive Time 2 */
+};
+
+/** Transmit Control Register fields */
+enum e1000_tctl {
+	TCTL_EN = (1 << 1),    /**< Transmit Enable */
+	TCTL_PSP =  (1 << 3),  /**< Pad Short Packets */
+	TCTL_CT_SHIFT = 4,     /**< Collision Threshold shift */
+	TCTL_COLD_SHIFT = 12   /**< Collision Distance shift */
+};
+
+/** ICR register fields */
+enum e1000_icr {
+	ICR_TXDW = (1 << 0),  /**< Transmit Descriptor Written Back */
+	ICR_RXT0 = (1 << 7)   /**< Receiver Timer Interrupt */
+};
+
+/** RAH register fields */
+enum e1000_rah {
+	RAH_AV = (1 << 31)   /**< Address Valid */
+};
+
+/** RCTL register fields */
+enum e1000_rctl {
+	RCTL_EN = (1 << 1),    /**< Receiver Enable */
+	RCTL_SBP = (1 << 2),   /**< Store Bad Packets */
+	RCTL_UPE = (1 << 3),   /**< Unicast Promiscuous Enabled */
+	RCTL_MPE = (1 << 4),   /**< Multicast Promiscuous Enabled */
+	RCTL_BAM = (1 << 15),  /**< Broadcast Accept Mode */
+	RCTL_VFE = (1 << 18)   /**< VLAN Filter Enable */
+};
+
+#endif
Index: uspace/drv/nic/e1k/e1k.ma
===================================================================
--- uspace/drv/nic/e1k/e1k.ma	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/e1k/e1k.ma	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,26 @@
+10 pci/ven=8086&dev=100e
+10 pci/ven=8086&dev=100f
+10 pci/ven=8086&dev=1010
+10 pci/ven=8086&dev=1011
+10 pci/ven=8086&dev=1012
+10 pci/ven=8086&dev=1013
+10 pci/ven=8086&dev=1015
+10 pci/ven=8086&dev=1016
+10 pci/ven=8086&dev=1017
+10 pci/ven=8086&dev=1018
+10 pci/ven=8086&dev=1019
+10 pci/ven=8086&dev=101a
+10 pci/ven=8086&dev=101d
+10 pci/ven=8086&dev=1026
+10 pci/ven=8086&dev=1027
+10 pci/ven=8086&dev=1028
+10 pci/ven=8086&dev=1076
+10 pci/ven=8086&dev=1077
+10 pci/ven=8086&dev=1078
+10 pci/ven=8086&dev=1079
+10 pci/ven=8086&dev=107a
+10 pci/ven=8086&dev=107b
+10 pci/ven=8086&dev=107c
+10 pci/ven=8086&dev=1107
+10 pci/ven=8086&dev=1112
+10 pci/ven=8086&dev=10b9
Index: uspace/drv/nic/lo/lo.c
===================================================================
--- uspace/drv/nic/lo/lo.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/nic/lo/lo.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -79,5 +79,5 @@
 }
 
-static int lo_add_device(ddf_dev_t *dev)
+static int lo_dev_add(ddf_dev_t *dev)
 {
 	nic_t *nic_data = nic_create_and_bind(dev);
@@ -118,5 +118,5 @@
 
 static driver_ops_t lo_driver_ops = {
-	.add_device = lo_add_device,
+	.dev_add = lo_dev_add,
 };
 
Index: uspace/drv/nic/lo/lo.ma
===================================================================
--- uspace/drv/nic/lo/lo.ma	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/nic/lo/lo.ma	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
Index: uspace/drv/nic/ne2k/dp8390.c
===================================================================
--- uspace/drv/nic/ne2k/dp8390.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/nic/ne2k/dp8390.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -142,8 +142,9 @@
 static void ne2k_upload(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
 {
+	size_t esize_ru = (size + 1) & ~1;
 	size_t esize = size & ~1;
 	
-	pio_write_8(ne2k->port + DP_RBCR0, esize & 0xff);
-	pio_write_8(ne2k->port + DP_RBCR1, (esize >> 8) & 0xff);
+	pio_write_8(ne2k->port + DP_RBCR0, esize_ru & 0xff);
+	pio_write_8(ne2k->port + DP_RBCR1, (esize_ru >> 8) & 0xff);
 	pio_write_8(ne2k->port + DP_RSAR0, addr & 0xff);
 	pio_write_8(ne2k->port + DP_RSAR1, (addr >> 8) & 0xff);
Index: uspace/drv/nic/ne2k/ne2k.c
===================================================================
--- uspace/drv/nic/ne2k/ne2k.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/nic/ne2k/ne2k.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -336,5 +336,5 @@
 }
 
-static int ne2k_add_device(ddf_dev_t *dev)
+static int ne2k_dev_add(ddf_dev_t *dev)
 {
 	/* Allocate driver data for the device. */
@@ -391,5 +391,5 @@
 
 static driver_ops_t ne2k_driver_ops = {
-	.add_device = ne2k_add_device
+	.dev_add = ne2k_dev_add
 };
 
Index: uspace/drv/nic/ne2k/ne2k.ma
===================================================================
--- uspace/drv/nic/ne2k/ne2k.ma	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/nic/ne2k/ne2k.ma	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
Index: uspace/drv/nic/rtl8139/Makefile
===================================================================
--- uspace/drv/nic/rtl8139/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/rtl8139/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2011 Radim Vansa
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBNET_PREFIX)/libnet.a $(LIBNIC_PREFIX)/libnic.a
+EXTRA_CFLAGS += -I$(LIBDRV_PREFIX)/include -I$(LIBNET_PREFIX)/include -I$(LIBNIC_PREFIX)/include
+BINARY = rtl8139
+
+SOURCES = \
+	driver.c \
+	general.c \
+	defs.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/nic/rtl8139/defs.c
===================================================================
--- uspace/drv/nic/rtl8139/defs.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/rtl8139/defs.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * 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 "rtl8139_defs.h"
+
+const char* model_names[RTL8139_VER_COUNT] = {
+	"RTL8139",
+	"RTL8139A",
+	"RTL8139A_G",
+	"RTL8139B",
+	"RTL8130",
+	"RTL8139C",
+	"RTL8100",
+	"RTL8139C+",
+	"RTL8139D",
+	"RTL8101"
+};
+
+#define HWVER(b1, b2, b3, b4, b5, b6, b7) ((b1 << 6) | (b2 << 5) | (b3 << 4) \
+    | (b4 << 3) | (b5 << 2) | (b6 << 1) | (b7))
+
+const struct rtl8139_hwver_map rtl8139_versions[RTL8139_VER_COUNT + 1] = {
+	{ HWVER(1,1,0,0,0,0,0), RTL8139 },
+	{ HWVER(1,1,1,0,0,0,0), RTL8139A },
+	{ HWVER(1,1,1,0,0,1,0), RTL8139A_G },
+	{ HWVER(1,1,1,1,0,0,0), RTL8139B },
+	{ HWVER(1,1,1,1,1,0,0), RTL8130 },
+	{ HWVER(1,1,1,0,1,0,0), RTL8139C },
+	{ HWVER(1,1,1,1,0,1,0), RTL8100 },
+	{ HWVER(1,1,1,0,1,0,1), RTL8139D },
+	{ HWVER(1,1,1,0,1,1,0), RTL8139Cp },
+	{ HWVER(1,1,1,0,1,1,1), RTL8101 },
+	/* End value */
+	{ 0, RTL8139_VER_COUNT}
+};
+
Index: uspace/drv/nic/rtl8139/defs.h
===================================================================
--- uspace/drv/nic/rtl8139/defs.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/rtl8139/defs.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * 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 rtl8139_defs.h
+ *
+ *  Registers, bit positions and masks definition of the RTL8139 network family 
+ *  cards
+ */
+
+#ifndef RTL8139_DEFS_H_INCLUDED_
+#define RTL8139_DEFS_H_INCLUDED_
+#include <sys/types.h>
+#include <libarch/ddi.h>
+
+
+/** The size of RTL8139 registers address space */
+#define RTL8139_IO_SIZE 256
+
+/** The maximal transmitted packet length in bytes allowed according to RTL8139
+ *  documentation (see SIZE part of TSD documentation)
+ */
+#define RTL8139_PACKET_MAX_LENGTH 1792
+
+
+/** HW version
+ *
+ *  as can be detected from HWVERID part of TCR
+ *  (Transmit Configuration Register)
+ */
+enum rtl8139_version_id {
+	RTL8139 = 0,          /**< RTL8139 */
+	RTL8139A,             /**< RTL8139A */
+	RTL8139A_G,           /**< RTL8139A-G */
+	RTL8139B,             /**< RTL8139B */
+	RTL8130,              /**< RTL8130 */
+	RTL8139C,             /**< RTL8139C */
+	RTL8100,              /**< RTL8100 */
+	RTL8139Cp,            /**< RTL8139C+ */
+	RTL8139D,             /**< RTL8139D */
+	RTL8100B = RTL8139D,  /**< RTL8100B and RTL8139D, the same HWVERID in TCR */
+	RTL8101,              /**< RTL8101 */
+	RTL8139_VER_COUNT     /**< Count of known RTL versions, the last value */
+};
+
+extern const char* model_names[RTL8139_VER_COUNT];
+
+/** Registers of RTL8139 family card offsets from the memory address base */
+enum rtl8139_registers {
+	IDR0  = 0x00,    /**< First MAC address bit, 6 1b registres sequence */
+	MAC0  = IDR0,    /**< Alias for IDR0 */
+
+	// 0x6 - 0x7 reserved
+
+	MAR0    = 0x08,  /**< Multicast mask registers 8 1b registers sequence */
+
+	TSD0    = 0x10,  /**< Transmit status of descriptor 0 */
+	TSD1    = 0x14,  /**< Transmit status of descriptor 1 */
+	TSD2    = 0x18,  /**< Transmit status of descriptor 2 */
+	TSD3    = 0x1C,  /**< Transmit status of descriptor 3 */
+
+	TSAD0   = 0x20,  /**< Physical address of the 1st transmitter buffer, 4b */
+	TSAD1   = 0x24,  /**< Physical address of the 2nd transmitter buffer, 4b */
+	TSAD2   = 0x28,  /**< Physical address of the 3rd transmitter buffer, 4b */
+	TSAD3   = 0x3C,  /**< Physical address of the 4th transmitter buffer, 4b */
+
+	RBSTART = 0x30,  /**< Receive (Rx) buffer start address, 4b */
+	ERBCR   = 0x34,  /**< Early receive (Rx) byte count register, 2b */
+	ERSR    = 0x36,  /**< Early receive (Rx) status register, 1b */
+
+	CR      = 0x37,  /**< Command register, 1b */
+	CAPR    = 0x38,  /**< Current address of packet read, 2b */
+	CBA     = 0x3a,  /**< Current buffer address, 2b */
+
+	IMR     = 0x3c,  /**< Interrupt mask register, 2b */
+	ISR     = 0x3e,  /**< Interrupt status register, 2b */
+
+	TCR     = 0x40,  /**< Transmit (Tx) configuration register, 4b */
+	RCR     = 0x44,  /**< Receive (Rx) configuration register, 4b */
+
+	TCTR    = 0x48,  /**< Timer count register */
+	MPC     = 0x4c,  /**< Missed packet count */
+
+	CR9346  = 0x50,  /**< 93C46 command register (locking of registers) */
+
+	CONFIG0 = 0x51,  /**< Configuration register 0, 1b */
+	CONFIG1 = 0x52,  /**< Configuration register 1, 1b */
+
+	// 0x53 reserved
+
+	TIMERINT = 0x54,  /**< Timer interrupt register, 4b */
+	MSR      = 0x58,  /**< Media status register, 1b */
+
+	CONFIG3  = 0x59,  /**< Configuration register 3, 1b */
+	CONFIG4  = 0x5a,  /**< Configuration register 4, 1b */
+
+	// 0x5b reserved
+
+	MULINT   = 0x5c,  /**< Multiple interrupt select, 2b */
+	RERID    = 0x5e,  /**< PCI revision ID = 0x10, 1b */
+
+	// 0x5f reserved
+
+	TSALLD  = 0x60,   /**< Transmit status of all descriptors, 2b */
+
+	BMCR    = 0x62,   /**< Basic mode control register */
+	BMSR    = 0x64,   /**< Basic mode status register */
+
+	ANAR    = 0x66,   /**< Auto-negotiation advertisement register */
+	ANLPAR  = 0x68,   /**< Auto-negotiation link partner register */
+	ANER    = 0x6a,   /**< Auto-negotiation expansion register */
+	DIS     = 0x6c,   /**< Disconnect counter */
+	FCSC    = 0x6e,   /**< False carrier sense counter */
+	NWAYTR  = 0x70,   /**< n-way test register */
+	REC     = 0x72,   /**< RX_ER counter */
+	CSCR    = 0x74,   /**< CS configuration register */
+
+	// 0x76 - 0x77 reserved
+
+	PHY1_PARM = 0x78, /**< PHY parameter 1 */
+	TW_PARM   = 0x7c, /**< Twister parameter */
+	PHY2_PARM = 0x80, /**< PHY parameter 2 */
+
+	// 0x81 reserved
+
+	TDOKLA  = 0x82,   /**< Low Address of a Tx Descriptor with Tx DMA Ok */
+	CRC0    = 0x84,   /**< Power Management CRC register0 for wakeup frame 0 */
+	WAKEUP0 = 0x8c,   /**< Power Management wakeup frame 0 */
+	LSBCRC0 = 0xcc,   /**< Least significant masked byte of WF0 */
+	FLASH   = 0xd4,   /**< Flash memory read/write register */
+
+	CONFIG5 = 0xd8,   /**< Configuration register 5 */
+
+	TPPOL   = 0xd9,   /**< Transmit priority polling register */
+
+	// 0xda - 0xdf reserved
+
+	CPCR    = 0xe0,   /**< C+ mode command register */
+
+	// 0xe2 - 0xe3 reserved
+
+	RDSAR   = 0xe4,   /**< Receive Descriptor Start Address Register */
+	ETTHR   = 0xec,   /**< Early transmit threshold register */
+
+	// 0xed - 0xef reserved
+
+	FER   = 0xf0,    /**< Function event register */
+	FEMR  = 0xf4,    /**< Function event mask register */
+	FPSR  = 0xf8,    /**< Function present state register */
+	FFER  = 0xfc,    /**< Function force event register */
+	MIIR  = 0xfc     /**< MII register */
+};
+
+/** Mask of valid bits in MPC value */
+#define MPC_VMASK UINT32_C(0xFFFFFF);
+
+/** Command register bits */
+enum rtl8139_cr {
+	CR_BUFE = (1 << 0),  /**< Buffer empty bit - read only */
+	CR_TE   = (1 << 2),  /**< Transmitter enable bit */
+	CR_RE   = (1 << 3),  /**< Receiver enable bit */
+	CR_RST  = (1 << 4)   /**< Reset -  set to 1 to force software reset */
+};
+
+/** Config1 register bits */
+enum rtl8139_config1 {
+	CONFIG1_LEDS_SHIFT = 6,       /**< Shift of CONFIG1_LEDS bits */
+	CONFIG1_LEDS_SIZE  = 2,       /**< Size of CONFIG1_LEDS bits */
+
+	CONFIG1_DVRLOAD  = (1 << 5),  /**< Driver load */
+	CONFIG1_LWACT    = (1 << 4),  /**< LWAKE active mode */
+	CONFIG1_MEMMAP   = (1 << 3),  /**< Memory mapping  */
+	CONFIG1_IOMAP    = (1 << 2),  /**< I/O space mapping */
+	CONFIG1_VPD      = (1 << 1),  /**< Set to enable Vital Product Data */
+	CONFIG1_PMEn     = (1 << 0)   /**< Power management enabled */
+};
+
+/** Mask of 9346CR register for lock configuration registers */
+#define RTL8139_REGS_LOCKED 0
+/** Mask of 9346CR register for unlock configuration registers */
+#define RTL8139_REGS_UNLOCKED 0xC0
+
+/** Put rtl8139 to normal mode.
+ *
+ * Writing to Config0-4 and part of BMCR registers is not allowed
+ */
+static inline void rtl8139_regs_lock(void *io_base)
+{
+	pio_write_8(io_base + CR9346, RTL8139_REGS_LOCKED);
+}
+/** Allow to change Config0-4 and BMCR register  */
+static inline void rtl8139_regs_unlock(void *io_base)
+{
+	pio_write_8((io_base) + CR9346, RTL8139_REGS_UNLOCKED);
+}
+
+/** Force soft reset of the chip. After it:
+ *	receiver and transmitter are disabled
+ *	transmitter FIFO is cleared
+ *	transmitter buffer is set to TSDA0
+ *	receiver buffer is empty
+ *
+ *	The reset bit in command register must be set to 1, the value of the
+ *	the register is 1 during reset operation
+ *
+ *	@param base_port The base address of the port mappings
+ */
+#define rtl8139_hw_reset(base_port)\
+	{\
+		pio_write_8(base_port + CR, CR_RST);\
+		while((pio_read_8(base_port + CR) & CR_RST) != 0);\
+	}
+
+/** Interrupt_masks
+ *
+ *  The masks are the same for both IMR and ISR
+ */
+enum rtl8139_interrupts {
+	INT_SERR          = (1 << 15),  /**< System error interrupt */
+	INT_TIME_OUT      = (1 << 14),  /**< Time out interrupt */
+	INT_LENGTH_CHANGE = (1 << 13),  /**< Cable length change interrupt  */
+
+	/* bits 7 - 12 reserved */
+
+	INT_FIFOOVW = (1 << 6),   /**< Receiver FIFO overflow interrupt */
+	INT_PUN     = (1 << 5),   /**< Packet Underrun/Link Change Interrupt  */
+	INT_RXOVW   = (1 << 4),   /**< Receiver buffer overflow */
+	INT_TER     = (1 << 3),   /**< Transmit error interrupt */
+	INT_TOK     = (1 << 2),   /**< Transmit OK interrupt */
+	INT_RER     = (1 << 1),   /**< Receive error interrupt */
+	INT_ROK     = (1 << 0)    /**< Receive OK interrupt */
+};
+
+/** Transmit status descriptor registers bits */
+enum rtl8139_tsd {
+	TSD_CRS          = (1 << 31),   /**< Carrier Sense Lost */
+	TSD_TABT         = (1 << 30),   /**<  Transmit Abort */
+	TSD_OWC          = (1 << 29),   /**< Out of Window Collision */
+	TSD_CDH          = (1 << 28),   /**< CD Heart Beat */
+	TSD_NCC_SHIFT    = 24,          /**< Collision Count - bit shift */
+	TSD_NCC_SIZE     = 4,           /**< Collision Count - bit size */
+	TSD_NCC_MASK     = (1 << 4)-1,  /**< Collision Count - bit size */
+	TSD_ERTXTH_SHIFT = 16,          /**< Early Tx Threshold - bit shift */
+	TSD_ERTXTH_SIZE  = 6,           /**< Early Tx  Treshold - bit size */
+	TSD_TOK          = (1 << 15),   /**< Transmit OK */
+	TSD_TUN          = (1 << 14),   /**< Transmit FIFO Underrun */
+	TSD_OWN          = (1 << 13),   /**< OWN */
+	TSD_SIZE_SHIFT   = 0,           /**< Size - bit shift */
+	TSD_SIZE_SIZE    = 13,          /**< Size - bit size */
+	TSD_SIZE_MASK    = 0x1fff       /**< Size - bit mask */
+};
+
+/** Receiver control register values */
+enum rtl8139_rcr {
+	RCR_ERTH_SHIFT = 24,       /**< Early Rx treshold part shift */
+	RCR_ERTH_SIZE = 4,         /**< Early Rx treshold part size */
+
+	RCR_MulERINT = 1 << 17,    /**< Multiple early interrupt select */
+
+	/** Minimal error packet length (1 = 8B, 0 = 64B). If AER/AR is set, RER8
+	 * is "Don't care"
+	 */
+	RCR_RER8 = 1 << 16,
+
+	RCR_RXFTH_SHIFT = 13,    /**< Rx FIFO treshold part shitf */
+	RCR_RXFTH_SIZE  = 3,     /**< Rx FIFO treshold part size */
+
+	RCR_RBLEN_SHIFT = 11,    /**< Rx buffer length part shift */
+	RCR_RBLEN_SIZE  = 2,     /**< Rx buffer length part size */
+
+	RCR_RBLEN_8k  = 0x00 << RCR_RBLEN_SHIFT,  /**< 8K + 16 byte rx buffer */
+	RCR_RBLEN_16k = 0x01 << RCR_RBLEN_SHIFT,  /**< 16K + 16 byte rx buffer */
+	RCR_RBLEN_32k = 0x02 << RCR_RBLEN_SHIFT,  /**< 32K + 16 byte rx buffer */
+	RCR_RBLEN_64k = 0x03 << RCR_RBLEN_SHIFT,  /**< 64K + 16 byte rx buffer */
+
+	RCR_MXDMA_SHIFT = 8,             /**< Max DMA Burst Size part shift */
+	RCR_MXDMA_SIZE  = 3,             /**< Max DMA Burst Size part size */
+
+	RCR_WRAP              = 1 << 7,  /**< Rx buffer wrapped */
+	RCR_ACCEPT_ERROR      = 1 << 5,  /**< Accept error packet */
+	RCR_ACCEPT_RUNT       = 1 << 4,  /**< Accept Runt (8-64 bytes) packets */
+	RCR_ACCEPT_BROADCAST  = 1 << 3,  /**< Accept broadcast */
+	RCR_ACCEPT_MULTICAST  = 1 << 2,  /**< Accept multicast */
+	RCR_ACCEPT_PHYS_MATCH = 1 << 1,  /**< Accept device MAC address match */
+	RCR_ACCEPT_ALL_PHYS   = 1 << 0,  /**< Accept all packets with 
+	                                  * phys. desticnation 
+									  */
+	RCR_ACCEPT_MASK = (1 << 6) - 1   /**< Mask of accept part */
+};
+
+
+/** CSCR register bits */
+enum rtl8139_cscr {
+	CS_Testfun       = (1 << 15),
+	CS_LD            = (1 << 9),  /**< Low TPI link disable signal */
+	CS_HEART_BEAT    = (1 << 8),  /**< Heart beat enable; 10Mbit mode only */
+	CS_JABBER_ENABLE = (1 << 7),  /**< Enable jabber function */
+	CS_F_LINK100     = (1 << 6),
+	CS_F_CONNECT     = (1 << 5),
+	CS_CON_STATUS    = (1 << 3),  /**< connection status: 
+	                               *   1 = valid, 0 = disconnected 
+								   */
+	CS_CON_STATUS_EN = (1 << 2),  /**< LED1 pin connection status indication */
+	CS_PASS_SCR      = (1 << 0)   /**< Bypass Scramble  */
+};
+
+/** MSR register bits */
+enum rtl8139_msr {
+	MSR_TXFCE       = (1 << 7),  /**< Transmitter flow control enable */
+	MSR_RXFCE       = (1 << 6),  /**< Receiver flow control enable */
+
+	MSR_AUX_PRESENT = (1 << 4),  /**< Aux. Power present Status */
+	MSR_SPEED10     = (1 << 3),  /**< 10MBit mode sign (1 = 10Mb, 0 = 100Mb) */
+	MSR_LINKB       = (1 << 2),  /**< Link Bad (fail) */
+	MSR_TXPF        = (1 << 1),  /**< Transmitter pause flag */
+	MSR_RXPF        = (1 << 0)   /**< Receiver pause flag */
+};
+
+/** BMCR register bits (basic mode control register) */
+enum rtl8139_bmcr {
+	BMCR_Reset     = (1 << 15),  /**< Software reset */
+	BMCR_Spd_100   = (1 << 13),  /**< 100 MBit mode set, 10 MBit otherwise */
+	BMCR_AN_ENABLE = (1 << 12),  /**< Autonegotion enable */
+
+	/* 10,11 reserved*/
+
+	BMCR_AN_RESTART = (1 << 9),  /**< Restart autonegotion */
+	BMCR_DUPLEX     = (1 << 8)   /**< Duplex mode: 1=full duplex */
+
+	/* 0-7 reserved */
+};
+
+/** Auto-negotiation advertisement register */
+enum rtl8139_anar {
+	ANAR_NEXT_PAGE    = (1 << 15),  /**< Next page bit, 0 - primary capability
+	                                 *  1 - protocol specific 
+									 */
+	ANAR_ACK          = (1 << 14),  /**< Capability reception acknowledge */
+	ANAR_REMOTE_FAULT = (1 << 13),  /**< Remote fault detection capability */
+	ANAR_PAUSE        = (1 << 10),  /**< Symetric pause packet capability */
+	ANAR_100T4        = (1 << 9),   /**< T4, not supported by the device */
+	ANAR_100TX_FD     = (1 << 8),   /**< 100BASE_TX full duplex */
+	ANAR_100TX_HD     = (1 << 7),   /**< 100BASE_TX half duplex */
+	ANAR_10_FD        = (1 << 6),   /**< 10BASE_T full duplex */
+	ANAR_10_HD        = (1 << 5),   /**< 10BASE_T half duplex */
+	ANAR_SELECTOR     = 0x1         /**< Selector, 
+	                                 *   CSMA/CD (0x1) supported only
+									 */
+};
+
+/**  Autonegotiation expansion register bits */
+enum rtl8139_aner {
+	ANER_MFL        = (1 << 4),  /**< Multiple link fault occured */
+	ANER_LP_NP_ABLE = (1 << 3),  /**< Link parent supports next page */
+	ANER_NP_ABLE    = (1 << 2),  /**< Local node is able to send next pages */
+	ANER_PAGE_RX    = (1 << 1),  /** New page received, cleared on LPAR read */
+	ANER_LP_NW_ABLE = (1 << 0)   /**< Link partner autonegotiation support */
+};
+
+enum rtl8139_config5 {
+	CONFIG5_BROADCAST_WAKEUP = (1 << 6),  /**< Broadcast wakeup frame enable */
+	CONFIG5_MULTICAST_WAKEUP = (1 << 5),  /**< Multicast wakeup frame enable */
+	CONFIG5_UNICAST_WAKEUP   = (1 << 4),  /**< Unicast wakeup frame enable */
+
+	/** Descending/ascending grow of Rx/Tx FIFO (to test FIFO SRAM only) */
+	CONFIG5_FIFO_ADDR_PTR = (1 << 3),    
+	/** Powersave if cable is disconnected */
+	CONFIG5_LINK_DOWN_POWERSAVE = (1 << 2), 
+
+	CONFIG5_LAN_WAKE     = (1 << 1),   /**< LANWake signal enabled */
+	CONFIG5_PME_STATUS   = (1 << 0)    /**< PMEn change: 0 = SW, 1 = SW+PCI */
+};
+
+enum rtl8139_config3 {
+	CONFIG3_GNT_SELECT = (1 << 7),  /**< Gnt select */
+	CONFIG3_PARM_EN    = (1 << 6),  /**< Parameter enabled (100MBit mode) */
+	CONFIG3_MAGIC      = (1 << 5),  /**< WoL Magic packet enable */
+	CONFIG3_LINK_UP    = (1 << 4),  /**< Wakeup if link is reestablished */
+	CONFIG3_CLKRUN_EN  = (1 << 2),  /**< CLKRUN enabled */ /* TODO: check what does it mean */
+	CONFIG3_FBTBEN     = (1 << 0)   /**< Fast back to back enabled */
+};
+
+enum rtl8139_config4 {
+	CONFIG4_RxFIFOAutoClr = (1 << 7),  /**< Automatic RxFIFO owerflow clear */
+	CONFIG4_AnaOff        = (1 << 6),  /**< Analog poweroff */
+	CONFIG4_LongWF        = (1 << 5),  /**< Long wakeup frame 
+	                                    *   (2xCRC8 + 3xCRC16) 
+										*/
+	CONFIG4_LWPME         = (1 << 4),  /**< LWAKE and PMEB assertion  */
+	CONFIG4_LWPTN         = (1 << 2),  /**< LWake pattern */
+	CONFIG4_PBWakeup      = (1 << 0)   /**< Preboot wakeup */
+};
+
+/** Maximal runt packet size + 1 */
+#define RTL8139_RUNT_MAX_SIZE 64
+
+/** Bits in packet header */
+enum rtl8139_packet_header {
+	RSR_MAR  = (1 << 15),  /**< Multicast received */
+	RSR_PAM  = (1 << 14),  /**< Physical address match */
+	RSR_BAR  = (1 << 13),  /**< Broadcast match */
+
+	RSR_ISE  = (1 << 5),   /**< Invalid symbol error, 100BASE-TX only */
+	RSR_RUNT = (1 << 4),   /**< Runt packet (< RTL8139_RUNT_MAX_SIZE bytes) */
+
+	RSR_LONG = (1 << 3),   /**< Long packet (size > 4k bytes) */
+	RSR_CRC  = (1 << 2),   /**< CRC error */
+	RSR_FAE  = (1 << 1),   /**< Frame alignment error */
+	RSR_ROK  = (1 << 0)    /**< Good packet received */
+};
+
+enum rtl8139_tcr_bits {
+	HWVERID_A_SHIFT = 26,           /**< HW version id, part A shift */
+	HWVERID_A_SIZE  = 5,            /**< HW version id, part A bit size */
+	HWVERID_A_MASK  = (1 << 5) - 1, /**< HW version id, part A mask */
+
+	IFG_SHIFT = 24,           /**< The interframe gap time setting shift */
+	IFG_SIZE  = 2,            /**< The interframe gap time setting bit size */
+
+	HWVERID_B_SHIFT = 22,           /**< HW version id, part B shift */
+	HWVERID_B_SIZE  = 2,            /**< HW version id, part B bit size */
+	HWVERID_B_MASK  = (1 << 2) - 1, /**< HW version id, part B mask */
+
+	LOOPBACK_SHIFT  = 17,           /**< Loopback mode shift */
+	LOOPBACK_SIZE   = 2,            /**< Loopback mode size 
+	                                  *  00 = normal, 11 = loopback 
+									  */
+
+	APPEND_CRC = 1 << 16,        /**< Append CRC at the end of a packet */
+
+	MXTxDMA_SHIFT = 8,  /**< Max. DMA Burst per TxDMA shift, burst = 16^value */
+	MXTxDMA_SIZE  = 3,  /**< Max. DMA Burst per TxDMA bit size */
+
+	TX_RETRY_COUNT_SHIFT = 4,            /**< Retries before aborting shift */
+	TX_RETRY_COUNT_SIZE  = 4,            /**< Retries before aborting size */
+
+	CLEAR_ABORT = 1 << 0    /**< Retransmit aborted packet at the last 
+	                          *  transmitted descriptor 
+							  */
+};
+
+#define RTL8139_HWVERID_A(tcr) (((tcr) >> HWVERID_A_SHIFT) & HWVERID_A_MASK)
+#define RTL8139_HWVERID_B(tcr) (((tcr) >> HWVERID_B_SHIFT) & HWVERID_B_MASK)
+#define RTL8139_HWVERID(tcr) ((RTL8139_HWVERID_A(tcr) << HWVERID_B_SIZE) | \
+    RTL8139_HWVERID_B(tcr))
+
+/** Mapping of HW version -> version ID */
+struct rtl8139_hwver_map { 
+	uint32_t hwverid;                /**< HW version value in the register */
+	enum rtl8139_version_id ver_id;  /**< appropriate version id */
+};
+
+/** Mapping of HW version -> version ID */
+extern const struct rtl8139_hwver_map rtl8139_versions[RTL8139_VER_COUNT + 1];
+
+/** Size in the packet header while copying from RxFIFO to Rx buffer */
+#define RTL8139_EARLY_SIZE UINT16_C(0xfff0)
+/** The only supported pause packet time value */
+#define RTL8139_PAUSE_VAL UINT16_C(0xFFFF)
+
+/** Size of the packet header in front of the received frame */
+#define RTL_PACKET_HEADER_SIZE 4
+
+/** 8k buffer */
+#define RTL8139_RXFLAGS_SIZE_8  0
+/** 16k buffer */
+#define RTL8139_RXFLAGS_SIZE_16 1
+/** 32k buffer */
+#define RTL8139_RXFLAGS_SIZE_32 2
+/** 64k buffer */
+#define RTL8139_RXFLAGS_SIZE_64 3
+
+/** Get the buffer initial size without 16B padding 
+ *  Size is (8 + 2^flags) kB (^ in mean power)
+ *
+ *  @param flags The flags for Rx buffer size, 0-3
+ */
+#define RTL8139_RXSIZE(flags) (1 << (13 + (flags)))
+
+/** Padding of the receiver buffer */
+#define RTL8139_RXBUF_PAD 16
+/** Size needed for buffer allocation */
+#define RTL8139_RXBUF_LENGTH(flags) (RTL8139_RXSIZE(flags) + RTL8139_RXBUF_PAD)
+
+#endif
Index: uspace/drv/nic/rtl8139/driver.c
===================================================================
--- uspace/drv/nic/rtl8139/driver.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/rtl8139/driver.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,2173 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * 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 <assert.h>
+#include <errno.h>
+#include <align.h>
+#include <byteorder.h>
+#include <libarch/ddi.h>
+#include <libarch/barrier.h>
+#include <nlog.h>
+
+#include <dma.h>
+#include <ddf/interrupt.h>
+#include <devman.h>
+#include <nic.h>
+#include <packet_client.h>
+#include <device/pci.h>
+
+#include <ipc/irc.h>
+#include <sysinfo.h>
+#include <ipc/ns.h>
+
+#include <net_checksum.h>
+
+#include <str.h>
+
+#include "rtl8139_defs.h"
+#include "rtl8139_driver.h"
+#include "rtl8139_general.h"
+
+/** Global mutex for work with shared irq structure */
+FIBRIL_MUTEX_INITIALIZE(irq_reg_lock);
+/** Lock interrupt structure mutex */
+#define RTL8139_IRQ_STRUCT_LOCK() fibril_mutex_lock(&irq_reg_lock)
+/** Unlock interrupt structure mutex */
+#define RTL8139_IRQ_STRUCT_UNLOCK() fibril_mutex_unlock(&irq_reg_lock)
+
+/** PCI clock frequency in kHz */
+#define RTL8139_PCI_FREQ_KHZ 33000
+
+#define RTL8139_AUTONEG_CAPS (ETH_AUTONEG_10BASE_T_HALF \
+    | ETH_AUTONEG_10BASE_T_FULL | ETH_AUTONEG_100BASE_TX_HALF \
+    | ETH_AUTONEG_100BASE_TX_FULL | ETH_AUTONEG_PAUSE_SYMETRIC)
+
+/** Lock transmitter and receiver data
+ *  This function shall be called whenever both transmitter and receiver locking
+ *  to force safe lock ordering (deadlock prevention)
+ *
+ *  @param rtl8139  RTL8139 private data
+ */
+inline static void rtl8139_lock_all(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+	fibril_mutex_lock(&rtl8139->tx_lock);
+	fibril_mutex_lock(&rtl8139->rx_lock);
+}
+
+/** Unlock transmitter and receiver data
+ *
+ *  @param rtl8139  RTL8139 private data
+ */
+inline static void rtl8139_unlock_all(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+	fibril_mutex_unlock(&rtl8139->tx_lock);
+}
+
+#ifndef RXBUF_SIZE_FLAGS
+	/** Flags for receiver buffer - 16kB default */
+	#define RXBUF_SIZE_FLAGS RTL8139_RXFLAGS_SIZE_16
+#endif
+
+#if (RXBUF_SIZE_FLAGS > RTL8139_RXFLAGS_SIZE_64) || (RXBUF_SIZE_FLAGS < 0)
+	#error Bad receiver buffer flags size flags
+#endif
+
+/** Size of the receiver buffer
+ *
+ *  Incrementing flags by one twices the buffer size
+ *  the lowest size is 8*1024 (flags = 0)
+ */
+#define RxBUF_SIZE RTL8139_RXSIZE(RXBUF_SIZE_FLAGS)
+
+/** Total size of the receiver buffer to allocate */
+#define RxBUF_TOT_LENGTH RTL8139_RXBUF_LENGTH(RXBUF_SIZE_FLAGS)
+
+
+/** Default interrupt mask */
+#define RTL_DEFAULT_INTERRUPTS UINT16_C(0xFFFF)
+
+/** Obtain the value of the register part
+ *  The bit operations will be done
+ *  The _SHIFT and _MASK for the register part must exists as macros
+ *  or variables
+ */
+#define REG_GET_VAL(value, reg_part)\
+		(((value) >> reg_part##_SHIFT) & reg_part##_MASK)
+
+
+/** Disable interrupts on controller
+ *
+ *  @param rtl8139  The card private structure
+ */
+inline static void rtl8139_hw_int_disable(rtl8139_t *rtl8139)
+{
+	pio_write_16(rtl8139->io_port + IMR, 0x0);
+}
+/** Enable interrupts on controller
+ *
+ *  @param rtl8139  The card private structure
+ */
+inline static void rtl8139_hw_int_enable(rtl8139_t *rtl8139)
+{
+	pio_write_16(rtl8139->io_port + IMR, rtl8139->int_mask);
+}
+
+/** Check on the controller if the receiving buffer is empty
+ *
+ *  @param rtl8139  The controller data
+ *
+ *  @return Nonzero if empty, zero otherwise
+ */
+inline static int rtl8139_hw_buffer_empty(rtl8139_t *rtl8139)
+{
+	return pio_read_16(rtl8139->io_port + CR) & CR_BUFE;
+}
+
+/** Update the mask of accepted packets in the RCR register according to
+ * rcr_accept_mode value in rtl8139_t
+ *
+ * @param rtl8139  The rtl8139 private data
+ */
+static void rtl8139_hw_update_rcr(rtl8139_t *rtl8139)
+{
+	uint32_t rcr = rtl8139->rcr_data.rcr_base | rtl8139->rcr_data.ucast_mask
+	    | rtl8139->rcr_data.mcast_mask | rtl8139->rcr_data.bcast_mask
+	    | rtl8139->rcr_data.defect_mask | 
+	    (RXBUF_SIZE_FLAGS << RCR_RBLEN_SHIFT);
+	
+	nlog_debug("Rewriting rcr: %x -> %x", pio_read_32(rtl8139->io_port + RCR),
+	    rcr);
+
+	pio_write_32(rtl8139->io_port + RCR, rcr);
+}
+
+/** Fill the mask of accepted multicast packets in the card registers
+ *
+ *  @param rtl8139  The rtl8139 private data
+ *  @param mask     The mask to set
+ */
+inline static void rtl8139_hw_set_mcast_mask(rtl8139_t *rtl8139,
+    uint64_t mask)
+{
+	pio_write_32(rtl8139->io_port + MAR0, (uint32_t) mask);
+	pio_write_32(rtl8139->io_port + MAR0 + sizeof(uint32_t),
+	    (uint32_t)(mask >> 32));
+	return;
+}
+
+#include <device/pci.h>
+
+/** Set PmEn (Power management enable) bit value
+ *
+ *  @param rtl8139  rtl8139 card data
+ *  @param bit_val  If bit_val is zero pmen is set to 0, otherwise pmen is set to 1
+ */
+inline static void rtl8139_hw_pmen_set(rtl8139_t *rtl8139, uint8_t bit_val)
+{
+	uint8_t config1 = pio_read_8(rtl8139->io_port + CONFIG1);
+	uint8_t config1_new;
+	if (bit_val)
+		config1_new = config1 | CONFIG1_PMEn;
+	else
+		config1_new = config1 & ~(uint8_t)(CONFIG1_PMEn);
+
+	if (config1_new == config1)
+		return;
+
+	rtl8139_regs_unlock(rtl8139->io_port);
+	pio_write_8(rtl8139->io_port + CONFIG1, config1_new);
+	rtl8139_regs_lock(rtl8139->io_port);
+
+	if (bit_val) {
+		async_sess_t *pci_sess =
+			nic_get_ddf_dev(rtl8139->nic_data)->parent_sess;
+		uint8_t pmen;
+		pci_config_space_read_8(pci_sess, 0x55, &pmen);
+		pci_config_space_write_8(pci_sess, 0x55, pmen | 1 | (1 << 7));
+	} else {
+		async_sess_t *pci_sess =
+			nic_get_ddf_dev(rtl8139->nic_data)->parent_sess;
+		uint8_t pmen;
+		pci_config_space_read_8(pci_sess, 0x55, &pmen);
+		pci_config_space_write_8(pci_sess, 0x55, pmen & ~(1 | (1 << 7)));
+	}
+}
+
+/** Get MAC address of the RTL8139 adapter
+ *
+ *  @param rtl8139  The RTL8139 device
+ *  @param address  The place to store the address
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+inline static void rtl8139_hw_get_addr(rtl8139_t *rtl8139,
+    nic_address_t *addr)
+{
+	assert(rtl8139);
+	assert(addr);
+
+	uint32_t *mac0_dest = (uint32_t *)addr->address;
+	uint16_t *mac4_dest = (uint16_t *)(addr->address + 4);
+
+	/* Read MAC address from the i/o (4byte + 2byte reads) */
+	*mac0_dest = pio_read_32(rtl8139->io_port + MAC0);
+	*mac4_dest = pio_read_16(rtl8139->io_port + MAC0 + 4);
+};
+
+/** Set MAC address to the device
+ *
+ *  @param rtl8139  Controller private structure
+ *  @param addr     The address to set
+ */
+static void rtl8139_hw_set_addr(rtl8139_t *rtl8139, const nic_address_t *addr)
+{
+	assert(rtl8139);
+	assert(addr);
+
+	const uint32_t *val1 = (const uint32_t*)addr->address;
+	const uint16_t *val2 = (const uint16_t*)(addr->address + sizeof(uint32_t));
+
+	rtl8139_regs_unlock(rtl8139->io_port);
+	pio_write_32(rtl8139->io_port + MAC0, *val1);
+	pio_write_32(rtl8139->io_port + MAC0 + 4, *val2);
+	rtl8139_regs_lock(rtl8139->io_port);
+}
+
+/**  Provide OR in the 8bit register (set selected bits to 1)
+ *
+ *   @param rtl8139     The rtl8139 structure
+ *   @param reg_offset  Register offset in the device IO space
+ *   @param bits_add    The value to or
+ */
+inline static void rtl8139_hw_reg_add_8(rtl8139_t * rtl8139, size_t reg_offset,
+    uint8_t bits_add)
+{
+	uint8_t value = pio_read_8(rtl8139->io_port + reg_offset);
+	value |= bits_add;
+	pio_write_8(rtl8139->io_port + reg_offset, value);
+}
+
+/**  Provide OR in the 32bit register (set selected bits to 1)
+ *
+ *   @param rtl8139     The rtl8139 structure
+ *   @param reg_offset  Register offset in the device IO space
+ *   @param bits_add    The value to or
+ */
+inline static void rtl8139_hw_reg_add_32(rtl8139_t * rtl8139, size_t reg_offset,
+    uint32_t bits_add)
+{
+	uint32_t value = pio_read_32(rtl8139->io_port + reg_offset);
+	value |= bits_add;
+	pio_write_32(rtl8139->io_port + reg_offset, value);
+}
+
+/**  Unset selected bits in 8bit register
+ *
+ *   @param rtl8139     The rtl8139 structure
+ *   @param reg_offset  Register offset in the device IO space
+ *   @param bits_add    The mask of bits to remove
+ */
+inline static void rtl8139_hw_reg_rem_8(rtl8139_t * rtl8139, size_t reg_offset,
+    uint8_t bits_add)
+{
+	uint8_t value = pio_read_8(rtl8139->io_port + reg_offset);
+	value &= ~bits_add;
+	pio_write_8(rtl8139->io_port + reg_offset, value);
+}
+
+/**  Unset selected bits in 32bit register
+ *
+ *   @param rtl8139     The rtl8139 structure
+ *   @param reg_offset  Register offset in the device IO space
+ *   @param bits_add    The mask of bits to remove
+ */
+inline static void rtl8139_hw_reg_rem_32(rtl8139_t * rtl8139, size_t reg_offset,
+    uint32_t bits_add)
+{
+	uint32_t value = pio_read_32(rtl8139->io_port + reg_offset);
+	value &= ~bits_add;
+	pio_write_32(rtl8139->io_port + reg_offset, value);
+}
+
+
+static int rtl8139_set_addr(ddf_fun_t *fun, const nic_address_t *);
+static int rtl8139_get_device_info(ddf_fun_t *fun, nic_device_info_t *info);
+static int rtl8139_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state);
+static int rtl8139_get_operation_mode(ddf_fun_t *fun, int *speed,
+    nic_channel_mode_t *duplex, nic_role_t *role);
+static int rtl8139_set_operation_mode(ddf_fun_t *fun, int speed,
+    nic_channel_mode_t duplex, nic_role_t);
+
+static int rtl8139_pause_get(ddf_fun_t*, nic_result_t*, nic_result_t*, 
+    uint16_t *);
+static int rtl8139_pause_set(ddf_fun_t*, int, int, uint16_t);
+
+static int rtl8139_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement);
+static int rtl8139_autoneg_disable(ddf_fun_t *fun);
+static int rtl8139_autoneg_probe(ddf_fun_t *fun, uint32_t *our_advertisement,
+    uint32_t *their_advertisement, nic_result_t *result, 
+    nic_result_t *their_result);
+static int rtl8139_autoneg_restart(ddf_fun_t *fun);
+
+static int rtl8139_defective_get_mode(ddf_fun_t *fun, uint32_t *mode);
+static int rtl8139_defective_set_mode(ddf_fun_t *fun, uint32_t mode);
+
+static int rtl8139_wol_virtue_add(nic_t *nic_data,
+	const nic_wol_virtue_t *virtue);
+static void rtl8139_wol_virtue_rem(nic_t *nic_data,
+	const nic_wol_virtue_t *virtue);
+
+static int rtl8139_poll_mode_change(nic_t *nic_data, nic_poll_mode_t mode,
+    const struct timeval *period);
+static void rtl8139_poll(nic_t *nic_data);
+
+/** Network interface options for RTL8139 card driver */
+static nic_iface_t rtl8139_nic_iface = {
+	.set_address = &rtl8139_set_addr,
+	.get_device_info = &rtl8139_get_device_info,
+	.get_cable_state = &rtl8139_get_cable_state,
+	.get_operation_mode = &rtl8139_get_operation_mode,
+	.set_operation_mode = &rtl8139_set_operation_mode,
+
+	.get_pause = &rtl8139_pause_get,
+	.set_pause = &rtl8139_pause_set,
+
+	.autoneg_enable = &rtl8139_autoneg_enable,
+	.autoneg_disable = &rtl8139_autoneg_disable,
+	.autoneg_probe = &rtl8139_autoneg_probe,
+	.autoneg_restart = &rtl8139_autoneg_restart,
+
+	.defective_get_mode = &rtl8139_defective_get_mode,
+	.defective_set_mode = &rtl8139_defective_set_mode,
+};
+
+/** Basic device operations for RTL8139 driver */
+static ddf_dev_ops_t rtl8139_dev_ops;
+
+static int rtl8139_add_device(ddf_dev_t *dev);
+
+/** Basic driver operations for RTL8139 driver */
+static driver_ops_t rtl8139_driver_ops = {
+	.add_device = &rtl8139_add_device,
+};
+
+/** Driver structure for RTL8139 driver */
+static driver_t rtl8139_driver = {
+	.name = NAME,
+	.driver_ops = &rtl8139_driver_ops
+};
+
+/* The default implementation callbacks */
+static int rtl8139_on_activated(nic_t *nic_data);
+static int rtl8139_on_stopped(nic_t *nic_data);
+static void rtl8139_write_packet(nic_t *nic_data, packet_t *packet);
+
+/** Check if the transmit buffer is busy */
+#define rtl8139_tbuf_busy(tsd) ((pio_read_32(tsd) & TSD_OWN) == 0)
+
+/** Send packet with the hardware
+ *
+ * note: the main_lock is locked when framework calls this function
+ *
+ * @param nic_data  The nic driver data structure
+ * @param packet    The packet to send
+ *
+ * @return EOK if succeed, error code in the case of error
+ */
+static void rtl8139_write_packet(nic_t *nic_data, packet_t *packet)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+	nlog_debug("Sending packet");
+
+	/* Get the packet data and check if it can be send */
+	size_t packet_length = packet_get_data_length(packet);
+	void *packet_data = packet_get_data(packet);
+
+	assert(packet_data);
+
+	if ((packet_length > RTL8139_PACKET_MAX_LENGTH) || !packet_data) {
+		nlog_error("Write packet length error: data %p, length %z", 
+		    packet_data, packet_length);
+		nic_report_send_error(rtl8139->nic_data, NIC_SEC_OTHER, 1);
+		goto err_size;
+	}
+
+	assert((packet_length & TSD_SIZE_MASK) == packet_length);
+
+	/* Lock transmitter structure for obtaining next buffer */
+	fibril_mutex_lock(&rtl8139->tx_lock);
+
+	/* Check if there is free buffer */
+	if (rtl8139->tx_next - TX_BUFF_COUNT == rtl8139->tx_used) {
+		nic_set_tx_busy(nic_data, 1);
+		fibril_mutex_unlock(&rtl8139->tx_lock);
+		nic_report_send_error(nic_data, NIC_SEC_BUFFER_FULL, 1);
+		goto err_busy_no_inc;
+	}
+
+	/* Get buffer id to use and set next buffer to use */
+	size_t tx_curr = rtl8139->tx_next++ % TX_BUFF_COUNT;
+
+	fibril_mutex_unlock(&rtl8139->tx_lock);
+
+	/* Get address of the buffer descriptor and packet data */
+	void *tsd = rtl8139->io_port + TSD0 + tx_curr * 4;
+	void *buf_addr = rtl8139->tx_buff[tx_curr];
+
+	/* Wait until the buffer is free */
+	assert(!rtl8139_tbuf_busy(tsd));
+
+	/* Write packet data to the buffer, set the size to TSD and clear OWN bit */
+	memcpy(buf_addr, packet_data, packet_length);
+
+	/* Set size of the data to send */
+	uint32_t tsd_value = pio_read_32(tsd);
+	tsd_value = rtl8139_tsd_set_size(tsd_value, packet_length);
+	pio_write_32(tsd, tsd_value);
+
+	/* barrier for HW to really see the current buffer data */
+	write_barrier();
+
+	tsd_value &= ~(uint32_t)TSD_OWN;
+	pio_write_32(tsd, tsd_value);
+	nic_release_packet(nic_data, packet);
+	return;
+
+err_busy_no_inc:
+err_size:
+	nic_release_packet(nic_data, packet);
+	return;
+};
+
+
+/** Reset the controller
+ *
+ *  @param io_base  The address of the i/o port mapping start
+ */
+inline static void rtl8139_hw_soft_reset(void *io_base)
+{
+	pio_write_8(io_base + CR, CR_RST);
+	memory_barrier();
+	while(pio_read_8(io_base + CR) & CR_RST) {
+		usleep(1);
+		read_barrier();
+	}
+}
+
+/** Provide soft reset of the controller
+ *
+ * The caller must lock tx_lock and rx_lock before calling this function
+ *
+ */
+static void rtl8139_soft_reset(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+
+	rtl8139_hw_soft_reset(rtl8139->io_port);
+	nic_t *nic_data = rtl8139->nic_data;
+
+	/* Write MAC address to the card */
+	nic_address_t addr;
+	nic_query_address(nic_data, &addr);
+	rtl8139_hw_set_addr(rtl8139, &addr);
+
+	/* Recover accept modes back */
+	rtl8139_hw_set_mcast_mask(rtl8139, nic_query_mcast_hash(nic_data));
+	rtl8139_hw_update_rcr(rtl8139);
+
+	rtl8139->tx_used = 0;
+	rtl8139->tx_next = 0;
+	nic_set_tx_busy(rtl8139->nic_data, 0);
+}
+
+/** Create packet structure from the buffer data
+ *
+ * @param nic_data      NIC driver data
+ * @param rx_buffer     The receiver buffer
+ * @param rx_size       The buffer size
+ * @param packet_start  The offset where packet data start
+ * @param packet_size   The size of the packet data
+ *
+ * @return The packet   list node (not connected)
+ */
+static nic_frame_t *rtl8139_read_packet(nic_t *nic_data,
+    void *rx_buffer, size_t rx_size, size_t packet_start, size_t packet_size)
+{
+	nic_frame_t *frame = nic_alloc_frame(nic_data, packet_size);
+	if (! frame) {
+		nlog_error("Can not allocate frame for received packet.");
+		return NULL;
+	}
+
+	void *packet_data = packet_suffix(frame->packet, packet_size);
+	if (!packet_data) {
+		nlog_error("Can not get the packet suffix.");
+		nic_release_frame(nic_data, frame);
+		return NULL;
+	}
+
+	void *ret = rtl8139_memcpy_wrapped(packet_data, rx_buffer, packet_start,
+	    RxBUF_SIZE, packet_size);
+	if (ret == NULL) {
+		nic_release_frame(nic_data, frame);
+		return NULL;
+	}
+	return frame;
+}
+
+/* Reset receiver
+ *
+ * Use in the case of receiver error (lost in the rx_buff)
+ *
+ * @param rtl8139  controller private data
+ */
+static void rtl8139_rx_reset(rtl8139_t *rtl8139) 
+{
+	/* Disable receiver, update offset and enable receiver again */
+	uint8_t cr = pio_read_8(rtl8139->io_port + CR);
+	rtl8139_regs_unlock(rtl8139);
+
+	pio_write_8(rtl8139->io_port + CR, cr & ~(uint8_t)CR_RE);
+
+	write_barrier();
+	pio_write_32(rtl8139->io_port + CAPR, 0);
+	pio_write_32(rtl8139->io_port + RBSTART, 
+	    PTR2U32(rtl8139->rx_buff.physical));
+
+	write_barrier();
+
+	rtl8139_hw_update_rcr(rtl8139);
+	pio_write_8(rtl8139->io_port + CR, cr);
+	rtl8139_regs_lock(rtl8139);
+
+	nic_report_receive_error(rtl8139->nic_data, NIC_REC_OTHER, 1);
+}
+
+/** Receive all packets in queue
+ *
+ *  @param nic_data  The controller data
+ *  @return The linked list of packet_list_t nodes, each containing one packet
+ */
+static nic_frame_list_t *rtl8139_packet_receive(nic_t *nic_data)
+{
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	if (rtl8139_hw_buffer_empty(rtl8139))
+		return NULL;
+
+	nic_frame_list_t *frames = nic_alloc_frame_list();
+	if (!frames)
+		nlog_error("Can not allocate frame list for received packets.");
+
+	void *rx_buffer = rtl8139->rx_buff.virtual;
+
+	/* where to start reading */
+	uint16_t rx_offset = pio_read_16(rtl8139->io_port + CAPR) + 16;
+	/* unread bytes count */
+	uint16_t bytes_received = pio_read_16(rtl8139->io_port + CBA);
+	uint16_t max_read;
+	uint16_t cur_read = 0;
+
+	/* get values to the <0, buffer size) */
+	bytes_received %= RxBUF_SIZE;
+	rx_offset %= RxBUF_SIZE;
+	
+	/* count how many bytes to read maximaly */
+	if (bytes_received < rx_offset)
+		max_read = bytes_received + (RxBUF_SIZE - rx_offset);
+	else
+		max_read = bytes_received - rx_offset;
+
+	memory_barrier();
+	while (!rtl8139_hw_buffer_empty(rtl8139)) {
+		void *rx_ptr = rx_buffer + rx_offset % RxBUF_SIZE;
+		uint32_t packet_header = uint32_t_le2host( *((uint32_t*)rx_ptr) );
+		uint16_t size = packet_header >> 16;
+		uint16_t packet_size = size - RTL8139_CRC_SIZE;
+		/* received packet flags in packet header */
+		uint16_t rcs = (uint16_t) packet_header;
+
+		if (size == RTL8139_EARLY_SIZE) {
+			/* The packet copying is still in progress, break receiving */
+			nlog_debug("Early threshold reached, not completely coppied");
+			break;
+		}
+
+		/* Check if the header is valid, otherwise we are lost in the buffer */
+		if (size == 0 || size > RTL8139_PACKET_MAX_LENGTH) {
+			nlog_error("Receiver error -> receiver reset (size: %4"PRIu16", "
+			    "header 0x%4"PRIx16". Offset: %zu)", size, packet_header, 
+			    rx_offset);
+			goto rx_err;
+		}
+		if (size < RTL8139_RUNT_MAX_SIZE && !(rcs & RSR_RUNT)) {
+			nlog_error("Receiver error -> receiver reset (%"PRIx16")", size);
+			goto rx_err;
+		}
+
+		cur_read += size + RTL_PACKET_HEADER_SIZE;
+		if (cur_read > max_read)
+			break;
+
+		if (frames) {
+			nic_frame_t *frame = rtl8139_read_packet(nic_data, rx_buffer,
+			    RxBUF_SIZE, rx_offset + RTL_PACKET_HEADER_SIZE, packet_size);
+
+			if (frame)
+				nic_frame_list_append(frames, frame);
+		}
+
+		/* Update offset */
+		rx_offset = ALIGN_UP(rx_offset + size + RTL_PACKET_HEADER_SIZE, 4);
+
+		/* Write lesser value to prevent overflow into unread packet
+		 * (the recomendation from the RealTech rtl8139 programming guide)
+		 */
+		uint16_t capr_val = rx_offset - 16;
+		pio_write_16(rtl8139->io_port + CAPR, capr_val);
+
+		/* Ensure no CR read optimalization during next empty buffer test */
+		memory_barrier();
+	}
+	return frames;
+rx_err:
+	rtl8139_rx_reset(rtl8139);
+	return frames;
+};
+
+
+
+/** Commands to deal with interrupt
+ *
+ *  Read ISR, check if tere is any interrupt pending.
+ *  If so, reset it and accept the interrupt.
+ *  The .addr of the first and third command must
+ *  be filled to the ISR port address
+ */
+irq_cmd_t rtl8139_irq_commands[] = {
+		{
+				/* Get the interrupt status */
+				.cmd = CMD_PIO_READ_16,
+				.addr = NULL,
+				.dstarg = 2
+		},
+		{
+				.cmd = CMD_PREDICATE,
+				.value = 3,
+				.srcarg = 2
+		},
+		{
+				/* Mark interrupts as solved */
+				.cmd = CMD_PIO_WRITE_16,
+				.addr = NULL,
+				.value = 0xFFFF
+		},
+		{
+				/* Disable interrupts until interrupt routine is finished */
+				.cmd = CMD_PIO_WRITE_16,
+				.addr = NULL,
+				.value = 0x0000
+		},
+		{
+				.cmd = CMD_ACCEPT
+		}
+};
+
+/** Interrupt code definition */
+irq_code_t rtl8139_irq_code = {
+	.cmdcount = sizeof(rtl8139_irq_commands)/sizeof(irq_cmd_t),
+	.cmds = rtl8139_irq_commands
+};
+
+/** Deal with transmitter interrupt
+ *
+ *  @param nic_data  Nic driver data
+ */
+static void rtl8139_tx_interrupt(nic_t *nic_data)
+{
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+
+	fibril_mutex_lock(&rtl8139->tx_lock);
+
+	size_t tx_next = rtl8139->tx_next;
+	size_t tx_used = rtl8139->tx_used;
+	while (tx_used != tx_next) {
+		size_t desc_to_check = tx_used % TX_BUFF_COUNT;
+		void * tsd_to_check = rtl8139->io_port + TSD0 
+		    + desc_to_check * sizeof(uint32_t);
+		uint32_t tsd_value = pio_read_32(tsd_to_check);
+
+		/* If sending is still in the progress */
+		if ((tsd_value & TSD_OWN) == 0)
+			break;
+
+		tx_used++;
+
+		/* If the packet was sent */
+		if (tsd_value & TSD_TOK) {
+			size_t size = REG_GET_VAL(tsd_value, TSD_SIZE);
+			nic_report_send_ok(nic_data, 1, size);
+		} else if (tsd_value & TSD_CRS) {
+			nic_report_send_error(nic_data, NIC_SEC_CARRIER_LOST, 1);
+		} else if (tsd_value & TSD_OWC) {
+			nic_report_send_error(nic_data, NIC_SEC_WINDOW_ERROR, 1);
+		} else if (tsd_value & TSD_TABT) {
+			nic_report_send_error(nic_data, NIC_SEC_ABORTED, 1);
+		} else if (tsd_value & TSD_CDH) {
+			nic_report_send_error(nic_data, NIC_SEC_HEARTBEAT, 1);
+		}
+
+		unsigned collisions = REG_GET_VAL(tsd_value, TSD_NCC);
+		if (collisions > 0) {
+			nic_report_collisions(nic_data, collisions);
+		}
+
+		if (tsd_value & TSD_TUN) {
+			nic_report_send_error(nic_data, NIC_SEC_FIFO_OVERRUN, 1);
+		}
+	}
+	if (rtl8139->tx_used != tx_used) {
+		rtl8139->tx_used = tx_used;
+		nic_set_tx_busy(nic_data, 0);
+	}
+	fibril_mutex_unlock(&rtl8139->tx_lock);
+}
+
+/** Receive all packets from the buffer
+ *
+ *  @param rtl8139  driver private data
+ */
+static void rtl8139_receive_packets(nic_t *nic_data)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	fibril_mutex_lock(&rtl8139->rx_lock);
+	nic_frame_list_t *frames = rtl8139_packet_receive(nic_data);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+
+	if (frames)
+		nic_received_frame_list(nic_data, frames);
+}
+
+
+/** Deal with poll interrupt
+ *
+ *  @param nic_data  Nic driver data
+ */
+static int rtl8139_poll_interrupt(nic_t *nic_data)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	uint32_t timer_val;
+	int receive = rtl8139_timer_act_step(&rtl8139->poll_timer, &timer_val);
+
+	assert(timer_val);
+	pio_write_32(rtl8139->io_port + TIMERINT, timer_val);
+	pio_write_32(rtl8139->io_port + TCTR, 0x0);
+	nlog_debug("rtl8139 timer: %"PRIu32"\treceive: %d", timer_val, receive);
+	return receive;
+}
+
+
+/** Poll device according to isr status
+ *
+ *  The isr value must be obtained and cleared by the caller. The reason
+ *  of this function separate is to allow polling from both interrupt
+ *  (which clears controller ISR before the handler runs) and the polling
+ *  callbacks.
+ *
+ *  @param nic_data  Driver data
+ *  @param isr       Interrupt status register value
+ */
+static void rtl8139_interrupt_impl(nic_t *nic_data, uint16_t isr)
+{
+	assert(nic_data);
+	
+	nic_poll_mode_t poll_mode = nic_query_poll_mode(nic_data, 0);
+
+	/* Process only when should in the polling mode */
+	if (poll_mode == NIC_POLL_PERIODIC) {
+		int receive = 0;
+		if (isr & INT_TIME_OUT) {
+			receive = rtl8139_poll_interrupt(nic_data);
+		}
+		if (! receive)
+			return;
+	}
+
+	/* Check transmittion interrupts first to allow transmit next packets
+	 * sooner
+	 */
+	if (isr & (INT_TOK | INT_TER)) {
+		rtl8139_tx_interrupt(nic_data);
+	}
+	if (isr & INT_ROK) {
+		rtl8139_receive_packets(nic_data);
+	}
+	if (isr & (INT_RER | INT_RXOVW | INT_FIFOOVW)) {
+		if (isr & INT_RER) {
+			//TODO: is this only the general error, or any particular?
+		}
+		if (isr & (INT_FIFOOVW)) {
+			nic_report_receive_error(nic_data, NIC_REC_FIFO_OVERRUN, 1);
+		} else if (isr & (INT_RXOVW)) {
+			rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+			assert(rtl8139);
+
+			uint32_t miss = pio_read_32(rtl8139->io_port + MPC) & MPC_VMASK;
+			pio_write_32(rtl8139->io_port + MPC, 0);
+			nic_report_receive_error(nic_data, NIC_REC_BUFFER_OVERFLOW, miss);
+		}
+	}
+}
+
+/** Handle device interrupt
+ *
+ *  @param dev    The rtl8139 device
+ *  @param iid    The IPC call id
+ *  @param icall  The IPC call structure
+ */
+static void rtl8139_interrupt_handler(ddf_dev_t *dev, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	assert(dev);
+	assert(icall);
+
+	uint16_t isr = (uint16_t) IPC_GET_ARG2(*icall);
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+
+	rtl8139_interrupt_impl(nic_data, isr);
+
+	/* Turn the interrupts on again */
+	rtl8139_hw_int_enable(rtl8139);
+};
+
+/** Register interrupt handler for the card in the system
+ *
+ *  Note: the global irq_reg_mutex is locked because of work with global
+ *  structure.
+ *
+ *  @param nic_data  The driver data
+ *
+ *  @return EOK if the handler was registered, negative error code otherwise
+ */
+inline static int rtl8139_register_int_handler(nic_t *nic_data)
+{
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+
+	/* Lock the mutex in whole driver while working with global structure */
+	RTL8139_IRQ_STRUCT_LOCK();
+
+	rtl8139_irq_code.cmds[0].addr = rtl8139->io_port + ISR;
+	rtl8139_irq_code.cmds[2].addr = rtl8139->io_port + ISR;
+	rtl8139_irq_code.cmds[3].addr = rtl8139->io_port + IMR;
+	int rc = register_interrupt_handler(nic_get_ddf_dev(nic_data),
+		rtl8139->irq, rtl8139_interrupt_handler, &rtl8139_irq_code);
+
+	RTL8139_IRQ_STRUCT_UNLOCK();
+
+	return rc;
+}
+
+/** Start the controller
+ *
+ * The caller must lock tx_lock and rx_lock before calling this function
+ *
+ * @param rtl8139  The card private data
+ */
+inline static void rtl8139_card_up(rtl8139_t *rtl8139)
+{
+	void *io_base = rtl8139->io_port;
+	size_t i;
+
+	/* Wake up the device */
+	pio_write_8(io_base + CONFIG1, 0x00);
+	/* Reset the device */
+	rtl8139_soft_reset(rtl8139);
+
+	/* Write transmittion buffer addresses */
+	for(i = 0; i < TX_BUFF_COUNT; ++i) {
+		uint32_t addr = PTR2U32(rtl8139->tx_buff_mem.physical + i*TX_BUFF_SIZE);
+		pio_write_32(io_base + TSAD0 + 4*i, addr);
+	}
+	rtl8139->tx_next = 0;
+	rtl8139->tx_used = 0;
+	nic_set_tx_busy(rtl8139->nic_data, 0);
+
+	pio_write_32(io_base + RBSTART, PTR2U32(rtl8139->rx_buff.physical));
+
+	/* Enable transmitter and receiver */
+	uint8_t cr_value = pio_read_8(io_base + CR);
+	pio_write_8(io_base + CR, cr_value | CR_TE | CR_RE);
+	rtl8139_hw_update_rcr(rtl8139);
+}
+
+/** Activate the device to receive and transmit packets
+ *
+ *  @param nic_data  The nic driver data
+ *
+ *  @return EOK if activated successfully, error code otherwise
+ */
+static int rtl8139_on_activated(nic_t *nic_data)
+{
+	assert(nic_data);
+	nlog_info("Activating device");
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	rtl8139_lock_all(rtl8139);
+	rtl8139_card_up(rtl8139);
+	rtl8139_unlock_all(rtl8139);
+
+	rtl8139->int_mask = RTL_DEFAULT_INTERRUPTS;
+	rtl8139_hw_int_enable(rtl8139);
+	nic_enable_interrupt(nic_data, rtl8139->irq);
+
+	nlog_debug("Device activated, interrupt %d registered", rtl8139->irq);
+	return EOK;
+}
+
+/** Callback for NIC_STATE_STOPPED change
+ *
+ *  @param nic_data  The nic driver data
+ *
+ *  @return EOK if succeed, error code otherwise
+ */
+static int rtl8139_on_stopped(nic_t *nic_data)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	rtl8139->rcr_data.ucast_mask = RTL8139_RCR_UCAST_DEFAULT;
+	rtl8139->rcr_data.mcast_mask = RTL8139_RCR_MCAST_DEFAULT;
+	rtl8139->rcr_data.bcast_mask = RTL8139_RCR_BCAST_DEFAULT;
+	rtl8139->rcr_data.defect_mask = RTL8139_RCR_DEFECT_DEFAULT;
+
+	/* Reset the card to the initial state (interrupts, Tx and Rx disabled) */
+	rtl8139_lock_all(rtl8139);
+	rtl8139_soft_reset(rtl8139);
+	rtl8139_unlock_all(rtl8139);
+	return EOK;
+}
+
+
+static int rtl8139_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
+    const nic_address_t *, size_t);
+static int rtl8139_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_count);
+static int rtl8139_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode);
+
+
+/** Create driver data structure
+ *
+ *  @return Intialized device data structure or NULL
+ */
+static rtl8139_t *rtl8139_create_dev_data(ddf_dev_t *dev)
+{
+	assert(dev);
+	assert(!nic_get_from_ddf_dev(dev));
+
+	nic_t *nic_data = nic_create_and_bind(dev);
+	if (!nic_data)
+		return NULL;
+
+	rtl8139_t *rtl8139 = malloc(sizeof(rtl8139_t));
+	if (!rtl8139) {
+		nic_unbind_and_destroy(dev);
+		return NULL;
+	}
+
+	bzero(rtl8139, sizeof(rtl8139_t));
+
+	rtl8139->nic_data = nic_data;
+	nic_set_specific(nic_data, rtl8139);
+	nic_set_write_packet_handler(nic_data, rtl8139_write_packet);
+	nic_set_state_change_handlers(nic_data,
+		rtl8139_on_activated, NULL, rtl8139_on_stopped);
+	nic_set_filtering_change_handlers(nic_data,
+		rtl8139_unicast_set, rtl8139_multicast_set, rtl8139_broadcast_set,
+		NULL, NULL);
+	nic_set_wol_virtue_change_handlers(nic_data,
+		rtl8139_wol_virtue_add, rtl8139_wol_virtue_rem);
+	nic_set_poll_handlers(nic_data, rtl8139_poll_mode_change, rtl8139_poll);
+
+
+	fibril_mutex_initialize(&rtl8139->rx_lock);
+	fibril_mutex_initialize(&rtl8139->tx_lock);
+
+	nic_set_wol_max_caps(nic_data, NIC_WV_BROADCAST, 1);
+	nic_set_wol_max_caps(nic_data, NIC_WV_LINK_CHANGE, 1);
+	nic_set_wol_max_caps(nic_data, NIC_WV_MAGIC_PACKET, 1);
+
+	return rtl8139;
+}
+
+/** Clean up the rtl8139 device structure.
+ *
+ * @param dev  The device structure.
+ */
+static void rtl8139_dev_cleanup(ddf_dev_t *dev)
+{
+	assert(dev);
+
+	if (dev->driver_data)
+		nic_unbind_and_destroy(dev);
+
+	if (dev->parent_sess != NULL) {
+		async_hangup(dev->parent_sess);
+		dev->parent_sess = NULL;
+	}
+}
+
+/** Fill the irq and io_addr part of device data structure
+ *
+ *  The hw_resources must be obtained before calling this function
+ *
+ *  @param dev           The device structure
+ *  @param hw_resources  Devices hardware resources
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+static int rtl8139_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t
+    *hw_resources)
+{
+	assert(dev);
+	assert(hw_resources);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_dev(dev));
+	assert(rtl8139);
+
+	if (hw_resources->irqs.count != 1) {
+		nlog_error("%s device: unexpected irq count", dev->name);
+		return EINVAL;
+	};
+	if (hw_resources->io_ranges.count != 1) {
+		nlog_error("%s device: unexpected io ranges count", dev->name);
+		return EINVAL;
+	}
+
+	rtl8139->irq = hw_resources->irqs.irqs[0];
+	nlog_debug("%s device: irq 0x%x assigned", dev->name, rtl8139->irq);
+
+	rtl8139->io_addr = IOADDR_TO_PTR(hw_resources->io_ranges.ranges[0].address);
+	if (hw_resources->io_ranges.ranges[0].size < RTL8139_IO_SIZE) {
+		nlog_error("i/o range assigned to the device "
+		    "%s is too small.", dev->name);
+		return EINVAL;
+	}
+	nlog_debug("%s device: i/o addr %p assigned.", dev->name, rtl8139->io_addr);
+
+	return EOK;
+}
+
+/** Obtain information about hardware resources of the device
+ *
+ *  The device must be connected to the parent
+ *
+ *  @param dev  The device structure
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+static int rtl8139_get_resource_info(ddf_dev_t *dev)
+{
+	assert(dev);
+
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	assert(nic_data);
+
+	hw_res_list_parsed_t hw_res_parsed;
+	hw_res_list_parsed_init(&hw_res_parsed);
+
+	/* Get hw resources form parent driver */
+	int rc = nic_get_resources(nic_data, &hw_res_parsed);
+	if (rc != EOK)
+		return rc;
+
+	/* Fill resources information to the device */
+	int ret = rtl8139_fill_resource_info(dev, &hw_res_parsed);
+	hw_res_list_parsed_clean(&hw_res_parsed);
+
+	return ret;
+}
+
+
+/** Allocate buffers using DMA framework
+ *
+ * The buffers structures in the device specific data is filled
+ *
+ * @param data  The device specific structure to fill
+ *
+ * @return EOK in the case of success, error code otherwise
+ */
+static int rtl8139_buffers_create(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+	size_t i = 0;
+	int rc;
+
+	nlog_debug("Creating buffers");
+
+	rtl8139->tx_buff_mem.size = TX_PAGES;
+	rtl8139->tx_buff_mem.mapping_flags = AS_AREA_WRITE;
+	rc = dma_allocate_anonymous(&rtl8139->tx_buff_mem, DMA_32_BITS);
+	if (rc != EOK) {
+		nlog_error("Can not allocate transmitter buffers.");
+		goto err_tx_alloc;
+	}
+
+	for(i = 0; i < TX_BUFF_COUNT; ++i)
+		rtl8139->tx_buff[i] = rtl8139->tx_buff_mem.virtual + i * TX_BUFF_SIZE;
+
+	nlog_debug("The transmittion buffers allocated");
+
+	/* Use the first buffer for next transmittion */
+	rtl8139->tx_next = 0;
+	rtl8139->tx_used = 0;
+
+	/* Allocate buffer for receiver */
+	size_t rx_pages = ALIGN_UP(RxBUF_TOT_LENGTH, PAGE_SIZE) / PAGE_SIZE;
+	nlog_debug("Allocating receiver buffer of the size %zd pages", rx_pages);
+
+	rtl8139->rx_buff.size = rx_pages;
+	rtl8139->rx_buff.mapping_flags = AS_AREA_READ;
+	rc = dma_allocate_anonymous(&rtl8139->rx_buff, DMA_32_BITS);
+	if( rc != EOK ) {
+		nlog_error("Can not allocate receiver buffer.");
+		goto err_rx_alloc;
+	}
+	nlog_debug("The buffers created");
+
+	return EOK;
+
+err_rx_alloc:
+	dma_free(&rtl8139->tx_buff_mem);
+err_tx_alloc:
+	return rc;
+}
+
+/** Initialize the rtl8139 device structure
+ *
+ *  @param dev  The device information
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+static int rtl8139_device_initialize(ddf_dev_t *dev)
+{
+	nlog_debug("rtl8139_dev_initialize %s", dev->name);
+
+	int ret = EOK;
+
+	nlog_debug("rtl8139: creating device data");
+
+	/* Allocate driver data for the device. */
+	rtl8139_t *rtl8139 = rtl8139_create_dev_data(dev);
+	if (rtl8139 == NULL) {
+		nlog_error("Not enough memory for initializing %s.", dev->name);
+		return ENOMEM;
+	}
+
+	nlog_debug("rtl8139: dev_data created");
+
+	/* Obtain and fill hardware resources info and connect to parent */
+	ret = rtl8139_get_resource_info(dev);
+	if (ret != EOK) {
+		nlog_error("Can not obatin hw resources information");
+		goto failed;
+	}
+
+	nlog_debug("rtl8139: resource_info obtained");
+
+	/* Allocate DMA buffers */
+	ret = rtl8139_buffers_create(rtl8139);
+	if (ret != EOK)
+		goto failed;
+
+	/* Set default packet acceptance */
+	rtl8139->rcr_data.ucast_mask = RTL8139_RCR_UCAST_DEFAULT;
+	rtl8139->rcr_data.mcast_mask = RTL8139_RCR_MCAST_DEFAULT;
+	rtl8139->rcr_data.bcast_mask = RTL8139_RCR_BCAST_DEFAULT;
+	rtl8139->rcr_data.defect_mask = RTL8139_RCR_DEFECT_DEFAULT;
+	/* Set receiver early treshold to 8/16 of packet length */
+	rtl8139->rcr_data.rcr_base = (0x8 << RCR_ERTH_SHIFT);
+
+	nlog_debug("The device is initialized");
+	return ret;
+
+failed:
+	nlog_error("The device initialization failed");
+	rtl8139_dev_cleanup(dev);
+	return ret;
+}
+
+/** Enable the i/o ports of the device.
+ *
+ * @param dev  The RTL8139 device.
+ *
+ * @return EOK if successed, negative error code otherwise
+ */
+static int rtl8139_pio_enable(ddf_dev_t *dev)
+{
+	nlog_debug(NAME ": rtl8139_pio_enable %s", dev->name);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_dev(dev));
+
+	/* Gain control over port's registers. */
+	if (pio_enable(rtl8139->io_addr, RTL8139_IO_SIZE, &rtl8139->io_port)) {
+		nlog_error("Cannot gain the port %lx for device %s.", rtl8139->io_addr,
+		    dev->name);
+		return EADDRNOTAVAIL;
+	}
+
+	return EOK;
+}
+
+/** Initialize the driver private data according to the
+ *  device registers
+ *
+ *  @param rtl8139 rtl8139 private data
+ */
+static void rtl8139_data_init(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+
+	/* Check the version id */
+	uint32_t tcr = pio_read_32(rtl8139->io_port + TCR);
+	uint32_t hwverid = RTL8139_HWVERID(tcr);
+	size_t i = 0;
+	rtl8139->hw_version = RTL8139_VER_COUNT;
+	for (i = 0; i < RTL8139_VER_COUNT; ++i) {
+		if (rtl8139_versions[i].hwverid == 0)
+			break;
+
+		if (rtl8139_versions[i].hwverid == hwverid) {
+			rtl8139->hw_version = rtl8139_versions[i].ver_id;
+			nlog_info("HW version found: index %zu, ver_id %d (%s)", i,
+			    rtl8139_versions[i].ver_id, model_names[rtl8139->hw_version]);
+		}
+	}
+}
+
+/** The add_device callback of RTL8139 callback
+ *
+ * Probe and initialize the newly added device.
+ *
+ * @param dev  The RTL8139 device.
+ *
+ * @return EOK if added successfully, negative error code otherwise
+ */
+int rtl8139_add_device(ddf_dev_t *dev)
+{
+	assert(dev);
+	nlog_info("RTL8139_add_device %s (handle = %d)", dev->name, dev->handle);
+
+	/* Init device structure for rtl8139 */
+	int rc = rtl8139_device_initialize(dev);
+	if (rc != EOK)
+		return rc;
+
+	/* Map I/O ports */
+	rc = rtl8139_pio_enable(dev);
+	if (rc != EOK)
+		goto err_destroy;
+
+	nic_t *nic_data = nic_get_from_ddf_dev(dev);
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+
+	nic_address_t addr;
+	rtl8139_hw_get_addr(rtl8139, &addr);
+	rc = nic_report_address(nic_data, &addr);
+	if (rc != EOK)
+		goto err_pio;
+
+	/* Initialize the driver private structure */
+	rtl8139_data_init(rtl8139);
+
+	/* Register interrupt handler */
+	rc = rtl8139_register_int_handler(nic_data);
+	if (rc != EOK)
+		goto err_pio;
+
+	rc = nic_connect_to_services(nic_data);
+	if (rc != EOK) {
+		nlog_error("Failed to connect to services", rc);
+		goto err_irq;
+	}
+
+	rc = nic_register_as_ddf_fun(nic_data, &rtl8139_dev_ops);
+	if (rc != EOK) {
+		nlog_error("Failed to register as DDF function - error %d", rc);
+		goto err_irq;
+	}
+
+	nlog_info("The %s device has been successfully initialized.",
+	    dev->name);
+
+	return EOK;
+
+err_irq:
+	unregister_interrupt_handler(dev, rtl8139->irq);
+err_pio:
+	// rtl8139_pio_disable(dev);
+	/* TODO: find out if the pio_disable is needed */
+err_destroy:
+	rtl8139_dev_cleanup(dev);
+	return rc;
+};
+
+/** Set card MAC address
+ *
+ *  @param device   The RTL8139 device
+ *  @param address  The place to store the address
+ *  @param max_len  Maximal addresss length to store
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+static int rtl8139_set_addr(ddf_fun_t *fun, const nic_address_t *addr)
+{
+	assert(fun);
+	assert(addr);
+
+	nic_t *nic_data =nic_get_from_ddf_fun((fun));
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	rtl8139_lock_all(rtl8139);
+
+	int rc = nic_report_address(nic_data, addr);
+	if ( rc != EOK) {
+		rtl8139_unlock_all(rtl8139);
+		return rc;
+	}
+
+	rtl8139_hw_set_addr(rtl8139, addr);
+
+	rtl8139_unlock_all(rtl8139);
+	return EOK;
+}
+
+/** Get the device information
+ *
+ *  @param dev   The NIC device
+ *  @param info  The information to fill
+ *
+ *  @return EOK
+ */
+static int rtl8139_get_device_info(ddf_fun_t *fun, nic_device_info_t *info)
+{
+	assert(fun);
+	assert(info);
+
+	nic_t *nic_data = nic_get_from_ddf_fun(fun);
+	assert(nic_data);
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	/* TODO: fill the information more completely */
+	info->vendor_id = 0x10ec;
+	str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "Realtek");
+
+	if (rtl8139->hw_version < RTL8139_VER_COUNT) {
+		str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, 
+		    model_names[rtl8139->hw_version]);
+	} else {
+		str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8139");
+	}
+
+	info->ethernet_support[ETH_10M] = ETH_10BASE_T;
+	info->ethernet_support[ETH_100M] = ETH_100BASE_TX;
+
+	info->autoneg_support = RTL8139_AUTONEG_CAPS;
+	return EOK;
+}
+
+/** Check the cable state
+ *
+ *  @param[in]  dev    The device
+ *  @param[out] state  The state to fill
+ *
+ *  @return EOK
+ */
+static int rtl8139_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state)
+{
+	assert(fun);
+	assert(state);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if (pio_read_16(rtl8139->io_port + CSCR) & CS_CON_STATUS) {
+		*state = NIC_CS_PLUGGED;
+	} else {
+		*state = NIC_CS_UNPLUGGED;
+	}
+
+	return EOK;
+}
+
+/** Get operation mode of the device
+ */
+static int rtl8139_get_operation_mode(ddf_fun_t *fun, int *speed,
+    nic_channel_mode_t *duplex, nic_role_t *role)
+{
+	assert(fun);
+	assert(speed);
+	assert(duplex);
+	assert(role);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	uint16_t bmcr_val = pio_read_16(rtl8139->io_port + BMCR);
+	uint8_t msr_val = pio_read_8(rtl8139->io_port + MSR);
+
+	if (bmcr_val & BMCR_DUPLEX) {
+		*duplex = NIC_CM_FULL_DUPLEX;
+	} else {
+		*duplex = NIC_CM_HALF_DUPLEX;
+	}
+
+	if (msr_val & MSR_SPEED10) {
+		*speed = 10;
+	} else {
+		*speed = 100;
+	}
+
+	*role = NIC_ROLE_UNKNOWN;
+	return EOK;
+}
+
+/** Value validity */
+enum access_mode {
+	/** Value is invalid now */
+	VALUE_INVALID = 0,
+	/** Read-only */
+	VALUE_RO,
+	/** Read-write */
+	VALUE_RW
+};
+
+/** Check if pause packet operations are valid in current situation 
+ *
+ *  @param rtl8139  RTL8139 private structure
+ *
+ *  @return VALUE_INVALID if the value has no sense in current moment
+ *  @return VALUE_RO if the state is read-only in current moment
+ *  @return VALUE_RW if the state can be modified
+ */
+static int rtl8139_pause_is_valid(rtl8139_t *rtl8139)
+{
+	assert(rtl8139);
+
+	uint16_t bmcr = pio_read_16(rtl8139->io_port + BMCR);
+	if ((bmcr & (BMCR_AN_ENABLE | BMCR_DUPLEX)) == 0)
+		return VALUE_INVALID;
+
+	if (bmcr & BMCR_AN_ENABLE) {
+		uint16_t anar_lp = pio_read_16(rtl8139->io_port + ANLPAR);
+		if (anar_lp & ANAR_PAUSE)
+			return VALUE_RO;
+	}
+
+	return VALUE_RW;
+}
+
+/** Get current pause packet configuration
+ *
+ *  Values are filled with NIC_RESULT_NOT_AVAILABLE if the value has no sense in
+ *  the moment (half-duplex).
+ *
+ *  @param[in]  fun         The DDF structure of the RTL8139
+ *  @param[out] we_send     Sign if local constroller sends pause packets
+ *  @param[out] we_receive  Sign if local constroller receives pause packets
+ *  @param[out] time        Time filled in pause packets. 0xFFFF in rtl8139
+ *
+ *  @return EOK if succeed
+ */
+static int rtl8139_pause_get(ddf_fun_t *fun, nic_result_t *we_send, 
+    nic_result_t *we_receive, uint16_t *time)
+{
+	assert(fun);
+	assert(we_send);
+	assert(we_receive);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if (rtl8139_pause_is_valid(rtl8139) == VALUE_INVALID) {
+		*we_send = NIC_RESULT_NOT_AVAILABLE;
+		*we_receive = NIC_RESULT_NOT_AVAILABLE;
+		*time = 0;
+		return EOK;
+	}
+
+	uint8_t msr = pio_read_8(rtl8139->io_port + MSR);
+
+	*we_send = (msr & MSR_TXFCE) ? NIC_RESULT_ENABLED : NIC_RESULT_DISABLED;
+	*we_receive = (msr & MSR_RXFCE) ? NIC_RESULT_ENABLED : NIC_RESULT_DISABLED;
+	*time = RTL8139_PAUSE_VAL;
+
+	return EOK;
+};
+
+/** Set current pause packet configuration
+ *
+ *  @param fun            The DDF structure of the RTL8139
+ *  @param allow_send     Sign if local constroller sends pause packets
+ *  @param allow_receive  Sign if local constroller receives pause packets
+ *  @param time           Time to use, ignored (not supported by device)
+ *
+ *  @return EOK if succeed, INVAL if the pause packet has no sence
+ */
+static int rtl8139_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive, 
+    uint16_t time)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if (rtl8139_pause_is_valid(rtl8139) != VALUE_RW)
+		return EINVAL;
+	
+	uint8_t msr = pio_read_8(rtl8139->io_port + MSR);
+	msr &= ~(uint8_t)(MSR_TXFCE | MSR_RXFCE);
+
+	if (allow_receive)
+		msr |= MSR_RXFCE;
+	if (allow_send)
+		msr |= MSR_TXFCE;
+	
+	pio_write_8(rtl8139->io_port + MSR, msr);
+
+	if (allow_send && time > 0) {
+		nlog_warning("Time setting is not supported in set_pause method.");
+	}
+	return EOK;
+};
+
+/** Set operation mode of the device
+ *
+ */
+static int rtl8139_set_operation_mode(ddf_fun_t *fun, int speed,
+    nic_channel_mode_t duplex, nic_role_t role)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if (speed != 10 && speed != 100)
+		return EINVAL;
+	if (duplex != NIC_CM_HALF_DUPLEX && duplex != NIC_CM_FULL_DUPLEX)
+		return EINVAL;
+
+	uint16_t bmcr_val = pio_read_16(rtl8139->io_port + BMCR);
+
+	/* Set autonegotion disabled */
+	bmcr_val &= ~(uint16_t)BMCR_AN_ENABLE;
+
+	if (duplex == NIC_CM_FULL_DUPLEX) {
+		bmcr_val |= BMCR_DUPLEX;
+	} else {
+		bmcr_val &= ~((uint16_t)BMCR_DUPLEX);
+	}
+
+	if (speed == 100) {
+		bmcr_val |= BMCR_Spd_100;
+	} else {
+		bmcr_val &= ~((uint16_t)BMCR_Spd_100);
+	}
+
+	rtl8139_regs_unlock(rtl8139->io_port);
+	pio_write_16(rtl8139->io_port + BMCR, bmcr_val);
+	rtl8139_regs_lock(rtl8139->io_port);
+	return EOK;
+}
+
+/** Enable autonegoation with specific advertisement
+ *
+ *  @param dev            The device to update
+ *  @param advertisement  The advertisement to set
+ *
+ *  @returns EINVAL if the advertisement mode is not supproted
+ *  @returns EOK if advertisement mode set successfully
+ */
+static int rtl8139_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if (advertisement == 0) {
+		advertisement = RTL8139_AUTONEG_CAPS;
+	}
+
+	if ((advertisement | RTL8139_AUTONEG_CAPS) != RTL8139_AUTONEG_CAPS)
+		return EINVAL; /* some unsuported mode is requested */
+	
+	assert(advertisement != 0);
+
+	/* Set the autonegotiation advertisement */
+	uint16_t anar = ANAR_SELECTOR; /* default selector */
+	if (advertisement & ETH_AUTONEG_10BASE_T_FULL)
+		anar |= ANAR_10_FD;
+	if (advertisement & ETH_AUTONEG_10BASE_T_HALF)
+		anar |= ANAR_10_HD;
+	if (advertisement & ETH_AUTONEG_100BASE_TX_FULL)
+		anar |= ANAR_100TX_FD;
+	if (advertisement & ETH_AUTONEG_100BASE_TX_HALF)
+		anar |= ANAR_100TX_HD;
+	if (advertisement & ETH_AUTONEG_PAUSE_SYMETRIC)
+		anar |= ANAR_PAUSE;
+
+	uint16_t bmcr_val = pio_read_16(rtl8139->io_port + BMCR);
+	bmcr_val |= BMCR_AN_ENABLE;
+
+	pio_write_16(rtl8139->io_port + ANAR, anar);
+
+	rtl8139_regs_unlock(rtl8139->io_port);
+	pio_write_16(rtl8139->io_port + BMCR, bmcr_val);
+	rtl8139_regs_lock(rtl8139->io_port);
+	return EOK;
+}
+
+/** Disable advertisement functionality
+ *
+ *  @param dev  The device to update
+ *
+ *  @returns EOK
+ */
+static int rtl8139_autoneg_disable(ddf_fun_t *fun)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	uint16_t bmcr_val = pio_read_16(rtl8139->io_port + BMCR);
+
+	bmcr_val &= ~((uint16_t)BMCR_AN_ENABLE);
+
+	rtl8139_regs_unlock(rtl8139->io_port);
+	pio_write_16(rtl8139->io_port + BMCR, bmcr_val);
+	rtl8139_regs_lock(rtl8139->io_port);
+
+	return EOK;
+}
+
+/** Obtain the advertisement NIC framework value from the ANAR/ANLPAR register
+ * value
+ *
+ *  @param[in]  anar           The ANAR register value
+ *  @param[out] advertisement  The advertisement result
+ */
+static void rtl8139_get_anar_state(uint16_t anar, uint32_t *advertisement)
+{
+	*advertisement = 0;
+	if (anar & ANAR_10_HD)
+		*advertisement |= ETH_AUTONEG_10BASE_T_HALF;
+	if (anar & ANAR_10_FD)
+		*advertisement |= ETH_AUTONEG_10BASE_T_FULL;
+	if (anar & ANAR_100TX_HD)
+		*advertisement |= ETH_AUTONEG_100BASE_TX_HALF;
+	if (anar & ANAR_100TX_FD)
+		*advertisement |= ETH_AUTONEG_100BASE_TX_FULL;
+	if (anar & ANAR_100T4)
+		*advertisement |= ETH_AUTONEG_100BASE_T4_HALF;
+	if (anar & ANAR_PAUSE)
+		*advertisement |= ETH_AUTONEG_PAUSE_SYMETRIC;
+}
+
+/** Check the autonegotion state
+ *
+ *  @param[in]  dev            The device to check
+ *  @param[out] advertisement  The device advertisement
+ *  @param[out] their_adv      The partners advertisement
+ *  @param[out] result         The autonegotion state
+ *  @param[out] their_result   The link partner autonegotion status
+ *
+ *  @returns EOK
+ */
+static int rtl8139_autoneg_probe(ddf_fun_t *fun, uint32_t *advertisement,
+    uint32_t *their_adv, nic_result_t *result, nic_result_t *their_result)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	uint16_t bmcr = pio_read_16(rtl8139->io_port + BMCR);
+	uint16_t anar = pio_read_16(rtl8139->io_port + ANAR);
+	uint16_t anar_lp = pio_read_16(rtl8139->io_port + ANLPAR);
+	uint16_t aner = pio_read_16(rtl8139->io_port + ANER);
+
+	if (bmcr & BMCR_AN_ENABLE) {
+		*result = NIC_RESULT_ENABLED;
+	} else {
+		*result = NIC_RESULT_DISABLED;
+	}
+
+	if (aner & ANER_LP_NW_ABLE) {
+		*their_result = NIC_RESULT_ENABLED;
+	} else {
+		*their_result = NIC_RESULT_DISABLED;
+	}
+
+	rtl8139_get_anar_state(anar, advertisement);
+	rtl8139_get_anar_state(anar_lp, their_adv);
+
+	return EOK;
+}
+
+/** Restart autonegotiation process
+ *
+ *  @param dev  The device to update
+ *
+ *  @returns EOK
+ */
+static int rtl8139_autoneg_restart(ddf_fun_t *fun)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	uint16_t bmcr = pio_read_16(rtl8139->io_port + BMCR);
+	bmcr |= BMCR_AN_RESTART;
+	bmcr |= BMCR_AN_ENABLE;
+
+	rtl8139_regs_unlock(rtl8139);
+	pio_write_16(rtl8139->io_port + BMCR, bmcr);
+	rtl8139_regs_lock(rtl8139);
+
+	return EOK;
+}
+
+/** Notify NIC framework about HW filtering state when promisc mode was disabled
+ *
+ *  @param nic_data     The NIC data
+ *  @param mcast_mode   Current multicast mode
+ *  @param was_promisc  Sign if the promiscuous mode was active before disabling
+ */
+inline static void rtl8139_rcx_promics_rem(nic_t *nic_data,
+    nic_multicast_mode_t mcast_mode, uint8_t was_promisc)
+{
+	assert(nic_data);
+
+	if (was_promisc != 0) {
+		if (mcast_mode == NIC_MULTICAST_LIST)
+			nic_report_hw_filtering(nic_data, 1, 0, -1);
+		else
+			nic_report_hw_filtering(nic_data, 1, 1, -1);
+	} else {
+		nic_report_hw_filtering(nic_data, 1, -1, -1);
+	}
+}
+
+/** Set unicast packets acceptance mode
+ *
+ *  @param nic_data  The nic device to update
+ *  @param mode      The mode to set
+ *  @param addr      Ignored, no HW support, just use unicast promisc
+ *  @param addr_cnt  Ignored, no HW support
+ *
+ *  @returns EOK
+ */
+static int rtl8139_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_cnt)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	uint8_t was_promisc = rtl8139->rcr_data.ucast_mask & RCR_ACCEPT_ALL_PHYS;
+
+	nic_multicast_mode_t mcast_mode;
+	nic_query_multicast(nic_data, &mcast_mode, 0, NULL, NULL);
+
+	switch (mode) {
+	case NIC_UNICAST_BLOCKED:
+		rtl8139->rcr_data.ucast_mask = 0;
+		rtl8139_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
+		break;
+	case NIC_UNICAST_DEFAULT:
+		rtl8139->rcr_data.ucast_mask = RCR_ACCEPT_PHYS_MATCH;
+		rtl8139_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
+		break;
+	case NIC_UNICAST_LIST:
+		rtl8139->rcr_data.ucast_mask = RCR_ACCEPT_PHYS_MATCH
+		    | RCR_ACCEPT_ALL_PHYS;
+
+		if (mcast_mode == NIC_MULTICAST_PROMISC)
+			nic_report_hw_filtering(nic_data, 0, 1, -1);
+		else
+			nic_report_hw_filtering(nic_data, 0, 0, -1);
+		break;
+	case NIC_UNICAST_PROMISC:
+		rtl8139->rcr_data.ucast_mask = RCR_ACCEPT_PHYS_MATCH
+		    | RCR_ACCEPT_ALL_PHYS;
+
+		if (mcast_mode == NIC_MULTICAST_PROMISC)
+			nic_report_hw_filtering(nic_data, 1, 1, -1);
+		else
+			nic_report_hw_filtering(nic_data, 1, 0, -1);
+		break;
+	default:
+		return ENOTSUP;
+	}
+	fibril_mutex_lock(&rtl8139->rx_lock);
+	rtl8139_hw_update_rcr(rtl8139);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+	return EOK;
+}
+
+/** Set multicast packets acceptance mode
+ *
+ *  @param nic_data  The nic device to update
+ *  @param mode      The mode to set
+ *  @param addr      Addresses to accept
+ *  @param addr_cnt  Addresses count
+ *
+ *  @returns EOK
+ */
+static int rtl8139_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
+    const nic_address_t *addr, size_t addr_count)
+{
+	assert(nic_data);
+	assert(addr_count == 0 || addr);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	switch (mode) {
+	case NIC_MULTICAST_BLOCKED:
+		rtl8139->rcr_data.mcast_mask = 0;
+		if ((rtl8139->rcr_data.ucast_mask & RCR_ACCEPT_ALL_PHYS) != 0)
+			nic_report_hw_filtering(nic_data, -1, 0, -1);
+		else
+			nic_report_hw_filtering(nic_data, -1, 1, -1);
+		break;
+	case NIC_MULTICAST_LIST:
+		rtl8139_hw_set_mcast_mask(rtl8139, nic_mcast_hash(addr, addr_count));
+		rtl8139->rcr_data.mcast_mask = RCR_ACCEPT_MULTICAST;
+		nic_report_hw_filtering(nic_data, -1, 0, -1);
+		break;
+	case NIC_MULTICAST_PROMISC:
+		rtl8139_hw_set_mcast_mask(rtl8139, RTL8139_MCAST_MASK_PROMISC);
+		rtl8139->rcr_data.mcast_mask = RCR_ACCEPT_MULTICAST;
+		nic_report_hw_filtering(nic_data, -1, 1, -1);
+		break;
+	default:
+		return ENOTSUP;
+	}
+	fibril_mutex_lock(&rtl8139->rx_lock);
+	rtl8139_hw_update_rcr(rtl8139);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+	return EOK;
+}
+
+/** Set broadcast packets acceptance mode
+ *
+ *  @param nic_data  The nic device to update
+ *  @param mode      The mode to set
+ *
+ *  @returns EOK
+ */
+static int rtl8139_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	switch (mode) {
+	case NIC_BROADCAST_BLOCKED:
+		rtl8139->rcr_data.bcast_mask = 0;
+		break;
+	case NIC_BROADCAST_ACCEPTED:
+		rtl8139->rcr_data.bcast_mask = RCR_ACCEPT_BROADCAST;
+		break;
+	default:
+		return ENOTSUP;
+	}
+	fibril_mutex_lock(&rtl8139->rx_lock);
+	rtl8139_hw_update_rcr(rtl8139);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+	return EOK;
+}
+
+/** Get state of acceptance of weird packets
+ *
+ *  @param[in]  device  The device to check
+ *  @param[out] mode    The current mode
+ */
+static int rtl8139_defective_get_mode(ddf_fun_t *fun, uint32_t *mode)
+{
+	assert(fun);
+	assert(mode);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	*mode = 0;
+	if (rtl8139->rcr_data.defect_mask & RCR_ACCEPT_ERROR)
+		*mode |= NIC_DEFECTIVE_BAD_CRC;
+	if (rtl8139->rcr_data.defect_mask & RCR_ACCEPT_RUNT)
+		*mode |= NIC_DEFECTIVE_SHORT;
+
+	return EOK;
+};
+
+/** Set acceptance of weird packets
+ *
+ *  @param device  The device to update
+ *  @param mode    The mode to set
+ *
+ *  @returns ENOTSUP if the mode is not supported
+ *  @returns EOK of mode was set
+ */
+static int rtl8139_defective_set_mode(ddf_fun_t *fun, uint32_t mode)
+{
+	assert(fun);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_get_from_ddf_fun(fun));
+	assert(rtl8139);
+
+	if ((mode & (NIC_DEFECTIVE_SHORT | NIC_DEFECTIVE_BAD_CRC)) != mode)
+		return ENOTSUP;
+
+	rtl8139->rcr_data.defect_mask = 0;
+	if (mode & NIC_DEFECTIVE_SHORT)
+		rtl8139->rcr_data.defect_mask |= RCR_ACCEPT_RUNT;
+	if (mode & NIC_DEFECTIVE_BAD_CRC)
+		rtl8139->rcr_data.defect_mask |= RCR_ACCEPT_ERROR;
+
+	fibril_mutex_lock(&rtl8139->rx_lock);
+	rtl8139_hw_update_rcr(rtl8139);
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+	return EOK;
+};
+
+
+/** Turn Wakeup On Lan method on
+ *
+ *  @param nic_data  The NIC to update
+ *  @param virtue    The method to turn on
+ *
+ *  @returns EINVAL if the method is not supported
+ *  @returns EOK if succeed
+ *  @returns ELIMIT if no more methods of this kind can be enabled
+ */
+static int rtl8139_wol_virtue_add(nic_t *nic_data,
+	const nic_wol_virtue_t *virtue)
+{
+	assert(nic_data);
+	assert(virtue);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	switch(virtue->type) {
+	case NIC_WV_BROADCAST:
+		rtl8139_hw_reg_add_8(rtl8139, CONFIG5, CONFIG5_BROADCAST_WAKEUP);
+		break;
+	case NIC_WV_LINK_CHANGE:
+		rtl8139_regs_unlock(rtl8139->io_port);
+		rtl8139_hw_reg_add_8(rtl8139, CONFIG3, CONFIG3_LINK_UP);
+		rtl8139_regs_lock(rtl8139->io_port);
+		break;
+	case NIC_WV_MAGIC_PACKET:
+		if (virtue->data)
+			return EINVAL;
+		rtl8139_regs_unlock(rtl8139->io_port);
+		rtl8139_hw_reg_add_8(rtl8139, CONFIG3, CONFIG3_MAGIC);
+		rtl8139_regs_lock(rtl8139->io_port);
+		break;
+	default:
+		return EINVAL;
+	};
+	if(rtl8139->pm.active++ == 0)
+		rtl8139_hw_pmen_set(rtl8139, 1);
+	return EOK;
+}
+
+/** Turn Wakeup On Lan method off
+ *
+ *  @param nic_data  The NIC to update
+ *  @param virtue    The method to turn off
+ */
+static void rtl8139_wol_virtue_rem(nic_t *nic_data,
+	const nic_wol_virtue_t *virtue)
+{
+	assert(nic_data);
+	assert(virtue);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	switch(virtue->type) {
+	case NIC_WV_BROADCAST:
+		rtl8139_hw_reg_rem_8(rtl8139, CONFIG5, CONFIG5_BROADCAST_WAKEUP);
+		break;
+	case NIC_WV_LINK_CHANGE:
+		rtl8139_regs_unlock(rtl8139->io_port);
+		rtl8139_hw_reg_rem_8(rtl8139, CONFIG3, CONFIG3_LINK_UP);
+		rtl8139_regs_lock(rtl8139->io_port);
+		break;
+	case NIC_WV_MAGIC_PACKET:
+		rtl8139_regs_unlock(rtl8139->io_port);
+		rtl8139_hw_reg_rem_8(rtl8139, CONFIG3, CONFIG3_MAGIC);
+		rtl8139_regs_lock(rtl8139->io_port);
+		break;
+	default:
+		return;
+	};
+	rtl8139->pm.active--;
+	if (rtl8139->pm.active == 0)
+		rtl8139_hw_pmen_set(rtl8139, 0);
+}
+
+
+/** Set polling mode
+ *
+ *  @param device  The device to set
+ *  @param mode    The mode to set
+ *  @param period  The period for NIC_POLL_PERIODIC
+ *
+ *  @returns EOK if succeed
+ *  @returns ENOTSUP if the mode is not supported
+ */
+static int rtl8139_poll_mode_change(nic_t *nic_data, nic_poll_mode_t mode,
+    const struct timeval *period)
+{
+	assert(nic_data);
+	int rc = EOK;
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	fibril_mutex_lock(&rtl8139->rx_lock);
+
+	switch(mode) {
+	case NIC_POLL_IMMEDIATE:
+		rtl8139->int_mask = RTL_DEFAULT_INTERRUPTS;
+		break;
+	case NIC_POLL_ON_DEMAND:
+		rtl8139->int_mask = 0;
+		break;
+	case NIC_POLL_PERIODIC:
+		assert(period);
+
+		rtl8139_timer_act_t new_timer;
+		rc = rtl8139_timer_act_init(&new_timer, RTL8139_PCI_FREQ_KHZ, period);
+		if (rc != EOK)
+			break;
+
+		/* Disable timer interrupts while working with timer-related data */
+		rtl8139->int_mask = 0;
+		rtl8139_hw_int_enable(rtl8139);
+
+		rtl8139->poll_timer = new_timer;
+		rtl8139->int_mask = INT_TIME_OUT;
+
+		/* Force timer interrupt start be writing nonzero value to timer 
+		 * interrutp register (should be small to prevent big delay)
+		 * Read TCTR to reset timer counter
+		 * Change values to simulate the last interrupt from the period.
+		 */
+		pio_write_32(rtl8139->io_port + TIMERINT, 10);
+		pio_write_32(rtl8139->io_port + TCTR, 0);
+
+		nlog_debug("Periodic mode. Interrupt mask %"PRIx16", poll.full_skips %"
+		    PRIu32", last timer %"PRIu32".", rtl8139->int_mask, 
+		    rtl8139->poll_timer.full_skips, rtl8139->poll_timer.last_val);
+		break;
+	default:
+		rc = ENOTSUP;
+		break;
+	}
+
+	rtl8139_hw_int_enable(rtl8139);
+
+	fibril_mutex_unlock(&rtl8139->rx_lock);
+
+	return rc;
+}
+
+/** Force receiving all packets in the receive buffer
+ *
+ *  @param device  The device to receive
+ */
+static void rtl8139_poll(nic_t *nic_data)
+{
+	assert(nic_data);
+
+	rtl8139_t *rtl8139 = nic_get_specific(nic_data);
+	assert(rtl8139);
+
+	uint16_t isr = pio_read_16(rtl8139->io_port + ISR);
+	pio_write_16(rtl8139->io_port + ISR, 0);
+
+	rtl8139_interrupt_impl(nic_data, isr);
+}
+
+
+/** Main function of RTL8139 driver
+ *
+ *  Just initialize the driver structures and
+ *  put it into the device drivers interface
+ */
+int main(void)
+{
+	int rc = nic_driver_init(NAME);
+	if (rc != EOK)
+		return rc;
+	nic_driver_implement(
+		&rtl8139_driver_ops, &rtl8139_dev_ops, &rtl8139_nic_iface);
+
+	nlog_set_min_severity(DEBUG);
+	nlog_info("HelenOS RTL8139 driver started");
+	return ddf_driver_main(&rtl8139_driver);
+}
Index: uspace/drv/nic/rtl8139/driver.h
===================================================================
--- uspace/drv/nic/rtl8139/driver.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/rtl8139/driver.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * 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 RTL8139_DRIVER_H_
+#define RTL8139_DRIVER_H_
+
+#include "rtl8139_defs.h"
+#include "rtl8139_general.h"
+#include <sys/types.h>
+#include <stdint.h>
+#include <dma.h>
+
+/** The driver name */
+#define NAME "rtl8139"
+/** Transmittion buffers count */
+#define TX_BUFF_COUNT 4
+/** Size of buffer for one packet
+ *  - 2kB
+ */
+#define TX_BUFF_SIZE (2 * 1024)
+/** Count of pages to allocate for TxBuffers */
+#define TX_PAGES 2
+
+/** Size of the CRC after the received frame in the receiver buffer */
+#define RTL8139_CRC_SIZE 4
+
+/** The default mode of accepting unicast packets */
+#define RTL8139_RCR_UCAST_DEFAULT RCR_ACCEPT_PHYS_MATCH
+/** The default mode of accepting multicast packets */
+#define RTL8139_RCR_MCAST_DEFAULT 0
+/** The default mode of accepting broadcast packets */
+#define RTL8139_RCR_BCAST_DEFAULT RCR_ACCEPT_BROADCAST
+/** The default mode of accepting defect packets */
+#define RTL8139_RCR_DEFECT_DEFAULT 0
+
+/** Mask for accepting all multicast */
+#define RTL8139_MCAST_MASK_PROMISC UINT64_MAX
+
+/** Data  */
+struct rtl8139_rcr_data {
+	/** Configuration part of RCR */
+	uint32_t rcr_base;
+	/** Mask of unicast  */
+	uint8_t ucast_mask;
+	/** Mask of multicast */
+	uint8_t mcast_mask;
+	/** Mask of broadcast */
+	uint8_t bcast_mask;
+	/** Mask of defective */
+	uint8_t defect_mask;
+};
+
+/** Power management related data */
+typedef struct rtl8139_pm {
+	/** Count of used activities which needs PMEn bit set */
+	int active;
+} rtl8139_pm_t;
+
+/** RTL8139 device data */
+typedef struct rtl8139_data {
+	/** I/O address of the device */
+	void *io_addr;
+	/** Mapped I/O port */
+	void *io_port;
+	/** The irq assigned */
+	int irq;
+
+	/** Mask of the turned interupts (IMR value) */
+	uint16_t int_mask;
+
+	/** The memory allocated for the transmittion buffers
+	 *  Each buffer takes 2kB
+	 */
+	dma_mem_t tx_buff_mem;
+	/** Virtual adresses of the Tx buffers */
+	void *tx_buff[TX_BUFF_COUNT];
+
+	/** The nubmer of the next buffer to use, index = tx_next % TX_BUFF_COUNT */
+	size_t tx_next;
+	/** The number of the first used buffer in the row
+	 *
+	 *  tx_used is in the interval tx_next - TX_BUFF_COUNT and tx_next:
+	 *  	tx_next - TX_BUFF_COUNT: there is no useable Tx descriptor
+	 *  	tx_next: all Tx descriptors are can be used
+	 */
+	size_t tx_used;
+
+	/** Buffer for receiving packets */
+	dma_mem_t rx_buff;
+
+	/** Receiver control register data */
+	struct rtl8139_rcr_data rcr_data;
+
+	/** Power management information */
+	rtl8139_pm_t pm;
+
+	/** Lock for receiver */
+	fibril_mutex_t rx_lock;
+	/** Lock for transmitter */
+	fibril_mutex_t tx_lock;
+
+	/** Polling mode information */
+	rtl8139_timer_act_t poll_timer;
+
+	/** Backward pointer to nic_data */
+	nic_t *nic_data;
+
+	/** Version of RT8139 controller */
+	enum rtl8139_version_id hw_version;
+} rtl8139_t;
+
+
+/* ***** Pointers casting - for both amd64 and ia32 ***** */
+
+/** Cast pointer to uint32_t
+ *
+ *  @param ptr The pointer to cast
+ *  @return The uint32_t pointer representation. The low 32 bit is taken
+ *  in the case of the 64 bit pointers
+ */
+#define PTR2U32(ptr) ((uint32_t)((size_t)(ptr)))
+
+/** Check if the pointer can be cast to uint32_t without the data lost
+ *
+ *  @param ptr The pointer to check
+ *  @return The true value if the pointer can be cast, false if not
+ */
+#define PTR_IS_32(ptr) ((size_t)PTR2U32(ptr) == (size_t)(ptr))
+
+/** Cast the ioaddr part to the void*
+ *
+ *  @param ioaddr The ioaddr value
+ */
+#define IOADDR_TO_PTR(ioaddr) ((void*)((size_t)(ioaddr)))
+
+
+
+/* ***** Bit operation macros ***** */
+
+/** Set the bits specified by the given bit mask to the different values
+ *
+ * The bit from the src is used if the corresponding bit in the mask is 0,
+ * the bit from the value is used if the corresponding bit in the mask is 1
+ *
+ * @param src The original value
+ * @param value The new bit value
+ * @param mask The mask to specify modified bits
+ * @param type The values type
+ *
+ * @return New value
+ */
+#define bit_set_part_g( src, value, mask, type ) \
+	((type)(((src) & ~((type)(mask))) | ((value) & (type)(mask))))
+
+/** Set the bits specified by the given bit mask to the different values
+ *
+ * The version of the uint32_t
+ *
+ * @see bit_set_part_g
+ */
+
+#define bit_set_part_32(src, value, mask) bit_set_part_g(src, value, mask, uint32_t)
+/** Set the bits specified by the given bit mask to the different values
+ *
+ * The version of the uint16_t
+ *
+ * @see bit_set_part_g
+ */
+
+#define bit_set_part_16(src, value, mask) bit_set_part_g(src, value, mask, uint16_t)
+
+/** Set the bits specified by the given bit mask to the different values
+ *
+ * The version of the uint8_t
+ *
+ * @see bit_set_part_g
+ */
+#define bit_set_part_8(src, value, mask) bit_set_part_g(src, value, mask, uint8_t)
+
+/** Clear specified bits in the value
+ *
+ * @param src Original value
+ * @param clear_mask Bits to clear mask
+ * @param type The values type
+ */
+#define bit_clear_g(src, clear_mask, type) ((type)((src) & ~((type)(clear_mask))))
+
+/** Clear specified bits in the value, 32bit version
+ *
+ *  @see bit_clear_g
+ */
+#define bit_clear_32(src, clear_mask) bit_clear_g(src, clear_mask, uint32_t)
+/** Clear specified bits in the value, 16bit version
+ *
+ *  @see bit_clear_g
+ */
+#define bit_clear_16(src, clear_mask) bit_clear_g(src, clear_mask, uint16_t)
+/** Clear specified bits in the value, 8bit version
+ *
+ *  @see bit_clear_g
+ */
+#define bit_clear_8(src, clear_mask) bit_clear_g(src, clear_mask, uint8_t)
+
+/** Obtain value of the TSD register with size part modified
+ *
+ *  @param tsd_value Old value of the TSD
+ *  @param size The size to set
+ */
+#define rtl8139_tsd_set_size(tsd_value, size) \
+	bit_set_part_32(tsd_value, (size) << TSD_SIZE_SHIFT, TSD_SIZE_MASK << TSD_SIZE_SHIFT)
+
+
+#endif
Index: uspace/drv/nic/rtl8139/general.c
===================================================================
--- uspace/drv/nic/rtl8139/general.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/rtl8139/general.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * 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
+ *
+ *  General functions and structures used in rtl8139 driver
+ */
+
+#include "rtl8139_general.h"
+
+#include <mem.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+
+/** Copy block of the memory from wrapped source buffer.
+ *
+ * Start on the specific offset in the source buffer and * copy data_size bytes
+ * - continue from the buffer start after getting the end
+ *
+ * @param dest        The destination memory
+ * @param src_begin   The begin of the source buffer
+ * @param src_offset  The offset in the source buffer to start copy
+ * @param src_size    The source buffer size
+ * @param data_size   The amount of data to copy
+ *
+ * @return NULL if the error occures, dest if succeed
+ */
+void* rtl8139_memcpy_wrapped(void *dest, const void *src, size_t src_offset,
+    size_t src_size, size_t data_size)
+{
+	src_offset %= src_size;
+	if (data_size > src_size)
+		return NULL;
+
+	size_t to_src_end = src_size - src_offset;
+	if (data_size <= to_src_end) {
+		return memcpy(dest, src + src_offset, data_size);
+	}
+
+	size_t rem_size = data_size - to_src_end;
+
+	/* First copy the end part of the data (from the source begining),
+	 * then copy the begining
+	 */
+	memcpy(dest + to_src_end, src, rem_size);
+	return memcpy(dest, src + src_offset, to_src_end);
+}
+
+/** Initialize the timer register structures 
+ *
+ *  The structure will be initialized to the state that the first call of 
+ *  rtl8139_timer_act_step function will be the period expiration
+ *
+ *  @param ta          The timer structure
+ *  @param timer_freq  The timer frequency in kHz
+ *  @param time        The requested time
+ *
+ *  @return EOK if succeed, negative error code otherwise
+ */
+int rtl8139_timer_act_init(rtl8139_timer_act_t * ta, uint32_t timer_freq,
+    const struct timeval *time) 
+{
+	if (!ta || timer_freq == 0 || !time)
+		return EINVAL;
+	memset(ta, 0, sizeof(rtl8139_timer_act_t));
+
+	uint32_t tics_per_ms = timer_freq;
+	uint32_t seconds_in_reg = UINT32_MAX / (tics_per_ms * 1000);
+	ta->full_val = seconds_in_reg * tics_per_ms * 1000;
+
+	struct timeval remains = *time;
+	ta->full_skips = remains.tv_sec / seconds_in_reg;
+	remains.tv_sec = remains.tv_sec % seconds_in_reg;
+
+	if (remains.tv_usec > RTL8139_USEC_IN_SEC) {
+		remains.tv_sec += remains.tv_usec / RTL8139_USEC_IN_SEC;
+		remains.tv_usec = remains.tv_usec % RTL8139_USEC_IN_SEC;
+
+		/* it can be increased above seconds_in_reg again */
+		ta->full_skips += remains.tv_sec / seconds_in_reg;
+		remains.tv_sec = remains.tv_sec % seconds_in_reg;
+	}
+
+	ta->last_val = remains.tv_sec * 1000 + remains.tv_usec / 1000;
+	ta->last_val *= tics_per_ms;
+
+	/* Force inital setting in the next step */
+	ta->full_skips_remains = 0;
+	ta->last_run = 1;
+	return EOK;
+};
+
+
+/** Make one step timer step
+ *
+ *  @param ta            Timer structure
+ *  @param new_reg[out]  Register value to set
+ *
+ *  @return Nonzero if whole period expired, zero if part of period expired
+ */
+int rtl8139_timer_act_step(rtl8139_timer_act_t * ta, uint32_t *new_reg)
+{
+	uint32_t next_val = 0;
+	int expired = 0;
+
+	if (ta->last_run || (ta->last_val == 0 && ta->full_skips_remains == 0)) {
+		ta->full_skips_remains = ta->full_skips;
+		ta->last_run = 0;
+		expired = 1;
+	}
+
+	if (ta->full_skips_remains > 0) {
+		next_val = ta->full_val;
+		ta->full_skips_remains--;
+	} else {
+		next_val = ta->last_val;
+		ta->last_run = 1;
+	}
+
+	if (new_reg)
+		*new_reg = next_val;
+
+	return expired;
+};
+
Index: uspace/drv/nic/rtl8139/general.h
===================================================================
--- uspace/drv/nic/rtl8139/general.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/rtl8139/general.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * 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
+ *
+ *  General functions and structures used in rtl8139 driver
+ */
+
+#ifndef RTL8139_GENERAL_H_
+#define RTL8139_GENERAL_H_
+
+#include <unistd.h>
+
+extern void* rtl8139_memcpy_wrapped(void *dest, const void *src_buf,
+    size_t src_offset, size_t src_size, size_t data_size);
+
+
+/** Structure for HW timer control */
+typedef struct rtl8139_timer_act {
+	/** Register value set in the last timer period */
+	uint32_t last_val;
+	/** Register value set in the common timer period */
+	uint32_t full_val;
+
+	/** Amount of full register periods in timer period */
+	size_t full_skips;
+	/** Remaining full register periods to the next period end */
+	size_t full_skips_remains;
+	/** Mark if there is a last run */
+	int last_run;
+} rtl8139_timer_act_t;
+
+/** Count of microseconds in second */
+#define RTL8139_USEC_IN_SEC 1000000
+
+extern int rtl8139_timer_act_init(rtl8139_timer_act_t *ta, uint32_t timer_freq,
+    const struct timeval *time);
+extern int rtl8139_timer_act_step(rtl8139_timer_act_t *ta, uint32_t *new_reg);
+
+
+#endif
Index: uspace/drv/nic/rtl8139/rtl8139.ma
===================================================================
--- uspace/drv/nic/rtl8139/rtl8139.ma	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/drv/nic/rtl8139/rtl8139.ma	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,1 @@
+10 pci/ven=10ec&dev=8139
Index: uspace/drv/test/test1/test1.c
===================================================================
--- uspace/drv/test/test1/test1.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/test/test1/test1.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -40,5 +40,5 @@
 #include "test1.h"
 
-static int test1_add_device(ddf_dev_t *dev);
+static int test1_dev_add(ddf_dev_t *dev);
 static int test1_dev_remove(ddf_dev_t *dev);
 static int test1_dev_gone(ddf_dev_t *dev);
@@ -47,5 +47,5 @@
 
 static driver_ops_t driver_ops = {
-	.add_device = &test1_add_device,
+	.dev_add = &test1_dev_add,
 	.dev_remove = &test1_dev_remove,
 	.dev_gone = &test1_dev_gone,
@@ -141,5 +141,5 @@
  * @return Error code reporting success of the operation.
  */
-static int test1_add_device(ddf_dev_t *dev)
+static int test1_dev_add(ddf_dev_t *dev)
 {
 	ddf_fun_t *fun_a;
@@ -147,5 +147,5 @@
 	int rc;
 
-	ddf_msg(LVL_DEBUG, "add_device(name=\"%s\", handle=%d)",
+	ddf_msg(LVL_DEBUG, "dev_add(name=\"%s\", handle=%d)",
 	    dev->name, (int) dev->handle);
 
Index: uspace/drv/test/test2/test2.c
===================================================================
--- uspace/drv/test/test2/test2.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/test/test2/test2.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -40,5 +40,5 @@
 #define NAME "test2"
 
-static int test2_add_device(ddf_dev_t *dev);
+static int test2_dev_add(ddf_dev_t *dev);
 static int test2_dev_remove(ddf_dev_t *dev);
 static int test2_dev_gone(ddf_dev_t *dev);
@@ -47,5 +47,5 @@
 
 static driver_ops_t driver_ops = {
-	.add_device = &test2_add_device,
+	.dev_add = &test2_dev_add,
 	.dev_remove = &test2_dev_remove,
 	.dev_gone = &test2_dev_gone,
@@ -193,9 +193,9 @@
 }
 
-static int test2_add_device(ddf_dev_t *dev)
+static int test2_dev_add(ddf_dev_t *dev)
 {
 	test2_t *test2;
 
-	ddf_msg(LVL_DEBUG, "test2_add_device(name=\"%s\", handle=%d)",
+	ddf_msg(LVL_DEBUG, "test2_dev_add(name=\"%s\", handle=%d)",
 	    dev->name, (int) dev->handle);
 
Index: uspace/drv/test/test3/test3.c
===================================================================
--- uspace/drv/test/test3/test3.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/drv/test/test3/test3.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -41,5 +41,5 @@
 #define NUM_FUNCS 20
 
-static int test3_add_device(ddf_dev_t *dev);
+static int test3_dev_add(ddf_dev_t *dev);
 static int test3_dev_remove(ddf_dev_t *dev);
 static int test3_fun_online(ddf_fun_t *fun);
@@ -47,5 +47,5 @@
 
 static driver_ops_t driver_ops = {
-	.add_device = &test3_add_device,
+	.dev_add = &test3_dev_add,
 	.dev_remove = &test3_dev_remove,
 	.fun_online = &test3_fun_online,
@@ -127,10 +127,10 @@
 }
 
-static int test3_add_device(ddf_dev_t *dev)
+static int test3_dev_add(ddf_dev_t *dev)
 {
 	int rc = EOK;
 	test3_t *test3;
 
-	ddf_msg(LVL_DEBUG, "add_device(name=\"%s\", handle=%d)",
+	ddf_msg(LVL_DEBUG, "dev_add(name=\"%s\", handle=%d)",
 	    dev->name, (int) dev->handle);
 
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -70,4 +70,5 @@
 	generic/device/char_dev.c \
 	generic/device/nic.c \
+	generic/device/pci.c \
 	generic/elf/elf_load.c \
 	generic/event.c \
Index: uspace/lib/c/generic/as.c
===================================================================
--- uspace/lib/c/generic/as.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/generic/as.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -117,26 +117,15 @@
 /** Find mapping to physical address.
  *
- * @param address Virtual address in question (virtual).
- * @param[out] frame Frame address (physical).
- * @return Error code.
- * @retval EOK No error, @p frame holds the translation.
- * @retval ENOENT Mapping not found.
+ * @param      virt Virtual address to find mapping for.
+ * @param[out] phys Physical adress.
+ *
+ * @return EOK on no error.
+ * @retval ENOENT if no mapping was found.
+ *
  */
-int as_get_physical_mapping(const void *address, uintptr_t *frame)
+int as_get_physical_mapping(const void *virt, uintptr_t *phys)
 {
-	uintptr_t tmp_frame;
-	uintptr_t virt = (uintptr_t) address;
-	
-	int rc = (int) __SYSCALL2(SYS_PAGE_FIND_MAPPING,
-	    (sysarg_t) virt, (sysarg_t) &tmp_frame);
-	if (rc != EOK) {
-		return rc;
-	}
-	
-	if (frame != NULL) {
-		*frame = tmp_frame;
-	}
-	
-	return EOK;
+	return (int) __SYSCALL2(SYS_PAGE_FIND_MAPPING, (sysarg_t) virt,
+	    (sysarg_t) phys);
 }
 
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/generic/async.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1846,5 +1846,5 @@
 	
 	fibril_mutex_lock(&async_sess_mutex);
-
+	
 	int rc = async_hangup_internal(sess->phone);
 	
Index: uspace/lib/c/generic/ddi.c
===================================================================
--- uspace/lib/c/generic/ddi.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/generic/ddi.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -33,4 +33,7 @@
  */
 
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
 #include <sys/types.h>
 #include <abi/ddi/arg.h>
@@ -53,22 +56,55 @@
 }
 
-/** Map piece of physical memory to task.
+/** Map a piece of physical memory to task.
  *
  * Caller of this function must have the CAP_MEM_MANAGER capability.
  *
- * @param pf		Physical address of the starting frame.
- * @param vp		Virtual address of the starting page.
- * @param pages		Number of pages to map.
- * @param flags		Flags for the new address space area.
+ * @param phys  Physical address of the starting frame.
+ * @param virt  Virtual address of the starting page.
+ * @param pages Number of pages to map.
+ * @param flags Flags for the new address space area.
  *
- * @return 		0 on success, EPERM if the caller lacks the
- *			CAP_MEM_MANAGER capability, ENOENT if there is no task
- *			with specified ID and ENOMEM if there was some problem
- *			in creating address space area.
+ * @return EOK on success
+ * @return EPERM if the caller lacks the CAP_MEM_MANAGER capability
+ * @return ENOENT if there is no task with specified ID
+ * @return ENOMEM if there was some problem in creating
+ *         the address space area.
+ *
  */
-int physmem_map(void *pf, void *vp, unsigned long pages, int flags)
+int physmem_map(void *phys, void *virt, size_t pages, unsigned int flags)
 {
-	return __SYSCALL4(SYS_PHYSMEM_MAP, (sysarg_t) pf, (sysarg_t) vp, pages,
-	    flags);
+	return __SYSCALL4(SYS_PHYSMEM_MAP, (sysarg_t) phys,
+	    (sysarg_t) virt, pages, flags);
+}
+
+int dmamem_map(void *virt, size_t size, unsigned int map_flags,
+    unsigned int flags, void **phys)
+{
+	return (int) __SYSCALL5(SYS_DMAMEM_MAP, (sysarg_t) virt,
+	    (sysarg_t) size, (sysarg_t) map_flags, (sysarg_t) flags,
+	    (sysarg_t) phys);
+}
+
+int dmamem_map_anonymous(size_t size, unsigned int map_flags,
+    unsigned int flags, void **phys, void **virt)
+{
+	*virt = as_get_mappable_page(size);
+	if (*virt == NULL)
+		return ENOMEM;
+	
+	return dmamem_map(*virt, size, map_flags,
+	    flags | DMAMEM_FLAGS_ANONYMOUS, phys);
+}
+
+int dmamem_unmap(void *virt, size_t size, unsigned int flags)
+{
+	return __SYSCALL3(SYS_DMAMEM_UNMAP, (sysarg_t) virt, (sysarg_t) size,
+	    (sysarg_t) flags);
+}
+
+int dmamem_unmap_anonymous(void *virt)
+{
+	return __SYSCALL3(SYS_DMAMEM_UNMAP, (sysarg_t) virt, 0,
+	    DMAMEM_FLAGS_ANONYMOUS);
 }
 
@@ -77,21 +113,22 @@
  * Caller of this function must have the IO_MEM_MANAGER capability.
  *
- * @param id		Task ID.
- * @param ioaddr	Starting address of the I/O range.
- * @param size		Size of the range.
+ * @param id     Task ID.
+ * @param ioaddr Starting address of the I/O range.
+ * @param size   Size of the range.
  *
- * @return		0 on success, EPERM if the caller lacks the
- *			CAP_IO_MANAGER capability, ENOENT if there is no task
- *			with specified ID and ENOMEM if there was some problem
- *			in allocating memory.
+ * @return EOK on success
+ * @return EPERM if the caller lacks the CAP_IO_MANAGER capability
+ * @return ENOENT if there is no task with specified ID
+ * @return ENOMEM if there was some problem in allocating memory.
+ *
  */
 int iospace_enable(task_id_t id, void *ioaddr, unsigned long size)
 {
 	ddi_ioarg_t arg;
-
+	
 	arg.task_id = id;
 	arg.ioaddr = ioaddr;
 	arg.size = size;
-
+	
 	return __SYSCALL1(SYS_IOSPACE_ENABLE, (sysarg_t) &arg);
 }
@@ -99,10 +136,11 @@
 /** Enable PIO for specified I/O range.
  *
- * @param pio_addr	I/O start address.
- * @param size		Size of the I/O region.
- * @param use_addr	Address where the final address for application's PIO
- * 			will be stored.
+ * @param pio_addr I/O start address.
+ * @param size     Size of the I/O region.
+ * @param use_addr Address where the final address for
+ *                 application's PIO will be stored.
  *
- * @return		Zero on success or negative error code.
+ * @return Zero on success or negative error code.
+ *
  */
 int pio_enable(void *pio_addr, size_t size, void **use_addr)
@@ -112,5 +150,5 @@
 	size_t offset;
 	unsigned int pages;
-
+	
 #ifdef IO_SPACE_BOUNDARY
 	if (pio_addr < IO_SPACE_BOUNDARY) {
@@ -119,5 +157,5 @@
 	}
 #endif
-
+	
 	phys = (void *) ALIGN_DOWN((uintptr_t) pio_addr, PAGE_SIZE);
 	offset = pio_addr - phys;
Index: uspace/lib/c/generic/device/nic.c
===================================================================
--- uspace/lib/c/generic/device/nic.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/generic/device/nic.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -895,5 +895,5 @@
  *
  */
-int nic_vlan_set_tag(async_sess_t *dev_sess, uint16_t tag, int add, int strip)
+int nic_vlan_set_tag(async_sess_t *dev_sess, uint16_t tag, bool add, bool strip)
 {
 	async_exch_t *exch = async_exchange_begin(dev_sess);
Index: uspace/lib/c/generic/device/pci.c
===================================================================
--- uspace/lib/c/generic/device/pci.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/lib/c/generic/device/pci.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * 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
+ */
+
+#include <ipc/dev_iface.h>
+#include <assert.h>
+#include <device/pci.h>
+#include <errno.h>
+#include <async.h>
+#include <ipc/services.h>
+
+int pci_config_space_read_8(async_sess_t *sess, uint32_t address, uint8_t *val)
+{
+	sysarg_t res = 0;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_READ_8, address, &res);
+	async_exchange_end(exch);
+	
+	*val = (uint8_t) res;
+	return rc;
+}
+
+int pci_config_space_read_16(async_sess_t *sess, uint32_t address,
+    uint16_t *val)
+{
+	sysarg_t res = 0;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_READ_16, address, &res);
+	async_exchange_end(exch);
+	
+	*val = (uint16_t) res;
+	return rc;
+}
+
+int pci_config_space_read_32(async_sess_t *sess, uint32_t address,
+    uint32_t *val)
+{
+	sysarg_t res = 0;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_READ_32, address, &res);
+	async_exchange_end(exch);
+	
+	*val = (uint32_t) res;
+	return rc;
+}
+
+int pci_config_space_write_8(async_sess_t *sess, uint32_t address, uint8_t val)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_0(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_WRITE_8, address, val);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+int pci_config_space_write_16(async_sess_t *sess, uint32_t address,
+    uint16_t val)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_0(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_WRITE_16, address, val);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+int pci_config_space_write_32(async_sess_t *sess, uint32_t address,
+    uint32_t val)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_0(exch, DEV_IFACE_ID(PCI_DEV_IFACE),
+	    IPC_M_CONFIG_SPACE_WRITE_32, address, val);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/fibril_synch.c
===================================================================
--- uspace/lib/c/generic/fibril_synch.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/generic/fibril_synch.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -447,4 +447,135 @@
 }
 
+/** Timer fibril.
+ *
+ * @param arg	Timer
+ */
+static int fibril_timer_func(void *arg)
+{
+	fibril_timer_t *timer = (fibril_timer_t *) arg;
+	int rc;
+
+	fibril_mutex_lock(&timer->lock);
+
+	while (true) {
+		while (timer->state != fts_active &&
+		    timer->state != fts_cleanup) {
+
+			if (timer->state == fts_cleanup)
+				break;
+
+			fibril_condvar_wait(&timer->cv, &timer->lock);
+		}
+
+		if (timer->state == fts_cleanup)
+			break;
+
+		rc = fibril_condvar_wait_timeout(&timer->cv, &timer->lock,
+		    timer->delay);
+		if (rc == ETIMEOUT) {
+			timer->state = fts_fired;
+			fibril_mutex_unlock(&timer->lock);
+			timer->fun(timer->arg);
+			fibril_mutex_lock(&timer->lock);
+		}
+	}
+
+	fibril_mutex_unlock(&timer->lock);
+	return 0;
+}
+
+/** Create new timer.
+ *
+ * @return		New timer on success, @c NULL if out of memory.
+ */
+fibril_timer_t *fibril_timer_create(void)
+{
+	fid_t fid;
+	fibril_timer_t *timer;
+
+	timer = calloc(1, sizeof(fibril_timer_t));
+	if (timer == NULL)
+		return NULL;
+
+	fid = fibril_create(fibril_timer_func, (void *) timer);
+	if (fid == 0) {
+		free(timer);
+		return NULL;
+	}
+
+	fibril_mutex_initialize(&timer->lock);
+	fibril_condvar_initialize(&timer->cv);
+
+	timer->fibril = fid;
+	timer->state = fts_not_set;
+
+	fibril_add_ready(fid);
+
+	return timer;
+}
+
+/** Destroy timer.
+ *
+ * @param timer		Timer, must not be active or accessed by other threads.
+ */
+void fibril_timer_destroy(fibril_timer_t *timer)
+{
+	fibril_mutex_lock(&timer->lock);
+	assert(timer->state != fts_active);
+	timer->state = fts_cleanup;
+	fibril_condvar_broadcast(&timer->cv);
+	fibril_mutex_unlock(&timer->lock);
+}
+
+/** Set timer.
+ *
+ * Set timer to execute a callback function after the specified
+ * interval.
+ *
+ * @param timer		Timer
+ * @param delay		Delay in microseconds
+ * @param fun		Callback function
+ * @param arg		Argument for @a fun
+ */
+void fibril_timer_set(fibril_timer_t *timer, suseconds_t delay,
+    fibril_timer_fun_t fun, void *arg)
+{
+	fibril_mutex_lock(&timer->lock);
+	timer->state = fts_active;
+	timer->delay = delay;
+	timer->fun = fun;
+	timer->arg = arg;
+	fibril_condvar_broadcast(&timer->cv);
+	fibril_mutex_unlock(&timer->lock);
+}
+
+/** Clear timer.
+ *
+ * Clears (cancels) timer and returns last state of the timer.
+ * This can be one of:
+ *    - fts_not_set	If the timer has not been set or has been cleared
+ *    - fts_active	Timer was set but did not fire
+ *    - fts_fired	Timer fired
+ *
+ * @param timer		Timer
+ * @return		Last timer state
+ */
+fibril_timer_state_t fibril_timer_clear(fibril_timer_t *timer)
+{
+	fibril_timer_state_t old_state;
+
+	fibril_mutex_lock(&timer->lock);
+	old_state = timer->state;
+	timer->state = fts_not_set;
+
+	timer->delay = 0;
+	timer->fun = NULL;
+	timer->arg = NULL;
+	fibril_condvar_broadcast(&timer->cv);
+	fibril_mutex_unlock(&timer->lock);
+
+	return old_state;
+}
+
 /** @}
  */
Index: uspace/lib/c/include/bitops.h
===================================================================
--- uspace/lib/c/include/bitops.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/include/bitops.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -40,9 +40,9 @@
 /** Mask with bit @a n set. */
 #define BIT_V(type, n) \
-    ((type)1 << ((n) - 1))
+    ((type) 1 << (n))
 
 /** Mask with rightmost @a n bits set. */
 #define BIT_RRANGE(type, n) \
-    (BIT_V(type, (n) + 1) - 1)
+    (BIT_V(type, (n)) - 1)
 
 /** Mask with bits @a hi .. @a lo set. @a hi >= @a lo. */
Index: uspace/lib/c/include/ddi.h
===================================================================
--- uspace/lib/c/include/ddi.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/include/ddi.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -41,7 +41,16 @@
 
 extern int device_assign_devno(void);
-extern int physmem_map(void *, void *, unsigned long, int);
+
+extern int physmem_map(void *, void *, size_t, unsigned int);
+
+extern int dmamem_map(void *, size_t, unsigned int, unsigned int, void **);
+extern int dmamem_map_anonymous(size_t, unsigned int, unsigned int, void **,
+    void **);
+extern int dmamem_unmap(void *, size_t, unsigned int);
+extern int dmamem_unmap_anonymous(void *);
+
 extern int iospace_enable(task_id_t, void *, unsigned long);
 extern int pio_enable(void *, size_t, void **);
+
 extern int register_irq(int, int, int, irq_code_t *);
 extern int unregister_irq(int, int);
Index: uspace/lib/c/include/device/nic.h
===================================================================
--- uspace/lib/c/include/device/nic.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/include/device/nic.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -127,5 +127,5 @@
 extern int nic_vlan_get_mask(async_sess_t *, nic_vlan_mask_t *);
 extern int nic_vlan_set_mask(async_sess_t *, const nic_vlan_mask_t *);
-extern int nic_vlan_set_tag(async_sess_t *, uint16_t, int, int);
+extern int nic_vlan_set_tag(async_sess_t *, uint16_t, bool, bool);
 
 extern int nic_wol_virtue_add(async_sess_t *, nic_wv_type_t, const void *,
Index: uspace/lib/c/include/device/pci.h
===================================================================
--- uspace/lib/c/include/device/pci.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/lib/c/include/device/pci.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * 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_DEVICE_PCI_H_
+#define LIBC_DEVICE_PCI_H_
+
+#include <async.h>
+
+#define PCI_DEVICE_ID  0x02
+
+typedef enum {
+	IPC_M_CONFIG_SPACE_READ_8,
+	IPC_M_CONFIG_SPACE_READ_16,
+	IPC_M_CONFIG_SPACE_READ_32,
+	
+	IPC_M_CONFIG_SPACE_WRITE_8,
+	IPC_M_CONFIG_SPACE_WRITE_16,
+	IPC_M_CONFIG_SPACE_WRITE_32
+} pci_dev_iface_funcs_t;
+
+extern int pci_config_space_read_8(async_sess_t *, uint32_t, uint8_t *);
+extern int pci_config_space_read_16(async_sess_t *, uint32_t, uint16_t *);
+extern int pci_config_space_read_32(async_sess_t *, uint32_t, uint32_t *);
+
+extern int pci_config_space_write_8(async_sess_t *, uint32_t, uint8_t);
+extern int pci_config_space_write_16(async_sess_t *, uint32_t, uint16_t);
+extern int pci_config_space_write_32(async_sess_t *, uint32_t, uint32_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/errno.h
===================================================================
--- uspace/lib/c/include/errno.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/include/errno.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -96,4 +96,8 @@
 #define ENOTCONN  (-10057)
 
+#define ECONNREFUSED  (-10058)
+
+#define ECONNABORTED  (-10059)
+
 /** The requested operation was not performed. Try again later. */
 #define EAGAIN  (-11002)
Index: uspace/lib/c/include/fibril_synch.h
===================================================================
--- uspace/lib/c/include/fibril_synch.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/include/fibril_synch.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -107,4 +107,35 @@
 	fibril_condvar_t name = FIBRIL_CONDVAR_INITIALIZER(name)
 
+typedef void (*fibril_timer_fun_t)(void *);
+
+typedef enum {
+	/** Timer has not been set or has been cleared */
+	fts_not_set,
+	/** Timer was set but did not fire yet */
+	fts_active,
+	/** Timer has fired and has not been cleared since */
+	fts_fired,
+	/** Timer is being destroyed */
+	fts_cleanup
+} fibril_timer_state_t;
+
+/** Fibril timer.
+ *
+ * When a timer is set it executes a callback function (in a separate
+ * fibril) after a specified time interval. The timer can be cleared
+ * (canceled) before that. From the return value of fibril_timer_clear()
+ * one can tell whether the timer fired or not.
+ */
+typedef struct {
+	fibril_mutex_t lock;
+	fibril_condvar_t cv;
+	fid_t fibril;
+	fibril_timer_state_t state;
+
+	suseconds_t delay;
+	fibril_timer_fun_t fun;
+	void *arg;
+} fibril_timer_t;
+
 extern void fibril_mutex_initialize(fibril_mutex_t *);
 extern void fibril_mutex_lock(fibril_mutex_t *);
@@ -129,4 +160,10 @@
 extern void fibril_condvar_broadcast(fibril_condvar_t *);
 
+extern fibril_timer_t *fibril_timer_create(void);
+extern void fibril_timer_destroy(fibril_timer_t *);
+extern void fibril_timer_set(fibril_timer_t *, suseconds_t, fibril_timer_fun_t,
+    void *);
+extern fibril_timer_state_t fibril_timer_clear(fibril_timer_t *);
+
 #endif
 
Index: uspace/lib/c/include/ipc/net.h
===================================================================
--- uspace/lib/c/include/ipc/net.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/include/ipc/net.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -305,5 +305,5 @@
  *
  */
-#define IPC_GET_DEVICE_HANDLE(call) ((devman_handle_t) IPC_GET_ARG2(call))
+#define IPC_GET_DEVICE_HANDLE(call)  ((devman_handle_t) IPC_GET_ARG2(call))
 
 /** Return the device driver service message argument.
Index: uspace/lib/c/include/net/device.h
===================================================================
--- uspace/lib/c/include/net/device.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/c/include/net/device.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -77,4 +77,12 @@
 #define NIC_PART_NUMBER_MAX_LENGTH    64
 #define NIC_SERIAL_NUMBER_MAX_LENGTH  64
+
+#define NIC_DEFECTIVE_LONG               0x0001
+#define NIC_DEFECTIVE_SHORT              0x0002
+#define NIC_DEFECTIVE_BAD_CRC            0x0010
+#define NIC_DEFECTIVE_BAD_IPV4_CHECKSUM  0x0020
+#define NIC_DEFECTIVE_BAD_IPV6_CHECKSUM  0x0040
+#define NIC_DEFECTIVE_BAD_TCP_CHECKSUM   0x0080
+#define NIC_DEFECTIVE_BAD_UDP_CHECKSUM   0x0100
 
 /**
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/drv/generic/driver.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -288,5 +288,5 @@
 	(void) parent_fun_handle;
 	
-	res = driver->driver_ops->add_device(dev);
+	res = driver->driver_ops->dev_add(dev);
 	
 	if (res != EOK) {
Index: uspace/lib/drv/generic/remote_nic.c
===================================================================
--- uspace/lib/drv/generic/remote_nic.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/drv/generic/remote_nic.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -829,6 +829,6 @@
 	
 	uint16_t tag = (uint16_t) IPC_GET_ARG2(*call);
-	int add = (int) IPC_GET_ARG3(*call);
-	int strip = (int) IPC_GET_ARG4(*call);
+	bool add = (int) IPC_GET_ARG3(*call);
+	bool strip = (int) IPC_GET_ARG4(*call);
 	
 	int rc = nic_iface->vlan_set_tag(dev, tag, add, strip);
Index: uspace/lib/drv/generic/remote_pci.c
===================================================================
--- uspace/lib/drv/generic/remote_pci.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/drv/generic/remote_pci.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -32,4 +32,5 @@
 /** @file
  */
+
 #include <assert.h>
 #include <async.h>
Index: uspace/lib/drv/generic/remote_usb.c
===================================================================
--- uspace/lib/drv/generic/remote_usb.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/drv/generic/remote_usb.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -39,15 +40,75 @@
 #include "ddf/driver.h"
 
+typedef enum {
+	IPC_M_USB_GET_MY_ADDRESS,
+	IPC_M_USB_GET_MY_INTERFACE,
+	IPC_M_USB_GET_HOST_CONTROLLER_HANDLE,
+} usb_iface_funcs_t;
 
-static void remote_usb_get_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usb_get_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+/** Tell USB address assigned to device.
+ * @param exch Vaid IPC exchange
+ * @param address Pointer to address storage place.
+ * @return Error code.
+ *
+ * Exch param is an open communication to device implementing usb_iface.
+ */
+int usb_get_my_address(async_exch_t *exch, usb_address_t *address)
+{
+	if (!exch)
+		return EINVAL;
+	sysarg_t addr;
+	const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_MY_ADDRESS, &addr);
+
+	if (ret == EOK && address != NULL)
+		*address = (usb_address_t) addr;
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Tell interface number given device can use.
+ * @param[in] exch IPC communication exchange
+ * @param[in] handle Id of the device
+ * @param[out] usb_iface Assigned USB interface
+ * @return Error code.
+ */
+int usb_get_my_interface(async_exch_t *exch, int *usb_iface)
+{
+	if (!exch)
+		return EINVAL;
+	sysarg_t iface_no;
+	const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_MY_INTERFACE, &iface_no);
+	if (ret == EOK && usb_iface)
+		*usb_iface = (int)iface_no;
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+/** Tell devman handle of device host controller.
+ * @param[in] exch IPC communication exchange
+ * @param[out] hc_handle devman handle of the HC used by the target device.
+ * @return Error code.
+ */
+int usb_get_hc_handle(async_exch_t *exch, devman_handle_t *hc_handle)
+{
+	if (!exch)
+		return EINVAL;
+	devman_handle_t h;
+	const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
+	    IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
+	if (ret == EOK && hc_handle)
+		*hc_handle = (devman_handle_t)h;
+	return ret;
+}
+
+
+static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usb_get_hc_handle(ddf_fun_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_address,
-	remote_usb_get_interface,
-	remote_usb_get_hc_handle
+	[IPC_M_USB_GET_MY_ADDRESS] = remote_usb_get_my_address,
+	[IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
+	[IPC_M_USB_GET_HOST_CONTROLLER_HANDLE] = remote_usb_get_hc_handle,
 };
 
@@ -60,51 +121,47 @@
 };
 
-
-void remote_usb_get_address(ddf_fun_t *fun, void *iface,
+/*----------------------------------------------------------------------------*/
+void remote_usb_get_my_address(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+	const usb_iface_t *usb_iface = (usb_iface_t *) iface;
 
-	if (usb_iface->get_address == NULL) {
+	if (usb_iface->get_my_address == NULL) {
 		async_answer_0(callid, ENOTSUP);
 		return;
 	}
 
-	devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
-
 	usb_address_t address;
-	int rc = usb_iface->get_address(fun, handle, &address);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
+	const int ret = usb_iface->get_my_address(fun, &address);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
 	} else {
 		async_answer_1(callid, EOK, address);
 	}
 }
-
-void remote_usb_get_interface(ddf_fun_t *fun, void *iface,
+/*----------------------------------------------------------------------------*/
+void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+	const usb_iface_t *usb_iface = (usb_iface_t *) iface;
 
-	if (usb_iface->get_interface == NULL) {
+	if (usb_iface->get_my_interface == NULL) {
 		async_answer_0(callid, ENOTSUP);
 		return;
 	}
 
-	devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
-
 	int iface_no;
-	int rc = usb_iface->get_interface(fun, handle, &iface_no);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
+	const int ret = usb_iface->get_my_interface(fun, &iface_no);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
 	} else {
 		async_answer_1(callid, EOK, iface_no);
 	}
 }
-
+/*----------------------------------------------------------------------------*/
 void remote_usb_get_hc_handle(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usb_iface_t *usb_iface = (usb_iface_t *) iface;
+	const usb_iface_t *usb_iface = (usb_iface_t *) iface;
 
 	if (usb_iface->get_hc_handle == NULL) {
@@ -114,14 +171,11 @@
 
 	devman_handle_t handle;
-	int rc = usb_iface->get_hc_handle(fun, &handle);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
+	const int ret = usb_iface->get_hc_handle(fun, &handle);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
 	}
 
 	async_answer_1(callid, EOK, (sysarg_t) handle);
 }
-
-
-
 /**
  * @}
Index: uspace/lib/drv/generic/remote_usbhc.c
===================================================================
--- uspace/lib/drv/generic/remote_usbhc.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010-2011 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -42,7 +43,285 @@
 #define USB_MAX_PAYLOAD_SIZE 1020
 
+/** IPC methods for communication with HC through DDF interface.
+ *
+ * Notes for async methods:
+ *
+ * Methods for sending data to device (OUT transactions)
+ * - e.g. IPC_M_USBHC_INTERRUPT_OUT -
+ * always use the same semantics:
+ * - first, IPC call with given method is made
+ *   - argument #1 is target address
+ *   - argument #2 is target endpoint
+ *   - argument #3 is max packet size of the endpoint
+ * - this call is immediately followed by IPC data write (from caller)
+ * - the initial call (and the whole transaction) is answer after the
+ *   transaction is scheduled by the HC and acknowledged by the device
+ *   or immediately after error is detected
+ * - the answer carries only the error code
+ *
+ * Methods for retrieving data from device (IN transactions)
+ * - e.g. IPC_M_USBHC_INTERRUPT_IN -
+ * also use the same semantics:
+ * - first, IPC call with given method is made
+ *   - argument #1 is target address
+ *   - argument #2 is target endpoint
+ * - this call is immediately followed by IPC data read (async version)
+ * - the call is not answered until the device returns some data (or until
+ *   error occurs)
+ *
+ * Some special methods (NO-DATA transactions) do not send any data. These
+ * might behave as both OUT or IN transactions because communication parts
+ * where actual buffers are exchanged are omitted.
+ **
+ * For all these methods, wrap functions exists. Important rule: functions
+ * for IN transactions have (as parameters) buffers where retrieved data
+ * will be stored. These buffers must be already allocated and shall not be
+ * touch until the transaction is completed
+ * (e.g. not before calling usb_wait_for() with appropriate handle).
+ * OUT transactions buffers can be freed immediately after call is dispatched
+ * (i.e. after return from wrapping function).
+ *
+ */
+typedef enum {
+	/** Asks for address assignment by host controller.
+	 * Answer:
+	 * - ELIMIT - host controller run out of address
+	 * - EOK - address assigned
+	 * Answer arguments:
+	 * - assigned address
+	 *
+	 * The address must be released by via IPC_M_USBHC_RELEASE_ADDRESS.
+	 */
+	IPC_M_USBHC_REQUEST_ADDRESS,
+
+	/** Bind USB address with devman handle.
+	 * Parameters:
+	 * - USB address
+	 * - devman handle
+	 * Answer:
+	 * - EOK - address binded
+	 * - ENOENT - address is not in use
+	 */
+	IPC_M_USBHC_BIND_ADDRESS,
+
+	/** Get handle binded with given USB address.
+	 * Parameters
+	 * - USB address
+	 * Answer:
+	 * - EOK - address binded, first parameter is the devman handle
+	 * - ENOENT - address is not in use at the moment
+	 */
+	IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,
+
+	/** Release address in use.
+	 * Arguments:
+	 * - address to be released
+	 * Answer:
+	 * - ENOENT - address not in use
+	 * - EPERM - trying to release default USB address
+	 */
+	IPC_M_USBHC_RELEASE_ADDRESS,
+
+	/** Register endpoint attributes at host controller.
+	 * This is used to reserve portion of USB bandwidth.
+	 * When speed is invalid, speed of the device is used.
+	 * Parameters:
+	 * - USB address + endpoint number
+	 *   - packed as ADDR << 16 + EP
+	 * - speed + transfer type + direction
+	 *   - packed as ( SPEED << 8 + TYPE ) << 8 + DIR
+	 * - maximum packet size + interval (in milliseconds)
+	 *   - packed as MPS << 16 + INT
+	 * Answer:
+	 * - EOK - reservation successful
+	 * - ELIMIT - not enough bandwidth to satisfy the request
+	 */
+	IPC_M_USBHC_REGISTER_ENDPOINT,
+
+	/** Revert endpoint registration.
+	 * Parameters:
+	 * - USB address
+	 * - endpoint number
+	 * - data direction
+	 * Answer:
+	 * - EOK - endpoint unregistered
+	 * - ENOENT - unknown endpoint
+	 */
+	IPC_M_USBHC_UNREGISTER_ENDPOINT,
+
+	/** Get data from device.
+	 * See explanation at usb_iface_funcs_t (IN transaction).
+	 */
+	IPC_M_USBHC_READ,
+
+	/** Send data to device.
+	 * See explanation at usb_iface_funcs_t (OUT transaction).
+	 */
+	IPC_M_USBHC_WRITE,
+} usbhc_iface_funcs_t;
+
+int usbhc_request_address(async_exch_t *exch, usb_address_t *address,
+    bool strict, usb_speed_t speed)
+{
+	if (!exch || !address)
+		return EINVAL;
+	sysarg_t new_address;
+	const int ret = async_req_4_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_REQUEST_ADDRESS, *address, strict, speed, &new_address);
+	if (ret == EOK)
+		*address = (usb_address_t)new_address;
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_bind_address(async_exch_t *exch, usb_address_t address,
+    devman_handle_t handle)
+{
+	if (!exch)
+		return EINVAL;
+	return async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_BIND_ADDRESS, address, handle);
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_get_handle(async_exch_t *exch, usb_address_t address,
+    devman_handle_t *handle)
+{
+	if (!exch)
+		return EINVAL;
+	sysarg_t h;
+	const int ret = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_GET_HANDLE_BY_ADDRESS, address, &h);
+	if (ret == EOK && handle)
+		*handle = (devman_handle_t)h;
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_release_address(async_exch_t *exch, usb_address_t address)
+{
+	if (!exch)
+		return EINVAL;
+	return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_RELEASE_ADDRESS, address);
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_register_endpoint(async_exch_t *exch, usb_address_t address,
+    usb_endpoint_t endpoint, usb_transfer_type_t type,
+    usb_direction_t direction, size_t mps, unsigned interval)
+{
+	if (!exch)
+		return EINVAL;
+	const usb_target_t target =
+	    {{ .address = address, .endpoint = endpoint }};
+#define _PACK2(high, low) (((high & 0xffff) << 16) | (low & 0xffff))
+
+	return async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_REGISTER_ENDPOINT, target.packed,
+	    _PACK2(type, direction), _PACK2(mps, interval));
+
+#undef _PACK2
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_unregister_endpoint(async_exch_t *exch, usb_address_t address,
+    usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	if (!exch)
+		return EINVAL;
+	return async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_UNREGISTER_ENDPOINT, address, endpoint, direction);
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_read(async_exch_t *exch, usb_address_t address,
+    usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,
+    size_t *rec_size)
+{
+	if (size == 0 && setup == 0)
+		return EOK;
+
+	if (!exch)
+		return EINVAL;
+	const usb_target_t target =
+	    {{ .address = address, .endpoint = endpoint }};
+
+	/* Make call identifying target USB device and type of transfer. */
+	aid_t opening_request = async_send_4(exch,
+	    DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_READ, target.packed,
+	    (setup & UINT32_MAX), (setup >> 32), NULL);
+
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	/* Retrieve the data. */
+	ipc_call_t data_request_call;
+	aid_t data_request =
+	    async_data_read(exch, data, size, &data_request_call);
+
+	if (data_request == 0) {
+		// FIXME: How to let the other side know that we want to abort?
+		async_wait_for(opening_request, NULL);
+		return ENOMEM;
+	}
+
+	/* Wait for the answer. */
+	sysarg_t data_request_rc;
+	sysarg_t opening_request_rc;
+	async_wait_for(data_request, &data_request_rc);
+	async_wait_for(opening_request, &opening_request_rc);
+
+	if (data_request_rc != EOK) {
+		/* Prefer the return code of the opening request. */
+		if (opening_request_rc != EOK) {
+			return (int) opening_request_rc;
+		} else {
+			return (int) data_request_rc;
+		}
+	}
+	if (opening_request_rc != EOK) {
+		return (int) opening_request_rc;
+	}
+
+	*rec_size = IPC_GET_ARG2(data_request_call);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+int usbhc_write(async_exch_t *exch, usb_address_t address,
+    usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)
+{
+	if (size == 0 && setup == 0)
+		return EOK;
+
+	if (!exch)
+		return EINVAL;
+	const usb_target_t target =
+	    {{ .address = address, .endpoint = endpoint }};
+
+	aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
+	    IPC_M_USBHC_WRITE, target.packed, size,
+	    (setup & UINT32_MAX), (setup >> 32), NULL);
+
+	if (opening_request == 0) {
+		return ENOMEM;
+	}
+
+	/* Send the data if any. */
+	if (size > 0) {
+		const int ret = async_data_write_start(exch, data, size);
+		if (ret != EOK) {
+			async_wait_for(opening_request, NULL);
+			return ret;
+		}
+	}
+
+	/* Wait for the answer. */
+	sysarg_t opening_request_rc;
+	async_wait_for(opening_request, &opening_request_rc);
+
+	return (int) opening_request_rc;
+}
+/*----------------------------------------------------------------------------*/
+
 static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
-static void remote_usbhc_find_by_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+static void remote_usbhc_get_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_release_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
 static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
@@ -55,7 +334,7 @@
 static remote_iface_func_ptr_t remote_usbhc_iface_ops[] = {
 	[IPC_M_USBHC_REQUEST_ADDRESS] = remote_usbhc_request_address,
+	[IPC_M_USBHC_RELEASE_ADDRESS] = remote_usbhc_release_address,
 	[IPC_M_USBHC_BIND_ADDRESS] = remote_usbhc_bind_address,
-	[IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_find_by_address,
-	[IPC_M_USBHC_RELEASE_ADDRESS] = remote_usbhc_release_address,
+	[IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_get_handle,
 
 	[IPC_M_USBHC_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
@@ -78,5 +357,4 @@
 	ipc_callid_t data_caller;
 	void *buffer;
-	size_t size;
 } async_transaction_t;
 
@@ -103,13 +381,12 @@
 	trans->data_caller = 0;
 	trans->buffer = NULL;
-	trans->size = 0;
 
 	return trans;
 }
-
+/*----------------------------------------------------------------------------*/
 void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	const usbhc_iface_t *usb_iface = iface;
 
 	if (!usb_iface->request_address) {
@@ -118,8 +395,9 @@
 	}
 
-	usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
-
-	usb_address_t address;
-	int rc = usb_iface->request_address(fun, speed, &address);
+	usb_address_t address = DEV_IPC_GET_ARG1(*call);
+	const bool strict = DEV_IPC_GET_ARG2(*call);
+	const usb_speed_t speed = DEV_IPC_GET_ARG3(*call);
+
+	const int rc = usb_iface->request_address(fun, &address, strict, speed);
 	if (rc != EOK) {
 		async_answer_0(callid, rc);
@@ -128,9 +406,9 @@
 	}
 }
-
+/*----------------------------------------------------------------------------*/
 void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	const usbhc_iface_t *usb_iface = iface;
 
 	if (!usb_iface->bind_address) {
@@ -139,37 +417,36 @@
 	}
 
-	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
-	devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
-
-	int rc = usb_iface->bind_address(fun, address, handle);
-
-	async_answer_0(callid, rc);
-}
-
-void remote_usbhc_find_by_address(ddf_fun_t *fun, void *iface,
+	const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+	const devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
+
+	const int ret = usb_iface->bind_address(fun, address, handle);
+	async_answer_0(callid, ret);
+}
+/*----------------------------------------------------------------------------*/
+void remote_usbhc_get_handle(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
-
-	if (!usb_iface->find_by_address) {
-		async_answer_0(callid, ENOTSUP);
-		return;
-	}
-
-	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+	const usbhc_iface_t *usb_iface = iface;
+
+	if (!usb_iface->get_handle) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
 	devman_handle_t handle;
-	int rc = usb_iface->find_by_address(fun, address, &handle);
-
-	if (rc == EOK) {
-		async_answer_1(callid, EOK, handle);
+	const int ret = usb_iface->get_handle(fun, address, &handle);
+
+	if (ret == EOK) {
+		async_answer_1(callid, ret, handle);
 	} else {
-		async_answer_0(callid, rc);
-	}
-}
-
+		async_answer_0(callid, ret);
+	}
+}
+/*----------------------------------------------------------------------------*/
 void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
 {
-	usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
+	const usbhc_iface_t *usb_iface = iface;
 
 	if (!usb_iface->release_address) {
@@ -178,16 +455,14 @@
 	}
 
-	usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
-
-	int rc = usb_iface->release_address(fun, address);
-
-	async_answer_0(callid, rc);
-}
-
-
+	const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
+
+	const int ret = usb_iface->release_address(fun, address);
+	async_answer_0(callid, ret);
+}
+/*----------------------------------------------------------------------------*/
 static void callback_out(ddf_fun_t *fun,
     int outcome, void *arg)
 {
-	async_transaction_t *trans = (async_transaction_t *)arg;
+	async_transaction_t *trans = arg;
 
 	async_answer_0(trans->caller, outcome);
@@ -195,5 +470,5 @@
 	async_transaction_destroy(trans);
 }
-
+/*----------------------------------------------------------------------------*/
 static void callback_in(ddf_fun_t *fun,
     int outcome, size_t actual_size, void *arg)
@@ -210,6 +485,4 @@
 	}
 
-	trans->size = actual_size;
-
 	if (trans->data_caller) {
 		async_data_read_finalize(trans->data_caller,
@@ -221,5 +494,5 @@
 	async_transaction_destroy(trans);
 }
-
+/*----------------------------------------------------------------------------*/
 void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
     ipc_callid_t callid, ipc_call_t *call)
@@ -233,19 +506,12 @@
 
 #define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
-	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
+	type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) >> 16)
 #define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
-	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 16)
-#define _INIT_FROM_HIGH_DATA3(type, var, arg_no) \
-	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
-#define _INIT_FROM_MIDDLE_DATA3(type, var, arg_no) \
-	type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) / (1 << 8)) % (1 << 8)
-#define _INIT_FROM_LOW_DATA3(type, var, arg_no) \
-	type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 8)
+	type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) & 0xffff)
 
 	const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
 
-	_INIT_FROM_HIGH_DATA3(usb_speed_t, speed, 2);
-	_INIT_FROM_MIDDLE_DATA3(usb_transfer_type_t, transfer_type, 2);
-	_INIT_FROM_LOW_DATA3(usb_direction_t, direction, 2);
+	_INIT_FROM_HIGH_DATA2(usb_transfer_type_t, transfer_type, 2);
+	_INIT_FROM_LOW_DATA2(usb_direction_t, direction, 2);
 
 	_INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
@@ -254,9 +520,6 @@
 #undef _INIT_FROM_HIGH_DATA2
 #undef _INIT_FROM_LOW_DATA2
-#undef _INIT_FROM_HIGH_DATA3
-#undef _INIT_FROM_MIDDLE_DATA3
-#undef _INIT_FROM_LOW_DATA3
-
-	int rc = usb_iface->register_endpoint(fun, target.address, speed,
+
+	int rc = usb_iface->register_endpoint(fun, target.address,
 	    target.endpoint, transfer_type, direction, max_packet_size, interval);
 
@@ -309,10 +572,11 @@
 	}
 
-	if (!async_data_read_receive(&trans->data_caller, &trans->size)) {
+	size_t size = 0;
+	if (!async_data_read_receive(&trans->data_caller, &size)) {
 		async_answer_0(callid, EPARTY);
 		return;
 	}
 
-	trans->buffer = malloc(trans->size);
+	trans->buffer = malloc(size);
 	if (trans->buffer == NULL) {
 		async_answer_0(trans->data_caller, ENOMEM);
@@ -322,5 +586,5 @@
 
 	const int rc = hc_iface->read(
-	    fun, target, setup, trans->buffer, trans->size, callback_in, trans);
+	    fun, target, setup, trans->buffer, size, callback_in, trans);
 
 	if (rc != EOK) {
@@ -330,5 +594,5 @@
 	}
 }
-
+/*----------------------------------------------------------------------------*/
 void remote_usbhc_write(
     ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
@@ -357,8 +621,9 @@
 	}
 
+	size_t size = 0;
 	if (data_buffer_len > 0) {
-		int rc = async_data_write_accept(&trans->buffer, false,
+		const int rc = async_data_write_accept(&trans->buffer, false,
 		    1, USB_MAX_PAYLOAD_SIZE,
-		    0, &trans->size);
+		    0, &size);
 
 		if (rc != EOK) {
@@ -369,6 +634,6 @@
 	}
 
-	int rc = hc_iface->write(
-	    fun, target, setup, trans->buffer, trans->size, callback_out, trans);
+	const int rc = hc_iface->write(
+	    fun, target, setup, trans->buffer, size, callback_out, trans);
 
 	if (rc != EOK) {
@@ -377,6 +642,4 @@
 	}
 }
-
-
 /**
  * @}
Index: uspace/lib/drv/include/ddf/driver.h
===================================================================
--- uspace/lib/drv/include/ddf/driver.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/drv/include/ddf/driver.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -136,11 +136,5 @@
 typedef struct driver_ops {
 	/** Callback method for passing a new device to the device driver */
-	int (*add_device)(ddf_dev_t *);
-	/**
-	 * Notification that the device was succesfully added.
-	 * The driver can do any blocking operation without
-	 * blocking the device manager.
-	 */
-	void (*device_added)(ddf_dev_t *dev);
+	int (*dev_add)(ddf_dev_t *);
 	/** Ask driver to remove a device */
 	int (*dev_remove)(ddf_dev_t *);
@@ -151,4 +145,13 @@
 	/** Ask driver to offline a specific function */
 	int (*fun_offline)(ddf_fun_t *);
+
+	/**
+	 * Notification that the device was succesfully added.
+	 * The driver can do any blocking operation without
+	 * blocking the device manager.
+	 *
+	 * XXX REMOVE THIS
+	 */
+	void (*device_added)(ddf_dev_t *dev);
 } driver_ops_t;
 
Index: uspace/lib/drv/include/ops/nic.h
===================================================================
--- uspace/lib/drv/include/ops/nic.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/drv/include/ops/nic.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -89,5 +89,5 @@
 	int (*vlan_get_mask)(ddf_fun_t *, nic_vlan_mask_t *);
 	int (*vlan_set_mask)(ddf_fun_t *, const nic_vlan_mask_t *);
-	int (*vlan_set_tag)(ddf_fun_t *, uint16_t, int, int);
+	int (*vlan_set_tag)(ddf_fun_t *, uint16_t, bool, bool);
 	
 	int (*wol_virtue_add)(ddf_fun_t *, nic_wv_type_t, const void *,
Index: uspace/lib/drv/include/usb_iface.h
===================================================================
--- uspace/lib/drv/include/usb_iface.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/drv/include/usb_iface.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -39,60 +39,17 @@
 
 #include "ddf/driver.h"
+#include <async.h>
 #include <usb/usb.h>
-typedef enum {
-	/** Tell USB address assigned to device.
-	 * Parameters:
-	 * - devman handle id
-	 * Answer:
-	 * - EINVAL - unknown handle or handle not managed by this driver
-	 * - ENOTSUP - operation not supported (shall not happen)
-	 * - arbitrary error code if returned by remote implementation
-	 * - EOK - handle found, first parameter contains the USB address
-	 *
-	 * The handle must be the one used for binding USB address with
-	 * it (IPC_M_USBHC_BIND_ADDRESS), otherwise the host controller
-	 * (that this request would eventually reach) would not be able
-	 * to find it.
-	 * The problem is that this handle is actually assigned to the
-	 * function inside driver of the parent device (usually hub driver).
-	 * To bypass this problem, the initial caller specify handle as
-	 * zero and the first parent assigns the actual value.
-	 * See usb_iface_get_address_hub_child_impl() implementation
-	 * that could be assigned to device ops of a child device of in a
-	 * hub driver.
-	 * For example, the USB multi interface device driver (MID)
-	 * passes this initial zero without any modification because the
-	 * handle must be resolved by its parent.
-	 */
-	IPC_M_USB_GET_ADDRESS,
 
-	/** Tell interface number given device can use.
-	 * Parameters
-	 * - devman handle id of the device
-	 * Answer:
-	 * - ENOTSUP - operation not supported (can also mean any interface)
-	 * - EOK - operation okay, first parameter contains interface number
-	 */
-	IPC_M_USB_GET_INTERFACE,
-
-	/** 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;
+int usb_get_my_address(async_exch_t *, usb_address_t *);
+int usb_get_my_interface(async_exch_t *, int *);
+int usb_get_hc_handle(async_exch_t *, devman_handle_t *);
 
 /** USB device communication interface. */
 typedef struct {
-	int (*get_address)(ddf_fun_t *, devman_handle_t, usb_address_t *);
-	int (*get_interface)(ddf_fun_t *, devman_handle_t, int *);
+	int (*get_my_address)(ddf_fun_t *, usb_address_t *);
+	int (*get_my_interface)(ddf_fun_t *, int *);
 	int (*get_hc_handle)(ddf_fun_t *, devman_handle_t *);
 } usb_iface_t;
-
 
 #endif
Index: uspace/lib/drv/include/usbhc_iface.h
===================================================================
--- uspace/lib/drv/include/usbhc_iface.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -42,122 +42,16 @@
 #include <bool.h>
 
-
-/** IPC methods for communication with HC through DDF interface.
- *
- * Notes for async methods:
- *
- * Methods for sending data to device (OUT transactions)
- * - e.g. IPC_M_USBHC_INTERRUPT_OUT -
- * always use the same semantics:
- * - first, IPC call with given method is made
- *   - argument #1 is target address
- *   - argument #2 is target endpoint
- *   - argument #3 is max packet size of the endpoint
- * - this call is immediately followed by IPC data write (from caller)
- * - the initial call (and the whole transaction) is answer after the
- *   transaction is scheduled by the HC and acknowledged by the device
- *   or immediately after error is detected
- * - the answer carries only the error code
- *
- * Methods for retrieving data from device (IN transactions)
- * - e.g. IPC_M_USBHC_INTERRUPT_IN -
- * also use the same semantics:
- * - first, IPC call with given method is made
- *   - argument #1 is target address
- *   - argument #2 is target endpoint
- * - this call is immediately followed by IPC data read (async version)
- * - the call is not answered until the device returns some data (or until
- *   error occurs)
- *
- * Some special methods (NO-DATA transactions) do not send any data. These
- * might behave as both OUT or IN transactions because communication parts
- * where actual buffers are exchanged are omitted.
- **
- * For all these methods, wrap functions exists. Important rule: functions
- * for IN transactions have (as parameters) buffers where retrieved data
- * will be stored. These buffers must be already allocated and shall not be
- * touch until the transaction is completed
- * (e.g. not before calling usb_wait_for() with appropriate handle).
- * OUT transactions buffers can be freed immediately after call is dispatched
- * (i.e. after return from wrapping function).
- *
- */
-typedef enum {
-	/** Asks for address assignment by host controller.
-	 * Answer:
-	 * - ELIMIT - host controller run out of address
-	 * - EOK - address assigned
-	 * Answer arguments:
-	 * - assigned address
-	 *
-	 * The address must be released by via IPC_M_USBHC_RELEASE_ADDRESS.
-	 */
-	IPC_M_USBHC_REQUEST_ADDRESS,
-
-	/** Bind USB address with devman handle.
-	 * Parameters:
-	 * - USB address
-	 * - devman handle
-	 * Answer:
-	 * - EOK - address binded
-	 * - ENOENT - address is not in use
-	 */
-	IPC_M_USBHC_BIND_ADDRESS,
-
-	/** Get handle binded with given USB address.
-	 * Parameters
-	 * - USB address
-	 * Answer:
-	 * - EOK - address binded, first parameter is the devman handle
-	 * - ENOENT - address is not in use at the moment
-	 */
-	IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,
-
-	/** Release address in use.
-	 * Arguments:
-	 * - address to be released
-	 * Answer:
-	 * - ENOENT - address not in use
-	 * - EPERM - trying to release default USB address
-	 */
-	IPC_M_USBHC_RELEASE_ADDRESS,
-
-	/** Register endpoint attributes at host controller.
-	 * This is used to reserve portion of USB bandwidth.
-	 * When speed is invalid, speed of the device is used.
-	 * Parameters:
-	 * - USB address + endpoint number
-	 *   - packed as ADDR << 16 + EP
-	 * - speed + transfer type + direction
-	 *   - packed as ( SPEED << 8 + TYPE ) << 8 + DIR
-	 * - maximum packet size + interval (in milliseconds)
-	 *   - packed as MPS << 16 + INT
-	 * Answer:
-	 * - EOK - reservation successful
-	 * - ELIMIT - not enough bandwidth to satisfy the request
-	 */
-	IPC_M_USBHC_REGISTER_ENDPOINT,
-
-	/** Revert endpoint registration.
-	 * Parameters:
-	 * - USB address
-	 * - endpoint number
-	 * - data direction
-	 * Answer:
-	 * - EOK - endpoint unregistered
-	 * - ENOENT - unknown endpoint
-	 */
-	IPC_M_USBHC_UNREGISTER_ENDPOINT,
-
-	/** Get data from device.
-	 * See explanation at usb_iface_funcs_t (IN transaction).
-	 */
-	IPC_M_USBHC_READ,
-
-	/** Send data to device.
-	 * See explanation at usb_iface_funcs_t (OUT transaction).
-	 */
-	IPC_M_USBHC_WRITE,
-} usbhc_iface_funcs_t;
+int usbhc_request_address(async_exch_t *, usb_address_t *, bool, usb_speed_t);
+int usbhc_bind_address(async_exch_t *, usb_address_t, devman_handle_t);
+int usbhc_get_handle(async_exch_t *, usb_address_t, devman_handle_t *);
+int usbhc_release_address(async_exch_t *, usb_address_t);
+int usbhc_register_endpoint(async_exch_t *, usb_address_t,  usb_endpoint_t,
+    usb_transfer_type_t, usb_direction_t, size_t, unsigned int);
+int usbhc_unregister_endpoint(async_exch_t *, usb_address_t, usb_endpoint_t,
+    usb_direction_t);
+int usbhc_read(async_exch_t *, usb_address_t, usb_endpoint_t,
+    uint64_t, void *, size_t, size_t *);
+int usbhc_write(async_exch_t *, usb_address_t, usb_endpoint_t,
+    uint64_t, const void *, size_t);
 
 /** Callback for outgoing transfer. */
@@ -170,11 +64,12 @@
 /** USB host controller communication interface. */
 typedef struct {
-	int (*request_address)(ddf_fun_t *, usb_speed_t, usb_address_t *);
+	int (*request_address)(ddf_fun_t *, usb_address_t *, bool, usb_speed_t);
 	int (*bind_address)(ddf_fun_t *, usb_address_t, devman_handle_t);
-	int (*find_by_address)(ddf_fun_t *, usb_address_t, devman_handle_t *);
+	int (*get_handle)(ddf_fun_t *, usb_address_t,
+	    devman_handle_t *);
 	int (*release_address)(ddf_fun_t *, usb_address_t);
 
 	int (*register_endpoint)(ddf_fun_t *,
-	    usb_address_t, usb_speed_t, usb_endpoint_t,
+	    usb_address_t, usb_endpoint_t,
 	    usb_transfer_type_t, usb_direction_t, size_t, unsigned int);
 	int (*unregister_endpoint)(ddf_fun_t *, usb_address_t, usb_endpoint_t,
Index: uspace/lib/minix/minix.h
===================================================================
--- uspace/lib/minix/minix.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/minix/minix.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -39,9 +39,9 @@
 #define S_ISDIR(m)		(((m) & S_IFMT) == S_IFDIR)
 #define S_ISREG(m)		(((m) & S_IFMT) == S_IFREG)
-#define S_IFDIR			0040000		/*Directory*/
-#define S_IFREG			0100000		/*Regular file*/
+#define S_IFDIR			0040000		/* Directory */
+#define S_IFREG			0100000		/* Regular file */
 #define S_IFMT			00170000
 
-/*The following block sizes are valid only on V3 filesystem*/
+/* The following block sizes are valid only on V3 filesystem */
 #define MFS_MIN_BLOCKSIZE	1024
 #define MFS_MAX_BLOCKSIZE	4096
@@ -88,19 +88,19 @@
 #define MFS_ERROR_FS		0x0002
 
-/*MFS V1/V2 superblock data on disk*/
+/* MFS V1/V2 superblock data on disk */
 struct mfs_superblock {
-	/*Total number of inodes on the device*/
+	/* Total number of inodes on the device */
 	uint16_t	s_ninodes;
-	/*Total number of zones on the device*/
+	/* Total number of zones on the device */
 	uint16_t	s_nzones;
-	/*Number of inode bitmap blocks*/
+	/* Number of inode bitmap blocks */
 	uint16_t	s_ibmap_blocks;
-	/*Number of zone bitmap blocks*/
+	/* Number of zone bitmap blocks */
 	uint16_t	s_zbmap_blocks;
-	/*First data zone on device*/
+	/* First data zone on device */
 	uint16_t	s_first_data_zone;
-	/*Base 2 logarithm of the zone to block ratio*/
+	/* Base 2 logarithm of the zone to block ratio */
 	uint16_t	s_log2_zone_size;
-	/*Maximum file size expressed in bytes*/
+	/* Maximum file size expressed in bytes */
 	uint32_t	s_max_file_size;
 	/*
@@ -109,28 +109,28 @@
 	 */
 	uint16_t	s_magic;
-	/*Flag used to detect FS errors*/
+	/* Flag used to detect FS errors*/
 	uint16_t	s_state;
-	/*Total number of zones on the device (V2 only)*/
+	/* Total number of zones on the device (V2 only) */
 	uint32_t	s_nzones2;
 } __attribute__ ((packed));
 
 
-/*MFS V3 superblock data on disk*/
+/* MFS V3 superblock data on disk */
 struct mfs3_superblock {
-	/*Total number of inodes on the device*/
+	/* Total number of inodes on the device */
 	uint32_t	s_ninodes;
 	uint16_t	s_pad0;
-	/*Number of inode bitmap blocks*/
+	/* Number of inode bitmap blocks */
 	int16_t		s_ibmap_blocks;
-	/*Number of zone bitmap blocks*/
+	/* Number of zone bitmap blocks */
 	int16_t		s_zbmap_blocks;
-	/*First data zone on device*/
+	/* First data zone on device */
 	uint16_t	s_first_data_zone;
-	/*Base 2 logarithm of the zone to block ratio*/
+	/* Base 2 logarithm of the zone to block ratio */
 	int16_t		s_log2_zone_size;
 	int16_t		s_pad1;
-	/*Maximum file size expressed in bytes*/
+	/* Maximum file size expressed in bytes */
 	uint32_t	s_max_file_size;
-	/*Total number of zones on the device*/
+	/* Total number of zones on the device */
 	uint32_t	s_nzones;
 	/*
@@ -140,11 +140,11 @@
 	int16_t		s_magic;
 	int16_t		s_pad2;
-	/*Filesystem block size expressed in bytes*/
+	/* Filesystem block size expressed in bytes */
 	uint16_t	s_block_size;
-	/*Filesystem disk format version*/
+	/* Filesystem disk format version */
 	int8_t		s_disk_version;
 } __attribute__ ((packed));
 
-/*MinixFS V1 inode structure as it is on disk*/
+/* MinixFS V1 inode structure as it is on disk */
 struct mfs_inode {
 	uint16_t	i_mode;
@@ -154,11 +154,11 @@
 	uint8_t		i_gid;
 	uint8_t		i_nlinks;
-	/*Block numbers for direct zones*/
+	/* Block numbers for direct zones */
 	uint16_t	i_dzone[V1_NR_DIRECT_ZONES];
-	/*Block numbers for indirect zones*/
+	/* Block numbers for indirect zones */
 	uint16_t	i_izone[V1_NR_INDIRECT_ZONES];
 } __attribute__ ((packed));
 
-/*MinixFS V2 inode structure as it is on disk (also valid for V3).*/
+/* MinixFS V2 inode structure as it is on disk (also valid for V3). */
 struct mfs2_inode {
 	uint16_t 	i_mode;
@@ -170,11 +170,11 @@
 	int32_t		i_mtime;
 	int32_t		i_ctime;
-	/*Block numbers for direct zones*/
+	/* Block numbers for direct zones */
 	uint32_t	i_dzone[V2_NR_DIRECT_ZONES];
-	/*Block numbers for indirect zones*/
+	/* Block numbers for indirect zones */
 	uint32_t	i_izone[V2_NR_INDIRECT_ZONES];
 } __attribute__ ((packed));
 
-/*MinixFS V1/V2 directory entry on-disk structure*/
+/* MinixFS V1/V2 directory entry on-disk structure */
 struct mfs_dentry {
 	uint16_t d_inum;
@@ -182,5 +182,5 @@
 };
 
-/*MinixFS V3 directory entry on-disk structure*/
+/* MinixFS V3 directory entry on-disk structure */
 struct mfs3_dentry {
 	uint32_t d_inum;
Index: uspace/lib/net/generic/generic.c
===================================================================
--- uspace/lib/net/generic/generic.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/net/generic/generic.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -104,21 +104,28 @@
     nic_device_id_t device_id, uint8_t *address, size_t max_len)
 {
-	if (!address)
-		return EBADMEM;
+	aid_t aid;
+	ipc_call_t result;
+	
+	assert(address != NULL);
 	
 	/* Request the address */
 	async_exch_t *exch = async_exchange_begin(sess);
-	aid_t aid = async_send_1(exch, message, (sysarg_t) device_id,
-	    NULL);
+	aid = async_send_1(exch, message, (sysarg_t) device_id, &result);
+	
+	sysarg_t ipcrc;
 	int rc = async_data_read_start(exch, address, max_len);
 	async_exchange_end(exch);
 	
-	sysarg_t result;
-	async_wait_for(aid, &result);
-	
-	if (rc != EOK)
+	if (rc != EOK) {
+		async_wait_for(aid, &ipcrc);
 		return rc;
-	
-	return (int) result;
+	}
+	
+	async_wait_for(aid, &ipcrc);
+	if (ipcrc == EOK) {
+		return IPC_GET_ARG1(result);
+	} else {
+		return (int) ipcrc;
+	}
 }
 
Index: uspace/lib/net/generic/packet_client.c
===================================================================
--- uspace/lib/net/generic/packet_client.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/net/generic/packet_client.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -39,5 +39,4 @@
 #include <unistd.h>
 #include <sys/mman.h>
-
 #include <packet_client.h>
 #include <packet_remote.h>
Index: uspace/lib/net/generic/packet_remote.c
===================================================================
--- uspace/lib/net/generic/packet_remote.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/net/generic/packet_remote.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -77,8 +77,6 @@
 	async_wait_for(message, &result);
 	
-	if (rc != EOK) {
-		munmap(*packet, size);
+	if (rc != EOK)
 		return rc;
-	}
 	
 	rc = pm_add(*packet);
Index: uspace/lib/net/tl/tl_common.c
===================================================================
--- uspace/lib/net/tl/tl_common.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/net/tl/tl_common.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -158,6 +158,5 @@
  * @return		ENOENT if the packet dimension is not cached.
  */
-int
-tl_update_ip_packet_dimension(packet_dimensions_t *packet_dimensions,
+int tl_update_ip_packet_dimension(packet_dimensions_t *packet_dimensions,
     nic_device_id_t device_id, size_t content)
 {
Index: uspace/lib/nic/include/nic.h
===================================================================
--- uspace/lib/nic/include/nic.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/nic/include/nic.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -275,6 +275,6 @@
 
 /* Packet DMA lock */
-extern void * nic_dma_lock_packet(packet_t * packet);
-extern void nic_dma_unlock_packet(packet_t * packet);
+extern int nic_dma_lock_packet(packet_t *, size_t, void **);
+extern int nic_dma_unlock_packet(packet_t *, size_t);
 
 #endif // __NIC_H__
Index: uspace/lib/nic/src/nic_driver.c
===================================================================
--- uspace/lib/nic/src/nic_driver.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/nic/src/nic_driver.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -46,5 +46,5 @@
 #include <ipc/irc.h>
 #include <sysinfo.h>
-
+#include <as.h>
 #include <devman.h>
 #include <ddf/interrupt.h>
@@ -1329,7 +1329,4 @@
 }
 
-// FIXME: Later
-#if 0
-
 /** Lock packet for DMA usage
  *
@@ -1337,14 +1334,7 @@
  * @return physical address of packet
  */
-void *nic_dma_lock_packet(packet_t *packet)
-{
-	void *phys_addr;
-	size_t locked;
-	int rc = dma_lock(packet, &phys_addr, 1, &locked);
-	if (rc != EOK)
-		return NULL;
-	
-	assert(locked == 1);
-	return phys_addr;
+int nic_dma_lock_packet(packet_t *packet, size_t size, void **phys)
+{
+	return dmamem_map(packet, SIZE2PAGES(size), 0, 0, phys);
 }
 
@@ -1353,15 +1343,8 @@
  * @param packet
  */
-void nic_dma_unlock_packet(packet_t *packet)
-{
-	size_t unlocked;
-	int rc = dma_unlock(packet, 1, &unlocked);
-	if (rc != EOK)
-		return;
-	
-	assert(unlocked == 1);
-}
-
-#endif
+int nic_dma_unlock_packet(packet_t *packet, size_t size)
+{
+	return dmamem_unmap(packet, size, 0);
+}
 
 /** @}
Index: uspace/lib/nic/src/nic_rx_control.c
===================================================================
--- uspace/lib/nic/src/nic_rx_control.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/nic/src/nic_rx_control.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -438,4 +438,5 @@
 		}
 	}
+	
 	/* Blocked source addresses */
 	if (rxc->block_sources) {
@@ -443,4 +444,5 @@
 			return false;
 	}
+	
 	/* VLAN filtering */
 	if (!rxc->vlan_exact && rxc->vlan_mask != NULL) {
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usb/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -31,4 +31,5 @@
 EXTRA_CFLAGS += \
 	-I$(LIBDRV_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
 	-Iinclude
 
Index: uspace/lib/usb/include/usb/ddfiface.h
===================================================================
--- uspace/lib/usb/include/usb/ddfiface.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usb/include/usb/ddfiface.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -39,16 +39,12 @@
 #include <usb_iface.h>
 
-int usb_iface_get_hc_handle_hub_impl(ddf_fun_t *, devman_handle_t *);
-int usb_iface_get_address_hub_impl(ddf_fun_t *, devman_handle_t,
-    usb_address_t *);
+int usb_iface_get_hc_handle_device_impl(ddf_fun_t *, devman_handle_t *);
+int usb_iface_get_my_address_forward_impl(ddf_fun_t *, usb_address_t *);
 extern usb_iface_t usb_iface_hub_impl;
 
-int usb_iface_get_hc_handle_hub_child_impl(ddf_fun_t *, devman_handle_t *);
-int usb_iface_get_address_hub_child_impl(ddf_fun_t *, devman_handle_t,
-    usb_address_t *);
+int usb_iface_get_my_address_from_device_data(ddf_fun_t *, usb_address_t *);
 extern usb_iface_t usb_iface_hub_child_impl;
 
 int usb_iface_get_hc_handle_hc_impl(ddf_fun_t *, devman_handle_t *);
-
 
 #endif
Index: uspace/lib/usb/include/usb/hc.h
===================================================================
--- uspace/lib/usb/include/usb/hc.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usb/include/usb/hc.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -62,5 +62,5 @@
     devman_handle_t *);
 
-usb_address_t usb_hc_get_address_by_handle(devman_handle_t);
+usb_address_t usb_get_address_by_handle(devman_handle_t);
 
 int usb_hc_find(devman_handle_t, devman_handle_t *);
Index: uspace/lib/usb/src/class.c
===================================================================
--- uspace/lib/usb/src/class.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usb/src/class.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -81,5 +81,5 @@
 			return "application";
 		case USB_CLASS_VENDOR_SPECIFIC:
-			return "vendor";
+			return "vendor-specific";
 		default:
 			return "unknown";
Index: uspace/lib/usb/src/ddfiface.c
===================================================================
--- uspace/lib/usb/src/ddfiface.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usb/src/ddfiface.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -36,20 +36,22 @@
 #include <devman.h>
 #include <async.h>
+#include <usb_iface.h>
 #include <usb/ddfiface.h>
 #include <usb/hc.h>
 #include <usb/debug.h>
+#include <usb/dev/hub.h>
 #include <errno.h>
 #include <assert.h>
 
 /** DDF interface for USB device, implementation for typical hub. */
-usb_iface_t  usb_iface_hub_impl = {
-	.get_hc_handle = usb_iface_get_hc_handle_hub_impl,
-	.get_address = usb_iface_get_address_hub_impl
+usb_iface_t usb_iface_hub_impl = {
+	.get_hc_handle = usb_iface_get_hc_handle_device_impl,
+	.get_my_address = usb_iface_get_my_address_forward_impl,
 };
 
 /** DDF interface for USB device, implementation for child of a typical hub. */
-usb_iface_t  usb_iface_hub_child_impl = {
-	.get_hc_handle = usb_iface_get_hc_handle_hub_child_impl,
-	.get_address = usb_iface_get_address_hub_child_impl
+usb_iface_t usb_iface_hub_child_impl = {
+	.get_hc_handle = usb_iface_get_hc_handle_device_impl,
+	.get_my_address = usb_iface_get_my_address_from_device_data,
 };
 
@@ -61,42 +63,8 @@
  * @return Error code.
  */
-int usb_iface_get_hc_handle_hub_impl(ddf_fun_t *fun, devman_handle_t *handle)
+int usb_iface_get_hc_handle_device_impl(ddf_fun_t *fun, devman_handle_t *handle)
 {
 	assert(fun);
 	return usb_hc_find(fun->handle, handle);
-}
-
-/** Get host controller handle, interface implementation for child of
- * a hub driver.
- *
- * @param[in] fun Device function the operation is running on.
- * @param[out] handle Storage for the host controller handle.
- * @return Error code.
- */
-int usb_iface_get_hc_handle_hub_child_impl(ddf_fun_t *fun,
-    devman_handle_t *handle)
-{
-	assert(fun != NULL);
-	
-	async_sess_t *parent_sess =
-	    devman_parent_device_connect(EXCHANGE_SERIALIZE, fun->handle,
-	    IPC_FLAG_BLOCKING);
-	if (!parent_sess)
-		return ENOMEM;
-	
-	async_exch_t *exch = async_exchange_begin(parent_sess);
-	
-	sysarg_t hc_handle;
-	int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &hc_handle);
-	
-	async_exchange_end(exch);
-	async_hangup(parent_sess);
-	
-	if (rc != EOK)
-		return rc;
-	
-	*handle = hc_handle;
-	return EOK;
 }
 
@@ -125,9 +93,9 @@
  * @return Error code.
  */
-int usb_iface_get_address_hub_impl(ddf_fun_t *fun, devman_handle_t handle,
+int usb_iface_get_my_address_forward_impl(ddf_fun_t *fun,
     usb_address_t *address)
 {
 	assert(fun);
-	
+
 	async_sess_t *parent_sess =
 	    devman_parent_device_connect(EXCHANGE_SERIALIZE, fun->handle,
@@ -135,25 +103,24 @@
 	if (!parent_sess)
 		return ENOMEM;
-	
+
 	async_exch_t *exch = async_exchange_begin(parent_sess);
-	
-	sysarg_t addr;
-	int rc = async_req_2_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_GET_ADDRESS, handle, &addr);
-	
+	if (!exch) {
+		async_hangup(parent_sess);
+		return ENOMEM;
+	}
+
+	const int ret = usb_get_my_address(exch, address);
+
 	async_exchange_end(exch);
 	async_hangup(parent_sess);
-	
-	if (rc != EOK)
-		return rc;
-	
-	if (address != NULL)
-		*address = (usb_address_t) addr;
-	
-	return EOK;
+
+	return ret;
 }
 
 /** Get USB device address, interface implementation for child of
  * a hub driver.
+ *
+ * This implementation eccepts 0 as valid handle and replaces it with fun's
+ * handle.
  *
  * @param[in] fun Device function the operation is running on.
@@ -162,11 +129,14 @@
  * @return Error code.
  */
-int usb_iface_get_address_hub_child_impl(ddf_fun_t *fun,
-    devman_handle_t handle, usb_address_t *address)
+int usb_iface_get_my_address_from_device_data(ddf_fun_t *fun,
+    usb_address_t *address)
 {
-	if (handle == 0) {
-		handle = fun->handle;
-	}
-	return usb_iface_get_address_hub_impl(fun, handle, address);
+	assert(fun);
+	assert(fun->driver_data);
+	usb_hub_attached_device_t *device = fun->driver_data;
+	assert(device->fun == fun);
+	if (address)
+		*address = device->address;
+	return EOK;
 }
 
Index: uspace/lib/usb/src/hc.c
===================================================================
--- uspace/lib/usb/src/hc.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usb/src/hc.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -153,18 +153,11 @@
 	if (!usb_hc_connection_is_opened(connection))
 		return ENOENT;
-	
+
 	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
-	
-	sysarg_t tmp;
-	int rc = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,
-	    address, &tmp);
-	
+	if (!exch)
+		return ENOMEM;
+	const int ret = usbhc_get_handle(exch, address, handle);
 	async_exchange_end(exch);
-	
-	if ((rc == EOK) && (handle != NULL))
-		*handle = tmp;
-	
-	return rc;
+	return ret;
 }
 
@@ -174,5 +167,5 @@
  * @return USB address or negative error code.
  */
-usb_address_t usb_hc_get_address_by_handle(devman_handle_t dev_handle)
+usb_address_t usb_get_address_by_handle(devman_handle_t dev_handle)
 {
 	async_sess_t *parent_sess =
@@ -181,19 +174,20 @@
 	if (!parent_sess)
 		return ENOMEM;
-	
+
 	async_exch_t *exch = async_exchange_begin(parent_sess);
-	
-	sysarg_t address;
-	int rc = async_req_2_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_GET_ADDRESS,
-	    dev_handle, &address);
-	
+	if (!exch) {
+		async_hangup(parent_sess);
+		return ENOMEM;
+	}
+	usb_address_t address;
+	const int ret = usb_get_my_address(exch, &address);
+
 	async_exchange_end(exch);
 	async_hangup(parent_sess);
-	
-	if (rc != EOK)
-		return rc;
-	
-	return (usb_address_t) address;
+
+	if (ret != EOK)
+		return ret;
+
+	return address;
 }
 
@@ -232,21 +226,16 @@
 	if (!parent_sess)
 		return ENOMEM;
-	
+
 	async_exch_t *exch = async_exchange_begin(parent_sess);
-	
-	devman_handle_t h;
-	int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
-	
+	if (!exch) {
+		async_hangup(parent_sess);
+		return ENOMEM;
+	}
+	const int ret = usb_get_hc_handle(exch, hc_handle);
+
 	async_exchange_end(exch);
 	async_hangup(parent_sess);
-	
-	if (rc != EOK)
-		return rc;
-	
-	if (hc_handle != NULL)
-		*hc_handle = h;
-	
-	return EOK;
+
+	return ret;
 }
 
Index: uspace/lib/usb/src/resolve.c
===================================================================
--- uspace/lib/usb/src/resolve.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usb/src/resolve.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -200,5 +200,5 @@
 		/* Try to get its address. */
 		if (!found_addr) {
-			dev_addr = usb_hc_get_address_by_handle(tmp_handle);
+			dev_addr = usb_get_address_by_handle(tmp_handle);
 			if (dev_addr >= 0) {
 				found_addr = true;
Index: uspace/lib/usbdev/include/usb/dev/dp.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/dp.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/include/usb/dev/dp.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -54,5 +54,5 @@
 } usb_dp_descriptor_nesting_t;
 
-extern usb_dp_descriptor_nesting_t usb_dp_standard_descriptor_nesting[];
+extern const usb_dp_descriptor_nesting_t usb_dp_standard_descriptor_nesting[];
 
 /** Descriptor parser structure. */
Index: uspace/lib/usbdev/include/usb/dev/driver.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/driver.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/include/usb/dev/driver.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -72,4 +72,8 @@
 /** USB device structure. */
 typedef struct {
+	/** Connection backing the pipes.
+	 * Typically, you will not need to use this attribute at all.
+	 */
+	usb_device_connection_t wire;
 	/** The default control pipe. */
 	usb_pipe_t ctrl_pipe;
@@ -87,14 +91,11 @@
 	int interface_no;
 
-	/** Alternative interfaces.
-	 * Set to NULL when the driver controls whole device
-	 * (i.e. more (or any) interfaces).
-	 */
-	usb_alternate_interfaces_t *alternate_interfaces;
+	/** Alternative interfaces. */
+	usb_alternate_interfaces_t alternate_interfaces;
 
 	/** Some useful descriptors. */
 	usb_device_descriptors_t descriptors;
 
-	/** Generic DDF device backing this one. RO: DO NOT TOUCH!*/
+	/** Generic DDF device backing this one. DO NOT TOUCH! */
 	ddf_dev_t *ddf_dev;
 	/** Custom driver data.
@@ -103,9 +104,4 @@
 	 */
 	void *driver_data;
-
-	/** Connection backing the pipes.
-	 * Typically, you will not need to use this attribute at all.
-	 */
-	usb_device_connection_t wire;
 } usb_device_t;
 
@@ -163,22 +159,25 @@
 int usb_driver_main(const usb_driver_t *);
 
+int usb_device_init(usb_device_t *, ddf_dev_t *,
+    const usb_endpoint_description_t **, const char **);
+void usb_device_deinit(usb_device_t *);
+
 int usb_device_select_interface(usb_device_t *, uint8_t,
     const usb_endpoint_description_t **);
 
 int usb_device_retrieve_descriptors(usb_pipe_t *, usb_device_descriptors_t *);
+void usb_device_release_descriptors(usb_device_descriptors_t *);
+
 int usb_device_create_pipes(const ddf_dev_t *, usb_device_connection_t *,
     const usb_endpoint_description_t **, const uint8_t *, size_t, int, int,
     usb_endpoint_mapping_t **, size_t *);
 int usb_device_destroy_pipes(const ddf_dev_t *, usb_endpoint_mapping_t *, size_t);
-int usb_device_init(usb_device_t *, ddf_dev_t *,
-    const usb_endpoint_description_t **, const char **);
-void usb_device_deinit(usb_device_t *);
 
 void * usb_device_data_alloc(usb_device_t *, size_t);
 
 size_t usb_interface_count_alternates(const uint8_t *, size_t, uint8_t);
-int usb_alternate_interfaces_create(const uint8_t *, size_t, int,
-    usb_alternate_interfaces_t **);
-void usb_alternate_interfaces_destroy(usb_alternate_interfaces_t *);
+int usb_alternate_interfaces_init(usb_alternate_interfaces_t *,
+    const uint8_t *, size_t, int);
+void usb_alternate_interfaces_deinit(usb_alternate_interfaces_t *);
 #endif
 /**
Index: uspace/lib/usbdev/include/usb/dev/hub.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/hub.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/include/usb/dev/hub.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -59,5 +59,6 @@
 } usb_hub_attached_device_t;
 
-usb_address_t usb_hc_request_address(usb_hc_connection_t *, usb_speed_t);
+usb_address_t usb_hc_request_address(usb_hc_connection_t *, usb_address_t,
+    bool, usb_speed_t);
 int usb_hc_register_device(usb_hc_connection_t *,
     const usb_hub_attached_device_t *);
Index: uspace/lib/usbdev/include/usb/dev/pipes.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/pipes.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/include/usb/dev/pipes.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -141,5 +141,5 @@
 typedef struct {
 	/** Endpoint pipe. */
-	usb_pipe_t *pipe;
+	usb_pipe_t pipe;
 	/** Endpoint description. */
 	const usb_endpoint_description_t *description;
@@ -149,7 +149,7 @@
 	int interface_setting;
 	/** Found descriptor fitting the description. */
-	usb_standard_endpoint_descriptor_t *descriptor;
+	const usb_standard_endpoint_descriptor_t *descriptor;
 	/** Interface descriptor the endpoint belongs to. */
-	usb_standard_interface_descriptor_t *interface;
+	const usb_standard_interface_descriptor_t *interface;
 	/** Whether the endpoint was actually found. */
 	bool present;
@@ -172,6 +172,4 @@
 int usb_pipe_initialize_from_configuration(usb_endpoint_mapping_t *,
     size_t, const uint8_t *, size_t, usb_device_connection_t *);
-int usb_pipe_register_with_speed(usb_pipe_t *, usb_speed_t,
-    unsigned int, usb_hc_connection_t *);
 int usb_pipe_register(usb_pipe_t *, unsigned int, usb_hc_connection_t *);
 int usb_pipe_unregister(usb_pipe_t *, usb_hc_connection_t *);
@@ -181,5 +179,5 @@
 
 int usb_pipe_read(usb_pipe_t *, void *, size_t, size_t *);
-int usb_pipe_write(usb_pipe_t *, void *, size_t);
+int usb_pipe_write(usb_pipe_t *, const void *, size_t);
 
 int usb_pipe_control_read(usb_pipe_t *, const void *, size_t,
Index: uspace/lib/usbdev/include/usb/dev/poll.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/poll.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/include/usb/dev/poll.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -84,6 +84,6 @@
 } usb_device_auto_polling_t;
 
-int usb_device_auto_polling(usb_device_t *, size_t, usb_device_auto_polling_t *,
-    size_t, void *);
+int usb_device_auto_polling(usb_device_t *, size_t,
+    const usb_device_auto_polling_t *, size_t, void *);
 
 typedef bool (*usb_polling_callback_t)(usb_device_t *,
Index: uspace/lib/usbdev/include/usb/dev/recognise.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/recognise.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/include/usb/dev/recognise.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -50,5 +50,5 @@
 int usb_device_create_match_ids(usb_pipe_t *, match_id_list_t *);
 
-int usb_device_register_child_in_devman(usb_address_t, devman_handle_t,
+int usb_device_register_child_in_devman(usb_pipe_t *ctrl_pipe,
     ddf_dev_t *, ddf_dev_ops_t *, void *, ddf_fun_t **);
 
Index: uspace/lib/usbdev/include/usb/dev/request.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/request.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/include/usb/dev/request.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -82,4 +82,6 @@
 	 */
 	uint8_t request_type;
+#define SETUP_REQUEST_TYPE_DEVICE_TO_HOST (1 << 7)
+
 	/** Request identification. */
 	uint8_t request;
@@ -115,7 +117,6 @@
 int usb_request_set_feature(usb_pipe_t *, usb_request_type_t,
     usb_request_recipient_t, uint16_t, uint16_t);
-int usb_request_set_address(usb_pipe_t *, usb_address_t);
 int usb_request_get_descriptor(usb_pipe_t *, usb_request_type_t,
-    usb_request_recipient_t, uint8_t, uint8_t, uint16_t, void *, size_t, 
+    usb_request_recipient_t, uint8_t, uint8_t, uint16_t, void *, size_t,
     size_t *);
 int usb_request_get_descriptor_alloc(usb_pipe_t *, usb_request_type_t,
@@ -131,4 +132,5 @@
 int usb_request_set_descriptor(usb_pipe_t *, usb_request_type_t,
     usb_request_recipient_t, uint8_t, uint8_t, uint16_t, void *, size_t);
+
 int usb_request_get_configuration(usb_pipe_t *, uint8_t *);
 int usb_request_set_configuration(usb_pipe_t *, uint8_t);
Index: uspace/lib/usbdev/src/altiface.c
===================================================================
--- uspace/lib/usbdev/src/altiface.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/src/altiface.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -65,13 +65,11 @@
 	size_t alternate_count = 0;
 
-	const uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
-	    &dp_data, config_descr);
+	const void *iface_ptr =
+	    usb_dp_get_nested_descriptor(&dp_parser, &dp_data, config_descr);
 	while (iface_ptr != NULL) {
-		usb_standard_interface_descriptor_t *iface
-		    = (usb_standard_interface_descriptor_t *) iface_ptr;
-		if (iface->descriptor_type == USB_DESCTYPE_INTERFACE) {
-			if (iface->interface_number == interface_no) {
-				alternate_count++;
-			}
+		const usb_standard_interface_descriptor_t *iface = iface_ptr;
+		if (iface->descriptor_type == USB_DESCTYPE_INTERFACE
+		    && iface->interface_number == interface_no) {
+			++alternate_count;
 		}
 		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
@@ -82,37 +80,33 @@
 }
 
-/** Create alternate interface representation structure.
+/** Initialize alternate interface representation structure.
  *
+ * @param[in] alternates Pointer to allocated structure.
  * @param[in] config_descr Configuration descriptor.
  * @param[in] config_descr_size Size of configuration descriptor.
  * @param[in] interface_number Interface number.
- * @param[out] alternates_ptr Where to store pointer to allocated structure.
  * @return Error code.
  */
-int usb_alternate_interfaces_create(const uint8_t *config_descr,
-    size_t config_descr_size, int interface_number,
-    usb_alternate_interfaces_t **alternates_ptr)
+int usb_alternate_interfaces_init(usb_alternate_interfaces_t *alternates,
+    const uint8_t *config_descr, size_t config_descr_size, int interface_number)
 {
-	assert(alternates_ptr != NULL);
+	assert(alternates != NULL);
 	assert(config_descr != NULL);
 	assert(config_descr_size > 0);
 
-	*alternates_ptr = NULL;
+	alternates->alternatives = NULL;
+	alternates->alternative_count = 0;
+	alternates->current = 0;
+
+	/* No interfaces. */
 	if (interface_number < 0) {
 		return EOK;
 	}
 
-	usb_alternate_interfaces_t *alternates
-	    = malloc(sizeof(usb_alternate_interfaces_t));
-	if (alternates == NULL) {
-		return ENOMEM;
-	}
-
 	alternates->alternative_count
 	    = usb_interface_count_alternates(config_descr, config_descr_size,
-	    interface_number);
+	        interface_number);
 
 	if (alternates->alternative_count == 0) {
-		free(alternates);
 		return ENOENT;
 	}
@@ -121,14 +115,11 @@
 	    sizeof(usb_alternate_interface_descriptors_t));
 	if (alternates->alternatives == NULL) {
-		free(alternates);
 		return ENOMEM;
 	}
 
-	alternates->current = 0;
-
-	usb_dp_parser_t dp_parser = {
+	const usb_dp_parser_t dp_parser = {
 		.nesting = usb_dp_standard_descriptor_nesting
 	};
-	usb_dp_parser_data_t dp_data = {
+	const usb_dp_parser_data_t dp_data = {
 		.data = config_descr,
 		.size = config_descr_size,
@@ -136,49 +127,49 @@
 	};
 
-	usb_alternate_interface_descriptors_t *cur_alt_iface
+	usb_alternate_interface_descriptors_t *iterator
 	    = &alternates->alternatives[0];
 
-	const uint8_t *iface_ptr = usb_dp_get_nested_descriptor(&dp_parser,
-	    &dp_data, dp_data.data);
-	while (iface_ptr != NULL) {
-		usb_standard_interface_descriptor_t *iface
-		    = (usb_standard_interface_descriptor_t *) iface_ptr;
+	const usb_alternate_interface_descriptors_t *end
+	    = &alternates->alternatives[alternates->alternative_count];
+
+	const void *iface_ptr =
+	    usb_dp_get_nested_descriptor(&dp_parser, &dp_data, dp_data.data);
+
+	while (iface_ptr != NULL && iterator < end) {
+		const usb_standard_interface_descriptor_t *iface = iface_ptr;
+
 		if ((iface->descriptor_type != USB_DESCTYPE_INTERFACE)
 		    || (iface->interface_number != interface_number)) {
+			/* This is not a valid alternate interface descriptor
+			 * for interface with number == interface_number. */
 			iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser,
-			    &dp_data,
-			    dp_data.data, iface_ptr);
+			    &dp_data, dp_data.data, iface_ptr);
 			continue;
 		}
 
-		cur_alt_iface->interface = iface;
-		cur_alt_iface->nested_descriptors = iface_ptr + sizeof(*iface);
+		iterator->interface = iface;
+		iterator->nested_descriptors = iface_ptr + sizeof(*iface);
 
 		/* Find next interface to count size of nested descriptors. */
 		iface_ptr = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
 		    dp_data.data, iface_ptr);
-		if (iface_ptr == NULL) {
-			const uint8_t *next = dp_data.data + dp_data.size;
-			cur_alt_iface->nested_descriptors_size
-			    = next - cur_alt_iface->nested_descriptors;
-		} else {
-			cur_alt_iface->nested_descriptors_size
-			    = iface_ptr - cur_alt_iface->nested_descriptors;
-		}
 
-		cur_alt_iface++;
+		const uint8_t *next = (iface_ptr == NULL) ?
+		    dp_data.data + dp_data.size : iface_ptr;
+
+		iterator->nested_descriptors_size
+		    = next - iterator->nested_descriptors;
+
+		++iterator;
 	}
-
-	*alternates_ptr = alternates;
 
 	return EOK;
 }
 
-void usb_alternate_interfaces_destroy(usb_alternate_interfaces_t *alternate)
+void usb_alternate_interfaces_deinit(usb_alternate_interfaces_t *alternate)
 {
 	if (!alternate)
 		return;
 	free(alternate->alternatives);
-	free(alternate);
 }
 /**
Index: uspace/lib/usbdev/src/devdrv.c
===================================================================
--- uspace/lib/usbdev/src/devdrv.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/src/devdrv.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -46,5 +46,5 @@
 
 static driver_ops_t generic_driver_ops = {
-	.add_device = generic_device_add,
+	.dev_add = generic_device_add,
 	.dev_remove = generic_device_remove,
 	.dev_gone = generic_device_gone,
@@ -81,15 +81,9 @@
  * @return Number of pipes (excluding default control pipe).
  */
-static size_t count_other_pipes(const usb_endpoint_description_t **endpoints)
-{
-	size_t count = 0;
-	if (endpoints == NULL) {
-		return 0;
-	}
-
-	while (endpoints[count] != NULL) {
-		count++;
-	}
-
+static inline size_t count_other_pipes(
+    const usb_endpoint_description_t **endpoints)
+{
+	size_t count;
+	for (count = 0; endpoints && endpoints[count] != NULL; ++count);
 	return count;
 }
@@ -104,4 +98,6 @@
     usb_device_t *dev, int alternate_setting)
 {
+	assert(dev);
+
 	if (endpoints == NULL) {
 		dev->pipes = NULL;
@@ -300,4 +296,15 @@
 
 	return rc;
+}
+
+/** Cleanup structure initialized via usb_device_retrieve_descriptors.
+ *
+ * @param[in] descriptors Where to store the descriptors.
+ */
+void usb_device_release_descriptors(usb_device_descriptors_t *descriptors)
+{
+	assert(descriptors);
+	free(descriptors->configuration);
+	descriptors->configuration = NULL;
 }
 
@@ -319,5 +326,5 @@
  *	(not NULL terminated).
  * @param[out] pipes_count_ptr Where to store number of pipes
- *	(set to if you wish to ignore the count).
+ *	(set to NULL if you wish to ignore the count).
  * @return Error code.
  */
@@ -340,5 +347,6 @@
 	const size_t pipe_count = count_other_pipes(endpoints);
 	if (pipe_count == 0) {
-		*pipes_count_ptr = pipe_count;
+		if (pipes_count_ptr)
+			*pipes_count_ptr = pipe_count;
 		*pipes_ptr = NULL;
 		return EOK;
@@ -346,21 +354,11 @@
 
 	usb_endpoint_mapping_t *pipes
-	    = malloc(sizeof(usb_endpoint_mapping_t) * pipe_count);
+	    = calloc(pipe_count, sizeof(usb_endpoint_mapping_t));
 	if (pipes == NULL) {
 		return ENOMEM;
 	}
 
-	/* Initialize to NULL to allow smooth rollback. */
-	for (i = 0; i < pipe_count; i++) {
-		pipes[i].pipe = NULL;
-	}
-
 	/* Now allocate and fully initialize. */
 	for (i = 0; i < pipe_count; i++) {
-		pipes[i].pipe = malloc(sizeof(usb_pipe_t));
-		if (pipes[i].pipe == NULL) {
-			rc = ENOMEM;
-			goto rollback_free_only;
-		}
 		pipes[i].description = endpoints[i];
 		pipes[i].interface_no = interface_no;
@@ -389,5 +387,5 @@
 	for (i = 0; i < pipe_count; i++) {
 		if (pipes[i].present) {
-			rc = usb_pipe_register(pipes[i].pipe,
+			rc = usb_pipe_register(&pipes[i].pipe,
 			    pipes[i].descriptor->poll_interval, &hc_conn);
 			if (rc != EOK) {
@@ -398,6 +396,6 @@
 
 	if (usb_hc_connection_close(&hc_conn) != EOK)
-		usb_log_warning("usb_device_create_pipes(): "
-		    "Failed to close connection.\n");
+		usb_log_warning("%s: Failed to close connection.\n",
+		    __FUNCTION__);
 
 	*pipes_ptr = pipes;
@@ -417,5 +415,5 @@
 	for (i = 0; i < pipe_count; i++) {
 		if (pipes[i].present) {
-			usb_pipe_unregister(pipes[i].pipe, &hc_conn);
+			usb_pipe_unregister(&pipes[i].pipe, &hc_conn);
 		}
 	}
@@ -431,9 +429,4 @@
 	 */
 rollback_free_only:
-	for (i = 0; i < pipe_count; i++) {
-		if (pipes[i].pipe != NULL) {
-			free(pipes[i].pipe);
-		}
-	}
 	free(pipes);
 
@@ -477,6 +470,5 @@
 		    i, pipes[i].present ? "" : "not ");
 		if (pipes[i].present)
-			usb_pipe_unregister(pipes[i].pipe, &hc_conn);
-		free(pipes[i].pipe);
+			usb_pipe_unregister(&pipes[i].pipe, &hc_conn);
 	}
 
@@ -489,32 +481,4 @@
 	return EOK;
 }
-
-/** Initialize control pipe in a device.
- *
- * @param dev USB device in question.
- * @param errmsg Where to store error context.
- * @return
- */
-static int init_wire_and_ctrl_pipe(usb_device_t *dev, const char **errmsg)
-{
-	int rc;
-
-	rc = usb_device_connection_initialize_from_device(&dev->wire,
-	    dev->ddf_dev);
-	if (rc != EOK) {
-		*errmsg = "device connection initialization";
-		return rc;
-	}
-
-	rc = usb_pipe_initialize_default_control(&dev->ctrl_pipe,
-	    &dev->wire);
-	if (rc != EOK) {
-		*errmsg = "default control pipe initialization";
-		return rc;
-	}
-
-	return EOK;
-}
-
 
 /** Initialize new instance of USB device.
@@ -533,14 +497,26 @@
 	assert(ddf_dev != NULL);
 
+	*errstr_ptr = NULL;
+
 	usb_dev->ddf_dev = ddf_dev;
 	usb_dev->driver_data = NULL;
 	usb_dev->descriptors.configuration = NULL;
-	usb_dev->alternate_interfaces = NULL;
 	usb_dev->pipes_count = 0;
 	usb_dev->pipes = NULL;
 
 	/* Initialize backing wire and control pipe. */
-	int rc = init_wire_and_ctrl_pipe(usb_dev, errstr_ptr);
-	if (rc != EOK) {
+	int rc = usb_device_connection_initialize_from_device(
+	    &usb_dev->wire, ddf_dev);
+	if (rc != EOK) {
+		*errstr_ptr = "device connection initialization";
+		return rc;
+	}
+
+	/* This pipe was registered by the hub driver,
+	 * during device initialization. */
+	rc = usb_pipe_initialize_default_control(&usb_dev->ctrl_pipe,
+	    &usb_dev->wire);
+	if (rc != EOK) {
+		*errstr_ptr = "default control pipe initialization";
 		return rc;
 	}
@@ -553,26 +529,28 @@
 	    &usb_dev->descriptors);
 	if (rc != EOK) {
-		/* Nothing allocated, nothing to free. */
 		*errstr_ptr = "descriptor retrieval";
 		return rc;
 	}
 
-	/* Create alternate interfaces. We will silently ignore failure. */
-	//TODO Why ignore?
-	usb_alternate_interfaces_create(usb_dev->descriptors.configuration,
-	    usb_dev->descriptors.configuration_size, usb_dev->interface_no,
-	    &usb_dev->alternate_interfaces);
-
-	rc = initialize_other_pipes(endpoints, usb_dev, 0);
+	/* Create alternate interfaces. We will silently ignore failure.
+	 * We might either control one interface or an entire device,
+	 * it makes no sense to speak about alternate interfaces when
+	 * controlling a device. */
+	rc = usb_alternate_interfaces_init(&usb_dev->alternate_interfaces,
+	    usb_dev->descriptors.configuration,
+	    usb_dev->descriptors.configuration_size, usb_dev->interface_no);
+	const int alternate_iface =
+	    (rc == EOK) ? usb_dev->alternate_interfaces.current : 0;
+
+	/* TODO Add comment here. */
+	rc = initialize_other_pipes(endpoints, usb_dev, alternate_iface);
 	if (rc != EOK) {
 		/* Full configuration descriptor is allocated. */
-		free(usb_dev->descriptors.configuration);
+		usb_device_release_descriptors(&usb_dev->descriptors);
 		/* Alternate interfaces may be allocated */
-		usb_alternate_interfaces_destroy(usb_dev->alternate_interfaces);
+		usb_alternate_interfaces_deinit(&usb_dev->alternate_interfaces);
 		*errstr_ptr = "pipes initialization";
 		return rc;
 	}
-
-	*errstr_ptr = NULL;
 
 	return EOK;
@@ -591,6 +569,6 @@
 		destroy_current_pipes(dev);
 
-		usb_alternate_interfaces_destroy(dev->alternate_interfaces);
-		free(dev->descriptors.configuration);
+		usb_alternate_interfaces_deinit(&dev->alternate_interfaces);
+		usb_device_release_descriptors(&dev->descriptors);
 		free(dev->driver_data);
 	}
Index: uspace/lib/usbdev/src/devpoll.c
===================================================================
--- uspace/lib/usbdev/src/devpoll.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/src/devpoll.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -46,11 +46,5 @@
 /** Data needed for polling. */
 typedef struct {
-	int debug;
-	size_t max_failures;
-	useconds_t delay;
-	bool auto_clear_halt;
-	bool (*on_data)(usb_device_t *, uint8_t *, size_t, void *);
-	void (*on_polling_end)(usb_device_t *, bool, void *);
-	bool (*on_error)(usb_device_t *, int, void *);
+	usb_device_auto_polling_t auto_polling;
 
 	usb_device_t *dev;
@@ -69,38 +63,38 @@
 static int polling_fibril(void *arg)
 {
-	polling_data_t *polling_data = (polling_data_t *) arg;
-	assert(polling_data);
+	assert(arg);
+	const polling_data_t *data = arg;
+	/* Helper to reduce typing. */
+	const usb_device_auto_polling_t *params = &data->auto_polling;
 
 	usb_pipe_t *pipe
-	    = polling_data->dev->pipes[polling_data->pipe_index].pipe;
-	
-	if (polling_data->debug > 0) {
-		usb_endpoint_mapping_t *mapping
-		    = &polling_data->dev->pipes[polling_data->pipe_index];
+	    = &data->dev->pipes[data->pipe_index].pipe;
+
+	if (params->debug > 0) {
+		const usb_endpoint_mapping_t *mapping
+		    = &data->dev->pipes[data->pipe_index];
 		usb_log_debug("Poll%p: started polling of `%s' - " \
 		    "interface %d (%s,%d,%d), %zuB/%zu.\n",
-		    polling_data,
-		    polling_data->dev->ddf_dev->name,
+		    data, data->dev->ddf_dev->name,
 		    (int) mapping->interface->interface_number,
 		    usb_str_class(mapping->interface->interface_class),
 		    (int) mapping->interface->interface_subclass,
 		    (int) mapping->interface->interface_protocol,
-		    polling_data->request_size, pipe->max_packet_size);
-	}
-
+		    data->request_size, pipe->max_packet_size);
+	}
+
+	usb_pipe_start_long_transfer(pipe);
 	size_t failed_attempts = 0;
-	while (failed_attempts <= polling_data->max_failures) {
-		int rc;
-
+	while (failed_attempts <= params->max_failures) {
 		size_t actual_size;
-		rc = usb_pipe_read(pipe, polling_data->buffer,
-		    polling_data->request_size, &actual_size);
-
-		if (polling_data->debug > 1) {
+		const int rc = usb_pipe_read(pipe, data->buffer,
+		    data->request_size, &actual_size);
+
+		if (params->debug > 1) {
 			if (rc == EOK) {
 				usb_log_debug(
 				    "Poll%p: received: '%s' (%zuB).\n",
-				    polling_data,
-				    usb_debug_str_buffer(polling_data->buffer,
+				    data,
+				    usb_debug_str_buffer(data->buffer,
 				        actual_size, 16),
 				    actual_size);
@@ -108,10 +102,10 @@
 				usb_log_debug(
 				    "Poll%p: polling failed: %s.\n",
-				    polling_data, str_error(rc));
+				    data, str_error(rc));
 			}
 		}
 
 		/* If the pipe stalled, we can try to reset the stall. */
-		if ((rc == ESTALL) && (polling_data->auto_clear_halt)) {
+		if ((rc == ESTALL) && (params->auto_clear_halt)) {
 			/*
 			 * We ignore error here as this is usually a futile
@@ -119,28 +113,24 @@
 			 */
 			usb_request_clear_endpoint_halt(
-			    &polling_data->dev->ctrl_pipe,
-			    pipe->endpoint_no);
+			    &data->dev->ctrl_pipe, pipe->endpoint_no);
 		}
 
 		if (rc != EOK) {
-			if (polling_data->on_error != NULL) {
-				bool cont = polling_data->on_error(
-				    polling_data->dev, rc,
-				    polling_data->custom_arg);
-				if (!cont) {
-					failed_attempts
-					    = polling_data->max_failures;
-				}
+			++failed_attempts;
+			const bool cont = (params->on_error == NULL) ? true :
+			    params->on_error(data->dev, rc, data->custom_arg);
+			if (!cont) {
+				failed_attempts = params->max_failures;
 			}
-			failed_attempts++;
 			continue;
 		}
 
 		/* We have the data, execute the callback now. */
-		bool carry_on = polling_data->on_data(polling_data->dev,
-		    polling_data->buffer, actual_size,
-		    polling_data->custom_arg);
+		assert(params->on_data);
+		const bool carry_on = params->on_data(
+		    data->dev, data->buffer, actual_size, data->custom_arg);
 
 		if (!carry_on) {
+			/* This is user requested abort, erases failures. */
 			failed_attempts = 0;
 			break;
@@ -151,29 +141,28 @@
 
 		/* Take a rest before next request. */
-		async_usleep(polling_data->delay);
-	}
-
-	if (polling_data->on_polling_end != NULL) {
-		polling_data->on_polling_end(polling_data->dev,
-		    failed_attempts > 0, polling_data->custom_arg);
-	}
-
-	if (polling_data->debug > 0) {
-		if (failed_attempts > 0) {
-			usb_log_error(
-			    "Polling of device `%s' terminated: %s.\n",
-			    polling_data->dev->ddf_dev->name,
-			    "recurring failures");
+		async_usleep(params->delay);
+	}
+
+	usb_pipe_end_long_transfer(pipe);
+
+	const bool failed = failed_attempts > 0;
+
+	if (params->on_polling_end != NULL) {
+		params->on_polling_end(data->dev, failed, data->custom_arg);
+	}
+
+	if (params->debug > 0) {
+		if (failed) {
+			usb_log_error("Polling of device `%s' terminated: "
+			    "recurring failures.\n", data->dev->ddf_dev->name);
 		} else {
-			usb_log_debug(
-			    "Polling of device `%s' terminated by user.\n",
-			    polling_data->dev->ddf_dev->name
-			);
+			usb_log_debug("Polling of device `%s' terminated: "
+			    "driver request.\n", data->dev->ddf_dev->name);
 		}
 	}
 
 	/* Free the allocated memory. */
-	free(polling_data->buffer);
-	free(polling_data);
+	free(data->buffer);
+	free(data);
 
 	return EOK;
@@ -202,35 +191,16 @@
     usb_polling_terminted_callback_t terminated_callback, void *arg)
 {
-	if ((dev == NULL) || (callback == NULL)) {
-		return EBADMEM;
-	}
-	if (request_size == 0) {
-		return EINVAL;
-	}
-	if ((dev->pipes[pipe_index].pipe->transfer_type != USB_TRANSFER_INTERRUPT)
-	    || (dev->pipes[pipe_index].pipe->direction != USB_DIRECTION_IN)) {
-		return EINVAL;
-	}
-
-	usb_device_auto_polling_t *auto_polling
-	    = malloc(sizeof(usb_device_auto_polling_t));
-	if (auto_polling == NULL) {
-		return ENOMEM;
-	}
-
-	auto_polling->debug = 1;
-	auto_polling->auto_clear_halt = true;
-	auto_polling->delay = 0;
-	auto_polling->max_failures = MAX_FAILED_ATTEMPTS;
-	auto_polling->on_data = callback;
-	auto_polling->on_polling_end = terminated_callback;
-	auto_polling->on_error = NULL;
-
-	int rc = usb_device_auto_polling(dev, pipe_index, auto_polling,
+	const usb_device_auto_polling_t auto_polling = {
+		.debug = 1,
+		.auto_clear_halt = true,
+		.delay = 0,
+		.max_failures = MAX_FAILED_ATTEMPTS,
+		.on_data = callback,
+		.on_polling_end = terminated_callback,
+		.on_error = NULL,
+	};
+
+	return usb_device_auto_polling(dev, pipe_index, &auto_polling,
 	   request_size, arg);
-
-	free(auto_polling);
-
-	return rc;
 }
 
@@ -253,19 +223,17 @@
  */
 int usb_device_auto_polling(usb_device_t *dev, size_t pipe_index,
-    usb_device_auto_polling_t *polling,
+    const usb_device_auto_polling_t *polling,
     size_t request_size, void *arg)
 {
-	if (dev == NULL) {
+	if ((dev == NULL) || (polling == NULL) || (polling->on_data == NULL)) {
 		return EBADMEM;
 	}
-	if (pipe_index >= dev->pipes_count) {
+
+	if (pipe_index >= dev->pipes_count || request_size == 0) {
 		return EINVAL;
 	}
-	if ((dev->pipes[pipe_index].pipe->transfer_type != USB_TRANSFER_INTERRUPT)
-	    || (dev->pipes[pipe_index].pipe->direction != USB_DIRECTION_IN)) {
+	if ((dev->pipes[pipe_index].pipe.transfer_type != USB_TRANSFER_INTERRUPT)
+	    || (dev->pipes[pipe_index].pipe.direction != USB_DIRECTION_IN)) {
 		return EINVAL;
-	}
-	if ((polling == NULL) || (polling->on_data == NULL)) {
-		return EBADMEM;
 	}
 
@@ -286,17 +254,12 @@
 	polling_data->custom_arg = arg;
 
-	polling_data->debug = polling->debug;
-	polling_data->max_failures = polling->max_failures;
-	if (polling->delay >= 0) {
-		polling_data->delay = (useconds_t) polling->delay;
-	} else {
-		polling_data->delay = (useconds_t) dev->pipes[pipe_index]
-		    .descriptor->poll_interval;
-	}
-	polling_data->auto_clear_halt = polling->auto_clear_halt;
-
-	polling_data->on_data = polling->on_data;
-	polling_data->on_polling_end = polling->on_polling_end;
-	polling_data->on_error = polling->on_error;
+	/* Copy provided settings. */
+	polling_data->auto_polling = *polling;
+
+	/* Negative value means use descriptor provided value. */
+	if (polling->delay < 0) {
+		polling_data->auto_polling.delay =
+		    (int) dev->pipes[pipe_index].descriptor->poll_interval;
+	}
 
 	fid_t fibril = fibril_create(polling_fibril, polling_data);
Index: uspace/lib/usbdev/src/dp.c
===================================================================
--- uspace/lib/usbdev/src/dp.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/src/dp.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -57,5 +57,5 @@
 
 /** Nesting of standard USB descriptors. */
-usb_dp_descriptor_nesting_t usb_dp_standard_descriptor_nesting[] = {
+const usb_dp_descriptor_nesting_t usb_dp_standard_descriptor_nesting[] = {
 	NESTING(CONFIGURATION, INTERFACE),
 	NESTING(INTERFACE, ENDPOINT),
Index: uspace/lib/usbdev/src/hub.c
===================================================================
--- uspace/lib/usbdev/src/hub.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/src/hub.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -66,4 +66,6 @@
  *
  * @param connection Opened connection to host controller.
+ * @param preferred Preferred SUB address.
+ * @param strict Fail if the preferred address is not avialable.
  * @param speed Speed of the new device (device that will be assigned
  *    the returned address).
@@ -71,21 +73,17 @@
  */
 usb_address_t usb_hc_request_address(usb_hc_connection_t *connection,
-    usb_speed_t speed)
+    usb_address_t preferred, bool strict, usb_speed_t speed)
 {
 	CHECK_CONNECTION(connection);
-	
+
 	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
-	
-	sysarg_t address;
-	int rc = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_REQUEST_ADDRESS, speed,
-	    &address);
-	
+	if (!exch)
+		return (usb_address_t)ENOMEM;
+
+	usb_address_t address = preferred;
+	const int ret = usbhc_request_address(exch, &address, strict, speed);
+
 	async_exchange_end(exch);
-	
-	if (rc != EOK)
-		return (usb_address_t) rc;
-	
-	return (usb_address_t) address;
+	return ret == EOK ? address : ret;
 }
 
@@ -96,19 +94,19 @@
  * @return Error code.
  */
-int usb_hc_register_device(usb_hc_connection_t * connection,
+int usb_hc_register_device(usb_hc_connection_t *connection,
     const usb_hub_attached_device_t *attached_device)
 {
 	CHECK_CONNECTION(connection);
-	
-	if (attached_device == NULL)
-		return EBADMEM;
-	
+	if (attached_device == NULL || attached_device->fun == NULL)
+		return EINVAL;
+
 	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
-	int rc = async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_BIND_ADDRESS,
+	if (!exch)
+		return ENOMEM;
+	const int ret = usbhc_bind_address(exch,
 	    attached_device->address, attached_device->fun->handle);
 	async_exchange_end(exch);
-	
-	return rc;
+
+	return ret;
 }
 
@@ -123,31 +121,60 @@
 {
 	CHECK_CONNECTION(connection);
-	
+
 	async_exch_t *exch = async_exchange_begin(connection->hc_sess);
-	int rc = async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_RELEASE_ADDRESS, address);
+	if (!exch)
+		return ENOMEM;
+	const int ret = usbhc_release_address(exch, address);
 	async_exchange_end(exch);
-	
-	return rc;
+
+	return ret;
 }
 
-
-static void unregister_control_endpoint_on_default_address(
-    usb_hc_connection_t *connection)
+/** Change address of connected device.
+ * This function automatically updates the backing connection to point to
+ * the new address. It also unregisterrs the old endpoint and registers
+ * a new one.
+ * This creates whole bunch of problems:
+ *  1. All pipes using this wire are broken because they are not
+ *     registered for new address
+ *  2. All other pipes for this device are using wrong address,
+ *     possibly targeting completely different device
+ *
+ * @param pipe Control endpoint pipe (session must be already started).
+ * @param new_address New USB address to be set (in native endianness).
+ * @return Error code.
+ */
+static int usb_request_set_address(usb_pipe_t *pipe, usb_address_t new_address,
+    usb_hc_connection_t *hc_conn)
 {
-	usb_device_connection_t dev_conn;
-	int rc = usb_device_connection_initialize_on_default_address(&dev_conn,
-	    connection);
-	if (rc != EOK) {
-		return;
-	}
-
-	usb_pipe_t ctrl_pipe;
-	rc = usb_pipe_initialize_default_control(&ctrl_pipe, &dev_conn);
-	if (rc != EOK) {
-		return;
-	}
-
-	usb_pipe_unregister(&ctrl_pipe, connection);
+	if ((new_address < 0) || (new_address >= USB11_ADDRESS_MAX)) {
+		return EINVAL;
+	}
+	assert(pipe);
+	assert(hc_conn);
+	assert(pipe->wire != NULL);
+
+	const uint16_t addr = uint16_host2usb((uint16_t)new_address);
+
+	int rc = usb_control_request_set(pipe,
+	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
+	    USB_DEVREQ_SET_ADDRESS, addr, 0, NULL, 0);
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	/* TODO: prevent others from accessing the wire now. */
+	if (usb_pipe_unregister(pipe, hc_conn) != EOK) {
+		usb_log_warning(
+		    "Failed to unregister the old pipe on address change.\n");
+	}
+	/* The address is already changed so set it in the wire */
+	pipe->wire->address = new_address;
+	rc = usb_pipe_register(pipe, 0, hc_conn);
+	if (rc != EOK)
+		return EADDRNOTAVAIL;
+
+	return EOK;
 }
 
@@ -171,5 +198,5 @@
  *
  * @param[in] parent Parent device (i.e. the hub device).
- * @param[in] connection Connection to host controller.
+ * @param[in] connection Connection to host controller. Must be non-null.
  * @param[in] dev_speed New device speed.
  * @param[in] enable_port Function for enabling signaling through the port the
@@ -177,10 +204,12 @@
  * @param[in] arg Any data argument to @p enable_port.
  * @param[out] assigned_address USB address of the device.
- * @param[in] dev_ops Child device ops.
+ * @param[in] dev_ops Child device ops. Will use default if not provided.
  * @param[in] new_dev_data Arbitrary pointer to be stored in the child
- *	as @c driver_data.
+ *	as @c driver_data. Will allocate and assign usb_hub_attached_device_t
+ *	structure if NULL.
  * @param[out] new_fun Storage where pointer to allocated child function
- *	will be written.
+ *	will be written. Must be non-null.
  * @return Error code.
+ * @retval EINVAL Either connection or new_fun is a NULL pointer.
  * @retval ENOENT Connection to HC not opened.
  * @retval EADDRNOTAVAIL Failed retrieving free address from host controller.
@@ -190,15 +219,15 @@
  *	request or requests for descriptors when creating match ids).
  */
-int usb_hc_new_device_wrapper(ddf_dev_t *parent, usb_hc_connection_t *connection,
-    usb_speed_t dev_speed,
+int usb_hc_new_device_wrapper(ddf_dev_t *parent,
+    usb_hc_connection_t *connection, usb_speed_t dev_speed,
     int (*enable_port)(void *arg), void *arg, usb_address_t *assigned_address,
     ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun)
 {
-	assert(connection != NULL);
-	// FIXME: this is awful, we are accessing directly the structure.
-	usb_hc_connection_t hc_conn = {
-		.hc_handle = connection->hc_handle,
-		.hc_sess = NULL
-	};
+	if (new_fun == NULL || connection == NULL)
+		return EINVAL;
+
+	// TODO: Why not use provided connection?
+	usb_hc_connection_t hc_conn;
+	usb_hc_connection_initialize(&hc_conn, connection->hc_handle);
 
 	int rc;
@@ -214,10 +243,10 @@
 		return rc;
 	}
-
 
 	/*
 	 * Request new address.
 	 */
-	usb_address_t dev_addr = usb_hc_request_address(&hc_conn, dev_speed);
+	usb_address_t dev_addr =
+	    usb_hc_request_address(&hc_conn, 0, false, dev_speed);
 	if (dev_addr < 0) {
 		rc = EADDRNOTAVAIL;
@@ -240,6 +269,5 @@
 
 	usb_pipe_t ctrl_pipe;
-	rc = usb_pipe_initialize_default_control(&ctrl_pipe,
-	    &dev_conn);
+	rc = usb_pipe_initialize_default_control(&ctrl_pipe, &dev_conn);
 	if (rc != EOK) {
 		rc = ENOTCONN;
@@ -248,11 +276,22 @@
 
 	do {
-		rc = usb_pipe_register_with_speed(&ctrl_pipe, dev_speed, 0,
-		    &hc_conn);
-		if (rc != EOK) {
+		rc = usb_hc_request_address(&hc_conn, USB_ADDRESS_DEFAULT,
+		    true, dev_speed);
+		if (rc == ENOENT) {
 			/* Do not overheat the CPU ;-). */
 			async_usleep(ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC);
 		}
-	} while (rc != EOK);
+	} while (rc == ENOENT);
+	if (rc < 0) {
+		goto leave_release_free_address;
+	}
+
+	/* Register control pipe on default address. */
+	rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
+	if (rc != EOK) {
+		rc = ENOTCONN;
+		goto leave_release_default_address;
+	}
+
 	struct timeval end_time;
 
@@ -267,13 +306,10 @@
 	 * above might use much of this time so we should only wait to fill
 	 * up the 100ms quota*/
-	suseconds_t elapsed = tv_sub(&end_time, &start_time);
+	const suseconds_t elapsed = tv_sub(&end_time, &start_time);
 	if (elapsed < 100000) {
 		async_usleep(100000 - elapsed);
 	}
 
-	/*
-	 * Endpoint is registered. We can enable the port and change
-	 * device address.
-	 */
+	/* Endpoint is registered. We can enable the port and change address. */
 	rc = enable_port(arg);
 	if (rc != EOK) {
@@ -287,4 +323,5 @@
 	async_usleep(10000);
 
+	/* Get max_packet_size value. */
 	rc = usb_pipe_probe_default_control(&ctrl_pipe);
 	if (rc != EOK) {
@@ -293,5 +330,5 @@
 	}
 
-	rc = usb_request_set_address(&ctrl_pipe, dev_addr);
+	rc = usb_request_set_address(&ctrl_pipe, dev_addr, &hc_conn);
 	if (rc != EOK) {
 		rc = ESTALL;
@@ -299,53 +336,40 @@
 	}
 
-	/*
-	 * Address changed. We can release the original endpoint, thus
-	 * allowing other to access the default address.
-	 */
-	unregister_control_endpoint_on_default_address(&hc_conn);
-
-	/*
-	 * Time to register the new endpoint.
-	 */
-	rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
-	if (rc != EOK) {
-		goto leave_release_free_address;
-	}
-
-	/*
-	 * It is time to register the device with devman.
-	 */
+	/* Address changed. We can release the default, thus
+	 * allowing other to access the default address. */
+	usb_hc_unregister_device(&hc_conn, USB_ADDRESS_DEFAULT);
+
+	/* Register the device with devman. */
 	/* FIXME: create device_register that will get opened ctrl pipe. */
 	ddf_fun_t *child_fun;
-	rc = usb_device_register_child_in_devman(dev_addr, dev_conn.hc_handle,
+	rc = usb_device_register_child_in_devman(&ctrl_pipe,
 	    parent, dev_ops, new_dev_data, &child_fun);
 	if (rc != EOK) {
-		rc = ESTALL;
 		goto leave_release_free_address;
 	}
 
-	/*
-	 * And now inform the host controller about the handle.
-	 */
-	usb_hub_attached_device_t new_device = {
+	const usb_hub_attached_device_t new_device = {
 		.address = dev_addr,
 		.fun = child_fun,
 	};
+
+
+	/* Inform the host controller about the handle. */
 	rc = usb_hc_register_device(&hc_conn, &new_device);
 	if (rc != EOK) {
+		/* We know nothing about that data. */
+		if (new_dev_data)
+			child_fun->driver_data = NULL;
+		/* The child function is already created. */
+		ddf_fun_destroy(child_fun);
 		rc = EDESTADDRREQ;
 		goto leave_release_free_address;
 	}
 
-
-	/*
-	 * And we are done.
-	 */
 	if (assigned_address != NULL) {
 		*assigned_address = dev_addr;
 	}
-	if (new_fun != NULL) {
-		*new_fun = child_fun;
-	}
+
+	*new_fun = child_fun;
 
 	rc = EOK;
@@ -357,13 +381,20 @@
 	 */
 leave_release_default_address:
-	usb_pipe_unregister(&ctrl_pipe, &hc_conn);
+	usb_hc_unregister_device(&hc_conn, USB_ADDRESS_DEFAULT);
 
 leave_release_free_address:
-	usb_hc_unregister_device(&hc_conn, dev_addr);
+	/* This might be either 0:0 or dev_addr:0 */
+	if (usb_pipe_unregister(&ctrl_pipe, &hc_conn) != EOK)
+		usb_log_warning("%s: Failed to unregister default pipe.\n",
+		    __FUNCTION__);
+
+	if (usb_hc_unregister_device(&hc_conn, dev_addr) != EOK)
+		usb_log_warning("%s: Failed to unregister device.\n",
+		    __FUNCTION__);
 
 close_connection:
 	if (usb_hc_connection_close(&hc_conn) != EOK)
-		usb_log_warning("usb_hc_new_device_wrapper(): Failed to close "
-		    "connection.\n");
+		usb_log_warning("%s: Failed to close hc connection.\n",
+		    __FUNCTION__);
 
 	return rc;
Index: uspace/lib/usbdev/src/pipepriv.c
===================================================================
--- uspace/lib/usbdev/src/pipepriv.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/src/pipepriv.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -87,4 +87,5 @@
 	
 	if (pipe->refcount == 0) {
+		assert(pipe->hc_sess == NULL);
 		/* Need to open the phone by ourselves. */
 		async_sess_t *sess =
Index: uspace/lib/usbdev/src/pipes.c
===================================================================
--- uspace/lib/usbdev/src/pipes.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/src/pipes.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -54,21 +54,15 @@
 static usb_address_t get_my_address(async_sess_t *sess, const ddf_dev_t *dev)
 {
+	assert(sess);
 	async_exch_t *exch = async_exchange_begin(sess);
-	
-	/*
-	 * We are sending special value as a handle - zero - to get
-	 * handle of the parent function (that handle was used
-	 * when registering our device @p dev.
-	 */
-	sysarg_t address;
-	int rc = async_req_2_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_GET_ADDRESS, 0, &address);
-	
+	if (!exch)
+		return ENOMEM;
+
+	usb_address_t address;
+	const int ret = usb_get_my_address(exch, &address);
+
 	async_exchange_end(exch);
-	
-	if (rc != EOK)
-		return rc;
-	
-	return (usb_address_t) address;
+
+	return (ret == EOK) ? address : ret;
 }
 
@@ -76,27 +70,25 @@
  *
  * @param device Device in question.
- * @return Interface number (negative code means any).
+ * @return Error code (ENOTSUP means any).
  */
 int usb_device_get_assigned_interface(const ddf_dev_t *device)
 {
+	assert(device);
 	async_sess_t *parent_sess =
 	    devman_parent_device_connect(EXCHANGE_ATOMIC, device->handle,
 	    IPC_FLAG_BLOCKING);
 	if (!parent_sess)
-		return -1;
-	
+		return ENOMEM;
+
 	async_exch_t *exch = async_exchange_begin(parent_sess);
-	
-	sysarg_t iface_no;
-	int rc = async_req_2_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
-	    IPC_M_USB_GET_INTERFACE, device->handle, &iface_no);
-	
-	async_exchange_end(exch);
-	async_hangup(parent_sess);
-	
-	if (rc != EOK)
-		return -1;
-	
-	return (int) iface_no;
+	if (!exch) {
+		async_hangup(parent_sess);
+		return ENOMEM;
+	}
+
+	int iface_no;
+	const int ret = usb_get_my_interface(exch, &iface_no);
+
+	return ret == EOK ? iface_no : ret;
 }
 
Index: uspace/lib/usbdev/src/pipesinit.c
===================================================================
--- uspace/lib/usbdev/src/pipesinit.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/src/pipesinit.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -54,5 +54,5 @@
 
 /** Nesting pairs of standard descriptors. */
-static usb_dp_descriptor_nesting_t descriptor_nesting[] = {
+static const usb_dp_descriptor_nesting_t descriptor_nesting[] = {
 	NESTING(CONFIGURATION, INTERFACE),
 	NESTING(INTERFACE, ENDPOINT),
@@ -192,12 +192,9 @@
 	}
 
-	if (ep_mapping->pipe == NULL) {
-		return EBADMEM;
-	}
 	if (ep_mapping->present) {
 		return EEXISTS;
 	}
 
-	int rc = usb_pipe_initialize(ep_mapping->pipe, wire,
+	int rc = usb_pipe_initialize(&ep_mapping->pipe, wire,
 	    ep_no, description.transfer_type, endpoint->max_packet_size,
 	    description.direction);
@@ -254,5 +251,5 @@
  *
  * The mapping array is expected to conform to following rules:
- * - @c pipe must point to already allocated structure with uninitialized pipe
+ * - @c pipe must be uninitialized pipe
  * - @c description must point to prepared endpoint description
  * - @c descriptor does not need to be initialized (will be overwritten)
@@ -297,9 +294,6 @@
 	}
 
-	/*
-	 * Go through the mapping and set all endpoints to not present.
-	 */
-	size_t i;
-	for (i = 0; i < mapping_count; i++) {
+	/* Go through the mapping and set all endpoints to not present. */
+	for (size_t i = 0; i < mapping_count; i++) {
 		mapping[i].present = false;
 		mapping[i].descriptor = NULL;
@@ -307,7 +301,5 @@
 	}
 
-	/*
-	 * Prepare the descriptor parser.
-	 */
+	/* Prepare the descriptor parser. */
 	const usb_dp_parser_t dp_parser = {
 		.nesting = descriptor_nesting
@@ -413,9 +405,4 @@
 	}
 
-#define TRY_LOOP(attempt_var) \
-	for (attempt_var = 0; attempt_var < 3; attempt_var++)
-
-	size_t failed_attempts;
-	int rc;
 
 	usb_pipe_start_long_transfer(pipe);
@@ -423,5 +410,6 @@
 	uint8_t dev_descr_start[CTRL_PIPE_MIN_PACKET_SIZE];
 	size_t transferred_size;
-	TRY_LOOP(failed_attempts) {
+	int rc;
+	for (size_t attempt_var = 0; attempt_var < 3; ++attempt_var) {
 		rc = usb_request_get_descriptor(pipe, USB_REQUEST_TYPE_STANDARD,
 		    USB_REQUEST_RECIPIENT_DEVICE, USB_DESCTYPE_DEVICE,
@@ -454,60 +442,5 @@
  * @return Error code.
  */
-int usb_pipe_register(usb_pipe_t *pipe,
-    unsigned int interval,
-    usb_hc_connection_t *hc_connection)
-{
-	return usb_pipe_register_with_speed(pipe, USB_SPEED_MAX + 1,
-	    interval, hc_connection);
-}
-
-/** Register endpoint with a speed at the host controller.
- *
- * You will rarely need to use this function because it is needed only
- * if the registered endpoint is of address 0 and there is no other way
- * to tell speed of the device at address 0.
- *
- * @param pipe Pipe to be registered.
- * @param speed Speed of the device
- *	(invalid speed means use previously specified one).
- * @param interval Polling interval.
- * @param hc_connection Connection to the host controller (must be opened).
- * @return Error code.
- */
-int usb_pipe_register_with_speed(usb_pipe_t *pipe, usb_speed_t speed,
-    unsigned int interval,
-    usb_hc_connection_t *hc_connection)
-{
-	assert(pipe);
-	assert(hc_connection);
-	
-	if (!usb_hc_connection_is_opened(hc_connection))
-		return EBADF;
-	
-	const usb_target_t target =
-	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
-#define _PACK2(high, low) (((high) << 16) + (low))
-#define _PACK3(high, middle, low) (((((high) << 8) + (middle)) << 8) + (low))
-	
-	async_exch_t *exch = async_exchange_begin(hc_connection->hc_sess);
-	int rc = async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_REGISTER_ENDPOINT, target.packed,
-	    _PACK3(speed, pipe->transfer_type, pipe->direction),
-	    _PACK2(pipe->max_packet_size, interval));
-	async_exchange_end(exch);
-	
-#undef _PACK2
-#undef _PACK3
-	
-	return rc;
-}
-
-/** Revert endpoint registration with the host controller.
- *
- * @param pipe Pipe to be unregistered.
- * @param hc_connection Connection to the host controller (must be opened).
- * @return Error code.
- */
-int usb_pipe_unregister(usb_pipe_t *pipe,
+int usb_pipe_register(usb_pipe_t *pipe, unsigned interval,
     usb_hc_connection_t *hc_connection)
 {
@@ -515,15 +448,42 @@
 	assert(pipe->wire);
 	assert(hc_connection);
-	
+
 	if (!usb_hc_connection_is_opened(hc_connection))
 		return EBADF;
-	
 	async_exch_t *exch = async_exchange_begin(hc_connection->hc_sess);
-	int rc = async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_UNREGISTER_ENDPOINT,
+	if (!exch)
+		return ENOMEM;
+	const int ret = usbhc_register_endpoint(exch,
+	    pipe->wire->address, pipe->endpoint_no, pipe->transfer_type,
+	    pipe->direction, pipe->max_packet_size, interval);
+
+	async_exchange_end(exch);
+	return ret;
+}
+
+/** Revert endpoint registration with the host controller.
+ *
+ * @param pipe Pipe to be unregistered.
+ * @param hc_connection Connection to the host controller (must be opened).
+ * @return Error code.
+ */
+int usb_pipe_unregister(usb_pipe_t *pipe,
+    usb_hc_connection_t *hc_connection)
+{
+	assert(pipe);
+	assert(pipe->wire);
+	assert(hc_connection);
+
+	if (!usb_hc_connection_is_opened(hc_connection))
+		return EBADF;
+
+	async_exch_t *exch = async_exchange_begin(hc_connection->hc_sess);
+	if (!exch)
+		return ENOMEM;
+	const int ret = usbhc_unregister_endpoint(exch,
 	    pipe->wire->address, pipe->endpoint_no, pipe->direction);
 	async_exchange_end(exch);
-	
-	return rc;
+
+	return ret;
 }
 
Index: uspace/lib/usbdev/src/pipesio.c
===================================================================
--- uspace/lib/usbdev/src/pipesio.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/src/pipesio.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -62,135 +62,34 @@
  * @return Error code.
  */
-static int usb_pipe_read_no_checks(usb_pipe_t *pipe,
+static int usb_pipe_read_no_check(usb_pipe_t *pipe, uint64_t setup,
     void *buffer, size_t size, size_t *size_transfered)
 {
-	/* Only interrupt and bulk transfers are supported */
+	/* Isochronous transfer are not supported (yet) */
 	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
-	    pipe->transfer_type != USB_TRANSFER_BULK)
+	    pipe->transfer_type != USB_TRANSFER_BULK &&
+	    pipe->transfer_type != USB_TRANSFER_CONTROL)
 	    return ENOTSUP;
 
-	const usb_target_t target =
-	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
-	
+	int ret = pipe_add_ref(pipe, false);
+	if (ret != EOK) {
+		return ret;
+	}
+
 	/* Ensure serialization over the phone. */
 	pipe_start_transaction(pipe);
 	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	
-	/*
-	 * Make call identifying target USB device and type of transfer.
-	 */
-	aid_t opening_request = async_send_2(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_READ, target.packed, NULL);
-	
-	if (opening_request == 0) {
-		async_exchange_end(exch);
+	if (!exch) {
 		pipe_end_transaction(pipe);
+		pipe_drop_ref(pipe);
 		return ENOMEM;
 	}
-	
-	/*
-	 * Retrieve the data.
-	 */
-	ipc_call_t data_request_call;
-	aid_t data_request = async_data_read(exch, buffer, size,
-	    &data_request_call);
-	
-	/*
-	 * Since now on, someone else might access the backing phone
-	 * without breaking the transfer IPC protocol.
-	 */
+
+	ret = usbhc_read(exch, pipe->wire->address, pipe->endpoint_no,
+	    setup, buffer, size, size_transfered);
 	async_exchange_end(exch);
 	pipe_end_transaction(pipe);
-	
-	if (data_request == 0) {
-		/*
-		 * FIXME:
-		 * How to let the other side know that we want to abort?
-		 */
-		async_wait_for(opening_request, NULL);
-		return ENOMEM;
-	}
-	
-	/*
-	 * Wait for the answer.
-	 */
-	sysarg_t data_request_rc;
-	sysarg_t opening_request_rc;
-	async_wait_for(data_request, &data_request_rc);
-	async_wait_for(opening_request, &opening_request_rc);
-	
-	if (data_request_rc != EOK) {
-		/* Prefer the return code of the opening request. */
-		if (opening_request_rc != EOK) {
-			return (int) opening_request_rc;
-		} else {
-			return (int) data_request_rc;
-		}
-	}
-	if (opening_request_rc != EOK) {
-		return (int) opening_request_rc;
-	}
-	
-	*size_transfered = IPC_GET_ARG2(data_request_call);
-	
-	return EOK;
-}
-
-
-/** Request a read (in) transfer on an endpoint pipe.
- *
- * @param[in] pipe Pipe used for the transfer.
- * @param[out] buffer Buffer where to store the data.
- * @param[in] size Size of the buffer (in bytes).
- * @param[out] size_transfered Number of bytes that were actually transfered.
- * @return Error code.
- */
-int usb_pipe_read(usb_pipe_t *pipe,
-    void *buffer, size_t size, size_t *size_transfered)
-{
-	assert(pipe);
-
-	if (buffer == NULL) {
-		return EINVAL;
-	}
-
-	if (size == 0) {
-		return EINVAL;
-	}
-
-	if (pipe->direction != USB_DIRECTION_IN) {
-		return EBADF;
-	}
-
-	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
-		return EBADF;
-	}
-
-	int rc;
-	rc = pipe_add_ref(pipe, false);
-	if (rc != EOK) {
-		return rc;
-	}
-
-
-	size_t act_size = 0;
-
-	rc = usb_pipe_read_no_checks(pipe, buffer, size, &act_size);
-
 	pipe_drop_ref(pipe);
-
-	if (rc != EOK) {
-		return rc;
-	}
-
-	if (size_transfered != NULL) {
-		*size_transfered = act_size;
-	}
-
-	return EOK;
-}
-
-
-
+	return ret;
+}
 
 /** Request an out transfer, no checking of input parameters.
@@ -201,97 +100,32 @@
  * @return Error code.
  */
-static int usb_pipe_write_no_check(usb_pipe_t *pipe,
-    void *buffer, size_t size)
+static int usb_pipe_write_no_check(usb_pipe_t *pipe, uint64_t setup,
+    const void *buffer, size_t size)
 {
 	/* Only interrupt and bulk transfers are supported */
 	if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
-	    pipe->transfer_type != USB_TRANSFER_BULK)
+	    pipe->transfer_type != USB_TRANSFER_BULK &&
+	    pipe->transfer_type != USB_TRANSFER_CONTROL)
 	    return ENOTSUP;
 
-	const usb_target_t target =
-	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
+	int ret = pipe_add_ref(pipe, false);
+	if (ret != EOK) {
+		return ret;
+	}
 
 	/* Ensure serialization over the phone. */
 	pipe_start_transaction(pipe);
 	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	
-	/*
-	 * Make call identifying target USB device and type of transfer.
-	 */
-	aid_t opening_request = async_send_3(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_WRITE, target.packed, size, NULL);
-	
-	if (opening_request == 0) {
-		async_exchange_end(exch);
+	if (!exch) {
 		pipe_end_transaction(pipe);
+		pipe_drop_ref(pipe);
 		return ENOMEM;
 	}
-	
-	/*
-	 * Send the data.
-	 */
-	int rc = async_data_write_start(exch, buffer, size);
-	
-	/*
-	 * Since now on, someone else might access the backing phone
-	 * without breaking the transfer IPC protocol.
-	 */
+	ret = usbhc_write(exch, pipe->wire->address, pipe->endpoint_no,
+	    setup, buffer, size);
 	async_exchange_end(exch);
 	pipe_end_transaction(pipe);
-	
-	if (rc != EOK) {
-		async_wait_for(opening_request, NULL);
-		return rc;
-	}
-	
-	/*
-	 * Wait for the answer.
-	 */
-	sysarg_t opening_request_rc;
-	async_wait_for(opening_request, &opening_request_rc);
-	
-	return (int) opening_request_rc;
-}
-
-/** Request a write (out) transfer on an endpoint pipe.
- *
- * @param[in] pipe Pipe used for the transfer.
- * @param[in] buffer Buffer with data to transfer.
- * @param[in] size Size of the buffer (in bytes).
- * @return Error code.
- */
-int usb_pipe_write(usb_pipe_t *pipe,
-    void *buffer, size_t size)
-{
-	assert(pipe);
-
-	if (buffer == NULL) {
-		return EINVAL;
-	}
-
-	if (size == 0) {
-		return EINVAL;
-	}
-
-	if (pipe->direction != USB_DIRECTION_OUT) {
-		return EBADF;
-	}
-
-	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
-		return EBADF;
-	}
-
-	int rc;
-
-	rc = pipe_add_ref(pipe, false);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	rc = usb_pipe_write_no_check(pipe, buffer, size);
-
 	pipe_drop_ref(pipe);
-
-	return rc;
+	return ret;
 }
 
@@ -309,5 +143,5 @@
 
 
-	/* Prevent indefinite recursion. */
+	/* Prevent infinite recursion. */
 	pipe->auto_reset_halt = false;
 	usb_request_clear_endpoint_halt(pipe, 0);
@@ -315,6 +149,7 @@
 }
 
-
-/** Request a control read transfer, no checking of input parameters.
+/** Request a control read transfer on an endpoint pipe.
+ *
+ * This function encapsulates all three stages of a control transfer.
  *
  * @param[in] pipe Pipe used for the transfer.
@@ -327,87 +162,4 @@
  * @return Error code.
  */
-static int usb_pipe_control_read_no_check(usb_pipe_t *pipe,
-    const void *setup_buffer, size_t setup_buffer_size,
-    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
-{
-	/* Ensure serialization over the phone. */
-	pipe_start_transaction(pipe);
-
-	const usb_target_t target =
-	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
-
-	assert(setup_buffer_size == 8);
-	uint64_t setup_packet;
-	memcpy(&setup_packet, setup_buffer, 8);
-	/*
-	 * Make call identifying target USB device and control transfer type.
-	 */
-	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	aid_t opening_request = async_send_4(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_READ, target.packed,
-	    (setup_packet & UINT32_MAX), (setup_packet >> 32), NULL);
-
-	if (opening_request == 0) {
-		async_exchange_end(exch);
-		return ENOMEM;
-	}
-
-	/*
-	 * Retrieve the data.
-	 */
-	ipc_call_t data_request_call;
-	aid_t data_request = async_data_read(exch, data_buffer,
-	    data_buffer_size, &data_request_call);
-	
-	/*
-	 * Since now on, someone else might access the backing phone
-	 * without breaking the transfer IPC protocol.
-	 */
-	async_exchange_end(exch);
-	pipe_end_transaction(pipe);
-	
-	if (data_request == 0) {
-		async_wait_for(opening_request, NULL);
-		return ENOMEM;
-	}
-
-	/*
-	 * Wait for the answer.
-	 */
-	sysarg_t data_request_rc;
-	sysarg_t opening_request_rc;
-	async_wait_for(data_request, &data_request_rc);
-	async_wait_for(opening_request, &opening_request_rc);
-
-	if (data_request_rc != EOK) {
-		/* Prefer the return code of the opening request. */
-		if (opening_request_rc != EOK) {
-			return (int) opening_request_rc;
-		} else {
-			return (int) data_request_rc;
-		}
-	}
-	if (opening_request_rc != EOK) {
-		return (int) opening_request_rc;
-	}
-
-	*data_transfered_size = IPC_GET_ARG2(data_request_call);
-
-	return EOK;
-}
-
-/** Request a control read transfer on an endpoint pipe.
- *
- * This function encapsulates all three stages of a control transfer.
- *
- * @param[in] pipe Pipe used for the transfer.
- * @param[in] setup_buffer Buffer with the setup packet.
- * @param[in] setup_buffer_size Size of the setup packet (in bytes).
- * @param[out] data_buffer Buffer for incoming data.
- * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
- * @param[out] data_transfered_size Number of bytes that were actually
- *                                  transfered during the DATA stage.
- * @return Error code.
- */
 int usb_pipe_control_read(usb_pipe_t *pipe,
     const void *setup_buffer, size_t setup_buffer_size,
@@ -416,5 +168,5 @@
 	assert(pipe);
 
-	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
+	if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
 		return EINVAL;
 	}
@@ -429,14 +181,9 @@
 	}
 
-	int rc;
-
-	rc = pipe_add_ref(pipe, false);
-	if (rc != EOK) {
-		return rc;
-	}
+	uint64_t setup_packet;
+	memcpy(&setup_packet, setup_buffer, 8);
 
 	size_t act_size = 0;
-	rc = usb_pipe_control_read_no_check(pipe,
-	    setup_buffer, setup_buffer_size,
+	const int rc = usb_pipe_read_no_check(pipe, setup_packet,
 	    data_buffer, data_buffer_size, &act_size);
 
@@ -445,19 +192,14 @@
 	}
 
-	pipe_drop_ref(pipe);
-
-	if (rc != EOK) {
-		return rc;
-	}
-
-	if (data_transfered_size != NULL) {
+	if (rc == EOK && data_transfered_size != NULL) {
 		*data_transfered_size = act_size;
 	}
 
-	return EOK;
-}
-
-
-/** Request a control write transfer, no checking of input parameters.
+	return rc;
+}
+
+/** Request a control write transfer on an endpoint pipe.
+ *
+ * This function encapsulates all three stages of a control transfer.
  *
  * @param[in] pipe Pipe used for the transfer.
@@ -468,71 +210,4 @@
  * @return Error code.
  */
-static int usb_pipe_control_write_no_check(usb_pipe_t *pipe,
-    const void *setup_buffer, size_t setup_buffer_size,
-    const void *data_buffer, size_t data_buffer_size)
-{
-	/* Ensure serialization over the phone. */
-	pipe_start_transaction(pipe);
-
-	const usb_target_t target =
-	    {{ .address = pipe->wire->address, .endpoint = pipe->endpoint_no }};
-	assert(setup_buffer_size == 8);
-	uint64_t setup_packet;
-	memcpy(&setup_packet, setup_buffer, 8);
-
-	/*
-	 * Make call identifying target USB device and control transfer type.
-	 */
-	async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
-	aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
-	    IPC_M_USBHC_WRITE, target.packed, data_buffer_size,
-	    (setup_packet & UINT32_MAX), (setup_packet >> 32), NULL);
-	
-	if (opening_request == 0) {
-		async_exchange_end(exch);
-		pipe_end_transaction(pipe);
-		return ENOMEM;
-	}
-
-	/*
-	 * Send the data (if any).
-	 */
-	if (data_buffer_size > 0) {
-		int rc = async_data_write_start(exch, data_buffer, data_buffer_size);
-		
-		/* All data sent, pipe can be released. */
-		async_exchange_end(exch);
-		pipe_end_transaction(pipe);
-	
-		if (rc != EOK) {
-			async_wait_for(opening_request, NULL);
-			return rc;
-		}
-	} else {
-		/* No data to send, we can release the pipe for others. */
-		async_exchange_end(exch);
-		pipe_end_transaction(pipe);
-	}
-	
-	/*
-	 * Wait for the answer.
-	 */
-	sysarg_t opening_request_rc;
-	async_wait_for(opening_request, &opening_request_rc);
-
-	return (int) opening_request_rc;
-}
-
-/** Request a control write transfer on an endpoint pipe.
- *
- * This function encapsulates all three stages of a control transfer.
- *
- * @param[in] pipe Pipe used for the transfer.
- * @param[in] setup_buffer Buffer with the setup packet.
- * @param[in] setup_buffer_size Size of the setup packet (in bytes).
- * @param[in] data_buffer Buffer with data to be sent.
- * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
- * @return Error code.
- */
 int usb_pipe_control_write(usb_pipe_t *pipe,
     const void *setup_buffer, size_t setup_buffer_size,
@@ -541,5 +216,5 @@
 	assert(pipe);
 
-	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
+	if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
 		return EINVAL;
 	}
@@ -558,13 +233,9 @@
 	}
 
-	int rc;
-
-	rc = pipe_add_ref(pipe, false);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	rc = usb_pipe_control_write_no_check(pipe,
-	    setup_buffer, setup_buffer_size, data_buffer, data_buffer_size);
+	uint64_t setup_packet;
+	memcpy(&setup_packet, setup_buffer, 8);
+
+	const int rc = usb_pipe_write_no_check(pipe, setup_packet,
+	    data_buffer, data_buffer_size);
 
 	if (rc == ESTALL) {
@@ -572,9 +243,72 @@
 	}
 
-	pipe_drop_ref(pipe);
-
 	return rc;
 }
 
+/** Request a read (in) transfer on an endpoint pipe.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[out] buffer Buffer where to store the data.
+ * @param[in] size Size of the buffer (in bytes).
+ * @param[out] size_transfered Number of bytes that were actually transfered.
+ * @return Error code.
+ */
+int usb_pipe_read(usb_pipe_t *pipe,
+    void *buffer, size_t size, size_t *size_transfered)
+{
+	assert(pipe);
+
+	if (buffer == NULL) {
+		return EINVAL;
+	}
+
+	if (size == 0) {
+		return EINVAL;
+	}
+
+	if (pipe->direction != USB_DIRECTION_IN) {
+		return EBADF;
+	}
+
+	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
+		return EBADF;
+	}
+
+	size_t act_size = 0;
+	const int rc = usb_pipe_read_no_check(pipe, 0, buffer, size, &act_size);
+
+
+	if (rc == EOK && size_transfered != NULL) {
+		*size_transfered = act_size;
+	}
+
+	return rc;
+}
+
+/** Request a write (out) transfer on an endpoint pipe.
+ *
+ * @param[in] pipe Pipe used for the transfer.
+ * @param[in] buffer Buffer with data to transfer.
+ * @param[in] size Size of the buffer (in bytes).
+ * @return Error code.
+ */
+int usb_pipe_write(usb_pipe_t *pipe, const void *buffer, size_t size)
+{
+	assert(pipe);
+
+	if (buffer == NULL || size == 0) {
+		return EINVAL;
+	}
+
+	if (pipe->direction != USB_DIRECTION_OUT) {
+		return EBADF;
+	}
+
+	if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
+		return EBADF;
+	}
+
+	return usb_pipe_write_no_check(pipe, 0, buffer, size);
+}
 
 /**
Index: uspace/lib/usbdev/src/recognise.c
===================================================================
--- uspace/lib/usbdev/src/recognise.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/src/recognise.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -35,4 +35,6 @@
 #include <sys/types.h>
 #include <fibril_synch.h>
+#include <usb/debug.h>
+#include <usb/dev/hub.h>
 #include <usb/dev/pipes.h>
 #include <usb/dev/recognise.h>
@@ -50,5 +52,5 @@
 
 /** DDF operations of child devices. */
-ddf_dev_ops_t child_ops = {
+static ddf_dev_ops_t child_ops = {
 	.interfaces[USB_DEV_IFACE] = &usb_iface_hub_child_impl
 };
@@ -64,7 +66,4 @@
 #define BCD_ARGS(a) BCD_INT((a)), BCD_FRAC((a))
 
-/* FIXME: make this dynamic */
-#define MATCH_STRING_MAX 256
-
 /** Add formatted match id.
  *
@@ -75,29 +74,11 @@
  */
 static int usb_add_match_id(match_id_list_t *matches, int score,
-    const char *format, ...)
+    const char *match_str)
 {
-	char *match_str = NULL;
-	match_id_t *match_id = NULL;
-	int rc;
-	
-	match_str = malloc(MATCH_STRING_MAX + 1);
-	if (match_str == NULL) {
-		rc = ENOMEM;
-		goto failure;
-	}
-
-	/*
-	 * FIXME: replace with dynamic allocation of exact size
-	 */
-	va_list args;
-	va_start(args, format	);
-	vsnprintf(match_str, MATCH_STRING_MAX, format, args);
-	match_str[MATCH_STRING_MAX] = 0;
-	va_end(args);
-
-	match_id = create_match_id();
+	assert(matches);
+
+	match_id_t *match_id = create_match_id();
 	if (match_id == NULL) {
-		rc = ENOMEM;
-		goto failure;
+		return ENOMEM;
 	}
 
@@ -107,15 +88,4 @@
 
 	return EOK;
-	
-failure:
-	if (match_str != NULL) {
-		free(match_str);
-	}
-	if (match_id != NULL) {
-		match_id->id = NULL;
-		delete_match_id(match_id);
-	}
-	
-	return rc;
 }
 
@@ -129,7 +99,11 @@
 #define ADD_MATCHID_OR_RETURN(match_ids, score, format, ...) \
 	do { \
-		int __rc = usb_add_match_id((match_ids), (score), \
-		    format, ##__VA_ARGS__); \
+		char *str = NULL; \
+		int __rc = asprintf(&str, format, ##__VA_ARGS__); \
+		if (__rc > 0) { \
+			__rc = usb_add_match_id((match_ids), (score), str); \
+		} \
 		if (__rc != EOK) { \
+			free(str); \
 			return __rc; \
 		} \
@@ -150,8 +124,5 @@
     match_id_list_t *matches)
 {
-	if (desc_interface == NULL) {
-		return EINVAL;
-	}
-	if (matches == NULL) {
+	if (desc_interface == NULL || matches == NULL) {
 		return EINVAL;
 	}
@@ -314,4 +285,5 @@
     match_id_list_t *matches)
 {
+	assert(ctrl_pipe);
 	int rc;
 	/*
@@ -336,8 +308,7 @@
 /** Probe for device kind and register it in devman.
  *
- * @param[in] address Address of the (unknown) attached device.
- * @param[in] hc_handle Handle of the host controller.
+ * @param[in] ctrl_pipe Control pipe to the device.
  * @param[in] parent Parent device.
- * @param[in] dev_ops Child device ops.
+ * @param[in] dev_ops Child device ops. Default child_ops will be used if NULL.
  * @param[in] dev_data Arbitrary pointer to be stored in the child
  *	as @c driver_data.
@@ -346,35 +317,22 @@
  * @return Error code.
  */
-int usb_device_register_child_in_devman(usb_address_t address,
-    devman_handle_t hc_handle, ddf_dev_t *parent,
-    ddf_dev_ops_t *dev_ops, void *dev_data, ddf_fun_t **child_fun)
+int usb_device_register_child_in_devman(usb_pipe_t *ctrl_pipe,
+    ddf_dev_t *parent, ddf_dev_ops_t *dev_ops, void *dev_data,
+    ddf_fun_t **child_fun)
 {
-	size_t this_device_name_index;
+	if (child_fun == NULL || ctrl_pipe == NULL)
+		return EINVAL;
+
+	if (!dev_ops && dev_data) {
+		usb_log_warning("Using standard fun ops with arbitrary "
+		    "driver data. This does not have to work.\n");
+	}
 
 	fibril_mutex_lock(&device_name_index_mutex);
-	this_device_name_index = device_name_index;
-	device_name_index++;
+	const size_t this_device_name_index = device_name_index++;
 	fibril_mutex_unlock(&device_name_index_mutex);
 
 	ddf_fun_t *child = NULL;
-	char *child_name = NULL;
 	int rc;
-	usb_device_connection_t dev_connection;
-	usb_pipe_t ctrl_pipe;
-
-	rc = usb_device_connection_initialize(&dev_connection, hc_handle, address);
-	if (rc != EOK) {
-		goto failure;
-	}
-
-	rc = usb_pipe_initialize_default_control(&ctrl_pipe,
-	    &dev_connection);
-	if (rc != EOK) {
-		goto failure;
-	}
-	rc = usb_pipe_probe_default_control(&ctrl_pipe);
-	if (rc != EOK) {
-		goto failure;
-	}
 
 	/*
@@ -382,6 +340,7 @@
 	 * naming etc., something more descriptive could be created.
 	 */
-	rc = asprintf(&child_name, "usb%02zu_a%d",
-	    this_device_name_index, address);
+	char child_name[12]; /* The format is: "usbAB_aXYZ", length 11 */
+	rc = snprintf(child_name, sizeof(child_name),
+	    "usb%02zu_a%d", this_device_name_index, ctrl_pipe->wire->address);
 	if (rc < 0) {
 		goto failure;
@@ -401,6 +360,19 @@
 
 	child->driver_data = dev_data;
-
-	rc = usb_device_create_match_ids(&ctrl_pipe, &child->match_ids);
+	/* Store the attached device in fun driver data if there is no
+	 * other data */
+	if (!dev_data) {
+		usb_hub_attached_device_t *new_device = ddf_fun_data_alloc(
+		    child, sizeof(usb_hub_attached_device_t));
+		if (!new_device) {
+			rc = ENOMEM;
+			goto failure;
+		}
+		new_device->address = ctrl_pipe->wire->address;
+		new_device->fun = child;
+	}
+
+
+	rc = usb_device_create_match_ids(ctrl_pipe, &child->match_ids);
 	if (rc != EOK) {
 		goto failure;
@@ -412,19 +384,16 @@
 	}
 
-	if (child_fun != NULL) {
-		*child_fun = child;
-	}
-
+	*child_fun = child;
 	return EOK;
 
 failure:
 	if (child != NULL) {
-		child->name = NULL;
+		/* We know nothing about the data if it came from outside. */
+		if (dev_data) {
+			child->driver_data = NULL;
+		}
 		/* This takes care of match_id deallocation as well. */
 		ddf_fun_destroy(child);
 	}
-	if (child_name != NULL) {
-		free(child_name);
-	}
 
 	return rc;
Index: uspace/lib/usbdev/src/request.c
===================================================================
--- uspace/lib/usbdev/src/request.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbdev/src/request.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -143,16 +143,15 @@
 	 */
 
-	usb_device_request_setup_packet_t setup_packet;
-	setup_packet.request_type = 128 | (request_type << 5) | recipient;
-	setup_packet.request = request;
-	setup_packet.value = value;
-	setup_packet.index = index;
-	setup_packet.length = (uint16_t) data_size;
-
-	int rc = usb_pipe_control_read(pipe,
-	    &setup_packet, sizeof(setup_packet),
+	const usb_device_request_setup_packet_t setup_packet = {
+		.request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST
+		    | (request_type << 5) | recipient,
+		.request = request,
+		.value = value,
+		.index = index,
+		.length = (uint16_t) data_size,
+	};
+
+	return usb_pipe_control_read(pipe, &setup_packet, sizeof(setup_packet),
 	    data, data_size, actual_data_size);
-
-	return rc;
 }
 
@@ -248,38 +247,4 @@
 
 	return rc;
-}
-
-/** Change address of connected device.
- * This function automatically updates the backing connection to point to
- * the new address.
- *
- * @param pipe Control endpoint pipe (session must be already started).
- * @param new_address New USB address to be set (in native endianness).
- * @return Error code.
- */
-int usb_request_set_address(usb_pipe_t *pipe,
-    usb_address_t new_address)
-{
-	if ((new_address < 0) || (new_address >= USB11_ADDRESS_MAX)) {
-		return EINVAL;
-	}
-
-	uint16_t addr = uint16_host2usb((uint16_t)new_address);
-
-	int rc = usb_control_request_set(pipe,
-	    USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
-	    USB_DEVREQ_SET_ADDRESS,
-	    addr, 0,
-	    NULL, 0);
-
-	if (rc != EOK) {
-		return rc;
-	}
-
-	assert(pipe->wire != NULL);
-	/* TODO: prevent other from accessing wire now. */
-	pipe->wire->address = new_address;
-
-	return EOK;
 }
 
@@ -310,5 +275,5 @@
 	}
 
-	uint16_t wValue = descriptor_index | (descriptor_type << 8);
+	const uint16_t wValue = descriptor_index | (descriptor_type << 8);
 
 	return usb_control_request_get(pipe,
Index: uspace/lib/usbhid/include/usb/hid/usages/consumer.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/usages/consumer.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhid/include/usb/hid/usages/consumer.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -37,5 +37,5 @@
 #define LIBUSBHID_CONSUMER_H_
 
-const char *usbhid_multimedia_usage_to_str(int usage);
+const char *usbhid_multimedia_usage_to_str(unsigned usage);
 
 #endif /* LIBUSBHID_CONSUMER_H_ */
Index: uspace/lib/usbhid/src/consumer.c
===================================================================
--- uspace/lib/usbhid/src/consumer.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhid/src/consumer.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -38,5 +38,5 @@
 #include <usb/hid/usages/consumer.h>
 
-static const char *usbhid_consumer_usage_str[0x29d] = {
+static const char *usbhid_consumer_usage_str[] = {
 	[0x01] = "Consumer Control",
 	[0x02] = "Numeric Key Pad",
@@ -358,5 +358,5 @@
 	[0x13e] = "Reserved",
 	[0x13f] = "Reserved",
-	[0x140] = "Reserved", 
+	[0x140] = "Reserved",
 	[0x141] = "Reserved",
 	[0x142] = "Reserved",
@@ -717,12 +717,12 @@
  * @retval HelenOS key code corresponding to the given USB Consumer Page Usage.
  */
-const char *usbhid_multimedia_usage_to_str(int usage)
+const char *usbhid_multimedia_usage_to_str(unsigned usage)
 {
-	size_t map_length = sizeof(usbhid_consumer_usage_str) / sizeof(char *);
+	static const size_t map_length =
+	    sizeof(usbhid_consumer_usage_str) / sizeof(char *);
 
-	if ((usage < 0) || ((size_t)usage >= map_length))
+	if (usage >= map_length)
 		return "Unknown usage";
 
-	/*! @todo What if the usage is not in the table? */
 	return usbhid_consumer_usage_str[usage];
 }
Index: uspace/lib/usbhid/src/hiddescriptor.c
===================================================================
--- uspace/lib/usbhid/src/hiddescriptor.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhid/src/hiddescriptor.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -135,5 +135,5 @@
 int usb_hid_report_init(usb_hid_report_t *report)
 {
-	if(report == NULL) {
+	if (report == NULL) {
 		return EINVAL;
 	}
@@ -144,5 +144,5 @@
 
 	report->use_report_ids = 0;
-    return EOK;   
+    return EOK;
 }
 
Index: uspace/lib/usbhid/src/hidpath.c
===================================================================
--- uspace/lib/usbhid/src/hidpath.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhid/src/hidpath.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -385,4 +385,6 @@
 void usb_hid_report_path_free(usb_hid_report_path_t *path)
 {
+	if (path == NULL)
+		return;
 	while(!list_empty(&path->items)){
 		usb_hid_report_remove_last_item(path);
Index: uspace/lib/usbhid/src/hidreq.c
===================================================================
--- uspace/lib/usbhid/src/hidreq.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhid/src/hidreq.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -84,10 +84,10 @@
 	usb_log_debug("Sending Set Report request to the device.\n");
 	
-	rc = usb_control_request_set(ctrl_pipe, 
-	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE, 
+	rc = usb_control_request_set(ctrl_pipe,
+	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
 	    USB_HIDREQ_SET_REPORT, value, iface_no, buffer, buf_size);
 
 	if (rc != EOK) {
-		usb_log_warning("Error sending Set Report request to the "
+		usb_log_error("Error sending Set Report request to the "
 		    "device: %s.\n", str_error(rc));
 		return rc;
Index: uspace/lib/usbhost/Makefile
===================================================================
--- uspace/lib/usbhost/Makefile	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhost/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -32,5 +32,5 @@
 	-I$(LIBUSB_PREFIX)/include \
 	-I$(LIBDRV_PREFIX)/include \
-	-Iinclude 
+	-Iinclude
 
 SOURCES = \
Index: uspace/lib/usbhost/include/usb/host/hcd.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/hcd.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhost/include/usb/host/hcd.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -63,14 +63,14 @@
 /*----------------------------------------------------------------------------*/
 /** Initialize hcd_t structure.
- * Initializes device and endpoint managers. Sets data nd hook pointer to NULL.
+ * Initializes device and endpoint managers. Sets data and hook pointer to NULL.
  * @param hcd hcd_t structure to initialize, non-null.
  * @param bandwidth Available bandwidth, passed to endpoint manager.
  * @param bw_count Bandwidth compute function, passed to endpoint manager.
  */
-static inline void hcd_init(hcd_t *hcd, size_t bandwidth,
+static inline void hcd_init(hcd_t *hcd, usb_speed_t max_speed, size_t bandwidth,
     size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t))
 {
 	assert(hcd);
-	usb_device_manager_init(&hcd->dev_manager);
+	usb_device_manager_init(&hcd->dev_manager, max_speed);
 	usb_endpoint_manager_init(&hcd->ep_manager, bandwidth, bw_count);
 	hcd->private_data = NULL;
Index: uspace/lib/usbhost/include/usb/host/usb_device_manager.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_device_manager.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhost/include/usb/host/usb_device_manager.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -59,4 +59,5 @@
 		devman_handle_t handle; /**< Devman handle of the device. */
 	} devices[USB_ADDRESS_COUNT];
+	usb_speed_t max_speed;
 	fibril_mutex_t guard;
 	/** The last reserved address */
@@ -64,13 +65,14 @@
 } usb_device_manager_t;
 
-void usb_device_manager_init(usb_device_manager_t *instance);
+void usb_device_manager_init(
+    usb_device_manager_t *instance, usb_speed_t max_speed);
 
-usb_address_t usb_device_manager_get_free_address(
-    usb_device_manager_t *instance, usb_speed_t speed);
+int usb_device_manager_request_address(usb_device_manager_t *instance,
+    usb_address_t *address, bool strict, usb_speed_t speed);
 
-int usb_device_manager_bind(usb_device_manager_t *instance,
+int usb_device_manager_bind_address(usb_device_manager_t *instance,
     usb_address_t address, devman_handle_t handle);
 
-int usb_device_manager_release(usb_device_manager_t *instance,
+int usb_device_manager_release_address(usb_device_manager_t *instance,
     usb_address_t address);
 
Index: uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -90,4 +90,7 @@
     usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
     void (*callback)(endpoint_t *, void *), void *arg);
+
+void usb_endpoint_manager_remove_address(usb_endpoint_manager_t *instance,
+    usb_address_t address, void (*callback)(endpoint_t *, void *), void *arg);
 #endif
 /**
Index: uspace/lib/usbhost/src/iface.c
===================================================================
--- uspace/lib/usbhost/src/iface.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhost/src/iface.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -89,79 +89,4 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Request address interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] speed Speed to associate with the new default address.
- * @param[out] address Place to write a new address.
- * @return Error code.
- */
-static int request_address(
-    ddf_fun_t *fun, usb_speed_t speed, usb_address_t *address)
-{
-	assert(fun);
-	hcd_t *hcd = fun_to_hcd(fun);
-	assert(hcd);
-	assert(address);
-
-	usb_log_debug("Address request speed: %s.\n", usb_str_speed(speed));
-	*address =
-	    usb_device_manager_get_free_address(&hcd->dev_manager, speed);
-	usb_log_debug("Address request with result: %d.\n", *address);
-	if (*address <= 0)
-		return *address;
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/** Bind address interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] address Address of the device
- * @param[in] handle Devman handle of the device driver.
- * @return Error code.
- */
-static int bind_address(
-  ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
-{
-	assert(fun);
-	hcd_t *hcd = fun_to_hcd(fun);
-	assert(hcd);
-
-	usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
-	return usb_device_manager_bind(&hcd->dev_manager, address, handle);
-}
-/*----------------------------------------------------------------------------*/
-/** Find device handle by address interface function.
- *
- * @param[in] fun DDF function that was called.
- * @param[in] address Address in question.
- * @param[out] handle Where to store device handle if found.
- * @return Error code.
- */
-static int find_by_address(ddf_fun_t *fun, usb_address_t address,
-    devman_handle_t *handle)
-{
-	assert(fun);
-	hcd_t *hcd = fun_to_hcd(fun);
-	assert(hcd);
-	return usb_device_manager_get_info_by_address(
-	    &hcd->dev_manager, address, handle, NULL);
-}
-/*----------------------------------------------------------------------------*/
-/** Release address interface function
- *
- * @param[in] fun DDF function that was called.
- * @param[in] address USB address to be released.
- * @return Error code.
- */
-static int release_address(ddf_fun_t *fun, usb_address_t address)
-{
-	assert(fun);
-	hcd_t *hcd = fun_to_hcd(fun);
-	assert(hcd);
-	usb_log_debug("Address release %d.\n", address);
-	usb_device_manager_release(&hcd->dev_manager, address);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
 static int register_helper(endpoint_t *ep, void *arg)
 {
@@ -183,7 +108,92 @@
 }
 /*----------------------------------------------------------------------------*/
+static void unregister_helper_warn(endpoint_t *ep, void *arg)
+{
+	hcd_t *hcd = arg;
+	assert(ep);
+	assert(hcd);
+	usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n",
+	    ep->address, ep->endpoint, usb_str_direction(ep->direction));
+	if (hcd->ep_remove_hook)
+		hcd->ep_remove_hook(hcd, ep);
+}
+/*----------------------------------------------------------------------------*/
+/** Request address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] speed Speed to associate with the new default address.
+ * @param[out] address Place to write a new address.
+ * @return Error code.
+ */
+static int request_address(
+    ddf_fun_t *fun, usb_address_t *address, bool strict, usb_speed_t speed)
+{
+	assert(fun);
+	hcd_t *hcd = fun_to_hcd(fun);
+	assert(hcd);
+	assert(address);
+
+	usb_log_debug("Address request: speed: %s, address: %d, strict: %s.\n",
+	    usb_str_speed(speed), *address, strict ? "YES" : "NO");
+	return usb_device_manager_request_address(
+	    &hcd->dev_manager, address, strict, speed);
+}
+/*----------------------------------------------------------------------------*/
+/** Bind address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address Address of the device
+ * @param[in] handle Devman handle of the device driver.
+ * @return Error code.
+ */
+static int bind_address(
+  ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
+{
+	assert(fun);
+	hcd_t *hcd = fun_to_hcd(fun);
+	assert(hcd);
+
+	usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
+	return usb_device_manager_bind_address(
+	    &hcd->dev_manager, address, handle);
+}
+/*----------------------------------------------------------------------------*/
+/** Find device handle by address interface function.
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address Address in question.
+ * @param[out] handle Where to store device handle if found.
+ * @return Error code.
+ */
+static int find_by_address(ddf_fun_t *fun, usb_address_t address,
+    devman_handle_t *handle)
+{
+	assert(fun);
+	hcd_t *hcd = fun_to_hcd(fun);
+	assert(hcd);
+	return usb_device_manager_get_info_by_address(
+	    &hcd->dev_manager, address, handle, NULL);
+}
+/*----------------------------------------------------------------------------*/
+/** Release address interface function
+ *
+ * @param[in] fun DDF function that was called.
+ * @param[in] address USB address to be released.
+ * @return Error code.
+ */
+static int release_address(ddf_fun_t *fun, usb_address_t address)
+{
+	assert(fun);
+	hcd_t *hcd = fun_to_hcd(fun);
+	assert(hcd);
+	usb_log_debug("Address release %d.\n", address);
+	usb_device_manager_release_address(&hcd->dev_manager, address);
+	usb_endpoint_manager_remove_address(&hcd->ep_manager, address,
+	    unregister_helper_warn, hcd);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 static int register_endpoint(
-    ddf_fun_t *fun, usb_address_t address, usb_speed_t ep_speed,
-    usb_endpoint_t endpoint,
+    ddf_fun_t *fun, usb_address_t address, usb_endpoint_t endpoint,
     usb_transfer_type_t transfer_type, usb_direction_t direction,
     size_t max_packet_size, unsigned int interval)
@@ -193,11 +203,10 @@
 	assert(hcd);
 	const size_t size = max_packet_size;
-	/* Default address is not bound or registered,
-	 * thus it does not provide speed info. */
-	usb_speed_t speed = ep_speed;
-	/* NOTE The function will return EINVAL and won't
-	 * touch speed variable for default address */
-	usb_device_manager_get_info_by_address(
+	usb_speed_t speed = USB_SPEED_MAX;
+	const int ret = usb_device_manager_get_info_by_address(
 	    &hcd->dev_manager, address, NULL, &speed);
+	if (ret != EOK) {
+		return ret;
+	}
 
 	usb_log_debug("Register endpoint %d:%d %s-%s %s %zuB %ums.\n",
@@ -243,5 +252,5 @@
 	.request_address = request_address,
 	.bind_address = bind_address,
-	.find_by_address = find_by_address,
+	.get_handle = find_by_address,
 	.release_address = release_address,
 
Index: uspace/lib/usbhost/src/usb_device_manager.c
===================================================================
--- uspace/lib/usbhost/src/usb_device_manager.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhost/src/usb_device_manager.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -38,11 +38,39 @@
 #include <usb/host/usb_device_manager.h>
 
+/** Get a free USB address
+ *
+ * @param[in] instance Device manager structure to use.
+ * @param[in] speed Speed of the device requiring address.
+ * @return Free address, or error code.
+ */
+static usb_address_t usb_device_manager_get_free_address(
+    usb_device_manager_t *instance)
+{
+
+	usb_address_t new_address = instance->last_address;
+	do {
+		new_address = (new_address + 1) % USB_ADDRESS_COUNT;
+		if (new_address == USB_ADDRESS_DEFAULT)
+			new_address = 1;
+		if (new_address == instance->last_address) {
+			return ENOSPC;
+		}
+	} while (instance->devices[new_address].occupied);
+
+	assert(new_address != USB_ADDRESS_DEFAULT);
+	instance->last_address = new_address;
+
+	return new_address;
+}
+/*----------------------------------------------------------------------------*/
 /** Initialize device manager structure.
  *
  * @param[in] instance Memory place to initialize.
+ * @param[in] max_speed Maximum allowed USB speed of devices (inclusive).
  *
  * Set all values to false/0.
  */
-void usb_device_manager_init(usb_device_manager_t *instance)
+void usb_device_manager_init(
+    usb_device_manager_t *instance, usb_speed_t max_speed)
 {
 	assert(instance);
@@ -52,45 +80,49 @@
 		instance->devices[i].speed = USB_SPEED_MAX;
 	}
-	// TODO: is this hack enough?
-	// (it is needed to allow smooth registration at default address)
-	instance->devices[0].occupied = true;
-	instance->last_address = 0;
+	instance->last_address = 1;
+	instance->max_speed = max_speed;
 	fibril_mutex_initialize(&instance->guard);
 }
 /*----------------------------------------------------------------------------*/
-/** Get a free USB address
- *
- * @param[in] instance Device manager structure to use.
- * @param[in] speed Speed of the device requiring address.
- * @return Free address, or error code.
- */
-usb_address_t usb_device_manager_get_free_address(
-    usb_device_manager_t *instance, usb_speed_t speed)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-
-	usb_address_t new_address = instance->last_address;
-	do {
-		++new_address;
-		if (new_address > USB11_ADDRESS_MAX)
-			new_address = 1; // NOTE it should be safe to put 0 here
-			                 // TODO Use mod
-		if (new_address == instance->last_address) {
+/** Request USB address.
+ * @param instance usb_device_manager
+ * @param address Pointer to requested address value, place to store new address
+ * @parma strict Fail if the requested address is not available.
+ * @return Error code.
+ * @note Default address is only available in strict mode.
+ */
+int usb_device_manager_request_address(usb_device_manager_t *instance,
+    usb_address_t *address, bool strict, usb_speed_t speed)
+{
+	assert(instance);
+	assert(address);
+	if (speed > instance->max_speed)
+		return ENOTSUP;
+
+	if ((*address) < 0 || (*address) >= USB_ADDRESS_COUNT)
+		return EINVAL;
+
+	fibril_mutex_lock(&instance->guard);
+	/* Only grant default address to strict requests */
+	if (( (*address) == USB_ADDRESS_DEFAULT) && !strict) {
+		*address = instance->last_address;
+	}
+
+	if (instance->devices[*address].occupied) {
+		if (strict) {
 			fibril_mutex_unlock(&instance->guard);
-			return ENOSPC;
+			return ENOENT;
 		}
-	} while (instance->devices[new_address].occupied);
-
-	assert(new_address != USB_ADDRESS_DEFAULT);
-	assert(instance->devices[new_address].occupied == false);
-	assert(instance->devices[new_address].handle == 0);
-
-	instance->devices[new_address].occupied = true;
-	instance->devices[new_address].speed = speed;
-	instance->last_address = new_address;
-
-	fibril_mutex_unlock(&instance->guard);
-	return new_address;
+		*address = usb_device_manager_get_free_address(instance);
+	}
+	assert(instance->devices[*address].occupied == false);
+	assert(instance->devices[*address].handle == 0);
+	assert(*address != USB_ADDRESS_DEFAULT || strict);
+
+	instance->devices[*address].occupied = true;
+	instance->devices[*address].speed = speed;
+
+	fibril_mutex_unlock(&instance->guard);
+	return EOK;
 }
 /*----------------------------------------------------------------------------*/
@@ -102,5 +134,5 @@
  * @return Error code.
  */
-int usb_device_manager_bind(usb_device_manager_t *instance,
+int usb_device_manager_bind_address(usb_device_manager_t *instance,
     usb_address_t address, devman_handle_t handle)
 {
@@ -132,8 +164,8 @@
  * @return Error code.
  */
-int usb_device_manager_release(
+int usb_device_manager_release_address(
     usb_device_manager_t *instance, usb_address_t address)
 {
-	if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) {
+	if ((address < 0) || (address >= USB_ADDRESS_COUNT)) {
 		return EINVAL;
 	}
@@ -188,5 +220,5 @@
 {
 	assert(instance);
-	if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) {
+	if ((address < 0) || (address >= USB_ADDRESS_COUNT)) {
 		return EINVAL;
 	}
Index: uspace/lib/usbhost/src/usb_endpoint_manager.c
===================================================================
--- uspace/lib/usbhost/src/usb_endpoint_manager.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/lib/usbhost/src/usb_endpoint_manager.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -384,2 +384,21 @@
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
+void usb_endpoint_manager_remove_address(usb_endpoint_manager_t *instance,
+    usb_address_t address, void (*callback)(endpoint_t *, void *), void *arg)
+{
+	assert(address >= 0);
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	list_foreach(*get_list(instance, address), iterator) {
+		endpoint_t *ep = endpoint_get_instance(iterator);
+		if (ep->address == address) {
+			iterator = iterator->next;
+			list_remove(&ep->link);
+			if (callback)
+				callback(ep, arg);
+			endpoint_destroy(ep);
+		}
+	}
+	fibril_mutex_unlock(&instance->guard);
+}
Index: uspace/srv/bd/rd/rd.c
===================================================================
--- uspace/srv/bd/rd/rd.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/bd/rd/rd.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -55,6 +55,7 @@
 #include <ipc/bd.h>
 #include <macros.h>
-
-#define NAME "rd"
+#include <inttypes.h>
+
+#define NAME  "rd"
 
 /** Pointer to the ramdisk's image */
@@ -208,39 +209,42 @@
 static bool rd_init(void)
 {
-	int ret = sysinfo_get_value("rd.size", &rd_size);
-	if ((ret != EOK) || (rd_size == 0)) {
+	sysarg_t size;
+	int ret = sysinfo_get_value("rd.size", &size);
+	if ((ret != EOK) || (size == 0)) {
 		printf("%s: No RAM disk found\n", NAME);
 		return false;
 	}
 	
-	sysarg_t rd_ph_addr;
-	ret = sysinfo_get_value("rd.address.physical", &rd_ph_addr);
-	if ((ret != EOK) || (rd_ph_addr == 0)) {
+	sysarg_t addr_phys;
+	ret = sysinfo_get_value("rd.address.physical", &addr_phys);
+	if ((ret != EOK) || (addr_phys == 0)) {
 		printf("%s: Invalid RAM disk physical address\n", NAME);
 		return false;
 	}
 	
+	rd_size = ALIGN_UP(size, block_size);
 	rd_addr = as_get_mappable_page(rd_size);
 	
-	int flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
-	int retval = physmem_map((void *) rd_ph_addr, rd_addr,
+	unsigned int flags =
+	    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
+	ret = physmem_map((void *) addr_phys, rd_addr,
 	    ALIGN_UP(rd_size, PAGE_SIZE) >> PAGE_WIDTH, flags);
-	
-	if (retval < 0) {
+	if (ret < 0) {
 		printf("%s: Error mapping RAM disk\n", NAME);
 		return false;
 	}
 	
-	printf("%s: Found RAM disk at %p, %zu bytes\n", NAME,
-	    (void *) rd_ph_addr, rd_size);
-	
-	int rc = loc_server_register(NAME, rd_connection);
-	if (rc < 0) {
-		printf("%s: Unable to register driver (%d)\n", NAME, rc);
+	printf("%s: Found RAM disk at %p, %" PRIun " bytes\n", NAME,
+	    (void *) addr_phys, size);
+	
+	ret = loc_server_register(NAME, rd_connection);
+	if (ret < 0) {
+		printf("%s: Unable to register driver (%d)\n", NAME, ret);
 		return false;
 	}
 	
 	service_id_t service_id;
-	if (loc_service_register("bd/initrd", &service_id) != EOK) {
+	ret = loc_service_register("bd/initrd", &service_id);
+	if (ret != EOK) {
 		printf("%s: Unable to register device service\n", NAME);
 		return false;
Index: uspace/srv/fs/exfat/exfat_bitmap.c
===================================================================
--- uspace/srv/fs/exfat/exfat_bitmap.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/fs/exfat/exfat_bitmap.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -45,5 +45,4 @@
 #include <assert.h>
 #include <fibril_synch.h>
-#include <malloc.h>
 #include <mem.h>
 
Index: uspace/srv/fs/exfat/exfat_dentry.c
===================================================================
--- uspace/srv/fs/exfat/exfat_dentry.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/fs/exfat/exfat_dentry.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -101,11 +101,30 @@
 bool exfat_valid_char(wchar_t ch)
 {
-	/* TODO */
-	return true;
+	switch (ch) {
+	case 0x01 ... 0x1F:
+	case '/':
+	case '\\':
+	case '?':
+	case '|':
+	case '>':
+	case '<':
+	case '"':
+	case '*':
+	case ':':
+		return false;
+	default:
+		return true;
+	}
 }
 
 bool exfat_valid_name(const char *name)
 {
-	/* TODO */
+	size_t off = 0;
+	wchar_t ch;
+
+	while ((ch = str_decode(name, &off, STR_NO_LIMIT)) != 0) {
+		if (!exfat_valid_char(ch))
+			return false;
+	}
 	return true;
 }
Index: uspace/srv/fs/exfat/exfat_directory.c
===================================================================
--- uspace/srv/fs/exfat/exfat_directory.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/fs/exfat/exfat_directory.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -92,6 +92,8 @@
 	int rc = EOK;
 	
-	if (di->b)
+	if (di->b) {
 		rc = block_put(di->b);
+		di->b = NULL;
+	}
 	
 	return rc;
@@ -101,5 +103,5 @@
 {
 	uint32_t i;
-	int rc;
+	int rc = EOK;
 
 	i = (di->pos * sizeof(exfat_dentry_t)) / BPS(di->bs);
@@ -108,6 +110,8 @@
 
 	if (di->b && di->bnum != i) {
-		block_put(di->b);
+		rc = block_put(di->b);
 		di->b = NULL;
+		if (rc != EOK)
+			return rc;
 	}
 	if (!di->b) {
@@ -126,5 +130,5 @@
 		di->bnum = i;
 	}
-	return EOK;
+	return rc;
 }
 
@@ -264,5 +268,6 @@
 		if (idx == 2 || idx == 3)
 			continue;
-		checksum = ((checksum << 15) | (checksum >> 1)) + (uint16_t)bytes[idx];
+		checksum = ((checksum << 15) | (checksum >> 1)) +
+		    (uint16_t)bytes[idx];
 	}
 	return checksum;
@@ -285,6 +290,8 @@
 	for (i = 0; i < count; i++) {
 		rc = exfat_directory_get(di, &de);
-		if (rc != EOK)
-			return rc;
+		if (rc != EOK) {
+			free(array);
+			return rc;
+		}
 		array[i] = *de;
 		rc = exfat_directory_next(di);
@@ -306,5 +313,6 @@
 	array[1].stream.valid_data_size = host2uint64_t_le(ds->valid_data_size);
 	array[1].stream.data_size = host2uint64_t_le(ds->data_size);
-	array[0].file.checksum = host2uint16_t_le(exfat_directory_set_checksum((uint8_t *)array,
+	array[0].file.checksum =
+	    host2uint16_t_le(exfat_directory_set_checksum((uint8_t *)array,
 	    count * sizeof(exfat_dentry_t)));
 
@@ -312,6 +320,8 @@
 	for (i = 0; i < count; i++) {
 		rc = exfat_directory_get(di, &de);
-		if (rc != EOK)
-			return rc;
+		if (rc != EOK) {
+			free(array);
+			return rc;
+		}
 		*de = array[i];
 		di->b->dirty = true;
@@ -346,5 +356,6 @@
 	uctablep = EXFAT_NODE(fn);
 
-	uctable_chars = ALIGN_DOWN(uctablep->size, sizeof(uint16_t)) / sizeof(uint16_t); 
+	uctable_chars = ALIGN_DOWN(uctablep->size,
+	    sizeof(uint16_t)) / sizeof(uint16_t); 
 	uctable = (uint16_t *) malloc(uctable_chars * sizeof(uint16_t));
 	rc = exfat_read_uctable(di->bs, uctablep, (uint8_t *)uctable);
@@ -411,6 +422,9 @@
 			return rc;
 
-		if (i == df.file.count - 2)
-			chars = ds.stream.name_size - EXFAT_NAME_PART_LEN*(df.file.count - 2);
+		if (i == df.file.count - 2) {
+			chars = ds.stream.name_size -
+			    EXFAT_NAME_PART_LEN*(df.file.count - 2);
+		}
+
 		rc = exfat_directory_get(di, &de);
 		if (rc != EOK)
@@ -424,5 +438,4 @@
 
 		di->b->dirty = true;
-		sname += chars;
 	}
 	
@@ -434,4 +447,6 @@
 	int rc, count;
 	exfat_dentry_t *de;
+
+	di->pos = pos;
 
 	rc = exfat_directory_get(di, &de);
Index: uspace/srv/fs/exfat/exfat_fat.c
===================================================================
--- uspace/srv/fs/exfat/exfat_fat.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/fs/exfat/exfat_fat.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -50,4 +50,5 @@
 #include <malloc.h>
 #include <mem.h>
+#include <str.h>
 
 
@@ -322,9 +323,9 @@
 			    (found == 0) ?  EXFAT_CLST_EOF : lifo[found - 1]);
 			if (rc != EOK)
-				break;
+				goto exit_error;
 			found++;
 			rc = bitmap_set_cluster(bs, service_id, clst);
 			if (rc != EOK)
-				break;
+				goto exit_error;
 
 		}
@@ -339,4 +340,8 @@
 	}
 
+	rc = ENOSPC;
+
+exit_error:
+
 	/* If something wrong - free the clusters */
 	while (found--) {
@@ -347,5 +352,5 @@
 	free(lifo);
 	fibril_mutex_unlock(&exfat_alloc_lock);
-	return ENOSPC;
+	return rc;
 }
 
@@ -537,5 +542,18 @@
 int exfat_sanity_check(exfat_bs_t *bs, service_id_t service_id)
 {
-	/* TODO */
+	if (str_cmp((char const *)bs->oem_name, "EXFAT   "))
+		return ENOTSUP;
+	else if (uint16_t_le2host(bs->signature) != 0xAA55)
+		return ENOTSUP;
+	else if (uint32_t_le2host(bs->fat_sector_count) == 0)
+		return ENOTSUP;
+	else if (uint32_t_le2host(bs->data_clusters) == 0)
+		return ENOTSUP;
+	else if (bs->fat_count != 1)
+		return ENOTSUP;
+	else if ((bs->bytes_per_sector + bs->sec_per_cluster) > 25) {
+		/* exFAT does not support cluster size > 32 Mb */
+		return ENOTSUP;
+	}
 	return EOK;
 }
Index: uspace/srv/fs/exfat/exfat_ops.c
===================================================================
--- uspace/srv/fs/exfat/exfat_ops.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/fs/exfat/exfat_ops.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -657,4 +657,11 @@
 			return rc;
 		}
+
+		rc = exfat_zero_cluster(bs, service_id, nodep->firstc);
+		if (rc != EOK) {
+			(void) exfat_node_put(FS_NODE(nodep));
+			return rc;
+		}
+
 		nodep->size = BPC(bs);
 	} else {
@@ -739,9 +746,14 @@
 	 */
 	rc = exfat_directory_write_file(&di, name);
-	if (rc != EOK)
-		return rc;
+	if (rc != EOK) {
+		(void) exfat_directory_close(&di);
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
 	rc = exfat_directory_close(&di);
-	if (rc != EOK)
-		return rc;
+	if (rc != EOK) {
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
 
 	fibril_mutex_unlock(&parentp->idx->lock);
@@ -1258,5 +1270,7 @@
 		exfat_directory_t di;
 		rc = exfat_directory_open(nodep, &di);
-		if (rc != EOK) goto err;
+		if (rc != EOK)
+			goto err;
+
 		rc = exfat_directory_seek(&di, pos);
 		if (rc != EOK) {
@@ -1268,7 +1282,9 @@
 		    &df, &ds);
 		if (rc == EOK)
-		    goto hit;
-		if (rc == ENOENT)
-		    goto miss;
+			goto hit;
+		else if (rc == ENOENT)
+			goto miss;
+
+		(void) exfat_directory_close(&di);
 
 err:
@@ -1279,5 +1295,5 @@
 miss:
 		rc = exfat_directory_close(&di);
-		if (rc!=EOK)
+		if (rc != EOK)
 			goto err;
 		rc = exfat_node_put(fn);
@@ -1397,5 +1413,5 @@
 
 	(void) async_data_write_finalize(callid,
-		b->data + pos % BPS(bs), bytes);
+	    b->data + pos % BPS(bs), bytes);
 	b->dirty = true;		/* need to sync block */
 	rc = block_put(b);
Index: uspace/srv/fs/mfs/mfs.h
===================================================================
--- uspace/srv/fs/mfs/mfs.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/fs/mfs/mfs.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -48,5 +48,5 @@
 #define NAME		"mfs"
 
-//#define DEBUG_MODE
+/* #define DEBUG_MODE */
 
 #define min(a, b)	((a) < (b) ? (a) : (b))
@@ -71,5 +71,5 @@
 } mfs_version_t;
 
-/*Generic MinixFS superblock*/
+/* Generic MinixFS superblock */
 struct mfs_sb_info {
 	uint32_t ninodes;
@@ -84,5 +84,5 @@
 	uint16_t state;
 
-	/*The following fields do not exist on disk but only in memory*/
+	/* The following fields do not exist on disk but only in memory */
 	unsigned long itable_size;
 	mfs_version_t fs_version;
@@ -97,5 +97,5 @@
 };
 
-/*Generic MinixFS inode*/
+/* Generic MinixFS inode */
 struct mfs_ino_info {
 	uint16_t	i_mode;
@@ -107,24 +107,24 @@
 	int32_t		i_mtime;
 	int32_t		i_ctime;
-	/*Block numbers for direct zones*/
+	/* Block numbers for direct zones */
 	uint32_t	i_dzone[V2_NR_DIRECT_ZONES];
-	/*Block numbers for indirect zones*/
+	/* Block numbers for indirect zones */
 	uint32_t	i_izone[V2_NR_INDIRECT_ZONES];
 
-	/*The following fields do not exist on disk but only in memory*/
+	/* The following fields do not exist on disk but only in memory */
 	bool dirty;
 	fs_index_t index;
 };
 
-/*Generic MFS directory entry*/
+/* Generic MFS directory entry */
 struct mfs_dentry_info {
 	uint32_t d_inum;
 	char d_name[MFS3_MAX_NAME_LEN + 1];
 
-	/*The following fields do not exist on disk but only in memory*/
-
-	/*Index of the dentry in the list*/
+	/* The following fields do not exist on disk but only in memory */
+
+	/* Index of the dentry in the list */
 	unsigned index;
-	/*Pointer to the node at witch the dentry belongs*/
+	/* Pointer to the node at witch the dentry belongs */
 	struct mfs_node *node;
 };
@@ -136,5 +136,5 @@
 };
 
-/*MinixFS node in core*/
+/* MinixFS node in core */
 struct mfs_node {
 	struct mfs_ino_info *ino_i;
@@ -145,5 +145,5 @@
 };
 
-/*mfs_ops.c*/
+/* mfs_ops.c */
 extern vfs_out_ops_t mfs_ops;
 extern libfs_ops_t mfs_libfs_ops;
@@ -152,8 +152,8 @@
 mfs_global_init(void);
 
-/*mfs_inode.c*/
+/* mfs_inode.c */
 extern int
 mfs_get_inode(struct mfs_instance *inst, struct mfs_ino_info **ino_i,
-	  fs_index_t index);
+    fs_index_t index);
 
 extern int
@@ -163,5 +163,5 @@
 mfs_inode_shrink(struct mfs_node *mnode, size_t size_shrink);
 
-/*mfs_rw.c*/
+/* mfs_rw.c */
 extern int
 mfs_read_map(uint32_t *b, const struct mfs_node *mnode, const uint32_t pos);
@@ -169,13 +169,13 @@
 extern int
 mfs_write_map(struct mfs_node *mnode, uint32_t pos, uint32_t new_zone,
-	  uint32_t *old_zone);
+    uint32_t *old_zone);
 
 extern int
 mfs_prune_ind_zones(struct mfs_node *mnode, size_t new_size);
 
-/*mfs_dentry.c*/
+/* mfs_dentry.c */
 extern int
 mfs_read_dentry(struct mfs_node *mnode,
-		     struct mfs_dentry_info *d_info, unsigned index);
+    struct mfs_dentry_info *d_info, unsigned index);
 
 extern int
@@ -188,5 +188,5 @@
 mfs_insert_dentry(struct mfs_node *mnode, const char *d_name, fs_index_t d_inum);
 
-/*mfs_balloc.c*/
+/* mfs_balloc.c */
 extern int
 mfs_alloc_inode(struct mfs_instance *inst, uint32_t *inum);
@@ -201,5 +201,5 @@
 mfs_free_zone(struct mfs_instance *inst, uint32_t zone);
 
-/*mfs_utils.c*/
+/* mfs_utils.c */
 extern uint16_t
 conv16(bool native, uint16_t n);
Index: uspace/srv/fs/mfs/mfs_balloc.c
===================================================================
--- uspace/srv/fs/mfs/mfs_balloc.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/fs/mfs/mfs_balloc.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -198,5 +198,5 @@
 		limit = sbi->nzones - sbi->firstdatazone - 1;
 	} else {
-		/*bid == BMAP_INODE*/
+		/* bid == BMAP_INODE */
 		search = &sbi->isearch;
 		start_block = 2;
@@ -212,5 +212,5 @@
 	for (i = *search / bits_per_block; i < nblocks; ++i) {
 		r = block_get(&b, inst->service_id, i + start_block,
-			      BLOCK_FLAGS_NONE);
+		    BLOCK_FLAGS_NONE);
 
 		if (r != EOK)
Index: uspace/srv/fs/mfs/mfs_dentry.c
===================================================================
--- uspace/srv/fs/mfs/mfs_dentry.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/fs/mfs/mfs_dentry.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -168,5 +168,5 @@
 		return ENAMETOOLONG;
 
-	/*Search the directory entry to be removed*/
+	/* Search the directory entry to be removed */
 	unsigned i;
 	for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize ; ++i) {
Index: uspace/srv/fs/mfs/mfs_inode.c
===================================================================
--- uspace/srv/fs/mfs/mfs_inode.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/fs/mfs/mfs_inode.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -235,6 +235,6 @@
 
 	r = block_get(&b, mnode->instance->service_id,
-		      itable_off + inum / sbi->ino_per_block,
-		      BLOCK_FLAGS_NONE);
+	    itable_off + inum / sbi->ino_per_block,
+	    BLOCK_FLAGS_NONE);
 
 	if (r != EOK)
@@ -278,6 +278,6 @@
 
 	r = block_get(&b, mnode->instance->service_id,
-		      itable_off + inum / sbi->ino_per_block,
-		      BLOCK_FLAGS_NONE);
+	    itable_off + inum / sbi->ino_per_block,
+	    BLOCK_FLAGS_NONE);
 
 	if (r != EOK)
Index: uspace/srv/fs/mfs/mfs_ops.c
===================================================================
--- uspace/srv/fs/mfs/mfs_ops.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/fs/mfs/mfs_ops.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -664,4 +664,5 @@
 	struct mfs_node *child = cfn->data;
 	struct mfs_sb_info *sbi = parent->instance->sbi;
+	bool destroy_dentry = false;
 
 	mfsdebug("%s()\n", __FUNCTION__);
@@ -672,17 +673,24 @@
 	int r = mfs_insert_dentry(parent, name, child->ino_i->index);
 	if (r != EOK)
-		goto exit_error;
-
-	child->ino_i->i_nlinks++;
-	child->ino_i->dirty = true;
+		return r;
 
 	if (S_ISDIR(child->ino_i->i_mode)) {
+		if (child->ino_i->i_nlinks != 1) {
+			/* It's not possible to hardlink directories in MFS */
+			destroy_dentry = true;
+			r = EMLINK;
+			goto exit;
+		}
 		r = mfs_insert_dentry(child, ".", child->ino_i->index);
-		if (r != EOK)
-			goto exit_error;
+		if (r != EOK) {
+			destroy_dentry = true;
+			goto exit;
+		}
 
 		r = mfs_insert_dentry(child, "..", parent->ino_i->index);
-		if (r != EOK)
-			goto exit_error;
+		if (r != EOK) {
+			destroy_dentry = true;
+			goto exit;
+		}
 
 		parent->ino_i->i_nlinks++;
@@ -690,5 +698,13 @@
 	}
 
-exit_error:
+exit:
+	if (destroy_dentry) {
+		int r2 = mfs_remove_dentry(parent, name);
+		if (r2 != EOK)
+			r = r2;
+	} else {
+		child->ino_i->i_nlinks++;
+		child->ino_i->dirty = true;
+	}
 	return r;
 }
@@ -821,5 +837,5 @@
 found:
 		async_data_read_finalize(callid, d_info.d_name,
-					 str_size(d_info.d_name) + 1);
+		    str_size(d_info.d_name) + 1);
 		bytes = ((pos - spos) + 1);
 	} else {
Index: uspace/srv/fs/mfs/mfs_rw.c
===================================================================
--- uspace/srv/fs/mfs/mfs_rw.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/fs/mfs/mfs_rw.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -147,5 +147,5 @@
 				ino_i->dirty = true;
 			} else {
-				/*Sparse block*/
+				/* Sparse block */
 				*b = 0;
 				return EOK;
@@ -233,5 +233,5 @@
 }
 
-/**Free unused indirect zones from a MINIX inode according to it's new size.
+/**Free unused indirect zones from a MINIX inode according to its new size.
  *
  * @param mnode		Pointer to a generic MINIX inode in memory.
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/hid/console/console.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -481,5 +481,6 @@
 				event->c = c;
 				
-				/* Kernel console does not read events
+				/*
+				 * Kernel console does not read events
 				 * from us, so we will redirect them
 				 * to the (last) active userspace console
@@ -487,5 +488,5 @@
 				 */
 				console_t *target_console = cons_get_active_uspace();
-
+				
 				prodcons_produce(&target_console->input_pc,
 				    &event->link);
Index: uspace/srv/hid/input/ctl/kbdev.c
===================================================================
--- uspace/srv/hid/input/ctl/kbdev.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/hid/input/ctl/kbdev.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -111,4 +111,5 @@
 		printf("%s: Failed allocating device structure for '%s'.\n",
 		    NAME, kdev->svc_name);
+		async_hangup(sess);
 		return -1;
 	}
@@ -169,5 +170,5 @@
 		callid = async_get_call(&call);
 		if (!IPC_GET_IMETHOD(call)) {
-			/* XXX Handle hangup */
+			kbdev_destroy(kbdev);
 			return;
 		}
Index: uspace/srv/hid/input/proto/mousedev.c
===================================================================
--- uspace/srv/hid/input/proto/mousedev.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/hid/input/proto/mousedev.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -54,7 +54,4 @@
 	/** Link to generic mouse device */
 	mouse_dev_t *mouse_dev;
-	
-	/** Session to mouse device */
-	async_sess_t *sess;
 } mousedev_t;
 
@@ -72,7 +69,4 @@
 static void mousedev_destroy(mousedev_t *mousedev)
 {
-	if (mousedev->sess != NULL)
-		async_hangup(mousedev->sess);
-	
 	free(mousedev);
 }
@@ -89,5 +83,5 @@
 		
 		if (!IPC_GET_IMETHOD(call)) {
-			/* XXX Handle hangup */
+			mousedev_destroy(mousedev);
 			return;
 		}
@@ -129,8 +123,7 @@
 		printf("%s: Failed allocating device structure for '%s'.\n",
 		    NAME, mdev->svc_name);
+		async_hangup(sess);
 		return -1;
 	}
-	
-	mousedev->sess = sess;
 	
 	async_exch_t *exch = async_exchange_begin(sess);
@@ -139,4 +132,5 @@
 		    mdev->svc_name);
 		mousedev_destroy(mousedev);
+		async_hangup(sess);
 		return -1;
 	}
@@ -144,4 +138,5 @@
 	int rc = async_connect_to_me(exch, 0, 0, 0, mousedev_callback_conn, mousedev);
 	async_exchange_end(exch);
+	async_hangup(sess);
 	
 	if (rc != EOK) {
Index: uspace/srv/net/cfg/e1k.nic
===================================================================
--- uspace/srv/net/cfg/e1k.nic	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/cfg/e1k.nic	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,21 @@
+# E1000 configuration
+
+NAME=e1k
+
+HWPATH=/hw/pci0/00:03.0/port0
+NIL=eth
+IL=ip
+
+# 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=1500
Index: uspace/srv/net/il/arp/arp.c
===================================================================
--- uspace/srv/net/il/arp/arp.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/net/il/arp/arp.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -703,5 +703,5 @@
 	length += device->addr_len;
 	memcpy(((uint8_t *) header) + length, target->value, target->length);
-
+	
 	int rc = packet_set_addr(packet, device->addr, device->broadcast_addr,
 	    device->addr_len);
Index: uspace/srv/net/net/packet_server.c
===================================================================
--- uspace/srv/net/net/packet_server.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/net/net/packet_server.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -304,15 +304,14 @@
 static int packet_reply(packet_t *packet)
 {
+	if (!packet_is_valid(packet))
+		return EINVAL;
+	
 	ipc_callid_t callid;
 	size_t size;
-
-	if (!packet_is_valid(packet))
-		return EINVAL;
-
 	if (!async_share_in_receive(&callid, &size)) {
 		async_answer_0(callid, EINVAL);
 		return EINVAL;
 	}
-
+	
 	if (size != packet->length) {
 		async_answer_0(callid, ENOMEM);
@@ -375,7 +374,7 @@
 	case NET_PACKET_GET:
 		packet = pm_find(IPC_GET_ID(*call));
-		if (!packet_is_valid(packet)) {
+		if (!packet_is_valid(packet))
 			return ENOENT;
-		}
+		
 		return packet_reply(packet);
 	
Index: uspace/srv/net/nil/eth/eth.c
===================================================================
--- uspace/srv/net/nil/eth/eth.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/net/nil/eth/eth.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -197,4 +197,5 @@
 	fibril_rwlock_write_lock(&eth_globals.devices_lock);
 	fibril_rwlock_write_lock(&eth_globals.protos_lock);
+	
 	eth_globals.net_sess = sess;
 	memcpy(eth_globals.broadcast_addr, "\xFF\xFF\xFF\xFF\xFF\xFF",
Index: uspace/srv/net/nil/nildummy/nildummy.h
===================================================================
--- uspace/srv/net/nil/nildummy/nildummy.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/net/nil/nildummy/nildummy.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -44,5 +44,4 @@
 #include <ipc/devman.h>
 #include <net/device.h>
-#include <adt/measured_strings.h>
 
 /** Type definition of the dummy nil global data.
Index: uspace/srv/net/tl/tcp/Makefile
===================================================================
--- uspace/srv/net/tl/tcp/Makefile	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/net/tl/tcp/Makefile	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,5 +1,4 @@
 #
-# Copyright (c) 2005 Martin Decky
-# Copyright (c) 2007 Jakub Jermar
+# Copyright (c) 2011 Jiri Svoboda
 # All rights reserved.
 #
@@ -34,5 +33,16 @@
 
 SOURCES = \
-	tcp.c
+	conn.c \
+	iqueue.c \
+	ncsim.c \
+	pdu.c \
+	rqueue.c \
+	segment.c \
+	seq_no.c \
+	sock.c \
+	tcp.c \
+	test.c \
+	tqueue.c \
+	ucall.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/net/tl/tcp/conn.c
===================================================================
--- uspace/srv/net/tl/tcp/conn.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/conn.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,1162 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file TCP connection processing and state machine
+ */
+
+#include <adt/list.h>
+#include <bool.h>
+#include <errno.h>
+#include <io/log.h>
+#include <macros.h>
+#include <stdlib.h>
+#include "conn.h"
+#include "iqueue.h"
+#include "segment.h"
+#include "seq_no.h"
+#include "tcp_type.h"
+#include "tqueue.h"
+#include "ucall.h"
+
+#define RCV_BUF_SIZE 4096/*2*/
+#define SND_BUF_SIZE 4096
+
+#define MAX_SEGMENT_LIFETIME	(15*1000*1000) //(2*60*1000*1000)
+#define TIME_WAIT_TIMEOUT	(2*MAX_SEGMENT_LIFETIME)
+
+LIST_INITIALIZE(conn_list);
+
+static void tcp_conn_seg_process(tcp_conn_t *conn, tcp_segment_t *seg);
+static void tcp_conn_tw_timer_set(tcp_conn_t *conn);
+static void tcp_conn_tw_timer_clear(tcp_conn_t *conn);
+
+/** Create new segment structure.
+ *
+ * @param lsock		Local socket (will be deeply copied)
+ * @param fsock		Foreign socket (will be deeply copied)
+ * @return		New segment or NULL
+ */
+tcp_conn_t *tcp_conn_new(tcp_sock_t *lsock, tcp_sock_t *fsock)
+{
+	tcp_conn_t *conn = NULL;
+	bool tqueue_inited = false;
+
+	/* Allocate connection structure */
+	conn = calloc(1, sizeof(tcp_conn_t));
+	if (conn == NULL)
+		goto error;
+
+	conn->tw_timer = fibril_timer_create();
+	if (conn->tw_timer == NULL)
+		goto error;
+
+	/* Allocate receive buffer */
+	fibril_mutex_initialize(&conn->rcv_buf_lock);
+	fibril_condvar_initialize(&conn->rcv_buf_cv);
+	conn->rcv_buf_size = RCV_BUF_SIZE;
+	conn->rcv_buf_used = 0;
+	conn->rcv_buf_fin = false;
+
+	conn->rcv_buf = calloc(1, conn->rcv_buf_size);
+	if (conn->rcv_buf == NULL)
+		goto error;
+
+	/** Allocate send buffer */
+	conn->snd_buf_size = SND_BUF_SIZE;
+	conn->snd_buf_used = 0;
+	conn->snd_buf_fin = false;
+	conn->snd_buf = calloc(1, conn->snd_buf_size);
+	if (conn->snd_buf == NULL)
+		goto error;
+
+	/* Set up receive window. */
+	conn->rcv_wnd = conn->rcv_buf_size;
+
+	/* Initialize incoming segment queue */
+	tcp_iqueue_init(&conn->incoming, conn);
+
+	/* Initialize retransmission queue */
+	if (tcp_tqueue_init(&conn->retransmit, conn) != EOK)
+		goto error;
+
+	tqueue_inited = true;
+
+	/* Connection state change signalling */
+	fibril_mutex_initialize(&conn->cstate_lock);
+	fibril_condvar_initialize(&conn->cstate_cv);
+
+	conn->cstate = st_listen;
+	conn->reset = false;
+	conn->ap = ap_passive;
+	conn->fin_is_acked = false;
+	conn->ident.local = *lsock;
+	if (fsock != NULL)
+		conn->ident.foreign = *fsock;
+
+	return conn;
+
+error:
+	if (tqueue_inited)
+		tcp_tqueue_fini(&conn->retransmit);
+	if (conn != NULL && conn->rcv_buf != NULL)
+		free(conn->rcv_buf);
+	if (conn != NULL && conn->snd_buf != NULL)
+		free(conn->snd_buf);
+	if (conn != NULL && conn->tw_timer != NULL)
+		fibril_timer_destroy(conn->tw_timer);
+	if (conn != NULL)
+		free(conn);
+
+	return NULL;
+}
+
+/** Enlist connection.
+ *
+ * Add connection to the connection map.
+ */
+void tcp_conn_add(tcp_conn_t *conn)
+{
+	list_append(&conn->link, &conn_list);
+}
+
+/** Delist connection.
+ *
+ * Remove connection from the connection map.
+ */
+void tcp_conn_remove(tcp_conn_t *conn)
+{
+	list_remove(&conn->link);
+}
+
+static void tcp_conn_state_set(tcp_conn_t *conn, tcp_cstate_t nstate)
+{
+	fibril_mutex_lock(&conn->cstate_lock);
+	conn->cstate = nstate;
+	fibril_condvar_broadcast(&conn->cstate_cv);
+	fibril_mutex_unlock(&conn->cstate_lock);
+}
+
+/** Synchronize connection.
+ *
+ * This is the first step of an active connection attempt,
+ * sends out SYN and sets up ISS and SND.xxx.
+ */
+void tcp_conn_sync(tcp_conn_t *conn)
+{
+	/* XXX select ISS */
+	conn->iss = 1;
+	conn->snd_nxt = conn->iss;
+	conn->snd_una = conn->iss;
+	conn->ap = ap_active;
+
+	tcp_tqueue_ctrl_seg(conn, CTL_SYN);
+	tcp_conn_state_set(conn, st_syn_sent);
+}
+
+/** FIN has been sent.
+ *
+ * This function should be called when FIN is sent over the connection,
+ * as a result the connection state is changed appropriately.
+ */
+void tcp_conn_fin_sent(tcp_conn_t *conn)
+{
+	switch (conn->cstate) {
+	case st_syn_received:
+	case st_established:
+		log_msg(LVL_DEBUG, "%s: FIN sent -> Fin-Wait-1", conn->name);
+		tcp_conn_state_set(conn, st_fin_wait_1);
+		break;
+	case st_close_wait:
+		log_msg(LVL_DEBUG, "%s: FIN sent -> Last-Ack", conn->name);
+		tcp_conn_state_set(conn, st_last_ack);
+		break;
+	default:
+		log_msg(LVL_ERROR, "%s: Connection state %d", conn->name,
+		    conn->cstate);
+		assert(false);
+	}
+
+	conn->fin_is_acked = false;
+}
+
+/** Compare two sockets.
+ *
+ * Two sockets are equal if the address is equal and the port number
+ * is equal.
+ */
+static bool tcp_socket_match(tcp_sock_t *sock, tcp_sock_t *patt)
+{
+	log_msg(LVL_DEBUG, "tcp_socket_match(sock=(%x,%u), pat=(%x,%u))",
+	    sock->addr.ipv4, sock->port, patt->addr.ipv4, patt->port);
+
+	if (patt->addr.ipv4 != TCP_IPV4_ANY &&
+	    patt->addr.ipv4 != sock->addr.ipv4)
+		return false;
+
+	if (patt->port != TCP_PORT_ANY &&
+	    patt->port != sock->port)
+		return false;
+
+	log_msg(LVL_DEBUG, " -> match");
+
+	return true;
+}
+
+/** Match socket with pattern. */
+static bool tcp_sockpair_match(tcp_sockpair_t *sp, tcp_sockpair_t *pattern)
+{
+	log_msg(LVL_DEBUG, "tcp_sockpair_match(%p, %p)", sp, pattern);
+
+	if (!tcp_socket_match(&sp->local, &pattern->local))
+		return false;
+
+	if (!tcp_socket_match(&sp->foreign, &pattern->foreign))
+		return false;
+
+	return true;
+}
+
+/** Find connection structure for specified socket pair.
+ *
+ * A connection is uniquely identified by a socket pair. Look up our
+ * connection map and return connection structure based on socket pair.
+ *
+ * @param sp	Socket pair
+ * @return	Connection structure or NULL if not found.
+ */
+tcp_conn_t *tcp_conn_find(tcp_sockpair_t *sp)
+{
+	log_msg(LVL_DEBUG, "tcp_conn_find(%p)", sp);
+
+	list_foreach(conn_list, link) {
+		tcp_conn_t *conn = list_get_instance(link, tcp_conn_t, link);
+		tcp_sockpair_t *csp = &conn->ident;
+		log_msg(LVL_DEBUG, "compare with conn (f:(%x,%u), l:(%x,%u))",
+		    csp->foreign.addr.ipv4, csp->foreign.port,
+		    csp->local.addr.ipv4, csp->local.port);
+		if (tcp_sockpair_match(sp, csp)) {
+			return conn;
+		}
+	}
+
+	return NULL;
+}
+
+/** Reset connection.
+ *
+ * @param conn	Connection
+ */
+static void tcp_conn_reset(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_reset()", conn->name);
+	tcp_conn_state_set(conn, st_closed);
+	conn->reset = true;
+
+	tcp_conn_tw_timer_clear(conn);
+	tcp_tqueue_clear(&conn->retransmit);
+
+	fibril_condvar_broadcast(&conn->rcv_buf_cv);
+}
+
+/** Signal to the user that connection has been reset.
+ *
+ * Send an out-of-band signal to the user.
+ */
+static void tcp_reset_signal(tcp_conn_t *conn)
+{
+	/* TODO */
+	log_msg(LVL_DEBUG, "%s: tcp_reset_signal()", conn->name);
+}
+
+/** Determine if SYN has been received.
+ *
+ * @param conn	Connection
+ * @return	@c true if SYN has been received, @c false otherwise.
+ */
+bool tcp_conn_got_syn(tcp_conn_t *conn)
+{
+	switch (conn->cstate) {
+	case st_listen:
+	case st_syn_sent:
+		return false;
+	case st_syn_received:
+	case st_established:
+	case st_fin_wait_1:
+	case st_fin_wait_2:
+	case st_close_wait:
+	case st_closing:
+	case st_last_ack:
+	case st_time_wait:
+		return true;
+	case st_closed:
+		log_msg(LVL_WARN, "state=%d", (int) conn->cstate);
+		assert(false);
+	}
+
+	assert(false);
+}
+
+/** Segment arrived in Listen state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+static void tcp_conn_sa_listen(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_conn_sa_listen(%p, %p)", conn, seg);
+
+	if ((seg->ctrl & CTL_RST) != 0) {
+		log_msg(LVL_DEBUG, "Ignoring incoming RST.");
+		return;
+	}
+
+	if ((seg->ctrl & CTL_ACK) != 0) {
+		log_msg(LVL_DEBUG, "Incoming ACK, send acceptable RST.");
+		tcp_reply_rst(&conn->ident, seg);
+		return;
+	}
+
+	if ((seg->ctrl & CTL_SYN) == 0) {
+		log_msg(LVL_DEBUG, "SYN not present. Ignoring segment.");
+		return;
+	}
+
+	log_msg(LVL_DEBUG, "Got SYN, sending SYN, ACK.");
+
+	conn->rcv_nxt = seg->seq + 1;
+	conn->irs = seg->seq;
+
+
+	log_msg(LVL_DEBUG, "rcv_nxt=%u", conn->rcv_nxt);
+
+	if (seg->len > 1)
+		log_msg(LVL_WARN, "SYN combined with data, ignoring data.");
+
+	/* XXX select ISS */
+	conn->iss = 1;
+	conn->snd_nxt = conn->iss;
+	conn->snd_una = conn->iss;
+
+	/*
+	 * Surprisingly the spec does not deal with initial window setting.
+	 * Set SND.WND = SEG.WND and set SND.WL1 so that next segment
+	 * will always be accepted as new window setting.
+	 */
+	conn->snd_wnd = seg->wnd;
+	conn->snd_wl1 = seg->seq;
+	conn->snd_wl2 = seg->seq;
+
+	tcp_conn_state_set(conn, st_syn_received);
+
+	tcp_tqueue_ctrl_seg(conn, CTL_SYN | CTL_ACK /* XXX */);
+
+	tcp_segment_delete(seg);
+}
+
+/** Segment arrived in Syn-Sent state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+static void tcp_conn_sa_syn_sent(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_conn_sa_syn_sent(%p, %p)", conn, seg);
+
+	if ((seg->ctrl & CTL_ACK) != 0) {
+		log_msg(LVL_DEBUG, "snd_una=%u, seg.ack=%u, snd_nxt=%u",
+		    conn->snd_una, seg->ack, conn->snd_nxt);
+		if (!seq_no_ack_acceptable(conn, seg->ack)) {
+			log_msg(LVL_WARN, "ACK not acceptable, send RST.");
+			tcp_reply_rst(&conn->ident, seg);
+			return;
+		}
+	}
+
+	if ((seg->ctrl & CTL_RST) != 0) {
+		log_msg(LVL_DEBUG, "%s: Connection reset. -> Closed",
+		    conn->name);
+		/* Reset connection */
+		tcp_conn_reset(conn);
+		/* XXX delete connection */
+		return;
+	}
+
+	/* XXX precedence */
+
+	if ((seg->ctrl & CTL_SYN) == 0) {
+		log_msg(LVL_DEBUG, "No SYN bit, ignoring segment.");
+		return;
+	}
+
+	conn->rcv_nxt = seg->seq + 1;
+	conn->irs = seg->seq;
+
+	if ((seg->ctrl & CTL_ACK) != 0) {
+		conn->snd_una = seg->ack;
+
+		/*
+		 * Prune acked segments from retransmission queue and
+		 * possibly transmit more data.
+		 */
+		tcp_tqueue_ack_received(conn);
+	}
+
+	log_msg(LVL_DEBUG, "Sent SYN, got SYN.");
+
+	/*
+	 * Surprisingly the spec does not deal with initial window setting.
+	 * Set SND.WND = SEG.WND and set SND.WL1 so that next segment
+	 * will always be accepted as new window setting.
+	 */
+	log_msg(LVL_DEBUG, "SND.WND := %" PRIu32 ", SND.WL1 := %" PRIu32 ", "
+	    "SND.WL2 = %" PRIu32, seg->wnd, seg->seq, seg->seq);
+	conn->snd_wnd = seg->wnd;
+	conn->snd_wl1 = seg->seq;
+	conn->snd_wl2 = seg->seq;
+
+	if (seq_no_syn_acked(conn)) {
+		log_msg(LVL_DEBUG, "%s: syn acked -> Established", conn->name);
+		tcp_conn_state_set(conn, st_established);
+		tcp_tqueue_ctrl_seg(conn, CTL_ACK /* XXX */);
+	} else {
+		log_msg(LVL_DEBUG, "%s: syn not acked -> Syn-Received",
+		    conn->name);
+		tcp_conn_state_set(conn, st_syn_received);
+		tcp_tqueue_ctrl_seg(conn, CTL_SYN | CTL_ACK /* XXX */);
+	}
+
+	tcp_segment_delete(seg);
+}
+
+/** Segment arrived in state where segments are processed in sequence order.
+ *
+ * Queue segment in incoming segments queue for processing.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+static void tcp_conn_sa_queue(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	tcp_segment_t *pseg;
+
+	log_msg(LVL_DEBUG, "tcp_conn_sa_seq(%p, %p)", conn, seg);
+
+	/* Discard unacceptable segments ("old duplicates") */
+	if (!seq_no_segment_acceptable(conn, seg)) {
+		log_msg(LVL_DEBUG, "Replying ACK to unacceptable segment.");
+		tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+		tcp_segment_delete(seg);
+		return;
+	}
+
+	/* Queue for processing */
+	tcp_iqueue_insert_seg(&conn->incoming, seg);
+
+	/*
+	 * Process all segments from incoming queue that are ready.
+	 * Unacceptable segments are discarded by tcp_iqueue_get_ready_seg().
+	 *
+	 * XXX Need to return ACK for unacceptable segments
+	 */
+	while (tcp_iqueue_get_ready_seg(&conn->incoming, &pseg) == EOK)
+		tcp_conn_seg_process(conn, pseg);
+}
+
+/** Process segment RST field.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_rst(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if ((seg->ctrl & CTL_RST) == 0)
+		return cp_continue;
+
+	switch (conn->cstate) {
+	case st_syn_received:
+		/* XXX In case of passive open, revert to Listen state */
+		if (conn->ap == ap_passive) {
+			tcp_conn_state_set(conn, st_listen);
+			/* XXX Revert conn->ident */
+			tcp_conn_tw_timer_clear(conn);
+			tcp_tqueue_clear(&conn->retransmit);
+		} else {
+			tcp_conn_reset(conn);
+		}
+		break;
+	case st_established:
+	case st_fin_wait_1:
+	case st_fin_wait_2:
+	case st_close_wait:
+		/* General "connection reset" signal */
+		tcp_reset_signal(conn);
+		tcp_conn_reset(conn);
+		break;
+	case st_closing:
+	case st_last_ack:
+	case st_time_wait:
+		tcp_conn_reset(conn);
+		break;
+	case st_listen:
+	case st_syn_sent:
+	case st_closed:
+		assert(false);
+	}
+
+	return cp_done;
+}
+
+/** Process segment security and precedence fields.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_sp(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	/* TODO */
+	return cp_continue;
+}
+
+/** Process segment SYN field.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_syn(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if ((seg->ctrl & CTL_SYN) == 0)
+		return cp_continue;
+
+	/*
+	 * Assert SYN is in receive window, otherwise this step should not
+	 * be reached.
+	 */
+	assert(seq_no_in_rcv_wnd(conn, seg->seq));
+
+	log_msg(LVL_WARN, "SYN is in receive window, should send reset. XXX");
+
+	/*
+	 * TODO
+	 *
+	 * Send a reset, resond "reset" to all outstanding RECEIVEs and SEND,
+	 * flush segment queues. Send unsolicited "connection reset" signal
+	 * to user, connection -> closed state, delete TCB, return.
+	 */
+	return cp_done;
+}
+
+/** Process segment ACK field in Syn-Received state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_sr(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if (!seq_no_ack_acceptable(conn, seg->ack)) {
+		/* ACK is not acceptable, send RST. */
+		log_msg(LVL_WARN, "Segment ACK not acceptable, sending RST.");
+		tcp_reply_rst(&conn->ident, seg);
+		tcp_segment_delete(seg);
+		return cp_done;
+	}
+
+	log_msg(LVL_DEBUG, "%s: SYN ACKed -> Established", conn->name);
+
+	tcp_conn_state_set(conn, st_established);
+
+	/* XXX Not mentioned in spec?! */
+	conn->snd_una = seg->ack;
+
+	return cp_continue;
+}
+
+/** Process segment ACK field in Established state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_est(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_conn_seg_proc_ack_est(%p, %p)", conn, seg);
+
+	log_msg(LVL_DEBUG, "SEG.ACK=%u, SND.UNA=%u, SND.NXT=%u",
+	    (unsigned)seg->ack, (unsigned)conn->snd_una,
+	    (unsigned)conn->snd_nxt);
+
+	if (!seq_no_ack_acceptable(conn, seg->ack)) {
+		log_msg(LVL_DEBUG, "ACK not acceptable.");
+		if (!seq_no_ack_duplicate(conn, seg->ack)) {
+			log_msg(LVL_WARN, "Not acceptable, not duplicate. "
+			    "Send ACK and drop.");
+			/* Not acceptable, not duplicate. Send ACK and drop. */
+			tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+			tcp_segment_delete(seg);
+			return cp_done;
+		} else {
+			log_msg(LVL_DEBUG, "Ignoring duplicate ACK.");
+		}
+	} else {
+		/* Update SND.UNA */
+		conn->snd_una = seg->ack;
+	}
+
+	if (seq_no_new_wnd_update(conn, seg)) {
+		conn->snd_wnd = seg->wnd;
+		conn->snd_wl1 = seg->seq;
+		conn->snd_wl2 = seg->ack;
+
+		log_msg(LVL_DEBUG, "Updating send window, SND.WND=%" PRIu32
+		    ", SND.WL1=%" PRIu32 ", SND.WL2=%" PRIu32,
+		    conn->snd_wnd, conn->snd_wl1, conn->snd_wl2);
+	}
+
+	/*
+	 * Prune acked segments from retransmission queue and
+	 * possibly transmit more data.
+	 */
+	tcp_tqueue_ack_received(conn);
+
+	return cp_continue;
+}
+
+/** Process segment ACK field in Fin-Wait-1 state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_fw1(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
+		return cp_done;
+
+	if (conn->fin_is_acked) {
+		log_msg(LVL_DEBUG, "%s: FIN acked -> Fin-Wait-2", conn->name);
+		tcp_conn_state_set(conn, st_fin_wait_2);
+	}
+
+	return cp_continue;
+}
+
+/** Process segment ACK field in Fin-Wait-2 state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_fw2(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
+		return cp_done;
+
+	/* TODO */
+	return cp_continue;
+}
+
+/** Process segment ACK field in Close-Wait state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_cw(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	/* The same processing as in Established state */
+	return tcp_conn_seg_proc_ack_est(conn, seg);
+}
+
+/** Process segment ACK field in Closing state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_cls(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
+		return cp_done;
+
+	/* TODO */
+	return cp_continue;
+}
+
+/** Process segment ACK field in Last-Ack state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_la(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
+		return cp_done;
+
+	if (conn->fin_is_acked) {
+		log_msg(LVL_DEBUG, "%s: FIN acked -> Closed", conn->name);
+		tcp_conn_remove(conn);
+		tcp_conn_state_set(conn, st_closed);
+		return cp_done;
+	}
+
+	return cp_continue;
+}
+
+/** Process segment ACK field in Time-Wait state.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack_tw(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	/* Nothing to do */
+	return cp_continue;
+}
+
+/** Process segment ACK field.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_ack(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_ack(%p, %p)",
+	    conn->name, conn, seg);
+
+	if ((seg->ctrl & CTL_ACK) == 0) {
+		log_msg(LVL_WARN, "Segment has no ACK. Dropping.");
+		tcp_segment_delete(seg);
+		return cp_done;
+	}
+
+	switch (conn->cstate) {
+	case st_syn_received:
+		return tcp_conn_seg_proc_ack_sr(conn, seg);
+	case st_established:
+		return tcp_conn_seg_proc_ack_est(conn, seg);
+	case st_fin_wait_1:
+		return tcp_conn_seg_proc_ack_fw1(conn, seg);
+	case st_fin_wait_2:
+		return tcp_conn_seg_proc_ack_fw2(conn, seg);
+	case st_close_wait:
+		return tcp_conn_seg_proc_ack_cw(conn, seg);
+	case st_closing:
+		return tcp_conn_seg_proc_ack_cls(conn, seg);
+	case st_last_ack:
+		return tcp_conn_seg_proc_ack_la(conn, seg);
+	case st_time_wait:
+		return tcp_conn_seg_proc_ack_tw(conn, seg);
+	case st_listen:
+	case st_syn_sent:
+	case st_closed:
+		assert(false);
+	}
+
+	assert(false);
+}
+
+/** Process segment URG field.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_urg(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	return cp_continue;
+}
+
+/** Process segment text.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_text(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	size_t text_size;
+	size_t xfer_size;
+
+	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_text(%p, %p)",
+	    conn->name, conn, seg);
+
+	switch (conn->cstate) {
+	case st_established:
+	case st_fin_wait_1:
+	case st_fin_wait_2:
+		/* OK */
+		break;
+	case st_close_wait:
+	case st_closing:
+	case st_last_ack:
+	case st_time_wait:
+		/* Invalid since FIN has been received. Ignore text. */
+		return cp_continue;
+	case st_listen:
+	case st_syn_sent:
+	case st_syn_received:
+	case st_closed:
+		assert(false);
+	}
+
+	/*
+	 * Process segment text
+	 */
+	assert(seq_no_segment_ready(conn, seg));
+
+	/* Trim anything outside our receive window */
+	tcp_conn_trim_seg_to_wnd(conn, seg);
+
+	fibril_mutex_lock(&conn->rcv_buf_lock);
+
+	/* Determine how many bytes to copy */
+	text_size = tcp_segment_text_size(seg);
+	xfer_size = min(text_size, conn->rcv_buf_size - conn->rcv_buf_used);
+
+	/* Copy data to receive buffer */
+	tcp_segment_text_copy(seg, conn->rcv_buf + conn->rcv_buf_used,
+	    xfer_size);
+	conn->rcv_buf_used += xfer_size;
+
+	/* Signal to the receive function that new data has arrived */
+	fibril_condvar_broadcast(&conn->rcv_buf_cv);
+	fibril_mutex_unlock(&conn->rcv_buf_lock);
+
+	log_msg(LVL_DEBUG, "Received %zu bytes of data.", xfer_size);
+
+	/* Advance RCV.NXT */
+	conn->rcv_nxt += xfer_size;
+
+	/* Update receive window. XXX Not an efficient strategy. */
+	conn->rcv_wnd -= xfer_size;
+
+	/* Send ACK */
+	if (xfer_size > 0)
+		tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+
+	if (xfer_size < seg->len) {
+		/* Trim part of segment which we just received */
+		tcp_conn_trim_seg_to_wnd(conn, seg);
+	} else {
+		log_msg(LVL_DEBUG, "%s: Nothing left in segment, dropping "
+		    "(xfer_size=%zu, SEG.LEN=%zu, seg->ctrl=%u)",
+		    conn->name, xfer_size, seg->len, (unsigned)seg->ctrl);
+		/* Nothing left in segment */
+		tcp_segment_delete(seg);
+		return cp_done;
+	}
+
+	return cp_continue;
+}
+
+/** Process segment FIN field.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ * @return		cp_done if we are done with this segment, cp_continue
+ *			if not
+ */
+static cproc_t tcp_conn_seg_proc_fin(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_seg_proc_fin(%p, %p)",
+	    conn->name, conn, seg);
+	log_msg(LVL_DEBUG, " seg->len=%zu, seg->ctl=%u", (size_t) seg->len,
+	    (unsigned) seg->ctrl);
+
+	/* Only process FIN if no text is left in segment. */
+	if (tcp_segment_text_size(seg) == 0 && (seg->ctrl & CTL_FIN) != 0) {
+		log_msg(LVL_DEBUG, " - FIN found in segment.");
+
+		/* Send ACK */
+		tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+
+		conn->rcv_nxt++;
+		conn->rcv_wnd--;
+
+		/* Change connection state */
+		switch (conn->cstate) {
+		case st_listen:
+		case st_syn_sent:
+		case st_closed:
+			/* Connection not synchronized */
+			assert(false);
+		case st_syn_received:
+		case st_established:
+			log_msg(LVL_DEBUG, "%s: FIN received -> Close-Wait",
+			    conn->name);
+			tcp_conn_state_set(conn, st_close_wait);
+			break;
+		case st_fin_wait_1:
+			log_msg(LVL_DEBUG, "%s: FIN received -> Closing",
+			    conn->name);
+			tcp_conn_state_set(conn, st_closing);
+			break;
+		case st_fin_wait_2:
+			log_msg(LVL_DEBUG, "%s: FIN received -> Time-Wait",
+			    conn->name);
+			tcp_conn_state_set(conn, st_time_wait);
+			/* Start the Time-Wait timer */
+			tcp_conn_tw_timer_set(conn);
+			break;
+		case st_close_wait:
+		case st_closing:
+		case st_last_ack:
+			/* Do nothing */
+			break;
+		case st_time_wait:
+			/* Restart the Time-Wait timer */
+			tcp_conn_tw_timer_set(conn);
+			break;
+		}
+
+		/* Add FIN to the receive buffer */
+		fibril_mutex_lock(&conn->rcv_buf_lock);
+		conn->rcv_buf_fin = true;
+		fibril_condvar_broadcast(&conn->rcv_buf_cv);
+		fibril_mutex_unlock(&conn->rcv_buf_lock);
+
+		tcp_segment_delete(seg);
+		return cp_done;
+	}
+
+	return cp_continue;
+}
+
+/** Process incoming segment.
+ *
+ * We are in connection state where segments are processed in order
+ * of sequence number. This processes one segment taken from the
+ * connection incoming segments queue.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+static void tcp_conn_seg_process(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_conn_seg_process(%p, %p)", conn, seg);
+	tcp_segment_dump(seg);
+
+	/* Check whether segment is acceptable */
+	/* XXX Permit valid ACKs, URGs and RSTs */
+/*	if (!seq_no_segment_acceptable(conn, seg)) {
+		log_msg(LVL_WARN, "Segment not acceptable, dropping.");
+		if ((seg->ctrl & CTL_RST) == 0) {
+			tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+		}
+		return;
+	}
+*/
+
+	if (tcp_conn_seg_proc_rst(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_sp(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_syn(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_ack(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_urg(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_text(conn, seg) == cp_done)
+		return;
+
+	if (tcp_conn_seg_proc_fin(conn, seg) == cp_done)
+		return;
+
+	/*
+	 * If anything is left from the segment, insert it back into the
+	 * incoming segments queue.
+	 */
+	if (seg->len > 0) {
+		log_msg(LVL_DEBUG, "Re-insert segment %p. seg->len=%zu",
+		    seg, (size_t) seg->len);
+		tcp_iqueue_insert_seg(&conn->incoming, seg);
+	} else {
+		tcp_segment_delete(seg);
+	}
+}
+
+/** Segment arrived on a connection.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+void tcp_conn_segment_arrived(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "%c: tcp_conn_segment_arrived(%p)",
+	    conn->name, seg);
+
+	switch (conn->cstate) {
+	case st_listen:
+		tcp_conn_sa_listen(conn, seg); break;
+	case st_syn_sent:
+		tcp_conn_sa_syn_sent(conn, seg); break;
+	case st_syn_received:
+	case st_established:
+	case st_fin_wait_1:
+	case st_fin_wait_2:
+	case st_close_wait:
+	case st_closing:
+	case st_last_ack:
+	case st_time_wait:
+		/* Process segments in order of sequence number */
+		tcp_conn_sa_queue(conn, seg); break;
+	case st_closed:
+		log_msg(LVL_DEBUG, "state=%d", (int) conn->cstate);
+		assert(false);
+	}
+}
+
+/** Time-Wait timeout handler.
+ *
+ * @param arg	Connection
+ */
+static void tw_timeout_func(void *arg)
+{
+	tcp_conn_t *conn = (tcp_conn_t *) arg;
+
+	log_msg(LVL_DEBUG, "tw_timeout_func(%p)", conn);
+
+	if (conn->cstate == st_closed) {
+		log_msg(LVL_DEBUG, "Connection already closed.");
+		return;
+	}
+
+	log_msg(LVL_DEBUG, "%s: TW Timeout -> Closed", conn->name);
+	tcp_conn_remove(conn);
+	tcp_conn_state_set(conn, st_closed);
+}
+
+/** Start or restart the Time-Wait timeout.
+ *
+ * @param conn		Connection
+ */
+void tcp_conn_tw_timer_set(tcp_conn_t *conn)
+{
+	fibril_timer_set(conn->tw_timer, TIME_WAIT_TIMEOUT, tw_timeout_func,
+	    (void *)conn);
+}
+
+/** Clear the Time-Wait timeout.
+ *
+ * @param conn		Connection
+ */
+void tcp_conn_tw_timer_clear(tcp_conn_t *conn)
+{
+	fibril_timer_clear(conn->tw_timer);
+}
+
+/** Trim segment to the receive window.
+ *
+ * @param conn		Connection
+ * @param seg		Segment
+ */
+void tcp_conn_trim_seg_to_wnd(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	uint32_t left, right;
+
+	seq_no_seg_trim_calc(conn, seg, &left, &right);
+	tcp_segment_trim(seg, left, right);
+}
+
+/** Handle unexpected segment received on a socket pair.
+ *
+ * We reply with an RST unless the received segment has RST.
+ *
+ * @param sp		Socket pair which received the segment
+ * @param seg		Unexpected segment
+ */
+void tcp_unexpected_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_unexpected_segment(%p, %p)", sp, seg);
+
+	if ((seg->ctrl & CTL_RST) == 0)
+		tcp_reply_rst(sp, seg);
+}
+
+/** Compute flipped socket pair for response.
+ *
+ * Flipped socket pair has local and foreign sockets exchanged.
+ *
+ * @param sp		Socket pair
+ * @param fsp		Place to store flipped socket pair
+ */
+void tcp_sockpair_flipped(tcp_sockpair_t *sp, tcp_sockpair_t *fsp)
+{
+	fsp->local = sp->foreign;
+	fsp->foreign = sp->local;
+}
+
+/** Send RST in response to an incoming segment.
+ *
+ * @param sp		Socket pair which received the segment
+ * @param seg		Incoming segment
+ */
+void tcp_reply_rst(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	tcp_segment_t *rseg;
+
+	log_msg(LVL_DEBUG, "tcp_reply_rst(%p, %p)", sp, seg);
+
+	rseg = tcp_segment_make_rst(seg);
+	tcp_transmit_segment(sp, rseg);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/conn.h
===================================================================
--- uspace/srv/net/tl/tcp/conn.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/conn.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP connection processing and state machine
+ */
+
+#ifndef CONN_H
+#define CONN_H
+
+#include <bool.h>
+#include "tcp_type.h"
+
+extern tcp_conn_t *tcp_conn_new(tcp_sock_t *, tcp_sock_t *);
+extern void tcp_conn_add(tcp_conn_t *);
+extern void tcp_conn_remove(tcp_conn_t *);
+extern void tcp_conn_sync(tcp_conn_t *);
+extern void tcp_conn_fin_sent(tcp_conn_t *);
+extern void tcp_conn_ack_of_fin_rcvd(tcp_conn_t *);
+extern tcp_conn_t *tcp_conn_find(tcp_sockpair_t *);
+extern bool tcp_conn_got_syn(tcp_conn_t *);
+extern void tcp_conn_segment_arrived(tcp_conn_t *, tcp_segment_t *);
+extern void tcp_conn_trim_seg_to_wnd(tcp_conn_t *, tcp_segment_t *);
+extern void tcp_unexpected_segment(tcp_sockpair_t *, tcp_segment_t *);
+extern void tcp_sockpair_flipped(tcp_sockpair_t *, tcp_sockpair_t *);
+extern void tcp_reply_rst(tcp_sockpair_t *, tcp_segment_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/iqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/iqueue.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/iqueue.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Connection incoming segments queue
+ *
+ * Segments are sorted in order of their sequence number.
+ */
+
+#include <adt/list.h>
+#include <errno.h>
+#include <io/log.h>
+#include <stdlib.h>
+#include "iqueue.h"
+#include "segment.h"
+#include "seq_no.h"
+#include "tcp_type.h"
+
+/** Initialize incoming segments queue.
+ *
+ * @param iqueue	Incoming queue
+ * @param conn		Connection the queue is associated with
+ */
+void tcp_iqueue_init(tcp_iqueue_t *iqueue, tcp_conn_t *conn)
+{
+	list_initialize(&iqueue->list);
+	iqueue->conn = conn;
+}
+
+/** Insert segment into incoming queue.
+ *
+ * @param iqueue	Incoming queue
+ * @param seg		Segment
+ */
+void tcp_iqueue_insert_seg(tcp_iqueue_t *iqueue, tcp_segment_t *seg)
+{
+	tcp_iqueue_entry_t *iqe;
+	tcp_iqueue_entry_t *qe;
+	link_t *link;
+	log_msg(LVL_DEBUG, "tcp_iqueue_insert_seg()");
+
+	iqe = calloc(1, sizeof(tcp_iqueue_entry_t));
+	if (iqe == NULL) {
+		log_msg(LVL_ERROR, "Failed allocating IQE.");
+		return;
+	}
+
+	iqe->seg = seg;
+
+	/* Sort by sequence number */
+
+	link = list_first(&iqueue->list);
+	while (link != NULL) {
+		qe = list_get_instance(link,
+		    tcp_iqueue_entry_t, link);
+
+		if (seq_no_seg_cmp(iqueue->conn, iqe->seg, qe->seg) >= 0)
+			break;
+	}
+
+	if (link != NULL)
+		list_insert_before(&iqe->link, &qe->link);
+	else
+		list_append(&iqe->link, &iqueue->list);
+}
+
+/** Get next ready segment from incoming queue.
+ *
+ * Return the segment with the earliest sequence number if it is ready.
+ * A segment is ready if its SEG.SEQ is earlier or equal to RCV.NXT.
+ *
+ * @param iqueue	Incoming queue
+ * @param seg		Place to store pointer to segment
+ * @return		EOK on success, ENOENT if no segment is ready
+ */
+int tcp_iqueue_get_ready_seg(tcp_iqueue_t *iqueue, tcp_segment_t **seg)
+{
+	tcp_iqueue_entry_t *iqe;
+	link_t *link;
+
+	log_msg(LVL_DEBUG, "tcp_get_ready_seg()");
+
+	link = list_first(&iqueue->list);
+	if (link == NULL) {
+		log_msg(LVL_DEBUG, "iqueue is empty");
+		return ENOENT;
+	}
+
+	iqe = list_get_instance(link, tcp_iqueue_entry_t, link);
+
+	while (!seq_no_segment_acceptable(iqueue->conn, iqe->seg)) {
+		log_msg(LVL_DEBUG, "Skipping unacceptable segment (RCV.NXT=%"
+		    PRIu32 ", RCV.NXT+RCV.WND=%" PRIu32 ", SEG.SEQ=%" PRIu32
+		    ", SEG.LEN=%" PRIu32 ")", iqueue->conn->rcv_nxt,
+		    iqueue->conn->rcv_nxt + iqueue->conn->rcv_wnd,
+		    iqe->seg->seq, iqe->seg->len);
+
+		list_remove(&iqe->link);
+		tcp_segment_delete(iqe->seg);
+
+         	link = list_first(&iqueue->list);
+		if (link == NULL) {
+			log_msg(LVL_DEBUG, "iqueue is empty");
+			return ENOENT;
+		}
+
+		iqe = list_get_instance(link, tcp_iqueue_entry_t, link);
+	}
+
+	/* Do not return segments that are not ready for processing */
+	if (!seq_no_segment_ready(iqueue->conn, iqe->seg)) {
+		log_msg(LVL_DEBUG, "Next segment not ready: SEG.SEQ=%u, "
+		    "RCV.NXT=%u, SEG.LEN=%u", iqe->seg->seq,
+		    iqueue->conn->rcv_nxt, iqe->seg->len);
+		return ENOENT;
+	}
+
+	log_msg(LVL_DEBUG, "Returning ready segment %p", iqe->seg);
+	list_remove(&iqe->link);
+	*seg = iqe->seg;
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/iqueue.h
===================================================================
--- uspace/srv/net/tl/tcp/iqueue.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/iqueue.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Connection incoming segments queue
+ */
+
+#ifndef IQUEUE_H
+#define IQUEUE_H
+
+#include "tcp_type.h"
+
+extern void tcp_iqueue_init(tcp_iqueue_t *, tcp_conn_t *);
+extern void tcp_iqueue_insert_seg(tcp_iqueue_t *, tcp_segment_t *);
+extern int tcp_iqueue_get_ready_seg(tcp_iqueue_t *, tcp_segment_t **);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/ncsim.c
===================================================================
--- uspace/srv/net/tl/tcp/ncsim.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/ncsim.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Network condition simulator
+ *
+ * Simulate network conditions for testing the reliability implementation:
+ *    - variable latency
+ *    - frame drop
+ */
+
+#include <adt/list.h>
+#include <async.h>
+#include <errno.h>
+#include <io/log.h>
+#include <stdlib.h>
+#include <thread.h>
+#include "conn.h"
+#include "ncsim.h"
+#include "rqueue.h"
+#include "segment.h"
+#include "tcp_type.h"
+
+static list_t sim_queue;
+static fibril_mutex_t sim_queue_lock;
+static fibril_condvar_t sim_queue_cv;
+
+/** Initialize segment receive queue. */
+void tcp_ncsim_init(void)
+{
+	list_initialize(&sim_queue);
+	fibril_mutex_initialize(&sim_queue_lock);
+	fibril_condvar_initialize(&sim_queue_cv);
+}
+
+/** Bounce segment through simulator into receive queue.
+ *
+ * @param sp	Socket pair, oriented for transmission
+ * @param seg	Segment
+ */
+void tcp_ncsim_bounce_seg(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	tcp_squeue_entry_t *sqe;
+	tcp_squeue_entry_t *old_qe;
+	link_t *link;
+
+	log_msg(LVL_DEBUG, "tcp_ncsim_bounce_seg()");
+	tcp_rqueue_bounce_seg(sp, seg);
+	return;
+
+	if (0 /*random() % 4 == 3*/) {
+		/* Drop segment */
+		log_msg(LVL_ERROR, "NCSim dropping segment");
+		tcp_segment_delete(seg);
+		return;
+	}
+
+	sqe = calloc(1, sizeof(tcp_squeue_entry_t));
+	if (sqe == NULL) {
+		log_msg(LVL_ERROR, "Failed allocating SQE.");
+		return;
+	}
+
+	sqe->delay = random() % (1000 * 1000);
+	sqe->sp = *sp;
+	sqe->seg = seg;
+
+	fibril_mutex_lock(&sim_queue_lock);
+
+	link = list_first(&sim_queue);
+	while (link != NULL && sqe->delay > 0) {
+		old_qe = list_get_instance(link, tcp_squeue_entry_t, link);
+		if (sqe->delay < old_qe->delay)
+			break;
+
+		sqe->delay -= old_qe->delay;
+
+		link = link->next;
+		if (link == &sim_queue.head)
+			link = NULL;
+	}
+
+	if (link != NULL)
+		list_insert_after(&sqe->link, link);
+	else
+		list_append(&sqe->link, &sim_queue);
+
+	fibril_condvar_broadcast(&sim_queue_cv);
+	fibril_mutex_unlock(&sim_queue_lock);
+}
+
+/** Network condition simulator handler thread. */
+static void tcp_ncsim_thread(void *arg)
+{
+	link_t *link;
+	tcp_squeue_entry_t *sqe;
+	int rc;
+
+	log_msg(LVL_DEBUG, "tcp_ncsim_thread()");
+
+
+	while (true) {
+		fibril_mutex_lock(&sim_queue_lock);
+
+		while (list_empty(&sim_queue))
+			fibril_condvar_wait(&sim_queue_cv, &sim_queue_lock);
+
+		do {
+			link = list_first(&sim_queue);
+			sqe = list_get_instance(link, tcp_squeue_entry_t, link);
+
+			log_msg(LVL_DEBUG, "NCSim - Sleep");
+			rc = fibril_condvar_wait_timeout(&sim_queue_cv,
+			    &sim_queue_lock, sqe->delay);
+		} while (rc != ETIMEOUT);
+
+		list_remove(link);
+		fibril_mutex_unlock(&sim_queue_lock);
+
+		log_msg(LVL_DEBUG, "NCSim - End Sleep");
+		tcp_rqueue_bounce_seg(&sqe->sp, sqe->seg);
+		free(sqe);
+	}
+}
+
+/** Start simulator handler thread. */
+void tcp_ncsim_thread_start(void)
+{
+	thread_id_t tid;
+        int rc;
+
+	log_msg(LVL_DEBUG, "tcp_ncsim_thread_start()");
+
+	rc = thread_create(tcp_ncsim_thread, NULL, "ncsim", &tid);
+	if (rc != EOK) {
+		log_msg(LVL_ERROR, "Failed creating ncsim thread.");
+		return;
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/ncsim.h
===================================================================
--- uspace/srv/net/tl/tcp/ncsim.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/ncsim.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Network condition simulator
+ */
+
+#ifndef NCSIM_H
+#define NCSIM_H
+
+#include "tcp_type.h"
+
+extern void tcp_ncsim_init(void);
+extern void tcp_ncsim_bounce_seg(tcp_sockpair_t *, tcp_segment_t *);
+extern void tcp_ncsim_thread_start(void);
+
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/pdu.c
===================================================================
--- uspace/srv/net/tl/tcp/pdu.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/pdu.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file TCP header encoding and decoding
+ */
+
+#include <bitops.h>
+#include <byteorder.h>
+#include <errno.h>
+#include <mem.h>
+#include <stdlib.h>
+#include "pdu.h"
+#include "segment.h"
+#include "seq_no.h"
+#include "std.h"
+#include "tcp_type.h"
+
+#define TCP_CHECKSUM_INIT 0xffff
+
+/** One's complement addition.
+ *
+ * Result is a + b + carry.
+ */
+static uint16_t tcp_ocadd16(uint16_t a, uint16_t b)
+{
+	uint32_t s;
+
+	s = (uint32_t)a + (uint32_t)b;
+	return (s & 0xffff) + (s >> 16);
+}
+
+static uint16_t tcp_checksum_calc(uint16_t ivalue, void *data, size_t size)
+{
+	uint16_t sum;
+	uint16_t w;
+	size_t words, i;
+	uint8_t *bdata;
+
+	sum = ~ivalue;
+	words = size / 2;
+	bdata = (uint8_t *)data;
+
+	for (i = 0; i < words; i++) {
+		w = ((uint16_t)bdata[2*i] << 8) | bdata[2*i + 1];
+		sum = tcp_ocadd16(sum, w);
+	}
+
+	if (size % 2 != 0) {
+		w = ((uint16_t)bdata[2*words] << 8);
+		sum = tcp_ocadd16(sum, w);
+	}
+
+	return ~sum;
+}
+
+static void tcp_header_decode_flags(uint16_t doff_flags, tcp_control_t *rctl)
+{
+	tcp_control_t ctl;
+
+	ctl = 0;
+
+	if ((doff_flags & BIT_V(uint16_t, DF_URG)) != 0)
+		ctl |= 0 /* XXX */;
+	if ((doff_flags & BIT_V(uint16_t, DF_ACK)) != 0)
+		ctl |= CTL_ACK;
+	if ((doff_flags & BIT_V(uint16_t, DF_PSH)) != 0)
+		ctl |= 0 /* XXX */;
+	if ((doff_flags & BIT_V(uint16_t, DF_RST)) != 0)
+		ctl |= CTL_RST;
+	if ((doff_flags & BIT_V(uint16_t, DF_SYN)) != 0)
+		ctl |= CTL_SYN;
+	if ((doff_flags & BIT_V(uint16_t, DF_FIN)) != 0)
+		ctl |= CTL_FIN;
+
+	*rctl = ctl;
+}
+
+static void tcp_header_encode_flags(tcp_control_t ctl, uint16_t doff_flags0,
+    uint16_t *rdoff_flags)
+{
+	uint16_t doff_flags;
+
+	doff_flags = doff_flags0;
+
+	if ((ctl & CTL_ACK) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_ACK);
+	if ((ctl & CTL_RST) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_RST);
+	if ((ctl & CTL_SYN) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_SYN);
+	if ((ctl & CTL_FIN) != 0)
+		doff_flags |= BIT_V(uint16_t, DF_FIN);
+
+	*rdoff_flags = doff_flags;
+}
+
+static void tcp_header_setup(tcp_sockpair_t *sp, tcp_segment_t *seg, tcp_header_t *hdr)
+{
+	uint16_t doff_flags;
+	uint16_t doff;
+
+	hdr->src_port = host2uint16_t_be(sp->local.port);
+	hdr->dest_port = host2uint16_t_be(sp->foreign.port);
+	hdr->seq = host2uint32_t_be(seg->seq);
+	hdr->ack = host2uint32_t_be(seg->ack);
+
+	doff = (sizeof(tcp_header_t) / sizeof(uint32_t)) << DF_DATA_OFFSET_l;
+	tcp_header_encode_flags(seg->ctrl, doff, &doff_flags);
+
+	hdr->doff_flags = host2uint16_t_be(doff_flags);
+	hdr->window = host2uint16_t_be(seg->wnd);
+	hdr->checksum = 0;
+	hdr->urg_ptr = host2uint16_t_be(seg->up);
+}
+
+static void tcp_phdr_setup(tcp_pdu_t *pdu, tcp_phdr_t *phdr)
+{
+	phdr->src_addr = host2uint32_t_be(pdu->src_addr.ipv4);
+	phdr->dest_addr = host2uint32_t_be(pdu->dest_addr.ipv4);
+	phdr->zero = 0;
+	phdr->protocol = 6; /* XXX Magic number */
+	phdr->tcp_length = host2uint16_t_be(pdu->header_size + pdu->text_size);
+}
+
+static void tcp_header_decode(tcp_header_t *hdr, tcp_segment_t *seg)
+{
+	tcp_header_decode_flags(uint16_t_be2host(hdr->doff_flags), &seg->ctrl);
+	seg->seq = uint32_t_be2host(hdr->seq);
+	seg->ack = uint32_t_be2host(hdr->ack);
+	seg->wnd = uint16_t_be2host(hdr->window);
+	seg->up = uint16_t_be2host(hdr->urg_ptr);
+}
+
+static int tcp_header_encode(tcp_sockpair_t *sp, tcp_segment_t *seg,
+    void **header, size_t *size)
+{
+	tcp_header_t *hdr;
+
+	hdr = calloc(1, sizeof(tcp_header_t));
+	if (hdr == NULL)
+		return ENOMEM;
+
+	tcp_header_setup(sp, seg, hdr);
+	*header = hdr;
+	*size = sizeof(tcp_header_t);
+
+	return EOK;
+}
+
+static tcp_pdu_t *tcp_pdu_new(void)
+{
+	return calloc(1, sizeof(tcp_pdu_t));
+}
+
+/** Create PDU with the specified header and text data.
+ *
+ * Note that you still need to set addresses in the returned PDU.
+ *
+ * @param hdr		Header data
+ * @param hdr_size      Header size in bytes
+ * @param text		Text data
+ * @param text_size	Text size in bytes
+ * @return		New PDU
+ */
+tcp_pdu_t *tcp_pdu_create(void *hdr, size_t hdr_size, void *text,
+    size_t text_size)
+{
+	tcp_pdu_t *pdu;
+
+	pdu = tcp_pdu_new();
+	if (pdu == NULL)
+		return NULL;
+
+	pdu->header = malloc(hdr_size);
+	pdu->text = malloc(text_size);
+	if (pdu->header == NULL || pdu->text == NULL)
+		goto error;
+
+	memcpy(pdu->header, hdr, hdr_size);
+	memcpy(pdu->text, text, text_size);
+
+	pdu->header_size = hdr_size;
+	pdu->text_size = text_size;
+
+	return pdu;
+
+error:
+	if (pdu->header != NULL)
+		free(pdu->header);
+	if (pdu->text != NULL)
+		free(pdu->text);
+
+	return NULL;
+}
+
+void tcp_pdu_delete(tcp_pdu_t *pdu)
+{
+	free(pdu->header);
+	free(pdu->text);
+	free(pdu);
+}
+
+static uint16_t tcp_pdu_checksum_calc(tcp_pdu_t *pdu)
+{
+	uint16_t cs_phdr;
+	uint16_t cs_headers;
+	uint16_t cs_all;
+	tcp_phdr_t phdr;
+
+	tcp_phdr_setup(pdu, &phdr);
+	cs_phdr = tcp_checksum_calc(TCP_CHECKSUM_INIT, (void *)&phdr,
+	    sizeof(tcp_phdr_t));
+	cs_headers = tcp_checksum_calc(cs_phdr, pdu->header, pdu->header_size);
+	cs_all = tcp_checksum_calc(cs_headers, pdu->text, pdu->text_size);
+
+	return cs_all;
+}
+
+static void tcp_pdu_set_checksum(tcp_pdu_t *pdu, uint16_t checksum)
+{
+	tcp_header_t *hdr;
+
+	hdr = (tcp_header_t *)pdu->header;
+	hdr->checksum = host2uint16_t_be(checksum);
+}
+
+/** Encode outgoing PDU */
+int tcp_pdu_decode(tcp_pdu_t *pdu, tcp_sockpair_t *sp, tcp_segment_t **seg)
+{
+	tcp_segment_t *nseg;
+	tcp_header_t *hdr;
+
+	nseg = tcp_segment_make_data(0, pdu->text, pdu->text_size);
+	if (nseg == NULL)
+		return ENOMEM;
+
+	tcp_header_decode(pdu->header, nseg);
+	nseg->len += seq_no_control_len(nseg->ctrl);
+
+	hdr = (tcp_header_t *)pdu->header;
+
+	sp->local.port = uint16_t_be2host(hdr->dest_port);
+	sp->local.addr = pdu->dest_addr;
+	sp->foreign.port = uint16_t_be2host(hdr->src_port);
+	sp->foreign.addr = pdu->src_addr;
+
+	*seg = nseg;
+	return EOK;
+}
+
+/** Decode incoming PDU */
+int tcp_pdu_encode(tcp_sockpair_t *sp, tcp_segment_t *seg, tcp_pdu_t **pdu)
+{
+	tcp_pdu_t *npdu;
+	size_t text_size;
+	uint16_t checksum;
+
+	npdu = tcp_pdu_new();
+	if (npdu == NULL)
+		return ENOMEM;
+
+	npdu->src_addr = sp->local.addr;
+	npdu->dest_addr = sp->foreign.addr;
+	tcp_header_encode(sp, seg, &npdu->header, &npdu->header_size);
+
+	text_size = tcp_segment_text_size(seg);
+	npdu->text = calloc(1, text_size);
+	if (npdu->text == NULL)
+		return ENOMEM;
+
+	npdu->text_size = text_size;
+	memcpy(npdu->text, seg->data, text_size);
+
+	/* Checksum calculation */
+	checksum = tcp_pdu_checksum_calc(npdu);
+	tcp_pdu_set_checksum(npdu, checksum);
+
+	*pdu = npdu;
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/pdu.h
===================================================================
--- uspace/srv/net/tl/tcp/pdu.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/pdu.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP PDU (encoded Protocol Data Unit) handling
+ */
+
+#ifndef PDU_H
+#define PDU_H
+
+#include <sys/types.h>
+#include "std.h"
+#include "tcp_type.h"
+
+extern tcp_pdu_t *tcp_pdu_create(void *, size_t, void *, size_t);
+extern void tcp_pdu_delete(tcp_pdu_t *);
+extern int tcp_pdu_decode(tcp_pdu_t *, tcp_sockpair_t *, tcp_segment_t **);
+extern int tcp_pdu_encode(tcp_sockpair_t *, tcp_segment_t *, tcp_pdu_t **);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/rqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/rqueue.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/rqueue.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Global segment receive queue
+ */
+
+#include <adt/prodcons.h>
+#include <errno.h>
+#include <io/log.h>
+#include <stdlib.h>
+#include <thread.h>
+#include "conn.h"
+#include "pdu.h"
+#include "rqueue.h"
+#include "segment.h"
+#include "tcp_type.h"
+#include "ucall.h"
+
+/** Transcode bounced segments.
+ *
+ * If defined, segments bounced via the internal debugging loopback will
+ * be encoded to a PDU and the decoded. Otherwise they will be bounced back
+ * directly without passing the encoder-decoder.
+ */
+#define BOUNCE_TRANSCODE
+
+static prodcons_t rqueue;
+
+/** Initialize segment receive queue. */
+void tcp_rqueue_init(void)
+{
+	prodcons_initialize(&rqueue);
+}
+
+/** Bounce segment directy into receive queue without constructing the PDU.
+ *
+ * This is for testing purposes only.
+ *
+ * @param sp	Socket pair, oriented for transmission
+ * @param seg	Segment
+ */
+void tcp_rqueue_bounce_seg(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	tcp_sockpair_t rident;
+
+	log_msg(LVL_DEBUG, "tcp_rqueue_bounce_seg()");
+
+#ifdef BOUNCE_TRANSCODE
+	tcp_pdu_t *pdu;
+	tcp_segment_t *dseg;
+
+	if (tcp_pdu_encode(sp, seg, &pdu) != EOK) {
+		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		return;
+	}
+
+	if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
+		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		return;
+	}
+
+	tcp_pdu_delete(pdu);
+
+	/** Insert decoded segment into rqueue */
+	tcp_rqueue_insert_seg(&rident, dseg);
+	tcp_segment_delete(seg);
+#else
+	/* Reverse the identification */
+	tcp_sockpair_flipped(sp, &rident);
+
+	/* Insert segment back into rqueue */
+	tcp_rqueue_insert_seg(&rident, seg);
+#endif
+}
+
+/** Insert segment into receive queue.
+ *
+ * @param sp	Socket pair, oriented for reception
+ * @param seg	Segment
+ */
+void tcp_rqueue_insert_seg(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	tcp_rqueue_entry_t *rqe;
+	log_msg(LVL_DEBUG, "tcp_rqueue_insert_seg()");
+
+	tcp_segment_dump(seg);
+
+	rqe = calloc(1, sizeof(tcp_rqueue_entry_t));
+	if (rqe == NULL) {
+		log_msg(LVL_ERROR, "Failed allocating RQE.");
+		return;
+	}
+
+	rqe->sp = *sp;
+	rqe->seg = seg;
+
+	prodcons_produce(&rqueue, &rqe->link);
+}
+
+/** Receive queue handler thread. */
+static void tcp_rqueue_thread(void *arg)
+{
+	link_t *link;
+	tcp_rqueue_entry_t *rqe;
+
+	log_msg(LVL_DEBUG, "tcp_rqueue_thread()");
+
+	while (true) {
+		link = prodcons_consume(&rqueue);
+		rqe = list_get_instance(link, tcp_rqueue_entry_t, link);
+
+		tcp_as_segment_arrived(&rqe->sp, rqe->seg);
+	}
+}
+
+/** Start receive queue handler thread. */
+void tcp_rqueue_thread_start(void)
+{
+	thread_id_t tid;
+        int rc;
+
+	log_msg(LVL_DEBUG, "tcp_rqueue_thread_start()");
+
+	rc = thread_create(tcp_rqueue_thread, NULL, "rqueue", &tid);
+	if (rc != EOK) {
+		log_msg(LVL_ERROR, "Failed creating rqueue thread.");
+		return;
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/rqueue.h
===================================================================
--- uspace/srv/net/tl/tcp/rqueue.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/rqueue.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Global segment receive queue
+ */
+
+#ifndef RQUEUE_H
+#define RQUEUE_H
+
+#include "tcp_type.h"
+
+extern void tcp_rqueue_init(void);
+extern void tcp_rqueue_bounce_seg(tcp_sockpair_t *, tcp_segment_t *);
+extern void tcp_rqueue_insert_seg(tcp_sockpair_t *, tcp_segment_t *);
+extern void tcp_rqueue_handler(void *);
+extern void tcp_rqueue_thread_start(void);
+
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/segment.c
===================================================================
--- uspace/srv/net/tl/tcp/segment.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/segment.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Segment processing
+ */
+
+#include <io/log.h>
+#include <mem.h>
+#include <stdlib.h>
+#include "segment.h"
+#include "seq_no.h"
+#include "tcp_type.h"
+
+/** Alocate new segment structure. */
+tcp_segment_t *tcp_segment_new(void)
+{
+	return calloc(1, sizeof(tcp_segment_t));
+}
+
+/** Delete segment. */
+void tcp_segment_delete(tcp_segment_t *seg)
+{
+	free(seg);
+}
+
+/** Create duplicate of segment.
+ *
+ * @param seg	Segment
+ * @return 	Duplicate segment
+ */
+tcp_segment_t *tcp_segment_dup(tcp_segment_t *seg)
+{
+	tcp_segment_t *scopy;
+	size_t tsize;
+
+	scopy = tcp_segment_new();
+	if (scopy == NULL)
+		return NULL;
+
+	scopy->ctrl = seg->ctrl;
+	scopy->seq = seg->seq;
+	scopy->ack = seg->ack;
+	scopy->len = seg->len;
+	scopy->wnd = seg->wnd;
+	scopy->up = seg->up;
+
+	tsize = tcp_segment_text_size(seg);
+	scopy->data = calloc(tsize, 1);
+	if (scopy->data == NULL) {
+		free(scopy);
+		return NULL;
+	}
+
+	memcpy(scopy->data, seg->data, tsize);
+	scopy->dfptr = scopy->data;
+
+	return scopy;
+}
+
+/** Create a control-only segment.
+ *
+  * @return	Segment
+ */
+tcp_segment_t *tcp_segment_make_ctrl(tcp_control_t ctrl)
+{
+	tcp_segment_t *seg;
+
+	seg = tcp_segment_new();
+	if (seg == NULL)
+		return NULL;
+
+	seg->ctrl = ctrl;
+	seg->len = seq_no_control_len(ctrl);
+
+	return seg;
+}
+
+/** Create an RST segment.
+ *
+ * @param seg	Segment we are replying to
+ * @return	RST segment
+ */
+tcp_segment_t *tcp_segment_make_rst(tcp_segment_t *seg)
+{
+	tcp_segment_t *rseg;
+
+	rseg = tcp_segment_new();
+	if (rseg == NULL)
+		return NULL;
+
+	rseg->ctrl = CTL_RST;
+	rseg->seq = seg->ack;
+
+	return rseg;
+}
+
+/** Create a control segment.
+ *
+  * @return	Segment
+ */
+tcp_segment_t *tcp_segment_make_data(tcp_control_t ctrl, void *data,
+    size_t size)
+{
+	tcp_segment_t *seg;
+
+	seg = tcp_segment_new();
+	if (seg == NULL)
+		return NULL;
+
+	seg->ctrl = ctrl;
+	seg->len = seq_no_control_len(ctrl) + size;
+
+	seg->dfptr = seg->data = malloc(size);
+	if (seg->dfptr == NULL) {
+		free(seg);
+		return NULL;
+	}
+
+	memcpy(seg->data, data, size);
+
+	return seg;
+}
+
+
+/** Trim segment from left and right by the specified amount.
+ *
+ * Trim any text or control to remove the specified amount of sequence
+ * numbers from the left (lower sequence numbers) and right side
+ * (higher sequence numbers) of the segment.
+ *
+ * @param seg		Segment, will be modified in place
+ * @param left		Amount of sequence numbers to trim from the left
+ * @param right		Amount of sequence numbers to trim from the right
+ */
+void tcp_segment_trim(tcp_segment_t *seg, uint32_t left, uint32_t right)
+{
+	uint32_t t_size;
+
+	assert(left + right <= seg->len);
+
+	/* Special case, entire segment trimmed from left */
+	if (left == seg->len) {
+		seg->seq = seg->seq + seg->len;
+		seg->len = 0;
+		return;
+	}
+
+	/* Special case, entire segment trimmed from right */
+	if (right == seg->len) {
+		seg->len = 0;
+		return;
+	}
+
+	/* General case */
+
+	t_size = tcp_segment_text_size(seg);
+
+	if (left > 0 && (seg->ctrl & CTL_SYN) != 0) {
+		/* Trim SYN */
+		seg->ctrl &= ~CTL_SYN;
+		seg->seq++;
+		seg->len--;
+		left--;
+	}
+
+	if (right > 0 && (seg->ctrl & CTL_FIN) != 0) {
+		/* Trim FIN */
+		seg->ctrl &= ~CTL_FIN;
+		seg->len--;
+		right--;
+	}
+
+	if (left > 0 || right > 0) {
+		/* Trim segment text */
+		assert(left + right <= t_size);
+
+		seg->data += left;
+		seg->len -= left + right;
+	}
+}
+
+/** Copy out text data from segment.
+ *
+ * Data is copied from the beginning of the segment text up to @a size bytes.
+ * @a size must not be greater than the size of the segment text, but
+ * it can be less.
+ *
+ * @param seg	Segment
+ * @param buf	Destination buffer
+ * @param size	Size of destination buffer
+ */
+void tcp_segment_text_copy(tcp_segment_t *seg, void *buf, size_t size)
+{
+	assert(size <= tcp_segment_text_size(seg));
+	memcpy(buf, seg->data, size);
+}
+
+/** Return number of bytes in segment text.
+ *
+ * @param seg	Segment
+ * @return	Number of bytes in segment text
+ */
+size_t tcp_segment_text_size(tcp_segment_t *seg)
+{
+	return seg->len - seq_no_control_len(seg->ctrl);
+}
+
+/** Dump segment contents to log.
+ *
+ * @param seg	Segment
+ */
+void tcp_segment_dump(tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "Segment dump:");
+	log_msg(LVL_DEBUG, " - ctrl = %u", (unsigned)seg->ctrl);
+	log_msg(LVL_DEBUG, " - seq = % " PRIu32, seg->seq);
+	log_msg(LVL_DEBUG, " - ack = % " PRIu32, seg->ack);
+	log_msg(LVL_DEBUG, " - len = % " PRIu32, seg->len);
+	log_msg(LVL_DEBUG, " - wnd = % " PRIu32, seg->wnd);
+	log_msg(LVL_DEBUG, " - up = % " PRIu32, seg->up);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/segment.h
===================================================================
--- uspace/srv/net/tl/tcp/segment.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/segment.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Segment processing
+ */
+
+#ifndef SEGMENT_H
+#define SEGMENT_H
+
+#include <sys/types.h>
+#include "tcp_type.h"
+
+extern tcp_segment_t *tcp_segment_new(void);
+extern void tcp_segment_delete(tcp_segment_t *);
+extern tcp_segment_t *tcp_segment_dup(tcp_segment_t *);
+extern tcp_segment_t *tcp_segment_make_ctrl(tcp_control_t);
+extern tcp_segment_t *tcp_segment_make_rst(tcp_segment_t *);
+extern tcp_segment_t *tcp_segment_make_data(tcp_control_t, void *, size_t);
+extern void tcp_segment_trim(tcp_segment_t *, uint32_t, uint32_t);
+extern void tcp_segment_text_copy(tcp_segment_t *, void *, size_t);
+extern size_t tcp_segment_text_size(tcp_segment_t *);
+extern void tcp_segment_dump(tcp_segment_t *);
+
+
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/seq_no.c
===================================================================
--- uspace/srv/net/tl/tcp/seq_no.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/seq_no.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Sequence number computations
+ */
+
+#include <assert.h>
+#include <bool.h>
+#include <sys/types.h>
+#include "seq_no.h"
+#include "tcp_type.h"
+
+/** a <= b < c modulo sequence space */
+static bool seq_no_le_lt(uint32_t a, uint32_t b, uint32_t c)
+{
+	if (a <= c) {
+		return (a <= b) && (b < c);
+	} else {
+		return (b < c) || (a <= b);
+	}
+}
+
+/** a < b <= c modulo sequence space */
+static bool seq_no_lt_le(uint32_t a, uint32_t b, uint32_t c)
+{
+	if (a <= c) {
+		return (a < b) && (b <= c);
+	} else {
+		return (b <= c) || (a < b);
+	}
+}
+
+/** Determine wheter ack is acceptable (new acknowledgement) */
+bool seq_no_ack_acceptable(tcp_conn_t *conn, uint32_t seg_ack)
+{
+	/* SND.UNA < SEG.ACK <= SND.NXT */
+	return seq_no_lt_le(conn->snd_una, seg_ack, conn->snd_nxt);
+}
+
+/** Determine wheter ack is duplicate.
+ *
+ * ACK is duplicate if it refers to a sequence number that has
+ * aleady been acked (SEG.ACK <= SND.UNA).
+ */
+bool seq_no_ack_duplicate(tcp_conn_t *conn, uint32_t seg_ack)
+{
+	uint32_t diff;
+
+	/*
+	 * There does not seem to be a three-point comparison
+	 * equivalent of SEG.ACK < SND.UNA. Thus we do it
+	 * on a best-effort basis, based on the difference.
+	 * [-2^31, 0) means less-than, 0 means equal, [0, 2^31)
+	 * means greater-than. Less-than or equal means duplicate.
+	 */
+	diff = seg_ack - conn->snd_una;
+	return diff == 0 || (diff & (0x1 << 31)) != 0;
+}
+
+/** Determine if sequence number is in receive window. */
+bool seq_no_in_rcv_wnd(tcp_conn_t *conn, uint32_t sn)
+{
+	return seq_no_le_lt(conn->rcv_nxt, sn, conn->rcv_nxt + conn->rcv_wnd);
+}
+
+/** Determine segment has new window update.
+ *
+ * Window update is new if either SND.WL1 < SEG.SEQ or
+ * (SND.WL1 = SEG.SEQ and SND.WL2 <= SEG.ACK).
+ */
+bool seq_no_new_wnd_update(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	bool n_seq, n_ack;
+
+	assert(seq_no_segment_acceptable(conn, seg));
+
+	/*
+	 * We make use of the fact that the peer should not ACK anything
+	 * beyond our send window (we surely haven't sent that yet)
+	 * as we should have filtered those acks out.
+	 * We use SND.UNA+SND.WND as the third point of comparison.
+	 */
+
+	n_seq = seq_no_lt_le(conn->snd_wl1, seg->seq,
+	    conn->snd_una + conn->snd_wnd);
+
+	n_ack = conn->snd_wl1 == seg->seq &&
+	    seq_no_le_lt(conn->snd_wl2, seg->ack,
+	    conn->snd_una + conn->snd_wnd + 1);
+
+	return n_seq || n_ack;
+}
+
+/** Determine if segment is ready for processing.
+ *
+ * Assuming segment is acceptable, a segment is ready if it intersects
+ * RCV.NXT, that is we can process it immediately.
+ */
+bool seq_no_segment_ready(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	assert(seq_no_segment_acceptable(conn, seg));
+
+	return seq_no_le_lt(seg->seq, conn->rcv_nxt, seg->seq + seg->len + 1);
+}
+
+/** Determine whether segment is fully acked */
+bool seq_no_segment_acked(tcp_conn_t *conn, tcp_segment_t *seg, uint32_t ack)
+{
+	assert(seg->len > 0);
+	return seq_no_lt_le(seg->seq, seg->seq + seg->len, ack);
+}
+
+/** Determine whether initial SYN is acked */
+bool seq_no_syn_acked(tcp_conn_t *conn)
+{
+	return seq_no_lt_le(conn->iss, conn->snd_una, conn->snd_nxt);
+}
+
+/** Determine whether segment overlaps the receive window */
+bool seq_no_segment_acceptable(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	bool b_in, e_in;
+
+	b_in = seq_no_le_lt(conn->rcv_nxt, seg->seq, conn->rcv_nxt
+	    + conn->rcv_wnd);
+
+	e_in = seq_no_le_lt(conn->rcv_nxt, seg->seq + seg->len - 1,
+	    conn->rcv_nxt + conn->rcv_wnd);
+
+	if (seg->len == 0 && conn->rcv_wnd == 0) {
+		return seg->seq == conn->rcv_nxt;
+	} else if (seg->len == 0 && conn->rcv_wnd != 0) {
+		return b_in;
+	} else if (seg->len > 0 && conn->rcv_wnd == 0) {
+		return false;
+	} else {
+		return b_in || e_in;
+	}
+}
+
+/** Determine size that control bits occupy in sequence space. */
+uint32_t seq_no_control_len(tcp_control_t ctrl)
+{
+	uint32_t len = 0;
+
+	if ((ctrl & CTL_SYN) != 0)
+		++len;
+
+	if ((ctrl & CTL_FIN) != 0)
+		++len;
+
+	return len;
+}
+
+/** Calculate the amount of trim needed to fit segment in receive window. */
+void seq_no_seg_trim_calc(tcp_conn_t *conn, tcp_segment_t *seg,
+    uint32_t *left, uint32_t *right)
+{
+	assert(seq_no_segment_acceptable(conn, seg));
+
+	/*
+	 * If RCV.NXT is between SEG.SEQ and RCV.NXT+RCV.WND, then
+	 * left trim amount is positive
+	 */
+	if (seq_no_lt_le(seg->seq, conn->rcv_nxt,
+	    conn->rcv_nxt + conn->rcv_wnd)) {
+		*left = conn->rcv_nxt - seg->seq;
+	} else {
+		*left = 0;
+	}
+
+	/*
+	 * If SEG.SEQ+SEG.LEN is between SEG.SEQ and RCV.NXT+RCV.WND,
+	 * then right trim is zero.
+	 */
+	if (seq_no_lt_le(seg->seq - 1, seg->seq + seg->len,
+	    conn->rcv_nxt + conn->rcv_wnd)) {
+		*right = 0;
+	} else {
+		*right = (seg->seq + seg->len) -
+		    (conn->rcv_nxt + conn->rcv_wnd);
+	}
+}
+
+/** Segment order comparison.
+ *
+ * Compare sequence order of two acceptable segments.
+ *
+ * @param conn		Connection
+ * @param sa		Segment A
+ * @param sb		Segment B
+ *
+ * @return		-1, 0, 1, resp. if A < B, A == B, A > B in terms
+ *			of sequence order of the beginning of the segment.
+ */
+int seq_no_seg_cmp(tcp_conn_t *conn, tcp_segment_t *sa, tcp_segment_t *sb)
+{
+	assert(seq_no_segment_acceptable(conn, sa));
+	assert(seq_no_segment_acceptable(conn, sb));
+
+	if (seq_no_lt_le(sa->seq, sb->seq, conn->rcv_nxt + conn->rcv_wnd))
+		return -1;
+
+	if (seq_no_lt_le(sb->seq, sa->seq, conn->rcv_nxt + conn->rcv_wnd))
+		return +1;
+
+	assert(sa->seq == sb->seq);
+	return 0;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/seq_no.h
===================================================================
--- uspace/srv/net/tl/tcp/seq_no.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/seq_no.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Sequence number computations
+ */
+
+#ifndef SEQ_NO_H
+#define SEQ_NO_H
+
+#include <sys/types.h>
+#include "tcp_type.h"
+
+extern bool seq_no_ack_acceptable(tcp_conn_t *, uint32_t);
+extern bool seq_no_ack_duplicate(tcp_conn_t *, uint32_t);
+extern bool seq_no_in_rcv_wnd(tcp_conn_t *, uint32_t);
+extern bool seq_no_new_wnd_update(tcp_conn_t *, tcp_segment_t *);
+extern bool seq_no_segment_acked(tcp_conn_t *, tcp_segment_t *, uint32_t);
+extern bool seq_no_syn_acked(tcp_conn_t *);
+extern bool seq_no_segment_ready(tcp_conn_t *, tcp_segment_t *);
+extern bool seq_no_segment_acceptable(tcp_conn_t *, tcp_segment_t *);
+extern void seq_no_seg_trim_calc(tcp_conn_t *, tcp_segment_t *, uint32_t *,
+    uint32_t *);
+extern int seq_no_seg_cmp(tcp_conn_t *, tcp_segment_t *, tcp_segment_t *);
+
+extern uint32_t seq_no_control_len(tcp_control_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/sock.c
===================================================================
--- uspace/srv/net/tl/tcp/sock.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/sock.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2008 Lukas Mejdrech
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Socket provider
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <io/log.h>
+#include <ip_client.h>
+#include <ipc/socket.h>
+#include <net/modules.h>
+#include <net/socket.h>
+
+#include "sock.h"
+#include "std.h"
+#include "tcp.h"
+#include "tcp_type.h"
+#include "ucall.h"
+
+#define FRAGMENT_SIZE 1024
+
+/** Free ports pool start. */
+#define TCP_FREE_PORTS_START		1025
+
+/** Free ports pool end. */
+#define TCP_FREE_PORTS_END		65535
+
+static int last_used_port = TCP_FREE_PORTS_START - 1;
+static socket_ports_t gsock;
+
+void tcp_sock_init(void)
+{
+	socket_ports_initialize(&gsock);
+}
+
+static void tcp_free_sock_data(socket_core_t *sock_core)
+{
+	tcp_sockdata_t *socket;
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+	(void)socket;
+}
+
+static void tcp_sock_notify_data(socket_core_t *sock_core)
+{
+	log_msg(LVL_DEBUG, "tcp_sock_notify_data(%d)", sock_core->socket_id);
+	async_exch_t *exch = async_exchange_begin(sock_core->sess);
+	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
+	    FRAGMENT_SIZE, 0, 0, 1);
+	async_exchange_end(exch);
+}
+
+static void tcp_sock_notify_aconn(socket_core_t *lsock_core)
+{
+	log_msg(LVL_DEBUG, "tcp_sock_notify_aconn(%d)", lsock_core->socket_id);
+	async_exch_t *exch = async_exchange_begin(lsock_core->sess);
+	async_msg_5(exch, NET_SOCKET_ACCEPTED, (sysarg_t)lsock_core->socket_id,
+	    FRAGMENT_SIZE, 0, 0, 0);
+	async_exchange_end(exch);
+}
+
+static void tcp_sock_socket(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	tcp_sockdata_t *sock;
+	int sock_id;
+	int rc;
+	ipc_call_t answer;
+
+	log_msg(LVL_DEBUG, "tcp_sock_socket()");
+	sock = calloc(sizeof(tcp_sockdata_t), 1);
+	if (sock == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	sock->client = client;
+	sock->laddr.ipv4 = TCP_IPV4_ANY;
+
+	sock_id = SOCKET_GET_SOCKET_ID(call);
+	rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	refresh_answer(&answer, NULL);
+	SOCKET_SET_SOCKET_ID(answer, sock_id);
+
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t));
+	answer_call(callid, EOK, &answer, 3);
+}
+
+static void tcp_sock_bind(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int rc;
+	struct sockaddr *addr;
+	size_t addr_len;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+
+	log_msg(LVL_DEBUG, "tcp_sock_bind()");
+	log_msg(LVL_DEBUG, " - async_data_write_accept");
+	rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	log_msg(LVL_DEBUG, " - call socket_bind");
+	rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
+	    addr, addr_len, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
+	    last_used_port);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	log_msg(LVL_DEBUG, " - call socket_cores_find");
+	sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
+	if (sock_core != NULL) {
+		socket = (tcp_sockdata_t *)sock_core->specific_data;
+		/* XXX Anything to do? */
+		(void) socket;
+	}
+
+	log_msg(LVL_DEBUG, " - success");
+	async_answer_0(callid, EOK);
+}
+
+static void tcp_sock_listen(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int socket_id;
+	int backlog;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+
+	log_msg(LVL_DEBUG, "tcp_sock_listen()");
+
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+	backlog = SOCKET_GET_BACKLOG(call);
+
+	if (backlog < 0) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+
+	/*
+	 * XXX We do not do anything and defer action to accept().
+	 * This is a slight difference in semantics, but most servers
+	 * would just listen() and immediately accept() in a loop.
+	 *
+	 * The only difference is that there is a window between
+	 * listen() and accept() or two accept()s where we refuse
+	 * connections.
+	 */
+	(void)backlog;
+	(void)socket;
+
+	async_answer_0(callid, EOK);
+	log_msg(LVL_DEBUG, "tcp_sock_listen(): notify data\n");
+	/* Push one accept notification to client's queue */
+	tcp_sock_notify_aconn(sock_core);
+}
+
+static void tcp_sock_connect(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int rc;
+	struct sockaddr_in *addr;
+	int socket_id;
+	size_t addr_len;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+	tcp_error_t trc;
+	tcp_sock_t lsocket;
+	tcp_sock_t fsocket;
+	nic_device_id_t dev_id;
+	tcp_phdr_t *phdr;
+	size_t phdr_len;
+
+	log_msg(LVL_DEBUG, "tcp_sock_connect()");
+
+	rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
+	if (rc != EOK || addr_len != sizeof(struct sockaddr_in)) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+	if (sock_core->port <= 0) {
+		rc = socket_bind_free_port(&gsock, sock_core,
+		    TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
+		    last_used_port);
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			return;
+		}
+
+		last_used_port = sock_core->port;
+	}
+
+	if (socket->laddr.ipv4 == TCP_IPV4_ANY) {
+		/* Find route to determine local IP address. */
+		rc = ip_get_route_req(ip_sess, IPPROTO_TCP,
+		    (struct sockaddr *)addr, sizeof(*addr), &dev_id,
+		    (void **)&phdr, &phdr_len);
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			log_msg(LVL_DEBUG, "tcp_transmit_connect: Failed to find route.");
+			return;
+		}
+
+		socket->laddr.ipv4 = uint32_t_be2host(phdr->src_addr);
+		log_msg(LVL_DEBUG, "Local IP address is %x", socket->laddr.ipv4);
+		free(phdr);
+	}
+
+	lsocket.addr.ipv4 = socket->laddr.ipv4;
+	lsocket.port = sock_core->port;
+	fsocket.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
+	fsocket.port = uint16_t_be2host(addr->sin_port);
+
+	trc = tcp_uc_open(&lsocket, &fsocket, ap_active, &socket->conn);
+
+	if (socket->conn != NULL)
+		socket->conn->name = (char *)"C";
+
+	switch (trc) {
+	case TCP_EOK:
+		rc = EOK;
+		break;
+	case TCP_ERESET:
+		rc = ECONNREFUSED;
+		break;
+	default:
+		assert(false);
+	}
+
+	async_answer_0(callid, rc);
+
+	/* Push one fragment notification to client's queue */
+	tcp_sock_notify_data(sock_core);
+	log_msg(LVL_DEBUG, "tcp_sock_connect(): notify conn\n");
+}
+
+static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	ipc_call_t answer;
+	int socket_id;
+	int asock_id;
+	socket_core_t *sock_core;
+	socket_core_t *asock_core;
+	tcp_sockdata_t *socket;
+	tcp_sockdata_t *asocket;
+	tcp_error_t trc;
+	tcp_sock_t lsocket;
+	tcp_sock_t fsocket;
+	tcp_conn_t *conn;
+	int rc;
+
+	log_msg(LVL_DEBUG, "tcp_sock_accept()");
+
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+	asock_id = SOCKET_GET_NEW_SOCKET_ID(call);
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+
+	log_msg(LVL_DEBUG, " - verify socket->conn");
+	if (socket->conn != NULL) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	log_msg(LVL_DEBUG, " - open connection");
+
+	lsocket.addr.ipv4 = TCP_IPV4_ANY;
+	lsocket.port = sock_core->port;
+	fsocket.addr.ipv4 = TCP_IPV4_ANY;
+	fsocket.port = TCP_PORT_ANY;
+
+	trc = tcp_uc_open(&lsocket, &fsocket, ap_passive, &conn);
+	if (conn != NULL)
+		conn->name = (char *)"S";
+
+	log_msg(LVL_DEBUG, " - decode TCP return code");
+
+	switch (trc) {
+	case TCP_EOK:
+		rc = EOK;
+		break;
+	case TCP_ERESET:
+		rc = ECONNABORTED;
+		break;
+	default:
+		assert(false);
+	}
+
+	log_msg(LVL_DEBUG, " - check TCP return code");
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	log_msg(LVL_DEBUG, "tcp_sock_accept(): allocate asocket\n");
+	asocket = calloc(sizeof(tcp_sockdata_t), 1);
+	if (asocket == NULL) {
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	asocket->client = client;
+	asocket->conn = conn;
+	log_msg(LVL_DEBUG, "tcp_sock_accept():create asocket\n");
+
+	rc = socket_create(&client->sockets, client->sess, asocket, &asock_id);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+	log_msg(LVL_DEBUG, "tcp_sock_accept(): find acore\n");
+
+	asock_core = socket_cores_find(&client->sockets, asock_id);
+	assert(asock_core != NULL);
+
+	refresh_answer(&answer, NULL);
+
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	SOCKET_SET_SOCKET_ID(answer, asock_id);
+	SOCKET_SET_ADDRESS_LENGTH(answer, sizeof(struct sockaddr_in));
+
+	answer_call(callid, asock_core->socket_id, &answer, 3);
+
+	/* Push one accept notification to client's queue */
+	tcp_sock_notify_aconn(sock_core);
+
+	/* Push one fragment notification to client's queue */
+	tcp_sock_notify_data(asock_core);
+	log_msg(LVL_DEBUG, "tcp_sock_accept(): notify aconn\n");
+}
+
+static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int socket_id;
+	int fragments;
+	int index;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+	ipc_call_t answer;
+	ipc_callid_t wcallid;
+	size_t length;
+	uint8_t buffer[FRAGMENT_SIZE];
+	tcp_error_t trc;
+	int rc;
+
+	log_msg(LVL_DEBUG, "tcp_sock_send()");
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+	fragments = SOCKET_GET_DATA_FRAGMENTS(call);
+	SOCKET_GET_FLAGS(call);
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+	if (socket->conn == NULL) {
+		async_answer_0(callid, ENOTCONN);
+		return;
+	}
+
+	for (index = 0; index < fragments; index++) {
+		if (!async_data_write_receive(&wcallid, &length)) {
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+
+		if (length > FRAGMENT_SIZE)
+			length = FRAGMENT_SIZE;
+
+		rc = async_data_write_finalize(wcallid, buffer, length);
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			return;
+		}
+
+		trc = tcp_uc_send(socket->conn, buffer, length, 0);
+
+		switch (trc) {
+		case TCP_EOK:
+			rc = EOK;
+			break;
+		case TCP_ENOTEXIST:
+			rc = ENOTCONN;
+			break;
+		case TCP_ECLOSING:
+			rc = ENOTCONN;
+			break;
+		case TCP_ERESET:
+			rc = ECONNABORTED;
+			break;
+		default:
+			assert(false);
+		}
+
+		if (rc != EOK) {
+			async_answer_0(callid, rc);
+			return;
+		}
+	}
+
+	refresh_answer(&answer, NULL);
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	answer_call(callid, EOK, &answer, 2);
+}
+
+static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	log_msg(LVL_DEBUG, "tcp_sock_sendto()");
+	async_answer_0(callid, ENOTSUP);
+}
+
+static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int socket_id;
+	int flags;
+	size_t addr_length, length;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+	ipc_call_t answer;
+	ipc_callid_t rcallid;
+	uint8_t buffer[FRAGMENT_SIZE];
+	size_t data_len;
+	xflags_t xflags;
+	tcp_error_t trc;
+	struct sockaddr_in addr;
+	tcp_sock_t *rsock;
+	int rc;
+
+	log_msg(LVL_DEBUG, "%p: tcp_sock_recv[from]()", client);
+
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+	flags = SOCKET_GET_FLAGS(call);
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+	if (socket->conn == NULL) {
+		async_answer_0(callid, ENOTCONN);
+		return;
+	}
+
+	(void)flags;
+
+	trc = tcp_uc_receive(socket->conn, buffer, FRAGMENT_SIZE, &data_len,
+	    &xflags);
+	log_msg(LVL_DEBUG, "**** tcp_uc_receive done");
+
+	switch (trc) {
+	case TCP_EOK:
+		rc = EOK;
+		break;
+	case TCP_ENOTEXIST:
+	case TCP_ECLOSING:
+		rc = ENOTCONN;
+		break;
+	case TCP_ERESET:
+		rc = ECONNABORTED;
+		break;
+	default:
+		assert(false);
+	}
+
+	log_msg(LVL_DEBUG, "**** tcp_uc_receive -> %d", rc);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	if (IPC_GET_IMETHOD(call) == NET_SOCKET_RECVFROM) {
+		/* Fill addr */
+		rsock = &socket->conn->ident.foreign;
+		addr.sin_family = AF_INET;
+		addr.sin_addr.s_addr = host2uint32_t_be(rsock->addr.ipv4);
+		addr.sin_port = host2uint16_t_be(rsock->port);
+
+		log_msg(LVL_DEBUG, "addr read receive");
+		if (!async_data_read_receive(&rcallid, &addr_length)) {
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+
+		if (addr_length > sizeof(addr))
+			addr_length = sizeof(addr);
+
+		log_msg(LVL_DEBUG, "addr read finalize");
+		rc = async_data_read_finalize(rcallid, &addr, addr_length);
+		if (rc != EOK) {
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+	}
+
+	log_msg(LVL_DEBUG, "data read receive");
+	if (!async_data_read_receive(&rcallid, &length)) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+
+	if (length > data_len)
+		length = data_len;
+
+	log_msg(LVL_DEBUG, "data read finalize");
+	rc = async_data_read_finalize(rcallid, buffer, length);
+
+	if (length < data_len && rc == EOK)
+		rc = EOVERFLOW;
+
+	SOCKET_SET_READ_DATA_LENGTH(answer, length);
+	answer_call(callid, EOK, &answer, 1);
+
+	/* Push one fragment notification to client's queue */
+	tcp_sock_notify_data(sock_core);
+}
+
+static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	int socket_id;
+	socket_core_t *sock_core;
+	tcp_sockdata_t *socket;
+	tcp_error_t trc;
+	int rc;
+	uint8_t buffer[FRAGMENT_SIZE];
+	size_t data_len;
+	xflags_t xflags;
+
+	log_msg(LVL_DEBUG, "tcp_sock_close()");
+	socket_id = SOCKET_GET_SOCKET_ID(call);
+
+	sock_core = socket_cores_find(&client->sockets, socket_id);
+	if (sock_core == NULL) {
+		async_answer_0(callid, ENOTSOCK);
+		return;
+	}
+
+	socket = (tcp_sockdata_t *)sock_core->specific_data;
+	rc = tcp_uc_close(socket->conn);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	/* Drain incoming data. This should really be done in the background. */
+	do {
+		trc = tcp_uc_receive(socket->conn, buffer, FRAGMENT_SIZE,
+		    &data_len, &xflags);
+	} while (trc == TCP_EOK);
+
+	rc = socket_destroy(net_sess, socket_id, &client->sockets, &gsock,
+	    tcp_free_sock_data);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	async_answer_0(callid, EOK);
+}
+
+static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	log_msg(LVL_DEBUG, "tcp_sock_getsockopt()");
+	async_answer_0(callid, ENOTSUP);
+}
+
+static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
+{
+	log_msg(LVL_DEBUG, "tcp_sock_setsockopt()");
+	async_answer_0(callid, ENOTSUP);
+}
+
+int tcp_sock_connection(async_sess_t *sess, ipc_callid_t iid, ipc_call_t icall)
+{
+	ipc_callid_t callid;
+	ipc_call_t call;
+	tcp_client_t client;
+
+	/* Accept the connection */
+	async_answer_0(iid, EOK);
+
+	client.sess = sess;
+	socket_cores_initialize(&client.sockets);
+
+	while (true) {
+		callid = async_get_call(&call);
+		if (!IPC_GET_IMETHOD(call))
+			break;
+
+		log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
+		    (int)IPC_GET_IMETHOD(call));
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case NET_SOCKET:
+			tcp_sock_socket(&client, callid, call);
+			break;
+		case NET_SOCKET_BIND:
+			tcp_sock_bind(&client, callid, call);
+			break;
+		case NET_SOCKET_LISTEN:
+			tcp_sock_listen(&client, callid, call);
+			break;
+		case NET_SOCKET_CONNECT:
+			tcp_sock_connect(&client, callid, call);
+			break;
+		case NET_SOCKET_ACCEPT:
+			tcp_sock_accept(&client, callid, call);
+			break;
+		case NET_SOCKET_SEND:
+			tcp_sock_send(&client, callid, call);
+			break;
+		case NET_SOCKET_SENDTO:
+			tcp_sock_sendto(&client, callid, call);
+			break;
+		case NET_SOCKET_RECV:
+		case NET_SOCKET_RECVFROM:
+			tcp_sock_recvfrom(&client, callid, call);
+			break;
+		case NET_SOCKET_CLOSE:
+			tcp_sock_close(&client, callid, call);
+			break;
+		case NET_SOCKET_GETSOCKOPT:
+			tcp_sock_getsockopt(&client, callid, call);
+			break;
+		case NET_SOCKET_SETSOCKOPT:
+			tcp_sock_setsockopt(&client, callid, call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/sock.h
===================================================================
--- uspace/srv/net/tl/tcp/sock.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/sock.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Socket provider
+ */
+
+#ifndef SOCK_H
+#define SOCK_H
+
+#include <async.h>
+
+extern void tcp_sock_init(void);
+extern int tcp_sock_connection(async_sess_t *, ipc_callid_t, ipc_call_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/std.h
===================================================================
--- uspace/srv/net/tl/tcp/std.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/std.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP header definitions
+ *
+ * Based on IETF RFC 793
+ */
+
+#ifndef STD_H
+#define STD_H
+
+#include <sys/types.h>
+
+/** TCP Header (fixed part) */
+typedef struct {
+	/** Source port */
+	uint16_t src_port;
+	/** Destination port */
+	uint16_t dest_port;
+	/** Sequence number */
+	uint32_t seq;
+	/** Acknowledgement number */
+	uint32_t ack;
+	/** Data Offset, Reserved, Flags */
+	uint16_t doff_flags;
+	/** Window */
+	uint16_t window;
+	/* Checksum */
+	uint16_t checksum;
+	/** Urgent pointer */
+	uint16_t urg_ptr;
+} tcp_header_t;
+
+/** Bits in tcp_header_t.doff_flags */
+enum doff_flags_bits {
+	DF_DATA_OFFSET_h	= 15,
+	DF_DATA_OFFSET_l	= 12,
+	DF_URG			= 5,
+	DF_ACK			= 4,
+	DF_PSH			= 3,
+	DF_RST			= 2,
+	DF_SYN			= 1,
+	DF_FIN			= 0
+};
+
+/** TCP pseudo header */
+typedef struct {
+	/** Source address */
+	uint32_t src_addr;
+	/** Destination address */
+	uint32_t dest_addr;
+	/** Zero */
+	uint8_t zero;
+	/** Protocol */
+	uint8_t protocol;
+	/** TCP length */
+	uint16_t tcp_length;
+} tcp_phdr_t;
+
+/** Option kind */
+enum opt_kind {
+	/** End of option list */
+	OPT_END_LIST		= 0,
+	/** No-operation */
+	OPT_NOP			= 1,
+	/** Maximum segment size */
+	OPT_MAX_SEG_SIZE	= 2
+};
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/tcp.c
===================================================================
--- uspace/srv/net/tl/tcp/tcp.c	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/net/tl/tcp/tcp.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2008 Lukas Mejdrech
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -31,229 +31,98 @@
  */
 
-/** @file
- * TCP module implementation.
- * @see tcp.h
+/**
+ * @file TCP (Transmission Control Protocol) network module
  */
 
-#include <assert.h>
 #include <async.h>
-#include <fibril_synch.h>
-#include <malloc.h>
-/* TODO remove stdio */
+#include <byteorder.h>
+#include <errno.h>
+#include <io/log.h>
 #include <stdio.h>
-#include <errno.h>
-
+#include <task.h>
+
+#include <icmp_remote.h>
+#include <ip_client.h>
+#include <ip_interface.h>
 #include <ipc/services.h>
-#include <ipc/net.h>
 #include <ipc/tl.h>
-#include <ipc/socket.h>
-
-#include <net/socket_codes.h>
-#include <net/ip_protocols.h>
-#include <net/in.h>
-#include <net/in6.h>
-#include <net/inet.h>
-#include <net/modules.h>
-
-#include <adt/dynamic_fifo.h>
+#include <tl_common.h>
+#include <tl_skel.h>
 #include <packet_client.h>
 #include <packet_remote.h>
-#include <net_checksum.h>
-#include <ip_client.h>
-#include <ip_interface.h>
-#include <icmp_client.h>
-#include <icmp_remote.h>
-#include <net_interface.h>
-#include <socket_core.h>
-#include <tl_common.h>
-#include <tl_remote.h>
-#include <tl_skel.h>
-
+
+#include "ncsim.h"
+#include "pdu.h"
+#include "rqueue.h"
+#include "sock.h"
+#include "std.h"
 #include "tcp.h"
-#include "tcp_header.h"
-
-/** TCP module name. */
-#define NAME  "tcp"
-
-/** The TCP window default value. */
-#define NET_DEFAULT_TCP_WINDOW		10240
-
-/** Initial timeout for new connections. */
-#define NET_DEFAULT_TCP_INITIAL_TIMEOUT	3000000L
-
-/** Default timeout for closing. */
-#define NET_DEFAULT_TCP_TIME_WAIT_TIMEOUT 2000L
-
-/** The initial outgoing sequence number. */
-#define TCP_INITIAL_SEQUENCE_NUMBER	2999
-
-/** Maximum TCP fragment size. */
-#define MAX_TCP_FRAGMENT_SIZE		65535
-
-/** Free ports pool start. */
-#define TCP_FREE_PORTS_START		1025
-
-/** Free ports pool end. */
-#define TCP_FREE_PORTS_END		65535
-
-/** Timeout for connection initialization, SYN sent. */
-#define TCP_SYN_SENT_TIMEOUT		1000000L
-
-/** The maximum number of timeouts in a row before singaling connection lost. */
-#define TCP_MAX_TIMEOUTS		8
-
-/** The number of acknowledgements before retransmit. */
-#define TCP_FAST_RETRANSMIT_COUNT	3
-
-/** Returns a value indicating whether the value is in the interval respecting
- * the possible overflow.
- *
- * The high end and/or the value may overflow, be lower than the low value.
- *
- * @param[in] lower	The last value before the interval.
- * @param[in] value	The value to be checked.
- * @param[in] higher_equal The last value in the interval.
- */
-#define IS_IN_INTERVAL_OVERFLOW(lower, value, higher_equal) \
-	((((lower) < (value)) && (((value) <= (higher_equal)) || \
-	((higher_equal) < (lower)))) || (((value) <= (higher_equal)) && \
-	((higher_equal) < (lower))))
-
-/** Type definition of the TCP timeout.
- *  @see tcp_timeout
- */
-typedef struct tcp_timeout tcp_timeout_t;
-
-/** TCP reply timeout data.
- *  Used as a timeouting fibril argument.
- *  @see tcp_timeout()
- */
-struct tcp_timeout {
-	/** TCP global data are going to be read only. */
-	int globals_read_only;
-
-	/** Socket port. */
-	int port;
-
-	/** Local sockets. */
-	socket_cores_t *local_sockets;
-
-	/** Socket identifier. */
-	int socket_id;
-
-	/** Socket state. */
-	tcp_socket_state_t state;
-
-	/** Sent packet sequence number. */
-	int sequence_number;
-
-	/** Timeout in microseconds. */
-	suseconds_t timeout;
-
-	/** Port map key. */
-	uint8_t *key;
-
-	/** Port map key length. */
-	size_t key_length;
-};
-
-static int tcp_release_and_return(packet_t *, int);
-static void tcp_prepare_operation_header(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *, int synchronize, int);
-static int tcp_prepare_timeout(int (*)(void *), socket_core_t *,
-    tcp_socket_data_t *, size_t, tcp_socket_state_t, suseconds_t, int);
-static void tcp_free_socket_data(socket_core_t *);
-
-static int tcp_timeout(void *);
-
-static int tcp_release_after_timeout(void *);
-
-static int tcp_process_packet(nic_device_id_t, packet_t *, services_t);
-static int tcp_connect_core(socket_core_t *, socket_cores_t *,
-    struct sockaddr *, socklen_t);
-static int tcp_queue_prepare_packet(socket_core_t *, tcp_socket_data_t *,
-    packet_t *, size_t);
-static int tcp_queue_packet(socket_core_t *, tcp_socket_data_t *, packet_t *,
-    size_t);
-static packet_t *tcp_get_packets_to_send(socket_core_t *, tcp_socket_data_t *);
-static void tcp_send_packets(nic_device_id_t, packet_t *);
-
-static void tcp_process_acknowledgement(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *);
-static packet_t *tcp_send_prepare_packet(socket_core_t *, tcp_socket_data_t *,
-    packet_t *, size_t, size_t);
-static packet_t *tcp_prepare_copy(socket_core_t *, tcp_socket_data_t *,
-    packet_t *, size_t, size_t);
-/* static */ void tcp_retransmit_packet(socket_core_t *, tcp_socket_data_t *,
-    size_t);
-static int tcp_create_notification_packet(packet_t **, socket_core_t *,
-    tcp_socket_data_t *, int, int);
-static void tcp_refresh_socket_data(tcp_socket_data_t *);
-
-static void tcp_initialize_socket_data(tcp_socket_data_t *);
-
-static int tcp_process_listen(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *, packet_t *, struct sockaddr *, struct sockaddr *, size_t);
-static int tcp_process_syn_sent(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *, packet_t *);
-static int tcp_process_syn_received(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *, packet_t *);
-static int tcp_process_established(socket_core_t *, tcp_socket_data_t *,
-    tcp_header_t *, packet_t *, int, size_t);
-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(nic_device_id_t, packet_t *, services_t, services_t);
-static int tcp_process_client_messages(async_sess_t *, ipc_callid_t,
-    ipc_call_t);
-
-static int tcp_listen_message(socket_cores_t *, int, int);
-static int tcp_connect_message(socket_cores_t *, int, struct sockaddr *,
-    socklen_t);
-static int tcp_recvfrom_message(socket_cores_t *, int, int, size_t *);
-static int tcp_send_message(socket_cores_t *, int, int, size_t *, int);
-static int tcp_accept_message(socket_cores_t *, int, int, size_t *, size_t *);
-static int tcp_close_message(socket_cores_t *, int);
-
-/** TCP global data. */
-tcp_globals_t tcp_globals;
-
-int tcp_received_msg(nic_device_id_t device_id, packet_t *packet,
-    services_t receiver, services_t error)
+#include "test.h"
+
+#define NAME       "tcp"
+
+async_sess_t *net_sess;
+static async_sess_t *icmp_sess;
+async_sess_t *ip_sess;
+packet_dimensions_t pkt_dims;
+
+static void tcp_received_pdu(tcp_pdu_t *pdu);
+
+/* Pull up packets into a single memory block. */
+static int pq_pullup(packet_t *packet, void **data, size_t *dsize)
+{
+	packet_t *npacket;
+	size_t tot_len;
+	int length;
+
+	npacket = packet;
+	tot_len = 0;
+	do {
+		length = packet_get_data_length(packet);
+		if (length <= 0)
+			return EINVAL;
+
+		tot_len += length;
+	} while ((npacket = pq_next(npacket)) != NULL);
+
+	uint8_t *buf;
+	uint8_t *dp;
+
+	buf = calloc(tot_len, 1);
+	if (buf == NULL) {
+		free(buf);
+		return ENOMEM;
+	}
+
+	npacket = packet;
+	dp = buf;
+	do {
+		length = packet_get_data_length(packet);
+		if (length <= 0) {
+			free(buf);
+			return EINVAL;
+		}
+
+		memcpy(dp, packet_get_data(packet), length);
+		dp += length;
+	} while ((npacket = pq_next(npacket)) != NULL);
+
+	*data = buf;
+	*dsize = tot_len;
+	return EOK;
+}
+
+/** Process packet received from network layer. */
+static int tcp_received_msg(nic_device_id_t device_id, packet_t *packet,
+    services_t error)
 {
 	int rc;
-
-	if (receiver != SERVICE_TCP)
-		return EREFUSED;
-
-	fibril_rwlock_write_lock(&tcp_globals.lock);
-	rc = tcp_process_packet(device_id, packet, error);
-	if (rc != EOK)
-		fibril_rwlock_write_unlock(&tcp_globals.lock);
-
-	printf("receive %d \n", rc);
-
-	return rc;
-}
-
-int tcp_process_packet(nic_device_id_t device_id, packet_t *packet, services_t error)
-{
-	size_t length;
 	size_t offset;
-	int result;
-	tcp_header_t *header;
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	packet_t *next_packet;
-	size_t total_length;
-	uint32_t checksum;
-	int fragments;
-	icmp_type_t type;
-	icmp_code_t code;
-	struct sockaddr *src;
-	struct sockaddr *dest;
-	size_t addrlen;
-	int rc;
+	int length;
+	struct sockaddr_in *src_addr;
+	struct sockaddr_in *dest_addr;
+	size_t addr_len;
+
+	log_msg(LVL_DEBUG, "tcp_received_msg()");
 
 	switch (error) {
@@ -261,2256 +130,297 @@
 		break;
 	case SERVICE_ICMP:
-		/* Process error */
-		result = icmp_client_process_packet(packet, &type, &code, NULL,
-		    NULL);
-		if (result < 0)
-			return tcp_release_and_return(packet, result);
-
-		length = (size_t) result;
-		rc = packet_trim(packet, length, 0);
-		if (rc != EOK)
-			return tcp_release_and_return(packet, rc);
-		break;
 	default:
-		return tcp_release_and_return(packet, ENOTSUP);
-	}
-
-	/* TODO process received ipopts? */
-	result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
-	if (result < 0)
-		return tcp_release_and_return(packet, result);
-
-	offset = (size_t) result;
-
+		log_msg(LVL_WARN, "Unsupported service number %u",
+		    (unsigned)error);
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return ENOTSUP;
+	}
+
+	/* Process and trim off IP header */
+	log_msg(LVL_DEBUG, "tcp_received_msg() - IP header");
+
+	rc = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
+	if (rc < 0) {
+		log_msg(LVL_WARN, "ip_client_process_packet() failed");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return rc;
+	}
+
+	offset = (size_t)rc;
 	length = packet_get_data_length(packet);
-	if (length <= 0)
-		return tcp_release_and_return(packet, EINVAL);
-
-	if (length < TCP_HEADER_SIZE + offset)
-		return tcp_release_and_return(packet, NO_DATA);
-
-	/* Trim all but TCP header */
+
+	if (length < 0 || (size_t)length < offset) {
+		log_msg(LVL_WARN, "length=%d, dropping.", length);
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return EINVAL;
+	}
+
+	addr_len = packet_get_addr(packet, (uint8_t **)&src_addr,
+	    (uint8_t **)&dest_addr);
+	if (addr_len <= 0) {
+		log_msg(LVL_WARN, "Failed to get packet address.");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return EINVAL;
+	}
+
+	if (addr_len != sizeof(struct sockaddr_in)) {
+		log_msg(LVL_WARN, "Unsupported address size %zu (!= %zu)",
+		    addr_len, sizeof(struct sockaddr_in));
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return EINVAL;
+	}
+
 	rc = packet_trim(packet, offset, 0);
-	if (rc != EOK)
-		return tcp_release_and_return(packet, rc);
-
-	/* Get tcp header */
-	header = (tcp_header_t *) packet_get_data(packet);
-	if (!header)
-		return tcp_release_and_return(packet, NO_DATA);
-
-#if 0
-	printf("header len %d, port %d \n", TCP_HEADER_LENGTH(header),
-	    ntohs(header->destination_port));
-#endif
-	result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
-	if (result <= 0)
-		return tcp_release_and_return(packet, result);
-
-	addrlen = (size_t) result;
-
-	rc = tl_set_address_port(src, addrlen, ntohs(header->source_port));
-	if (rc != EOK)
-		return tcp_release_and_return(packet, rc);
-	
-	/* Find the destination socket */
-	socket = socket_port_find(&tcp_globals.sockets,
-	    ntohs(header->destination_port), (uint8_t *) src, addrlen);
-	if (!socket) {
-		/* Find the listening destination socket */
-		socket = socket_port_find(&tcp_globals.sockets,
-		    ntohs(header->destination_port),
-		    (uint8_t *) SOCKET_MAP_KEY_LISTENING, 0);
-	}
-
-	if (!socket) {
-		if (tl_prepare_icmp_packet(tcp_globals.net_sess,
-		    tcp_globals.icmp_sess, packet, error) == EOK) {
-			icmp_destination_unreachable_msg(tcp_globals.icmp_sess,
-			    ICMP_PORT_UNREACH, 0, packet);
-		}
-		return EADDRNOTAVAIL;
-	}
-
-	printf("socket id %d\n", socket->socket_id);
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	/* Some data received, clear the timeout counter */
-	socket_data->timeout_count = 0;
-
-	/* Count the received packet fragments */
-	next_packet = packet;
-	fragments = 0;
-	checksum = 0;
-	total_length = 0;
-	do {
-		fragments++;
-		length = packet_get_data_length(next_packet);
-		if (length <= 0)
-			return tcp_release_and_return(packet, NO_DATA);
-
-		total_length += length;
-
-		/* Add partial checksum if set */
-		if (!error) {
-			checksum = compute_checksum(checksum,
-			    packet_get_data(packet),
-			    packet_get_data_length(packet));
-		}
-
-	} while ((next_packet = pq_next(next_packet)));
-
-	fibril_rwlock_write_lock(socket_data->local_lock);
-
-	if (error)
-		goto has_error_service;
-	
-	if (socket_data->state == TCP_SOCKET_LISTEN) {
-		if (socket_data->pseudo_header) {
-			free(socket_data->pseudo_header);
-			socket_data->pseudo_header = NULL;
-			socket_data->headerlen = 0;
-		}
-
-		rc = ip_client_get_pseudo_header(IPPROTO_TCP, src, addrlen,
-		    dest, addrlen, total_length, &socket_data->pseudo_header,
-		    &socket_data->headerlen);
-		if (rc != EOK) {
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-			return tcp_release_and_return(packet, rc);
-		}
-	} else {
-		rc = ip_client_set_pseudo_header_data_length(
-		    socket_data->pseudo_header, socket_data->headerlen,
-		    total_length);
-		if (rc != EOK) {
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-			return tcp_release_and_return(packet, rc);
-		}
-	}
-	
-	checksum = compute_checksum(checksum, socket_data->pseudo_header,
-	    socket_data->headerlen);
-	if (flip_checksum(compact_checksum(checksum)) != IP_CHECKSUM_ZERO) {
-		printf("checksum err %x -> %x\n", header->checksum,
-		    flip_checksum(compact_checksum(checksum)));
-		fibril_rwlock_write_unlock(socket_data->local_lock);
-
-		rc = tl_prepare_icmp_packet(tcp_globals.net_sess,
-		    tcp_globals.icmp_sess, packet, error);
-		if (rc == EOK) {
-			/* Checksum error ICMP */
-			icmp_parameter_problem_msg(tcp_globals.icmp_sess,
-			    ICMP_PARAM_POINTER,
-			    ((size_t) ((void *) &header->checksum)) -
-			    ((size_t) ((void *) header)), packet);
-		}
-
+	if (rc != EOK) {
+		log_msg(LVL_WARN, "Failed to trim packet.");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return rc;
+	}
+
+	/* Pull up packets into a single memory block, pdu_raw. */
+	log_msg(LVL_DEBUG, "tcp_received_msg() - pull up");
+	uint8_t *pdu_raw;
+	size_t pdu_raw_size = 0;
+
+	pq_pullup(packet, (void **)&pdu_raw, &pdu_raw_size);
+
+	/* Split into header and payload. */
+
+	log_msg(LVL_DEBUG, "tcp_received_msg() - split header/payload");
+
+	tcp_pdu_t *pdu;
+	size_t hdr_size;
+
+	/* XXX Header options */
+	hdr_size = sizeof(tcp_header_t);
+
+	if (pdu_raw_size < hdr_size) {
+		log_msg(LVL_WARN, "pdu_raw_size = %zu < hdr_size = %zu",
+		    pdu_raw_size, hdr_size);
+		pq_release_remote(net_sess, packet_get_id(packet));
 		return EINVAL;
 	}
 
-has_error_service:
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-
-	/* TODO error reporting/handling */
-	switch (socket_data->state) {
-	case TCP_SOCKET_LISTEN:
-		rc = tcp_process_listen(socket, socket_data, header, packet,
-		    src, dest, addrlen);
-		break;
-	case TCP_SOCKET_SYN_RECEIVED:
-		rc = tcp_process_syn_received(socket, socket_data, header,
-		    packet);
-		break;
-	case TCP_SOCKET_SYN_SENT:
-		rc = tcp_process_syn_sent(socket, socket_data, header, packet);
-		break;
-	case TCP_SOCKET_FIN_WAIT_1:
-		/* ack changing the state to FIN_WAIT_2 gets processed later */
-	case TCP_SOCKET_FIN_WAIT_2:
-		/* fin changing state to LAST_ACK gets processed later */
-	case TCP_SOCKET_LAST_ACK:
-		/* ack releasing the socket get processed later */
-	case TCP_SOCKET_CLOSING:
-		/* ack releasing the socket gets processed later */
-	case TCP_SOCKET_ESTABLISHED:
-		rc = tcp_process_established(socket, socket_data, header,
-		    packet, fragments, total_length);
-		break;
-	default:
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-	}
-
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(socket_data->local_lock);
-		printf("process %d\n", rc);
-	}
+	log_msg(LVL_DEBUG, "pdu_raw_size=%zu, hdr_size=%zu",
+	    pdu_raw_size, hdr_size);
+	pdu = tcp_pdu_create(pdu_raw, hdr_size, pdu_raw + hdr_size,
+	    pdu_raw_size - hdr_size);
+	if (pdu == NULL) {
+		log_msg(LVL_WARN, "Failed creating PDU. Dropped.");
+		return ENOMEM;
+	}
+
+	free(pdu_raw);
+
+	pdu->src_addr.ipv4 = uint32_t_be2host(src_addr->sin_addr.s_addr);
+	pdu->dest_addr.ipv4 = uint32_t_be2host(dest_addr->sin_addr.s_addr);
+	log_msg(LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
+	    pdu->src_addr.ipv4, pdu->dest_addr.ipv4);
+
+	tcp_received_pdu(pdu);
+	tcp_pdu_delete(pdu);
 
 	return EOK;
 }
 
-int tcp_process_established(socket_core_t *socket, tcp_socket_data_t *
-    socket_data, tcp_header_t *header, packet_t *packet, int fragments,
-    size_t total_length)
-{
-	packet_t *next_packet;
-	packet_t *tmp_packet;
-	uint32_t old_incoming;
-	size_t order;
-	uint32_t sequence_number;
-	size_t length;
-	size_t offset;
-	uint32_t new_sequence_number;
-	bool forced_ack;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(header);
-	assert(packet);
-
-	forced_ack = false;
-
-	new_sequence_number = ntohl(header->sequence_number);
-	old_incoming = socket_data->next_incoming;
-
-	if (GET_TCP_HEADER_FINALIZE(header)) {
-		socket_data->fin_incoming = new_sequence_number +
-		    total_length - TCP_HEADER_LENGTH(header);
-	}
-
-	/* Trim begining if containing expected data */
-	if (IS_IN_INTERVAL_OVERFLOW(new_sequence_number,
-	    socket_data->next_incoming, new_sequence_number + total_length)) {
-
-		/* Get the acknowledged offset */
-		if (socket_data->next_incoming < new_sequence_number) {
-			offset = new_sequence_number -
-			    socket_data->next_incoming;
-		} else {
-			offset = socket_data->next_incoming -
-			    new_sequence_number;
-		}
-
-		new_sequence_number += offset;
-		total_length -= offset;
-		length = packet_get_data_length(packet);
-
-		/* Trim the acknowledged data */
-		while (length <= offset) {
-			/* Release the acknowledged packets */
-			next_packet = pq_next(packet);
-			pq_release_remote(tcp_globals.net_sess,
-			    packet_get_id(packet));
-			packet = next_packet;
-			offset -= length;
-			length = packet_get_data_length(packet);
-		}
-
-		if (offset > 0) {
-			rc = packet_trim(packet, offset, 0);
-			if (rc != EOK)
-				return tcp_release_and_return(packet, rc);
-		}
-
-		assert(new_sequence_number == socket_data->next_incoming);
-	}
-
-	/* Release if overflowing the window */
-/*
-	if (IS_IN_INTERVAL_OVERFLOW(socket_data->next_incoming +
-	    socket_data->window, new_sequence_number, new_sequence_number +
-	    total_length)) {
-		return tcp_release_and_return(packet, EOVERFLOW);
-	}
-
-	// trim end if overflowing the window
-	if (IS_IN_INTERVAL_OVERFLOW(new_sequence_number,
-	    socket_data->next_incoming + socket_data->window,
-	    new_sequence_number + total_length)) {
-		// get the allowed data length
-		if (socket_data->next_incoming + socket_data->window <
-		    new_sequence_number) {
-			offset = new_sequence_number -
-			    socket_data->next_incoming + socket_data->window;
-		} else {
-			offset = socket_data->next_incoming +
-			    socket_data->window - new_sequence_number;
-		}
-		next_packet = packet;
-		// trim the overflowing data
-		while (next_packet && (offset > 0)) {
-			length = packet_get_data_length(packet);
-			if (length <= offset)
-				next_packet = pq_next(next_packet);
-			else {
-				rc = packet_trim(next_packet, 0,
-				    length - offset));
-				if (rc != EOK)
-					return tcp_release_and_return(packet,
-					    rc);
-			}
-			offset -= length;
-			total_length -= length - offset;
-		}
-		// release the overflowing packets
-		next_packet = pq_next(next_packet);
-		if (next_packet) {
-			tmp_packet = next_packet;
-			next_packet = pq_next(next_packet);
-			pq_insert_after(tmp_packet, next_packet);
-			pq_release_remote(tcp_globals.net_sess,
-			    packet_get_id(tmp_packet));
-		}
-		assert(new_sequence_number + total_length ==
-		    socket_data->next_incoming + socket_data->window);
-	}
-*/
-	/* The expected one arrived? */
-	if (new_sequence_number == socket_data->next_incoming) {
-		printf("expected\n");
-		/* Process acknowledgement */
-		tcp_process_acknowledgement(socket, socket_data, header);
-
-		/* Remove the header */
-		total_length -= TCP_HEADER_LENGTH(header);
-		rc = packet_trim(packet, TCP_HEADER_LENGTH(header), 0);
-		if (rc != EOK)
-			return tcp_release_and_return(packet, rc);
-
-		if (total_length) {
-			rc = tcp_queue_received_packet(socket, socket_data,
-			    packet, fragments, total_length);
-			if (rc != EOK)
-				return rc;
-		} else {
-			total_length = 1;
-		}
-
-		socket_data->next_incoming = old_incoming + total_length;
-		packet = socket_data->incoming;
-		while (packet) {
-			rc = pq_get_order(socket_data->incoming, &order, NULL);
-			if (rc != EOK) {
-				/* Remove the corrupted packet */
-				next_packet = pq_detach(packet);
-				if (packet == socket_data->incoming)
-					socket_data->incoming = next_packet;
-				pq_release_remote(tcp_globals.net_sess,
-				    packet_get_id(packet));
-				packet = next_packet;
-				continue;
-			}
-
-			sequence_number = (uint32_t) order;
-			if (IS_IN_INTERVAL_OVERFLOW(sequence_number,
-			    old_incoming, socket_data->next_incoming)) {
-				/* Move to the next */
-				packet = pq_next(packet);
-				/* Coninual data? */
-			} else if (IS_IN_INTERVAL_OVERFLOW(old_incoming,
-			    sequence_number, socket_data->next_incoming)) {
-				/* Detach the packet */
-				next_packet = pq_detach(packet);
-				if (packet == socket_data->incoming)
-					socket_data->incoming = next_packet;
-				/* Get data length */
-				length = packet_get_data_length(packet);
-				new_sequence_number = sequence_number + length;
-				if (length <= 0) {
-					/* Remove the empty packet */
-					pq_release_remote(tcp_globals.net_sess,
-					    packet_get_id(packet));
-					packet = next_packet;
-					continue;
-				}
-				/* Exactly following */
-				if (sequence_number ==
-				    socket_data->next_incoming) {
-					/* Queue received data */
-					rc = tcp_queue_received_packet(socket,
-					    socket_data, packet, 1,
-					    packet_get_data_length(packet));
-					if (rc != EOK)
-						return rc;
-					socket_data->next_incoming =
-					    new_sequence_number;
-					packet = next_packet;
-					continue;
-					/* At least partly following data? */
-				}
-				if (IS_IN_INTERVAL_OVERFLOW(sequence_number,
-				    socket_data->next_incoming, new_sequence_number)) {
-					if (socket_data->next_incoming <
-					    new_sequence_number) {
-						length = new_sequence_number -
-						    socket_data->next_incoming;
-					} else {
-						length =
-						    socket_data->next_incoming -
-						    new_sequence_number;
-					}
-					rc = packet_trim(packet,length, 0);
-					if (rc == EOK) {
-						/* Queue received data */
-						rc = tcp_queue_received_packet(
-						    socket, socket_data, packet,
-						    1, packet_get_data_length(
-						    packet));
-						if (rc != EOK)
-							return rc;
-						socket_data->next_incoming =
-						    new_sequence_number;
-						packet = next_packet;
-						continue;
-					}
-				}
-				/* Remove the duplicit or corrupted packet */
-				pq_release_remote(tcp_globals.net_sess,
-				    packet_get_id(packet));
-				packet = next_packet;
-				continue;
-			} else {
-				break;
-			}
-		}
-	} else if (IS_IN_INTERVAL(socket_data->next_incoming,
-	    new_sequence_number,
-	    socket_data->next_incoming + socket_data->window)) {
-		printf("in window\n");
-		/* Process acknowledgement */
-		tcp_process_acknowledgement(socket, socket_data, header);
-
-		/* Remove the header */
-		total_length -= TCP_HEADER_LENGTH(header);
-		rc = packet_trim(packet, TCP_HEADER_LENGTH(header), 0);
-		if (rc != EOK)
-			return tcp_release_and_return(packet, rc);
-
-		next_packet = pq_detach(packet);
-		length = packet_get_data_length(packet);
-		rc = pq_add(&socket_data->incoming, packet, new_sequence_number,
-		    length);
-		if (rc != EOK) {
-			/* Remove the corrupted packets */
-			pq_release_remote(tcp_globals.net_sess,
-			    packet_get_id(packet));
-			pq_release_remote(tcp_globals.net_sess,
-			    packet_get_id(next_packet));
-		} else {
-			while (next_packet) {
-				new_sequence_number += length;
-				tmp_packet = pq_detach(next_packet);
-				length = packet_get_data_length(next_packet);
-
-				rc = pq_set_order(next_packet,
-				    new_sequence_number, length);
-				if (rc != EOK) {
-					pq_release_remote(tcp_globals.net_sess,
-					    packet_get_id(next_packet));
-				}
-				rc = pq_insert_after(packet, next_packet);
-				if (rc != EOK) {
-					pq_release_remote(tcp_globals.net_sess,
-					    packet_get_id(next_packet));
-				}
-				next_packet = tmp_packet;
-			}
-		}
-	} else {
-		printf("unexpected\n");
-		/* Release duplicite or restricted */
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-		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:
-		case TCP_SOCKET_FIN_WAIT_2:
-		case TCP_SOCKET_CLOSING:
-			socket_data->state = TCP_SOCKET_CLOSING;
-			break;
-		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;
-			break;
-		}
-	}
-
-	packet = tcp_get_packets_to_send(socket, socket_data);
-	if (!packet && (socket_data->next_incoming != old_incoming || forced_ack)) {
-		/* Create the notification packet */
-		rc = tcp_create_notification_packet(&packet, socket,
-		    socket_data, 0, 0);
-		if (rc != EOK)
-			return rc;
-		rc = tcp_queue_prepare_packet(socket, socket_data, packet, 1);
-		if (rc != EOK)
-			return rc;
-		packet = tcp_send_prepare_packet(socket, socket_data, packet, 1,
-		    socket_data->last_outgoing + 1);
-	}
-
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-
-	/* Send the packet */
-	tcp_send_packets(socket_data->device_id, packet);
-
-	return EOK;
-}
-
-int tcp_queue_received_packet(socket_core_t *socket,
-    tcp_socket_data_t *socket_data, packet_t *packet, int fragments,
-    size_t total_length)
-{
-	packet_dimension_t *packet_dimension;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(packet);
-	assert(fragments >= 1);
-	assert(socket_data->window > total_length);
-
-	/* Queue the received packet */
-	rc = dyn_fifo_push(&socket->received, packet_get_id(packet),
-	    SOCKET_MAX_RECEIVED_SIZE);
-	if (rc != EOK)
-		return tcp_release_and_return(packet, rc);
-	rc = tl_get_ip_packet_dimension(tcp_globals.ip_sess,
-	    &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
-	if (rc != EOK)
-		return tcp_release_and_return(packet, rc);
-
-	/* Decrease the window size */
-	socket_data->window -= total_length;
-
-	/* Notify the destination socket */
-	async_exch_t *exch = async_exchange_begin(socket->sess);
-	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t) socket->socket_id,
-	    ((packet_dimension->content < socket_data->data_fragment_size) ?
-	    packet_dimension->content : socket_data->data_fragment_size), 0, 0,
-	    (sysarg_t) fragments);
-	async_exchange_end(exch);
-
-	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_exch_t *exch = async_exchange_begin(socket->sess);
-	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t) socket->socket_id,
-	    0, 0, 0, (sysarg_t) 0 /* 0 fragments == no more data */);
-	async_exchange_end(exch);
-}
-
-int tcp_process_syn_sent(socket_core_t *socket, tcp_socket_data_t *
-    socket_data, tcp_header_t *header, packet_t *packet)
-{
-	packet_t *next_packet;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(header);
-	assert(packet);
-
-	if (!GET_TCP_HEADER_SYNCHRONIZE(header))
-		return tcp_release_and_return(packet, EINVAL);
-	
-	/* Process acknowledgement */
-	tcp_process_acknowledgement(socket, socket_data, header);
-
-	socket_data->next_incoming = ntohl(header->sequence_number) + 1;
-
-	/* Release additional packets */
-	next_packet = pq_detach(packet);
-	if (next_packet) {
-		pq_release_remote(tcp_globals.net_sess,
-		    packet_get_id(next_packet));
-	}
-
-	/* Trim if longer than the header */
-	if (packet_get_data_length(packet) > sizeof(*header)) {
-		rc = packet_trim(packet, 0,
-		    packet_get_data_length(packet) - sizeof(*header));
-		if (rc != EOK)
-			return tcp_release_and_return(packet, rc);
-	}
-
-	tcp_prepare_operation_header(socket, socket_data, header, 0, 0);
-	fibril_mutex_lock(&socket_data->operation.mutex);
-	socket_data->operation.result = tcp_queue_packet(socket, socket_data,
-	    packet, 1);
-
-	if (socket_data->operation.result == EOK) {
-		socket_data->state = TCP_SOCKET_ESTABLISHED;
-		packet = tcp_get_packets_to_send(socket, socket_data);
-		if (packet) {
-			fibril_rwlock_write_unlock( socket_data->local_lock);
-			/* Send the packet */
-			tcp_send_packets(socket_data->device_id, packet);
-			/* Signal the result */
-			fibril_condvar_signal( &socket_data->operation.condvar);
-			fibril_mutex_unlock( &socket_data->operation.mutex);
-			return EOK;
-		}
-	}
-
-	fibril_mutex_unlock(&socket_data->operation.mutex);
-	return tcp_release_and_return(packet, EINVAL);
-}
-
-int tcp_process_listen(socket_core_t *listening_socket,
-    tcp_socket_data_t *listening_socket_data, tcp_header_t *header,
-    packet_t *packet, struct sockaddr *src, struct sockaddr *dest,
-    size_t addrlen)
-{
-	packet_t *next_packet;
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	int socket_id;
-	int listening_socket_id = listening_socket->socket_id;
-	int listening_port = listening_socket->port;
-	int rc;
-
-	assert(listening_socket);
-	assert(listening_socket_data);
-	assert(listening_socket->specific_data == listening_socket_data);
-	assert(header);
-	assert(packet);
-
-	if (!GET_TCP_HEADER_SYNCHRONIZE(header))
-		return tcp_release_and_return(packet, EINVAL);
-
-	socket_data = (tcp_socket_data_t *) malloc(sizeof(*socket_data));
-	if (!socket_data)
-		return tcp_release_and_return(packet, ENOMEM);
-
-	tcp_initialize_socket_data(socket_data);
-	socket_data->local_lock = listening_socket_data->local_lock;
-	socket_data->local_sockets = listening_socket_data->local_sockets;
-	socket_data->listening_socket_id = listening_socket->socket_id;
-	socket_data->next_incoming = ntohl(header->sequence_number);
-	socket_data->treshold = socket_data->next_incoming +
-	    ntohs(header->window);
-	socket_data->addrlen = addrlen;
-	socket_data->addr = malloc(socket_data->addrlen);
-	if (!socket_data->addr) {
-		free(socket_data);
-		return tcp_release_and_return(packet, ENOMEM);
-	}
-
-	memcpy(socket_data->addr, src, socket_data->addrlen);
-	socket_data->dest_port = ntohs(header->source_port);
-	rc = tl_set_address_port(socket_data->addr, socket_data->addrlen,
-	    socket_data->dest_port);
-	if (rc != EOK) {
-		free(socket_data->addr);
-		free(socket_data);
-		return tcp_release_and_return(packet, rc);
-	}
-
-	/* Create a socket */
-	socket_id = -1;
-	rc = socket_create(socket_data->local_sockets, listening_socket->sess,
-	    socket_data, &socket_id);
-	if (rc != EOK) {
-		free(socket_data->addr);
-		free(socket_data);
-		return tcp_release_and_return(packet, rc);
-	}
-
-	printf("new_sock %d\n", socket_id);
-	socket_data->pseudo_header = listening_socket_data->pseudo_header;
-	socket_data->headerlen = listening_socket_data->headerlen;
-	listening_socket_data->pseudo_header = NULL;
-	listening_socket_data->headerlen = 0;
-
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-	fibril_rwlock_write_lock(&tcp_globals.lock);
-
-	/* Find the destination socket */
-	listening_socket = socket_port_find(&tcp_globals.sockets,
-	    listening_port, (uint8_t *) SOCKET_MAP_KEY_LISTENING, 0);
-	if (!listening_socket ||
-	    (listening_socket->socket_id != listening_socket_id)) {
-		fibril_rwlock_write_unlock(&tcp_globals.lock);
-		/* A shadow may remain until app hangs up */
-		return tcp_release_and_return(packet, EOK /*ENOTSOCK*/);
-	}
-	listening_socket_data =
-	    (tcp_socket_data_t *) listening_socket->specific_data;
-	assert(listening_socket_data);
-
-	fibril_rwlock_write_lock(listening_socket_data->local_lock);
-
-	socket = socket_cores_find(listening_socket_data->local_sockets,
-	    socket_id);
-	if (!socket) {
-		/* Where is the socket?!? */
-		fibril_rwlock_write_unlock(&tcp_globals.lock);
-		return ENOTSOCK;
-	}
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	rc = socket_port_add(&tcp_globals.sockets, listening_port, socket,
-	    (uint8_t *) socket_data->addr, socket_data->addrlen);
-	assert(socket == socket_port_find(&tcp_globals.sockets, listening_port,
-	    (uint8_t *) socket_data->addr, socket_data->addrlen));
-
-//	rc = socket_bind_free_port(&tcp_globals.sockets, socket,
-//	    TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
-//	    tcp_globals.last_used_port);
-//	tcp_globals.last_used_port = socket->port;
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-	if (rc != EOK) {
-		socket_destroy(tcp_globals.net_sess, socket->socket_id,
-		    socket_data->local_sockets, &tcp_globals.sockets,
-		    tcp_free_socket_data);
-		return tcp_release_and_return(packet, rc);
-	}
-
-	socket_data->state = TCP_SOCKET_LISTEN;
-	socket_data->next_incoming = ntohl(header->sequence_number) + 1;
-
-	/* Release additional packets */
-	next_packet = pq_detach(packet);
-	if (next_packet) {
-		pq_release_remote(tcp_globals.net_sess,
-		    packet_get_id(next_packet));
-	}
-
-	/* Trim if longer than the header */
-	if (packet_get_data_length(packet) > sizeof(*header)) {
-		rc = packet_trim(packet, 0,
-		    packet_get_data_length(packet) - sizeof(*header));
-		if (rc != EOK) {
-			socket_destroy(tcp_globals.net_sess, socket->socket_id,
-			    socket_data->local_sockets, &tcp_globals.sockets,
-			    tcp_free_socket_data);
-			return tcp_release_and_return(packet, rc);
-		}
-	}
-
-	tcp_prepare_operation_header(socket, socket_data, header, 1, 0);
-
-	rc = tcp_queue_packet(socket, socket_data, packet, 1);
-	if (rc != EOK) {
-		socket_destroy(tcp_globals.net_sess, socket->socket_id,
-		    socket_data->local_sockets, &tcp_globals.sockets,
-		    tcp_free_socket_data);
-		return rc;
-	}
-
-	packet = tcp_get_packets_to_send(socket, socket_data);
-	if (!packet) {
-		socket_destroy(tcp_globals.net_sess, socket->socket_id,
-		    socket_data->local_sockets, &tcp_globals.sockets,
-		    tcp_free_socket_data);
-		return EINVAL;
-	}
-
-	socket_data->state = TCP_SOCKET_SYN_RECEIVED;
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-
-	/* Send the packet */
-	tcp_send_packets(socket_data->device_id, packet);
-
-	return EOK;
-}
-
-int tcp_process_syn_received(socket_core_t *socket,
-    tcp_socket_data_t *socket_data, tcp_header_t *header, packet_t *packet)
-{
-	socket_core_t *listening_socket;
-	tcp_socket_data_t *listening_socket_data;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(header);
-	assert(packet);
-
-	if (!GET_TCP_HEADER_ACKNOWLEDGE(header))
-		return tcp_release_and_return(packet, EINVAL);
-
-	/* Process acknowledgement */
-	tcp_process_acknowledgement(socket, socket_data, header);
-
-	socket_data->next_incoming = ntohl(header->sequence_number); /* + 1; */
-	pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-	socket_data->state = TCP_SOCKET_ESTABLISHED;
-	listening_socket = socket_cores_find(socket_data->local_sockets,
-	    socket_data->listening_socket_id);
-	if (listening_socket) {
-		listening_socket_data =
-		    (tcp_socket_data_t *) listening_socket->specific_data;
-		assert(listening_socket_data);
-
-		/* Queue the received packet */
-		rc = dyn_fifo_push(&listening_socket->accepted,
-		    (-1 * socket->socket_id), listening_socket_data->backlog);
-		if (rc == EOK) {
-			/* Notify the destination socket */
-			async_exch_t *exch = async_exchange_begin(socket->sess);
-			async_msg_5(exch, NET_SOCKET_ACCEPTED,
-			    (sysarg_t) listening_socket->socket_id,
-			    socket_data->data_fragment_size, TCP_HEADER_SIZE,
-			    0, (sysarg_t) socket->socket_id);
-			async_exchange_end(exch);
-
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-			return EOK;
-		}
-	}
-	/* Send FIN */
-	socket_data->state = TCP_SOCKET_FIN_WAIT_1;
-
-	/* Create the notification packet */
-	rc = tcp_create_notification_packet(&packet, socket, socket_data, 0, 1);
-	if (rc != EOK)
-		return rc;
-
-	/* Send the packet */
-	rc = tcp_queue_packet(socket, socket_data, packet, 1);
-	if (rc != EOK)
-		return rc;
-
-	/* Flush packets */
-	packet = tcp_get_packets_to_send(socket, socket_data);
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-	if (packet) {
-		/* Send the packet */
-		tcp_send_packets(socket_data->device_id, packet);
-	}
-
-	return EOK;
-}
-
-void tcp_process_acknowledgement(socket_core_t *socket,
-    tcp_socket_data_t *socket_data, tcp_header_t *header)
-{
-	size_t number;
-	size_t length;
-	packet_t *packet;
-	packet_t *next;
-	packet_t *acknowledged = NULL;
-	uint32_t old;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(header);
-
-	if (!GET_TCP_HEADER_ACKNOWLEDGE(header))
-		return;
-
-	number = ntohl(header->acknowledgement_number);
-
-	/* If more data acknowledged */
-	if (number != socket_data->expected) {
-		old = socket_data->expected;
-		if (IS_IN_INTERVAL_OVERFLOW(old, socket_data->fin_outgoing,
-		    number)) {
-			switch (socket_data->state) {
-			case TCP_SOCKET_FIN_WAIT_1:
-				socket_data->state = TCP_SOCKET_FIN_WAIT_2;
-				break;
-			case TCP_SOCKET_LAST_ACK:
-			case TCP_SOCKET_CLOSING:
-				/*
-				 * FIN acknowledged - release the socket in
-				 * another fibril.
-				 */
-				tcp_prepare_timeout(tcp_release_after_timeout,
-				    socket, socket_data, 0,
-				    TCP_SOCKET_TIME_WAIT,
-				    NET_DEFAULT_TCP_TIME_WAIT_TIMEOUT, true);
-				break;
-			default:
-				break;
-			}
-		}
-
-		/* Update the treshold if higher than set */
-		if (number + ntohs(header->window) >
-		    socket_data->expected + socket_data->treshold) {
-			socket_data->treshold = number + ntohs(header->window) -
-			    socket_data->expected;
-		}
-
-		/* Set new expected sequence number */
-		socket_data->expected = number;
-		socket_data->expected_count = 1;
-		packet = socket_data->outgoing;
-		while (pq_get_order(packet, &number, &length) == EOK) {
-			if (IS_IN_INTERVAL_OVERFLOW((uint32_t) old,
-			    (uint32_t) (number + length),
-			    (uint32_t) socket_data->expected)) {
-				next = pq_detach(packet);
-				if (packet == socket_data->outgoing)
-					socket_data->outgoing = next;
-
-				/* Add to acknowledged or release */
-				if (pq_add(&acknowledged, packet, 0, 0) != EOK)
-					pq_release_remote(tcp_globals.net_sess,
-					    packet_get_id(packet));
-				packet = next;
-			} else if (old < socket_data->expected)
-				break;
-		}
-
-		/* Release acknowledged */
-		if (acknowledged) {
-			pq_release_remote(tcp_globals.net_sess,
-			    packet_get_id(acknowledged));
-		}
-		return;
-		/* If the same as the previous time */
-	}
-
-	if (number == socket_data->expected) {
-		/* Increase the counter */
-		socket_data->expected_count++;
-		if (socket_data->expected_count == TCP_FAST_RETRANSMIT_COUNT) {
-			socket_data->expected_count = 1;
-			/* TODO retransmit lock */
-			//tcp_retransmit_packet(socket, socket_data, number);
-		}
-	}
-}
-
-/** Per-connection initialization
- *
- */
-void tl_connection(void)
-{
-}
-
-/** Processes the TCP message.
- *
- * @param[in] callid	The message identifier.
- * @param[in] call	The message parameters.
- * @param[out] answer	The message answer parameters.
- * @param[out] answer_count The last parameter for the actual answer in the
- *			answer parameter.
- * @return		EOK on success.
- * @return		ENOTSUP if the message is not known.
- *
- * @see tcp_interface.h
- * @see IS_NET_TCP_MESSAGE()
- */
-int tl_message(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *answer_count)
-{
-	assert(call);
-	assert(answer);
-	assert(answer_count);
-	
-	*answer_count = 0;
-	
-	async_sess_t *callback =
-	    async_callback_receive_start(EXCHANGE_SERIALIZE, call);
-	if (callback)
-		return tcp_process_client_messages(callback, callid, *call);
-	
-	return ENOTSUP;
-}
-
-void tcp_refresh_socket_data(tcp_socket_data_t *socket_data)
-{
-	assert(socket_data);
-
-	bzero(socket_data, sizeof(*socket_data));
-	socket_data->state = TCP_SOCKET_INITIAL;
-	socket_data->device_id = NIC_DEVICE_INVALID_ID;
-	socket_data->window = NET_DEFAULT_TCP_WINDOW;
-	socket_data->treshold = socket_data->window;
-	socket_data->last_outgoing = TCP_INITIAL_SEQUENCE_NUMBER;
-	socket_data->timeout = NET_DEFAULT_TCP_INITIAL_TIMEOUT;
-	socket_data->acknowledged = socket_data->last_outgoing;
-	socket_data->next_outgoing = socket_data->last_outgoing + 1;
-	socket_data->expected = socket_data->next_outgoing;
-}
-
-void tcp_initialize_socket_data(tcp_socket_data_t *socket_data)
-{
-	assert(socket_data);
-
-	tcp_refresh_socket_data(socket_data);
-	fibril_mutex_initialize(&socket_data->operation.mutex);
-	fibril_condvar_initialize(&socket_data->operation.condvar);
-	socket_data->data_fragment_size = MAX_TCP_FRAGMENT_SIZE;
-}
-
-int tcp_process_client_messages(async_sess_t *sess, ipc_callid_t callid,
-    ipc_call_t call)
-{
-	int res;
-	socket_cores_t local_sockets;
-	struct sockaddr *addr;
-	int socket_id;
-	size_t addrlen;
-	size_t size;
-	fibril_rwlock_t lock;
-	ipc_call_t answer;
-	size_t answer_count;
-	tcp_socket_data_t *socket_data;
-	socket_core_t *socket;
-	packet_dimension_t *packet_dimension;
-
-	/*
-	 * Accept the connection
-	 *  - Answer the first IPC_M_CONNECT_ME_TO call.
-	 */
-	res = EOK;
-	answer_count = 0;
-
-	socket_cores_initialize(&local_sockets);
-	fibril_rwlock_initialize(&lock);
-
-	while (true) {
-
-		/* Answer the call */
-		answer_call(callid, res, &answer, answer_count);
-		/* Refresh data */
-		refresh_answer(&answer, &answer_count);
-		/* Get the next call */
-		callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call)) {
-			res = EHANGUP;
-			break;
-		}
-
-		/* Process the call */
-		switch (IPC_GET_IMETHOD(call)) {
-		case NET_SOCKET:
-			socket_data =
-			    (tcp_socket_data_t *) malloc(sizeof(*socket_data));
-			if (!socket_data) {
-				res = ENOMEM;
-				break;
-			}
-			
-			tcp_initialize_socket_data(socket_data);
-			socket_data->local_lock = &lock;
-			socket_data->local_sockets = &local_sockets;
-			fibril_rwlock_write_lock(&lock);
-			socket_id = SOCKET_GET_SOCKET_ID(call);
-			res = socket_create(&local_sockets, sess,
-			    socket_data, &socket_id);
-			SOCKET_SET_SOCKET_ID(answer, socket_id);
-			fibril_rwlock_write_unlock(&lock);
-			if (res != EOK) {
-				free(socket_data);
-				break;
-			}
-			if (tl_get_ip_packet_dimension(tcp_globals.ip_sess,
-			    &tcp_globals.dimensions, NIC_DEVICE_INVALID_ID,
-			    &packet_dimension) == EOK) {
-				SOCKET_SET_DATA_FRAGMENT_SIZE(answer,
-				    ((packet_dimension->content <
-				    socket_data->data_fragment_size) ?
-				    packet_dimension->content :
-				    socket_data->data_fragment_size));
-			}
-//                      SOCKET_SET_DATA_FRAGMENT_SIZE(answer, MAX_TCP_FRAGMENT_SIZE);
-			SOCKET_SET_HEADER_SIZE(answer, TCP_HEADER_SIZE);
-			answer_count = 3;
-			break;
-
-		case NET_SOCKET_BIND:
-			res = async_data_write_accept((void **) &addr, false,
-			    0, 0, 0, &addrlen);
-			if (res != EOK)
-				break;
-			fibril_rwlock_write_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = socket_bind(&local_sockets, &tcp_globals.sockets,
-			    SOCKET_GET_SOCKET_ID(call), addr, addrlen,
-			    TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
-			    tcp_globals.last_used_port);
-			if (res == EOK) {
-				socket = socket_cores_find(&local_sockets,
-				    SOCKET_GET_SOCKET_ID(call));
-				if (socket) {
-					socket_data = (tcp_socket_data_t *)
-					    socket->specific_data;
-					assert(socket_data);
-					socket_data->state = TCP_SOCKET_LISTEN;
-				}
-			}
-			fibril_rwlock_write_unlock(&lock);
-			fibril_rwlock_write_unlock(&tcp_globals.lock);
-			free(addr);
-			break;
-
-		case NET_SOCKET_LISTEN:
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-//                      fibril_rwlock_write_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_listen_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call),
-			    SOCKET_GET_BACKLOG(call));
-			fibril_rwlock_write_unlock(&lock);
-//                      fibril_rwlock_write_unlock(&tcp_globals.lock);
-			fibril_rwlock_read_unlock(&tcp_globals.lock);
-			break;
-
-		case NET_SOCKET_CONNECT:
-			res = async_data_write_accept((void **) &addr, false,
-			    0, 0, 0, &addrlen);
-			if (res != EOK)
-				break;
-			/*
-			 * The global lock may be released in the
-			 * tcp_connect_message() function.
-			 */
-			fibril_rwlock_write_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_connect_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call), addr, addrlen);
-			if (res != EOK) {
-				fibril_rwlock_write_unlock(&lock);
-				fibril_rwlock_write_unlock(&tcp_globals.lock);
-				free(addr);
-			}
-			break;
-
-		case NET_SOCKET_ACCEPT:
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_accept_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call),
-			    SOCKET_GET_NEW_SOCKET_ID(call), &size, &addrlen);
-			SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
-			fibril_rwlock_write_unlock(&lock);
-			fibril_rwlock_read_unlock(&tcp_globals.lock);
-			if (res > 0) {
-				SOCKET_SET_SOCKET_ID(answer, res);
-				SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
-				answer_count = 3;
-			}
-			break;
-
-		case NET_SOCKET_SEND:
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_send_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call),
-			    SOCKET_GET_DATA_FRAGMENTS(call), &size,
-			    SOCKET_GET_FLAGS(call));
-			SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
-			if (res != EOK) {
-				fibril_rwlock_write_unlock(&lock);
-				fibril_rwlock_read_unlock(&tcp_globals.lock);
-			} else {
-				answer_count = 2;
-			}
-			break;
-
-		case NET_SOCKET_SENDTO:
-			res = async_data_write_accept((void **) &addr, false,
-			    0, 0, 0, &addrlen);
-			if (res != EOK)
-				break;
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_send_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call),
-			    SOCKET_GET_DATA_FRAGMENTS(call), &size,
-			    SOCKET_GET_FLAGS(call));
-			SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size);
-			if (res != EOK) {
-				fibril_rwlock_write_unlock(&lock);
-				fibril_rwlock_read_unlock(&tcp_globals.lock);
-			} else {
-				answer_count = 2;
-			}
-			free(addr);
-			break;
-
-		case NET_SOCKET_RECV:
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_recvfrom_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call),
-			    NULL);
-			fibril_rwlock_write_unlock(&lock);
-			fibril_rwlock_read_unlock(&tcp_globals.lock);
-			if (res > 0) {
-				SOCKET_SET_READ_DATA_LENGTH(answer, res);
-				answer_count = 1;
-				res = EOK;
-			}
-			break;
-
-		case NET_SOCKET_RECVFROM:
-			fibril_rwlock_read_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_recvfrom_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call),
-			    &addrlen);
-			fibril_rwlock_write_unlock(&lock);
-			fibril_rwlock_read_unlock(&tcp_globals.lock);
-			if (res > 0) {
-				SOCKET_SET_READ_DATA_LENGTH(answer, res);
-				SOCKET_SET_ADDRESS_LENGTH(answer, addrlen);
-				answer_count = 3;
-				res = EOK;
-			}
-			break;
-
-		case NET_SOCKET_CLOSE:
-			fibril_rwlock_write_lock(&tcp_globals.lock);
-			fibril_rwlock_write_lock(&lock);
-			res = tcp_close_message(&local_sockets,
-			    SOCKET_GET_SOCKET_ID(call));
-			if (res != EOK) {
-				fibril_rwlock_write_unlock(&lock);
-				fibril_rwlock_write_unlock(&tcp_globals.lock);
-			}
-			break;
-
-		case NET_SOCKET_GETSOCKOPT:
-		case NET_SOCKET_SETSOCKOPT:
-		default:
-			res = ENOTSUP;
-			break;
-		}
-	}
-
-	/* Release the application session */
-	async_hangup(sess);
-
-	printf("release\n");
-	/* Release all local sockets */
-	socket_cores_release(tcp_globals.net_sess, &local_sockets,
-	    &tcp_globals.sockets, tcp_free_socket_data);
-
-	return EOK;
-}
-
-int tcp_timeout(void *data)
-{
-	tcp_timeout_t *timeout = data;
-	int keep_write_lock = false;
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-
-	assert(timeout);
-
-	/* Sleep the given timeout */
-	async_usleep(timeout->timeout);
-	/* Lock the globals */
-	if (timeout->globals_read_only) 
-		fibril_rwlock_read_lock(&tcp_globals.lock);
-	else 
-		fibril_rwlock_write_lock(&tcp_globals.lock);
-
-	/* Find the pending operation socket */
-	socket = socket_port_find(&tcp_globals.sockets, timeout->port,
-	    timeout->key, timeout->key_length);
-	if (!socket || (socket->socket_id != timeout->socket_id))
-		goto out;
-	
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-	if (socket_data->local_sockets != timeout->local_sockets)
-		goto out;
-	
-	fibril_rwlock_write_lock(socket_data->local_lock);
-	if (timeout->sequence_number) {
-		/* Increase the timeout counter */
-		socket_data->timeout_count++;
-		if (socket_data->timeout_count == TCP_MAX_TIMEOUTS) {
-			/* TODO release as connection lost */
-			//tcp_refresh_socket_data(socket_data);
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-		} else {
-			/* Retransmit */
-//                      tcp_retransmit_packet(socket,
-//			    socket_data, timeout->sequence_number);
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-		}
-	} else {
-		fibril_mutex_lock(&socket_data->operation.mutex);
-		/* Set the timeout operation result if state not changed */
-		if (socket_data->state == timeout->state) {
-			socket_data->operation.result = ETIMEOUT;
-
-			/* Notify the main fibril */
-			fibril_condvar_signal(&socket_data->operation.condvar);
-
-			/* Keep the global write lock */
-			keep_write_lock = true;
-		} else {
-			/*
-			 * Operation is ok, do nothing.
-			 * Unlocking from now on, so the unlocking
-			 * order does not matter.
-			 */
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-		}
-		fibril_mutex_unlock(&socket_data->operation.mutex);
-	}
-
-out:
-	/* Unlock only if no socket */
-	if (timeout->globals_read_only)
-		fibril_rwlock_read_unlock(&tcp_globals.lock);
-	else if (!keep_write_lock)
-		/* Release if not desired */
-		fibril_rwlock_write_unlock(&tcp_globals.lock);
-	
-	/* Release the timeout structure */
-	free(timeout);
-	return EOK;
-}
-
-int tcp_release_after_timeout(void *data)
-{
-	tcp_timeout_t *timeout = data;
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	fibril_rwlock_t *local_lock;
-
-	assert(timeout);
-
-	/* Sleep the given timeout */
-	async_usleep(timeout->timeout);
-
-	/* Lock the globals */
-	fibril_rwlock_write_lock(&tcp_globals.lock);
-
-	/* Find the pending operation socket */
-	socket = socket_port_find(&tcp_globals.sockets, timeout->port,
-	    timeout->key, timeout->key_length);
-
-	if (socket && (socket->socket_id == timeout->socket_id)) {
-		socket_data = (tcp_socket_data_t *) socket->specific_data;
-		assert(socket_data);
-		if (socket_data->local_sockets == timeout->local_sockets) {
-			local_lock = socket_data->local_lock;
-			fibril_rwlock_write_lock(local_lock);
-			socket_destroy(tcp_globals.net_sess,
-			    timeout->socket_id, timeout->local_sockets,
-			    &tcp_globals.sockets, tcp_free_socket_data);
-			fibril_rwlock_write_unlock(local_lock);
-		}
-	}
-
-	/* Unlock the globals */
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-
-	/* Release the timeout structure */
-	free(timeout);
-
-	return EOK;
-}
-
-void tcp_retransmit_packet(socket_core_t *socket, tcp_socket_data_t *
-    socket_data, size_t sequence_number)
-{
-	packet_t *packet;
-	packet_t *copy;
-	size_t data_length;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	/* Sent packet? */
-	packet = pq_find(socket_data->outgoing, sequence_number);
-	if (packet) {
-		pq_get_order(packet, NULL, &data_length);
-		copy = tcp_prepare_copy(socket, socket_data, packet,
-		    data_length, sequence_number);
-		fibril_rwlock_write_unlock(socket_data->local_lock);
-//              printf("r send %d\n", packet_get_id(packet));
-		if (copy) 
-			tcp_send_packets(socket_data->device_id, copy);
-	} else {
-		fibril_rwlock_write_unlock(socket_data->local_lock);
-	}
-}
-
-int tcp_listen_message(socket_cores_t *local_sockets, int socket_id,
-    int backlog)
-{
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-
-	assert(local_sockets);
-
-	if (backlog < 0) 
-		return EINVAL;
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket) 
-		return ENOTSOCK;
-	
-	/* Get the socket specific data */
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	/* Set the backlog */
-	socket_data->backlog = backlog;
-
-	return EOK;
-}
-
-int tcp_connect_message(socket_cores_t *local_sockets, int socket_id,
-    struct sockaddr *addr, socklen_t addrlen)
-{
-	socket_core_t *socket;
-	int rc;
-
-	assert(local_sockets);
-	assert(addr);
-	assert(addrlen > 0);
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket)
-		return ENOTSOCK;
-	
-	rc = tcp_connect_core(socket, local_sockets, addr, addrlen);
-	if (rc != EOK) {
-		tcp_free_socket_data(socket);
-		/* Unbind if bound */
-		if (socket->port > 0) {
-			socket_ports_exclude(&tcp_globals.sockets,
-			    socket->port, free);
-			socket->port = 0;
-		}
-	}
-	return rc;
-}
-
-int tcp_connect_core(socket_core_t *socket, socket_cores_t *local_sockets,
-    struct sockaddr *addr, socklen_t addrlen)
-{
-	tcp_socket_data_t *socket_data;
+/** Receive packets from network layer. */
+static void tcp_receiver(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
 	packet_t *packet;
 	int rc;
 
-	assert(socket);
-	assert(addr);
-	assert(addrlen > 0);
-
-	/* Get the socket specific data */
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	if ((socket_data->state != TCP_SOCKET_INITIAL) &&
-	    ((socket_data->state != TCP_SOCKET_LISTEN) ||
-	    (socket->port <= 0)))
-		return EINVAL;
-
-	/* Get the destination port */
-	rc = tl_get_address_port(addr, addrlen, &socket_data->dest_port);
-	if (rc != EOK)
-		return rc;
-	
-	if (socket->port <= 0) {
-		/* Try to find a free port */
-		rc = socket_bind_free_port(&tcp_globals.sockets, socket,
-		    TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
-		    tcp_globals.last_used_port);
-		if (rc != EOK)
-			return rc;
-		/* Set the next port as the search starting port number */
-		tcp_globals.last_used_port = socket->port;
-	}
-
-	rc = ip_get_route_req(tcp_globals.ip_sess, IPPROTO_TCP,
-	    addr, addrlen, &socket_data->device_id,
-	    &socket_data->pseudo_header, &socket_data->headerlen);
-	if (rc != EOK)
-		return rc;
-
-	/* Create the notification packet */
-	rc = tcp_create_notification_packet(&packet, socket, socket_data, 1, 0);
-	if (rc != EOK)
-		return rc;
-
-	/* Unlock the globals and wait for an operation */
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-
-	socket_data->addr = addr;
-	socket_data->addrlen = addrlen;
-
-	/* Send the packet */
-
-	if (((rc = tcp_queue_packet(socket, socket_data, packet, 1)) != EOK) ||
-	    ((rc = tcp_prepare_timeout(tcp_timeout, socket, socket_data, 0,
-	    TCP_SOCKET_INITIAL, NET_DEFAULT_TCP_INITIAL_TIMEOUT, false)) !=
-	    EOK)) {
-		socket_data->addr = NULL;
-		socket_data->addrlen = 0;
-		fibril_rwlock_write_lock(&tcp_globals.lock);
-	} else {
-		packet = tcp_get_packets_to_send(socket, socket_data);
-		if (packet) {
-			fibril_mutex_lock(&socket_data->operation.mutex);
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-
-			socket_data->state = TCP_SOCKET_SYN_SENT;
-
-			/* Send the packet */
-			tcp_send_packets(socket_data->device_id, packet);
-
-			/* Wait for a reply */
-			fibril_condvar_wait(&socket_data->operation.condvar,
-			    &socket_data->operation.mutex);
-			rc = socket_data->operation.result;
-			if (rc != EOK) {
-				socket_data->addr = NULL;
-				socket_data->addrlen = 0;
-			}
-		} else {
-			socket_data->addr = NULL;
-			socket_data->addrlen = 0;
-			rc = EINTR;
-		}
-	}
-
-	fibril_mutex_unlock(&socket_data->operation.mutex);
-	return rc;
-}
-
-int tcp_queue_prepare_packet(socket_core_t *socket,
-    tcp_socket_data_t *socket_data, packet_t *packet, size_t data_length)
-{
-	tcp_header_t *header;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	/* Get TCP header */
-	header = (tcp_header_t *) packet_get_data(packet);
-	if (!header)
-		return NO_DATA;
-	
-	header->destination_port = htons(socket_data->dest_port);
-	header->source_port = htons(socket->port);
-	header->sequence_number = htonl(socket_data->next_outgoing);
-
-	rc = packet_set_addr(packet, NULL, (uint8_t *) socket_data->addr,
-	    socket_data->addrlen);
-	if (rc != EOK)
-		return tcp_release_and_return(packet, EINVAL);
-
-	/* Remember the outgoing FIN */
-	if (GET_TCP_HEADER_FINALIZE(header))
-		socket_data->fin_outgoing = socket_data->next_outgoing;
-	
-	return EOK;
-}
-
-int tcp_queue_packet(socket_core_t *socket, tcp_socket_data_t *socket_data,
-    packet_t *packet, size_t data_length)
-{
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	rc = tcp_queue_prepare_packet(socket, socket_data, packet, data_length);
-	if (rc != EOK)
-		return rc;
-
-	rc = pq_add(&socket_data->outgoing, packet, socket_data->next_outgoing,
-	    data_length);
-	if (rc != EOK)
-		return tcp_release_and_return(packet, rc);
-
-	socket_data->next_outgoing += data_length;
-	return EOK;
-}
-
-packet_t *tcp_get_packets_to_send(socket_core_t *socket, tcp_socket_data_t *
-    socket_data)
-{
-	packet_t *packet;
-	packet_t *copy;
-	packet_t *sending = NULL;
-	packet_t *previous = NULL;
-	size_t data_length;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	packet = pq_find(socket_data->outgoing, socket_data->last_outgoing + 1);
-	while (packet) {
-		pq_get_order(packet, NULL, &data_length);
-
-		/*
-		 * Send only if fits into the window, respecting the possible
-		 * overflow.
-		 */
-		if (!IS_IN_INTERVAL_OVERFLOW(
-		    (uint32_t) socket_data->last_outgoing,
-		    (uint32_t) (socket_data->last_outgoing + data_length),
-		    (uint32_t) (socket_data->expected + socket_data->treshold)))
-			break;
-
-		copy = tcp_prepare_copy(socket, socket_data, packet,
-		    data_length, socket_data->last_outgoing + 1);
-		if (!copy) 
-			return sending;
-			
-		if (!sending) {
-			sending = copy;
-		} else {
-			rc = pq_insert_after(previous, copy);
-			if (rc != EOK) {
-				pq_release_remote(tcp_globals.net_sess,
-				    packet_get_id(copy));
-				return sending;
-			}
-		}
-
-		previous = copy;
-		packet = pq_next(packet);
-
-		/* Overflow occurred? */
-		if (!packet &&
-		    (socket_data->last_outgoing > socket_data->next_outgoing)) {
-			printf("gpts overflow\n");
-			/* Continue from the beginning */
-			packet = socket_data->outgoing;
-		}
-		socket_data->last_outgoing += data_length;
-	}
-
-	return sending;
-}
-
-packet_t *tcp_send_prepare_packet(socket_core_t *socket, tcp_socket_data_t *
-    socket_data, packet_t *packet, size_t data_length, size_t sequence_number)
-{
-	tcp_header_t *header;
-	uint32_t checksum;
-	int rc;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	/* Adjust the pseudo header */
-	rc = ip_client_set_pseudo_header_data_length(socket_data->pseudo_header,
-	    socket_data->headerlen, packet_get_data_length(packet));
-	if (rc != EOK) {
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-		return NULL;
-	}
-
-	/* Get the header */
-	header = (tcp_header_t *) packet_get_data(packet);
-	if (!header) {
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-		return NULL;
-	}
-	assert(ntohl(header->sequence_number) == sequence_number);
-
-	/* Adjust the header */
-	if (socket_data->next_incoming) {
-		header->acknowledgement_number =
-		    htonl(socket_data->next_incoming);
-		SET_TCP_HEADER_ACKNOWLEDGE(header, 1);
-	}
-	header->window = htons(socket_data->window);
-
-	/* Checksum */
-	header->checksum = 0;
-	checksum = compute_checksum(0, socket_data->pseudo_header,
-	    socket_data->headerlen);
-	checksum = compute_checksum(checksum,
-	    (uint8_t *) packet_get_data(packet),
-	    packet_get_data_length(packet));
-	header->checksum = htons(flip_checksum(compact_checksum(checksum)));
-
-	/* Prepare the packet */
-	rc = ip_client_prepare_packet(packet, IPPROTO_TCP, 0, 0, 0, 0);
-	if (rc != EOK) {
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-		return NULL;
-	}
-
-	rc = tcp_prepare_timeout(tcp_timeout, socket, socket_data,
-	    sequence_number, socket_data->state, socket_data->timeout, true);
-	if (rc != EOK) {
-		pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-		return NULL;
-	}
-
-	return packet;
-}
-
-packet_t *tcp_prepare_copy(socket_core_t *socket, tcp_socket_data_t *
-    socket_data, packet_t *packet, size_t data_length, size_t sequence_number)
-{
-	packet_t *copy;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	/* Make a copy of the packet */
-	copy = packet_get_copy(tcp_globals.net_sess, packet);
-	if (!copy)
-		return NULL;
-
-	return tcp_send_prepare_packet(socket, socket_data, copy, data_length,
-	    sequence_number);
-}
-
-void tcp_send_packets(nic_device_id_t device_id, packet_t *packet)
-{
-	packet_t *next;
-
-	while (packet) {
-		next = pq_detach(packet);
-		ip_send_msg(tcp_globals.ip_sess, device_id, packet,
-		    SERVICE_TCP, 0);
-		packet = next;
-	}
-}
-
-void tcp_prepare_operation_header(socket_core_t *socket,
-    tcp_socket_data_t *socket_data, tcp_header_t *header, int synchronize,
-    int finalize)
-{
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-	assert(header);
-
-	bzero(header, sizeof(*header));
-	header->source_port = htons(socket->port);
-	header->source_port = htons(socket_data->dest_port);
-	SET_TCP_HEADER_LENGTH(header,
-	    TCP_COMPUTE_HEADER_LENGTH(sizeof(*header)));
-	SET_TCP_HEADER_SYNCHRONIZE(header, synchronize);
-	SET_TCP_HEADER_FINALIZE(header, finalize);
-}
-
-int tcp_prepare_timeout(int (*timeout_function)(void *tcp_timeout_t),
-    socket_core_t *socket, tcp_socket_data_t *socket_data,
-    size_t sequence_number, tcp_socket_state_t state, suseconds_t timeout,
-    int globals_read_only)
-{
-	tcp_timeout_t *operation_timeout;
-	fid_t fibril;
-
-	assert(socket);
-	assert(socket_data);
-	assert(socket->specific_data == socket_data);
-
-	/* Prepare the timeout with key bundle structure */
-	operation_timeout = malloc(sizeof(*operation_timeout) +
-	    socket->key_length + 1);
-	if (!operation_timeout)
-		return ENOMEM;
-
-	bzero(operation_timeout, sizeof(*operation_timeout));
-	operation_timeout->globals_read_only = globals_read_only;
-	operation_timeout->port = socket->port;
-	operation_timeout->local_sockets = socket_data->local_sockets;
-	operation_timeout->socket_id = socket->socket_id;
-	operation_timeout->timeout = timeout;
-	operation_timeout->sequence_number = sequence_number;
-	operation_timeout->state = state;
-
-	/* Copy the key */
-	operation_timeout->key = ((uint8_t *) operation_timeout) +
-	    sizeof(*operation_timeout);
-	operation_timeout->key_length = socket->key_length;
-	memcpy(operation_timeout->key, socket->key, socket->key_length);
-	operation_timeout->key[operation_timeout->key_length] = '\0';
-
-	/* Prepare the timeouting thread */
-	fibril = fibril_create(timeout_function, operation_timeout);
-	if (!fibril) {
-		free(operation_timeout);
-		return ENOMEM;
-	}
-
-//      fibril_mutex_lock(&socket_data->operation.mutex);
-	/* Start the timeout fibril */
-	fibril_add_ready(fibril);
-	//socket_data->state = state;
-	return EOK;
-}
-
-int tcp_recvfrom_message(socket_cores_t *local_sockets, int socket_id,
-    int flags, size_t *addrlen)
-{
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	int packet_id;
-	packet_t *packet;
-	size_t length;
-	int rc;
-
-	assert(local_sockets);
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket)
-		return ENOTSOCK;
-
-	/* Get the socket specific data */
-	if (!socket->specific_data)
-		return NO_DATA;
-
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-
-	/* Check state */
-	if ((socket_data->state != TCP_SOCKET_ESTABLISHED) &&
-	    (socket_data->state != TCP_SOCKET_CLOSE_WAIT))
-		return ENOTCONN;
-
-	/* Send the source address if desired */
-	if (addrlen) {
-		rc = data_reply(socket_data->addr, socket_data->addrlen);
-		if (rc != EOK)
-			return rc;
-		*addrlen = socket_data->addrlen;
-	}
-
-	/* Get the next received packet */
-	packet_id = dyn_fifo_value(&socket->received);
-	if (packet_id < 0)
-		return NO_DATA;
-
-	rc = packet_translate_remote(tcp_globals.net_sess, &packet, packet_id);
-	if (rc != EOK)
-		return rc;
-
-	/* Reply the packets */
-	rc = socket_reply_packets(packet, &length);
-	if (rc != EOK)
-		return rc;
-
-	/* Release the packet */
-	dyn_fifo_pop(&socket->received);
-	pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-
-	/* Return the total length */
-	return (int) length;
-}
-
-int tcp_send_message(socket_cores_t *local_sockets, int socket_id,
-    int fragments, size_t *data_fragment_size, int flags)
-{
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	packet_dimension_t *packet_dimension;
-	packet_t *packet;
-	size_t total_length;
-	tcp_header_t *header;
-	int index;
-	int result;
-	int rc;
-
-	assert(local_sockets);
-	assert(data_fragment_size);
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket)
-		return ENOTSOCK;
-
-	/* Get the socket specific data */
-	if (!socket->specific_data)
-		return NO_DATA;
-
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-
-	/* Check state */
-	if ((socket_data->state != TCP_SOCKET_ESTABLISHED) &&
-	    (socket_data->state != TCP_SOCKET_CLOSE_WAIT))
-		return ENOTCONN;
-
-	rc = tl_get_ip_packet_dimension(tcp_globals.ip_sess,
-	    &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
-	if (rc != EOK)
-		return rc;
-
-	*data_fragment_size =
-	    ((packet_dimension->content < socket_data->data_fragment_size) ?
-	    packet_dimension->content : socket_data->data_fragment_size);
-
-	for (index = 0; index < fragments; index++) {
-		/* Read the data fragment */
-		result = tl_socket_read_packet_data(tcp_globals.net_sess,
-		    &packet, TCP_HEADER_SIZE, packet_dimension,
-		    socket_data->addr, socket_data->addrlen);
-		if (result < 0)
-			return result;
-
-		total_length = (size_t) result;
-
-		/* Prefix the TCP header */
-		header = PACKET_PREFIX(packet, tcp_header_t);
-		if (!header)
-			return tcp_release_and_return(packet, ENOMEM);
-
-		tcp_prepare_operation_header(socket, socket_data, header, 0, 0);
-		rc = tcp_queue_packet(socket, socket_data, packet, total_length);
-		if (rc != EOK)
-			return rc;
-	}
-
-	/* Flush packets */
-	packet = tcp_get_packets_to_send(socket, socket_data);
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-	fibril_rwlock_read_unlock(&tcp_globals.lock);
-
-	if (packet) {
-		/* Send the packet */
-		tcp_send_packets(socket_data->device_id, packet);
-	}
-
-	return EOK;
-}
-
-int
-tcp_close_message(socket_cores_t *local_sockets, int socket_id)
-{
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	packet_t *packet;
-	int rc;
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket)
-		return ENOTSOCK;
-
-	/* Get the socket specific data */
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	/* Check state */
-	switch (socket_data->state) {
-	case TCP_SOCKET_ESTABLISHED:
-		socket_data->state = TCP_SOCKET_FIN_WAIT_1;
-		break;
-
-	case TCP_SOCKET_CLOSE_WAIT:
-		socket_data->state = TCP_SOCKET_LAST_ACK;
-		break;
-
-//      case TCP_SOCKET_LISTEN:
-
-	default:
-		/* Just destroy */
-		rc = socket_destroy(tcp_globals.net_sess, socket_id,
-		    local_sockets, &tcp_globals.sockets,
-		    tcp_free_socket_data);
-		if (rc == EOK) {
-			fibril_rwlock_write_unlock(socket_data->local_lock);
-			fibril_rwlock_write_unlock(&tcp_globals.lock);
-		}
-		return rc;
-	}
-
-	/*
-	 * Send FIN.
-	 * TODO should I wait to complete?
-	 */
-
-	/* Create the notification packet */
-	rc = tcp_create_notification_packet(&packet, socket, socket_data, 0, 1);
-	if (rc != EOK)
-		return rc;
-
-	/* Send the packet */
-	rc = tcp_queue_packet(socket, socket_data, packet, 1);
-	if (rc != EOK)
-		return rc;
-
-	/* Flush packets */
-	packet = tcp_get_packets_to_send(socket, socket_data);
-	fibril_rwlock_write_unlock(socket_data->local_lock);
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-
-	if (packet) {
-		/* Send the packet */
-		tcp_send_packets(socket_data->device_id, packet);
-	}
-
-	return EOK;
-}
-
-int tcp_create_notification_packet(packet_t **packet, socket_core_t *socket,
-    tcp_socket_data_t *socket_data, int synchronize, int finalize)
-{
-	packet_dimension_t *packet_dimension;
-	tcp_header_t *header;
-	int rc;
-
-	assert(packet);
-
-	/* Get the device packet dimension */
-	rc = tl_get_ip_packet_dimension(tcp_globals.ip_sess,
-	    &tcp_globals.dimensions, socket_data->device_id, &packet_dimension);
-	if (rc != EOK)
-		return rc;
-
-	/* Get a new packet */
-	*packet = packet_get_4_remote(tcp_globals.net_sess, TCP_HEADER_SIZE,
-	    packet_dimension->addr_len, packet_dimension->prefix,
-	    packet_dimension->suffix);
-	
-	if (!*packet) 
-		return ENOMEM;
-
-	/* Allocate space in the packet */
-	header = PACKET_SUFFIX(*packet, tcp_header_t);
-	if (!header)
-		tcp_release_and_return(*packet, ENOMEM);
-
-	tcp_prepare_operation_header(socket, socket_data, header, synchronize,
-	    finalize);
-
-	return EOK;
-}
-
-int tcp_accept_message(socket_cores_t *local_sockets, int socket_id,
-    int new_socket_id, size_t *data_fragment_size, size_t *addrlen)
-{
-	socket_core_t *accepted;
-	socket_core_t *socket;
-	tcp_socket_data_t *socket_data;
-	packet_dimension_t *packet_dimension;
-	int rc;
-
-	assert(local_sockets);
-	assert(data_fragment_size);
-	assert(addrlen);
-
-	/* Find the socket */
-	socket = socket_cores_find(local_sockets, socket_id);
-	if (!socket)
-		return ENOTSOCK;
-
-	/* Get the socket specific data */
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	/* Check state */
-	if (socket_data->state != TCP_SOCKET_LISTEN)
-		return EINVAL;
-
-	do {
-		socket_id = dyn_fifo_value(&socket->accepted);
-		if (socket_id < 0)
-			return ENOTSOCK;
-		socket_id *= -1;
-
-		accepted = socket_cores_find(local_sockets, socket_id);
-		if (!accepted)
-			return ENOTSOCK;
-
-		/* Get the socket specific data */
-		socket_data = (tcp_socket_data_t *) accepted->specific_data;
-		assert(socket_data);
-		/* TODO can it be in another state? */
-		if (socket_data->state == TCP_SOCKET_ESTABLISHED) {
-			rc = data_reply(socket_data->addr,
-			    socket_data->addrlen);
-			if (rc != EOK)
-				return rc;
-			rc = tl_get_ip_packet_dimension(tcp_globals.ip_sess,
-			    &tcp_globals.dimensions, socket_data->device_id,
-			    &packet_dimension);
-			if (rc != EOK)
-				return rc;
-			*addrlen = socket_data->addrlen;
-
-			*data_fragment_size =
-			    ((packet_dimension->content <
-			    socket_data->data_fragment_size) ?
-			    packet_dimension->content :
-			    socket_data->data_fragment_size);
-	
-			if (new_socket_id > 0) {
-				rc = socket_cores_update(local_sockets,
-				    accepted->socket_id, new_socket_id);
-				if (rc != EOK)
-					return rc;
-				accepted->socket_id = new_socket_id;
-			}
-		}
-		dyn_fifo_pop(&socket->accepted);
-	} while (socket_data->state != TCP_SOCKET_ESTABLISHED);
-
-	printf("ret accept %d\n", accepted->socket_id);
-	return accepted->socket_id;
-}
-
-void tcp_free_socket_data(socket_core_t *socket)
-{
-	tcp_socket_data_t *socket_data;
-
-	assert(socket);
-
-	printf("destroy_socket %d\n", socket->socket_id);
-
-	/* Get the socket specific data */
-	socket_data = (tcp_socket_data_t *) socket->specific_data;
-	assert(socket_data);
-
-	/* Free the pseudo header */
-	if (socket_data->pseudo_header) {
-		if (socket_data->headerlen) {
-			printf("d pseudo\n");
-			free(socket_data->pseudo_header);
-			socket_data->headerlen = 0;
-		}
-		socket_data->pseudo_header = NULL;
-	}
-
-	socket_data->headerlen = 0;
-
-	/* Free the address */
-	if (socket_data->addr) {
-		if (socket_data->addrlen) {
-			printf("d addr\n");
-			free(socket_data->addr);
-			socket_data->addrlen = 0;
-		}
-		socket_data->addr = NULL;
-	}
-	socket_data->addrlen = 0;
-}
-
-/** Releases the packet and returns the result.
- *
- * @param[in] packet	The packet queue to be released.
- * @param[in] result	The result to be returned.
- * @return		The result parameter.
- */
-int tcp_release_and_return(packet_t *packet, int result)
-{
-	pq_release_remote(tcp_globals.net_sess, packet_get_id(packet));
-	return result;
-}
-
-/** Process IPC messages from the IP module
- *
- * @param[in]     iid   Message identifier.
- * @param[in,out] icall Message parameters.
- * @param[in]     arg   Local argument.
- *
- */
-static void tcp_receiver(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	packet_t *packet;
-	int rc;
-	
+	log_msg(LVL_DEBUG, "tcp_receiver()");
+
 	while (true) {
 		switch (IPC_GET_IMETHOD(*icall)) {
 		case NET_TL_RECEIVED:
-			rc = packet_translate_remote(tcp_globals.net_sess, &packet,
+			log_msg(LVL_DEBUG, "method = NET_TL_RECEIVED");
+			rc = packet_translate_remote(net_sess, &packet,
 			    IPC_GET_PACKET(*icall));
-			if (rc == EOK)
-				rc = tcp_received_msg(IPC_GET_DEVICE(*icall), packet,
-				    SERVICE_TCP, IPC_GET_ERROR(*icall));
-			
-			async_answer_0(iid, (sysarg_t) rc);
+			if (rc != EOK) {
+				log_msg(LVL_DEBUG, "Error %d translating packet.", rc);
+				async_answer_0(iid, (sysarg_t)rc);
+				break;
+			}
+			rc = tcp_received_msg(IPC_GET_DEVICE(*icall), packet,
+			    IPC_GET_ERROR(*icall));
+			async_answer_0(iid, (sysarg_t)rc);
 			break;
 		default:
-			async_answer_0(iid, (sysarg_t) ENOTSUP);
+			log_msg(LVL_DEBUG, "method = %u",
+			    (unsigned)IPC_GET_IMETHOD(*icall));
+			async_answer_0(iid, ENOTSUP);
+			break;
 		}
-		
+
 		iid = async_get_call(icall);
 	}
 }
 
-/** Initialize the TCP module.
- *
- * @param[in] sess Network module session.
- *
- * @return EOK on success.
- * @return ENOMEM if there is not enough memory left.
- *
+/** Transmit PDU over network layer. */
+void tcp_transmit_pdu(tcp_pdu_t *pdu)
+{
+	struct sockaddr_in dest;
+	nic_device_id_t dev_id;
+	void *phdr;
+	size_t phdr_len;
+	packet_dimension_t *pkt_dim;
+	int rc;
+	packet_t *packet;
+	void *pkt_data;
+	size_t pdu_size;
+
+	dest.sin_family = AF_INET;
+	dest.sin_port = 0; /* not needed */
+	dest.sin_addr.s_addr = host2uint32_t_be(pdu->dest_addr.ipv4);
+
+	/* Find route. Obtained pseudo-header is not used. */
+	rc = ip_get_route_req(ip_sess, IPPROTO_TCP, (struct sockaddr *)&dest,
+	    sizeof(dest), &dev_id, &phdr, &phdr_len);
+	if (rc != EOK) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to find route.");
+		return;
+	}
+
+	rc = tl_get_ip_packet_dimension(ip_sess, &pkt_dims, dev_id, &pkt_dim);
+	if (rc != EOK) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get dimension.");
+		return;
+	}
+
+	pdu_size = pdu->header_size + pdu->text_size;
+
+	packet = packet_get_4_remote(net_sess, pdu_size, pkt_dim->addr_len,
+	    pkt_dim->prefix, pkt_dim->suffix);
+	if (!packet) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get packet.");
+		return;
+	}
+
+	pkt_data = packet_suffix(packet, pdu_size);
+	if (!pkt_data) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get pkt_data ptr.");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return;
+	}
+
+	rc = ip_client_prepare_packet(packet, IPPROTO_TCP, 0, 0, 0, 0);
+	if (rc != EOK) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to prepare IP packet part.");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return;
+	}
+
+	rc = packet_set_addr(packet, NULL, (uint8_t *)&dest, sizeof(dest));
+	if (rc != EOK) {
+		log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to set packet address.");
+		pq_release_remote(net_sess, packet_get_id(packet));
+		return;
+	}
+
+	/* Copy PDU data to packet */
+	memcpy(pkt_data, pdu->header, pdu->header_size);
+	memcpy((uint8_t *)pkt_data + pdu->header_size, pdu->text,
+	    pdu->text_size);
+
+	/* Transmit packet. XXX Transfers packet ownership to IP? */
+	ip_send_msg(ip_sess, dev_id, packet, SERVICE_TCP, 0);
+}
+
+/** Process received PDU. */
+static void tcp_received_pdu(tcp_pdu_t *pdu)
+{
+	tcp_segment_t *dseg;
+	tcp_sockpair_t rident;
+
+	log_msg(LVL_DEBUG, "tcp_received_pdu()");
+
+	if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
+		log_msg(LVL_WARN, "Not enough memory. PDU dropped.");
+		return;
+	}
+
+	/* Insert decoded segment into rqueue */
+	tcp_rqueue_insert_seg(&rident, dseg);
+}
+
+/* Called from libnet */
+void tl_connection(void)
+{
+	log_msg(LVL_DEBUG, "tl_connection()");
+}
+
+/* Called from libnet */
+int tl_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
+    size_t *answer_count)
+{
+	async_sess_t *callback;
+
+	log_msg(LVL_DEBUG, "tl_message()");
+
+	*answer_count = 0;
+	callback = async_callback_receive_start(EXCHANGE_SERIALIZE, call);
+	if (callback)
+		return tcp_sock_connection(callback, callid, *call);
+
+	return ENOTSUP;
+}
+
+/* Called from libnet */
+int tl_initialize(async_sess_t *sess)
+{
+	int rc;
+
+	net_sess = sess;
+	icmp_sess = icmp_connect_module();
+
+	log_msg(LVL_DEBUG, "tl_initialize()");
+
+	tcp_sock_init();
+
+	ip_sess = ip_bind_service(SERVICE_IP, IPPROTO_TCP, SERVICE_TCP,
+	    tcp_receiver);
+	if (ip_sess == NULL)
+		return ENOENT;
+
+	rc = packet_dimensions_initialize(&pkt_dims);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
+}
+
+int main(int argc, char **argv)
+{
+	int rc;
+
+	printf(NAME ": TCP (Transmission Control Protocol) network module\n");
+
+	rc = log_init(NAME, LVL_ERROR);
+	if (rc != EOK) {
+		printf(NAME ": Failed to initialize log.\n");
+		return 1;
+	}
+
+//	printf(NAME ": Accepting connections\n");
+//	task_retval(0);
+
+	tcp_rqueue_init();
+	tcp_rqueue_thread_start();
+
+	tcp_ncsim_init();
+	tcp_ncsim_thread_start();
+
+	if (0) tcp_test();
+/*
+	async_manager();
+*/
+	tl_module_start(SERVICE_TCP);
+
+	/* Not reached */
+	return 0;
+}
+
+/**
+ * @}
  */
-int tl_initialize(async_sess_t *sess)
-{
-	fibril_rwlock_initialize(&tcp_globals.lock);
-	fibril_rwlock_write_lock(&tcp_globals.lock);
-	
-	tcp_globals.net_sess = sess;
-	
-	tcp_globals.icmp_sess = icmp_connect_module();
-	tcp_globals.ip_sess = ip_bind_service(SERVICE_IP, IPPROTO_TCP,
-	    SERVICE_TCP, tcp_receiver);
-	if (tcp_globals.ip_sess == NULL) {
-		fibril_rwlock_write_unlock(&tcp_globals.lock);
-		return ENOENT;
-	}
-	
-	int rc = socket_ports_initialize(&tcp_globals.sockets);
-	if (rc != EOK)
-		goto out;
-
-	rc = packet_dimensions_initialize(&tcp_globals.dimensions);
-	if (rc != EOK) {
-		socket_ports_destroy(&tcp_globals.sockets, free);
-		goto out;
-	}
-
-	tcp_globals.last_used_port = TCP_FREE_PORTS_START - 1;
-
-out:
-	fibril_rwlock_write_unlock(&tcp_globals.lock);
-	return rc;
-}
-
-int main(int argc, char *argv[])
-{
-	return tl_module_start(SERVICE_TCP);
-}
-
-/** @}
- */
Index: uspace/srv/net/tl/tcp/tcp.h
===================================================================
--- uspace/srv/net/tl/tcp/tcp.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ uspace/srv/net/tl/tcp/tcp.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2008 Lukas Mejdrech
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -30,277 +30,17 @@
  * @{
  */
-
-/** @file
- * TCP module.
+/** @file TCP (Transmission Control Protocol) network module
  */
 
-#ifndef NET_TCP_H_
-#define NET_TCP_H_
+#ifndef TCP_H
+#define TCP_H
 
 #include <async.h>
-#include <fibril_synch.h>
-#include <net/packet.h>
-#include <net/device.h>
-#include <socket_core.h>
-#include <tl_common.h>
+#include <packet_remote.h>
+#include "tcp_type.h"
 
-/** Type definition of the TCP global data.
- * @see tcp_globals
- */
-typedef struct tcp_globals tcp_globals_t;
-
-/** Type definition of the TCP socket specific data.
- * @see tcp_socket_data
- */
-typedef struct tcp_socket_data tcp_socket_data_t;
-
-/** Type definition of the TCP operation data.
- * @see tcp_operation
- */
-typedef struct tcp_operation tcp_operation_t;
-
-/** TCP socket state type definition.
- * @see tcp_socket_state
- */
-typedef enum tcp_socket_state tcp_socket_state_t;
-
-/** TCP socket state. */
-enum tcp_socket_state {
-	/** Initial.
-	 *
-	 * Not connected or bound.
-	 */
-	TCP_SOCKET_INITIAL,
-	
-	/** Listening.
-	 *
-	 * Awaiting a connection request from another TCP layer.
-	 * When SYN is received a new bound socket in the
-	 * TCP_SOCKET_SYN_RECEIVED state should be created.
-	 */
-	TCP_SOCKET_LISTEN,
-	
-	/** Connecting issued.
-	 *
-	 * A SYN has been sent, and TCP is awaiting the response SYN.
-	 * Should continue to the TCP_SOCKET_ESTABLISHED state.
-	 */
-	TCP_SOCKET_SYN_SENT,
-	
-	/** Connecting received.
-	 *
-	 * A SYN has been received, a SYN has been sent, and TCP is awaiting an
-	 * ACK. Should continue to the TCP_SOCKET_ESTABLISHED state.
-	 */
-	TCP_SOCKET_SYN_RECEIVED,
-	
-	/** Connected.
-	 *
-	 * The three-way handshake has been completed.
-	 */
-	TCP_SOCKET_ESTABLISHED,
-	
-	/** Closing started.
-	 *
-	 * The local application has issued a CLOSE.
-	 * TCP has sent a FIN, and is awaiting an ACK or a FIN.
-	 * Should continue to the TCP_SOCKET_FIN_WAIT_2 state when an ACK is
-	 * received.
-	 * Should continue to the TCP_SOCKET_CLOSING state when a FIN is
-	 * received.
-	 */
-	TCP_SOCKET_FIN_WAIT_1,
-	
-	/** Closing confirmed.
-	 *
-	 * A FIN has been sent, and an ACK received.
-	 * TCP is awaiting a~FIN from the remote TCP layer.
-	 * Should continue to the TCP_SOCKET_CLOSING state.
-	 */
-	TCP_SOCKET_FIN_WAIT_2,
-	
-	/** Closing.
-	 *
-	 * A FIN has been sent, a FIN has been received, and an ACK has been
-	 * sent.
-	 * TCP is awaiting an ACK for the FIN that was sent.
-	 * Should continue to the TCP_SOCKET_TIME_WAIT state.
-	 */
-	TCP_SOCKET_CLOSING,
-	
-	/** Closing received.
-	 *
-	 * TCP has received a FIN, and has sent an ACK.
-	 * It is awaiting a close request from the local application before
-	 * sending a FIN.
-	 * Should continue to the TCP_SOCKET_SOCKET_LAST_ACK state.
-	 */
-	TCP_SOCKET_CLOSE_WAIT,
-	
-	/**
-	 * A FIN has been received, and an ACK and a FIN have been sent.
-	 * TCP is awaiting an ACK.
-	 * Should continue to the TCP_SOCKET_TIME_WAIT state.
-	 */
-	TCP_SOCKET_LAST_ACK,
-	
-	/** Closing finished.
-	 *
-	 * FINs have been received and ACK’d, and TCP is waiting two MSLs to
-	 * remove the connection from the table.
-	 */
-	TCP_SOCKET_TIME_WAIT,
-	
-	/** Closed.
-	 *
-	 * Imaginary, this indicates that a connection has been removed from
-	 * the connection table.
-	 */
-	TCP_SOCKET_CLOSED
-};
-
-/** TCP operation data. */
-struct tcp_operation {
-	/** Operation result. */
-	int result;
-	/** Safety lock. */
-	fibril_mutex_t mutex;
-	/** Operation result signaling. */
-	fibril_condvar_t condvar;
-};
-
-/** TCP socket specific data. */
-struct tcp_socket_data {
-	/** TCP socket state. */
-	tcp_socket_state_t state;
-	
-	/**
-	 * Data fragment size.
-	 * Sending optimalization.
-	 */
-	size_t data_fragment_size;
-	
-	/** Device identifier. */
-	nic_device_id_t device_id;
-	
-	/**
-	 * Listening backlog.
-	 * The maximal number of connected but not yet accepted sockets.
-	 */
-	int backlog;
-	
-	/**
-	 * Parent listening socket identifier.
-	 * Set if this socket is an accepted one.
-	 */
-	int listening_socket_id;
-	
-	/** Treshold size in bytes. */
-	size_t treshold;
-	/** Window size in bytes. */
-	size_t window;
-	/** Acknowledgement timeout. */
-	suseconds_t timeout;
-	/** Last acknowledged byte. */
-	uint32_t acknowledged;
-	/** Next incoming sequence number. */
-	uint32_t next_incoming;
-	/** Incoming FIN. */
-	uint32_t fin_incoming;
-	/** Next outgoing sequence number. */
-	uint32_t next_outgoing;
-	/** Last outgoing sequence number. */
-	uint32_t last_outgoing;
-	/** Outgoing FIN. */
-	uint32_t fin_outgoing;
-	
-	/**
-	 * Expected sequence number by the remote host.
-	 * The sequence number the other host expects.
-	 * The notification is sent only upon a packet reecival.
-	 */
-	uint32_t expected;
-	
-	/**
-	 * Expected sequence number counter.
-	 * Counts the number of received notifications for the same sequence
-	 * number.
-	 */
-	int expected_count;
-	
-	/** Incoming packet queue.
-	 *
-	 * Packets are buffered until received in the right order.
-	 * The packets are excluded after successfully read.
-	 * Packets are sorted by their starting byte.
-	 * Packets metric is set as their data length.
-	 */
-	packet_t *incoming;
-	
-	/** Outgoing packet queue.
-	 *
-	 * Packets are buffered until acknowledged by the remote host in the
-	 * right order.
-	 * The packets are excluded after acknowledged.
-	 * Packets are sorted by their starting byte.
-	 * Packets metric is set as their data length.
-	 */
-	packet_t *outgoing;
-	
-	/** IP pseudo header. */
-	void *pseudo_header;
-	/** IP pseudo header length. */
-	size_t headerlen;
-	/** Remote host address. */
-	struct sockaddr *addr;
-	/** Remote host address length. */
-	socklen_t addrlen;
-	/** Remote host port. */
-	uint16_t dest_port;
-	/** Parent local sockets. */
-	socket_cores_t *local_sockets;
-	
-	/** Local sockets safety lock.
-	 *
-	 * May be locked for writing while holding the global lock for reading
-	 * when changing the local sockets only.
-	 * The global lock may be locked only before locking the local lock.
-	 * The global lock may be locked more weakly than the local lock.
-	 * The global lock may be released before releasing the local lock.
-	 * @see tcp_globals:lock
-	 */
-	fibril_rwlock_t *local_lock;
-	
-	/** Pending operation data. */
-	tcp_operation_t operation;
-	
-	/**
-	 * Timeouts in a row counter.
-	 * If TCP_MAX_TIMEOUTS is reached, the connection is lost.
-	 */
-	int timeout_count;
-};
-
-/** TCP global data. */
-struct tcp_globals {
-	/** Networking module session. */
-	async_sess_t *net_sess;
-	/** IP module session. */
-	async_sess_t *ip_sess;
-	/** ICMP module session. */
-	async_sess_t *icmp_sess;
-	/** Last used free port. */
-	int last_used_port;
-	/** Active sockets. */
-	socket_ports_t sockets;
-	/** Device packet dimensions. */
-	packet_dimensions_t dimensions;
-	
-	/**
-	 * Safety lock.
-	 * Write lock is used only for adding or removing socket ports.
-	 */
-	fibril_rwlock_t lock;
-};
+extern async_sess_t *net_sess;
+extern async_sess_t *ip_sess;
+extern void tcp_transmit_pdu(tcp_pdu_t *);
 
 #endif
Index: pace/srv/net/tl/tcp/tcp_header.h
===================================================================
--- uspace/srv/net/tl/tcp/tcp_header.h	(revision 3b71e84dce17092725ada79fab0ccaf7ded86420)
+++ 	(revision )
@@ -1,163 +1,0 @@
-/*
- * Copyright (c) 2009 Lukas Mejdrech
- * 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 tcp
- * @{
- */
-
-/** @file
- * TCP header definition.
- * Based on the RFC 793.
- */
-
-#ifndef NET_TCP_HEADER_H_
-#define NET_TCP_HEADER_H_
-
-#include <sys/types.h>
-
-/** TCP header size in bytes. */
-#define TCP_HEADER_SIZE				sizeof(tcp_header_t)
-
-/** Returns the actual TCP header length in bytes.
- * @param[in] header The TCP packet header.
- */
-#define TCP_HEADER_LENGTH(header)		(GET_TCP_HEADER_LENGTH(header) * 4U)
-
-/** Returns the TCP header length.
- * @param[in] length The TCP header length in bytes.
- */
-#define TCP_COMPUTE_HEADER_LENGTH(length)	((uint8_t) ((length) / 4U))
-
-/** Type definition of the transmission datagram header.
- * @see tcp_header
- */
-typedef struct tcp_header tcp_header_t;
-
-/** Type definition of the transmission datagram header option.
- * @see tcp_option
- */
-typedef struct tcp_option tcp_option_t;
-
-/** Type definition of the Maximum segment size TCP option. */
-typedef struct tcp_max_segment_size_option tcp_max_segment_size_option_t;
-
-/** Transmission datagram header. */
-struct tcp_header {
-	uint16_t source_port;
-	uint16_t destination_port;
-	uint32_t sequence_number;
-	uint32_t acknowledgement_number;
-
-	uint8_t hlr; /* header length, reserved1 */
-
-#define GET_TCP_HEADER_LENGTH(header) \
-	(((header)->hlr & 0xf0) >> 4)
-#define SET_TCP_HEADER_LENGTH(header, length) \
-	((header)->hlr = \
-	 ((length & 0x0f) << 4) | ((header)->hlr & 0x0f))
-
-#define GET_TCP_HEADER_RESERVED1(header) \
-	((header)->hlr & 0x0f)
-#define SET_TCP_HEADER_RESERVED1(header, reserved1) \
-	((header)->hlr = \
-	 (reserved1 & 0x0f) | ((header)->hlr & 0xf0))
-
-	/* reserved2, urgent, acknowledge, push, reset, synchronize, finalize */
-	uint8_t ruaprsf;  
-
-#define GET_TCP_HEADER_RESERVED2(header) \
-	(((header)->ruaprsf & 0xc0) >> 6)
-#define SET_TCP_HEADER_RESERVED2(header, reserved2) \
-	((header)->ruaprsf = \
-	 ((reserved2 & 0x03) << 6) | ((header)->ruaprsf & 0x3f))
-
-#define GET_TCP_HEADER_URGENT(header) \
-	(((header)->ruaprsf & 0x20) >> 5)
-#define SET_TCP_HEADER_URGENT(header, urgent) \
-	((header)->ruaprsf = \
-	 ((urgent & 0x01) << 5) | ((header)->ruaprsf & 0xdf))
-
-#define GET_TCP_HEADER_ACKNOWLEDGE(header) \
-	(((header)->ruaprsf & 0x10) >> 4)
-#define SET_TCP_HEADER_ACKNOWLEDGE(header, acknowledge) \
-	((header)->ruaprsf = \
-	 ((acknowledge & 0x01) << 4) | ((header)->ruaprsf & 0xef))
-
-#define GET_TCP_HEADER_PUSH(header) \
-	(((header)->ruaprsf & 0x08) >> 3)
-#define SET_TCP_HEADER_PUSH(header, push) \
-	((header)->ruaprsf = \
-	 ((push & 0x01) << 3) | ((header)->ruaprsf & 0xf7))
-
-#define GET_TCP_HEADER_RESET(header) \
-	(((header)->ruaprsf & 0x04) >> 2)
-#define SET_TCP_HEADER_RESET(header, reset) \
-	((header)->ruaprsf = \
-	 ((reset & 0x01) << 2) | ((header)->ruaprsf & 0xfb))
-
-#define GET_TCP_HEADER_SYNCHRONIZE(header) \
-	(((header)->ruaprsf & 0x02) >> 1)
-#define SET_TCP_HEADER_SYNCHRONIZE(header, synchronize) \
-	((header)->ruaprsf = \
-	 ((synchronize & 0x01) << 1) | ((header)->ruaprsf & 0xfd))
-
-#define GET_TCP_HEADER_FINALIZE(header) \
-	((header)->ruaprsf & 0x01)
-#define SET_TCP_HEADER_FINALIZE(header, finalize) \
-	((header)->ruaprsf = \
-	 (finalize & 0x01) | ((header)->ruaprsf & 0xfe))
-
-	uint16_t window;
-	uint16_t checksum;
-	uint16_t urgent_pointer;
-} __attribute__ ((packed));
-
-/** Transmission datagram header option. */
-struct tcp_option {
-	/** Option type. */
-	uint8_t type;
-	/** Option length. */
-	uint8_t length;
-};
-
-/** Maximum segment size TCP option. */
-struct tcp_max_segment_size_option {
-	/** TCP option.
-	 * @see TCPOPT_MAX_SEGMENT_SIZE
-	 * @see TCPOPT_MAX_SEGMENT_SIZE_LENGTH
-	 */
-	tcp_option_t option;
-	
-	/** Maximum segment size in bytes. */
-	uint16_t max_segment_size;
-} __attribute__ ((packed));
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/tl/tcp/tcp_type.h
===================================================================
--- uspace/srv/net/tl/tcp/tcp_type.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/tcp_type.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP type definitions
+ */
+
+#ifndef TCP_TYPE_H
+#define TCP_TYPE_H
+
+#include <adt/list.h>
+#include <async.h>
+#include <bool.h>
+#include <fibril_synch.h>
+#include <socket_core.h>
+#include <sys/types.h>
+
+struct tcp_conn;
+
+typedef enum {
+	/** Listen */
+	st_listen,
+	/** Syn-sent */
+	st_syn_sent,
+	/** Syn-received */
+	st_syn_received,
+	/** Established */
+	st_established,
+	/** Fin-wait-1 */
+	st_fin_wait_1,
+	/** Fin-wait-2 */
+	st_fin_wait_2,
+	/** Close-wait */
+	st_close_wait,
+	/** Closing */
+	st_closing,
+	/** Last-ack */
+	st_last_ack,
+	/** Time-wait */
+	st_time_wait,
+	/** Closed */
+	st_closed
+} tcp_cstate_t;
+
+/** Error codes returned by TCP user calls (per the spec). */
+typedef enum {
+	/* OK */
+	TCP_EOK,
+	/* Connection aborted due to user timeout */
+	TCP_EABORTED,
+	/* Connection already exists */
+	TCP_EEXISTS,
+	/* Connection closing */
+	TCP_ECLOSING,
+	/* Connection does not exist */
+	TCP_ENOTEXIST,
+	/* Connection illegal for this process */
+	TCP_EILLEGAL,
+	/* Connection not open */
+	TCP_ENOTOPEN,
+	/* Connection reset */
+	TCP_ERESET,
+	/* Foreign socket unspecified */
+	TCP_EUNSPEC,
+	/* Insufficient resources */
+	TCP_ENORES,
+	/* Precedence not allowed */
+	TCP_EINVPREC,
+	/* Security/compartment not allowed */
+	TCP_EINVCOMP
+} tcp_error_t;
+
+typedef enum {
+	XF_PUSH		= 0x1,
+	XF_URGENT	= 0x2
+} xflags_t;
+
+typedef enum {
+	CTL_SYN		= 0x1,
+	CTL_FIN		= 0x2,
+	CTL_RST		= 0x4,
+	CTL_ACK		= 0x8
+} tcp_control_t;
+
+typedef struct {
+	uint32_t ipv4;
+} netaddr_t;
+
+typedef struct {
+	netaddr_t addr;
+	uint16_t port;
+} tcp_sock_t;
+
+enum netaddr {
+	TCP_IPV4_ANY = 0
+};
+
+enum tcp_port {
+	TCP_PORT_ANY = 0
+};
+
+typedef struct {
+	tcp_sock_t local;
+	tcp_sock_t foreign;
+} tcp_sockpair_t;
+
+/** Connection incoming segments queue */
+typedef struct {
+	struct tcp_conn *conn;
+	list_t list;
+} tcp_iqueue_t;
+
+/** Retransmission queue */
+typedef struct {
+	struct tcp_conn *conn;
+	list_t list;
+
+	/** Retransmission timer */
+	fibril_timer_t *timer;
+} tcp_tqueue_t;
+
+typedef enum {
+	ap_active,
+	ap_passive
+} acpass_t;
+
+typedef struct tcp_conn {
+	char *name;
+	link_t link;
+
+	/** Connection identification (local and foreign socket) */
+	tcp_sockpair_t ident;
+
+	/** Active or passive connection */
+	acpass_t ap;
+
+	/** Connection state */
+	tcp_cstate_t cstate;
+	/** True if connection was reset */
+	bool reset;
+	/** Protects @c cstate */
+	fibril_mutex_t cstate_lock;
+	/** Signalled when @c cstate changes */
+	fibril_condvar_t cstate_cv;
+
+	/** Set when FIN is removed from the retransmission queue */
+	bool fin_is_acked;
+
+	/** Queue of incoming segments */
+	tcp_iqueue_t incoming;
+
+	/** Retransmission queue */
+	tcp_tqueue_t retransmit;
+
+	/** Time-Wait timeout timer */
+	fibril_timer_t *tw_timer;
+
+	/** Receive buffer */
+	uint8_t *rcv_buf;
+	/** Receive buffer size */
+	size_t rcv_buf_size;
+	/** Receive buffer number of bytes used */
+	size_t rcv_buf_used;
+	/** Receive buffer contains FIN */
+	bool rcv_buf_fin;
+	/** Receive buffer lock */
+	fibril_mutex_t rcv_buf_lock;
+	/** Receive buffer CV. Broadcast when new data is inserted */
+	fibril_condvar_t rcv_buf_cv;
+
+	/** Send buffer */
+	uint8_t *snd_buf;
+	/** Send buffer size */
+	size_t snd_buf_size;
+	/** Send buffer number of bytes used */
+	size_t snd_buf_used;
+	/** Send buffer contains FIN */
+	bool snd_buf_fin;
+
+	/** Send unacknowledged */
+	uint32_t snd_una;
+	/** Send next */
+	uint32_t snd_nxt;
+	/** Send window */
+	uint32_t snd_wnd;
+	/** Send urgent pointer */
+	uint32_t snd_up;
+	/** Segment sequence number used for last window update */
+	uint32_t snd_wl1;
+	/** Segment acknowledgement number used for last window update */
+	uint32_t snd_wl2;
+	/** Initial send sequence number */
+	uint32_t iss;
+
+	/** Receive next */
+	uint32_t rcv_nxt;
+	/** Receive window */
+	uint32_t rcv_wnd;
+	/** Receive urgent pointer */
+	uint32_t rcv_up;
+	/** Initial receive sequence number */
+	uint32_t irs;
+} tcp_conn_t;
+
+typedef struct {
+	unsigned dummy;
+} tcp_conn_status_t;
+
+typedef struct {
+	/** SYN, FIN */
+	tcp_control_t ctrl;
+
+	/** Segment sequence number */
+	uint32_t seq;
+	/** Segment acknowledgement number */
+	uint32_t ack;
+	/** Segment length in sequence space */
+	uint32_t len;
+	/** Segment window */
+	uint32_t wnd;
+	/** Segment urgent pointer */
+	uint32_t up;
+
+	/** Segment data, may be moved when trimming segment */
+	void *data;
+	/** Segment data, original pointer used to free data */
+	void *dfptr;
+} tcp_segment_t;
+
+
+typedef struct {
+	link_t link;
+	tcp_sockpair_t sp;
+	tcp_segment_t *seg;
+} tcp_rqueue_entry_t;
+
+/** NCSim queue entry */
+typedef struct {
+	link_t link;
+	suseconds_t delay;
+	tcp_sockpair_t sp;
+	tcp_segment_t *seg;
+} tcp_squeue_entry_t;
+
+typedef struct {
+	link_t link;
+	tcp_segment_t *seg;
+} tcp_iqueue_entry_t;
+
+/** Retransmission queue entry */
+typedef struct {
+	link_t link;
+	tcp_conn_t *conn;
+	tcp_segment_t *seg;
+} tcp_tqueue_entry_t;
+
+typedef enum {
+	cp_continue,
+	cp_done
+} cproc_t;
+
+/** Encoded PDU */
+typedef struct {
+	/** Source address */
+	netaddr_t src_addr;
+	/** Destination address */
+	netaddr_t dest_addr;
+
+	/** Encoded header */
+	void *header;
+	/** Encoded header size */
+	size_t header_size;
+	/** Text */
+	void *text;
+	/** Text size */
+	size_t text_size;
+} tcp_pdu_t;
+
+typedef struct {
+	async_sess_t *sess;
+	socket_cores_t sockets;
+} tcp_client_t;
+
+typedef struct {
+	/** Client */
+	tcp_client_t *client;
+	/** Connection */
+	tcp_conn_t *conn;
+	/** Local address */
+	netaddr_t laddr;
+} tcp_sockdata_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/test.c
===================================================================
--- uspace/srv/net/tl/tcp/test.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/test.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file Internal TCP test
+ */
+
+#include <async.h>
+#include <errno.h>
+#include <stdio.h>
+#include <thread.h>
+#include <str.h>
+#include "tcp_type.h"
+#include "ucall.h"
+
+#include "test.h"
+
+#define RCV_BUF_SIZE 64
+
+static void test_srv(void *arg)
+{
+	tcp_conn_t *conn;
+	tcp_sock_t lsock;
+	tcp_sock_t fsock;
+	char rcv_buf[RCV_BUF_SIZE + 1];
+	size_t rcvd;
+	xflags_t xflags;
+
+	printf("test_srv()\n");
+	lsock.port = 80;
+	lsock.addr.ipv4 = 0x7f000001;
+	fsock.port = 1024;
+	fsock.addr.ipv4 = 0x7f000001;
+	printf("S: User open...\n");
+	tcp_uc_open(&lsock, &fsock, ap_passive, &conn);
+	conn->name = (char *) "S";
+
+	while (true) {
+		printf("S: User receive...\n");
+		tcp_uc_receive(conn, rcv_buf, RCV_BUF_SIZE, &rcvd, &xflags);
+		if (rcvd == 0) {
+			printf("S: End of data reached.\n");
+			break;
+		}
+		rcv_buf[rcvd] = '\0';
+		printf("S: User received %zu bytes '%s'.\n", rcvd, rcv_buf);
+
+		async_usleep(1000*1000*2);
+	}
+
+	async_usleep(/*10**/1000*1000);
+
+	printf("S: User close...\n");
+	tcp_uc_close(conn);
+
+	printf("test_srv() terminating\n");
+}
+
+static void test_cli(void *arg)
+{
+	tcp_conn_t *conn;
+	tcp_sock_t lsock;
+	tcp_sock_t fsock;
+	const char *msg = "Hello World!";
+
+	printf("test_cli()\n");
+
+	lsock.port = 1024;
+	lsock.addr.ipv4 = 0x7f000001;
+	fsock.port = 80;
+	fsock.addr.ipv4 = 0x7f000001;
+
+	async_usleep(1000*1000*3);
+	printf("C: User open...\n");
+	tcp_uc_open(&lsock, &fsock, ap_active, &conn);
+	conn->name = (char *) "C";
+
+	async_usleep(1000*1000*10);
+	printf("C: User send...\n");
+	tcp_uc_send(conn, (void *)msg, str_size(msg), 0);
+
+	async_usleep(1000*1000*20/**20*2*/);
+	printf("C: User close...\n");
+	tcp_uc_close(conn);
+}
+
+void tcp_test(void)
+{
+	thread_id_t srv_tid;
+	thread_id_t cli_tid;
+	int rc;
+
+	printf("tcp_test()\n");
+
+	async_usleep(1000*1000);
+
+	if (0) {
+		rc = thread_create(test_srv, NULL, "test_srv", &srv_tid);
+		if (rc != EOK) {
+			printf("Failed to create server thread.\n");
+			return;
+		}
+	}
+
+	if (0) {
+		rc = thread_create(test_cli, NULL, "test_cli", &cli_tid);
+		if (rc != EOK) {
+			printf("Failed to create client thread.\n");
+			return;
+		}
+	}
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/test.h
===================================================================
--- uspace/srv/net/tl/tcp/test.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/test.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file Internal TCP test
+ */
+
+#ifndef TEST_H
+#define TEST_H
+
+extern void tcp_test(void);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/tqueue.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/tqueue.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file TCP transmission queue
+ */
+
+#include <adt/list.h>
+#include <errno.h>
+#include <fibril_synch.h>
+#include <byteorder.h>
+#include <io/log.h>
+#include <macros.h>
+#include <mem.h>
+#include <stdlib.h>
+#include "conn.h"
+#include "ncsim.h"
+#include "pdu.h"
+#include "rqueue.h"
+#include "segment.h"
+#include "seq_no.h"
+#include "tqueue.h"
+#include "tcp.h"
+#include "tcp_type.h"
+
+#define RETRANSMIT_TIMEOUT	(2*1000*1000)
+
+static void retransmit_timeout_func(void *arg);
+static void tcp_tqueue_timer_set(tcp_conn_t *conn);
+static void tcp_tqueue_timer_clear(tcp_conn_t *conn);
+
+int tcp_tqueue_init(tcp_tqueue_t *tqueue, tcp_conn_t *conn)
+{
+	tqueue->conn = conn;
+	tqueue->timer = fibril_timer_create();
+	if (tqueue->timer == NULL)
+		return ENOMEM;
+
+	list_initialize(&tqueue->list);
+
+	return EOK;
+}
+
+void tcp_tqueue_clear(tcp_tqueue_t *tqueue)
+{
+	tcp_tqueue_timer_clear(tqueue->conn);
+}
+
+void tcp_tqueue_fini(tcp_tqueue_t *tqueue)
+{
+	if (tqueue->timer != NULL) {
+		fibril_timer_destroy(tqueue->timer);
+		tqueue->timer = NULL;
+	}
+}
+
+void tcp_tqueue_ctrl_seg(tcp_conn_t *conn, tcp_control_t ctrl)
+{
+	tcp_segment_t *seg;
+
+	log_msg(LVL_DEBUG, "tcp_tqueue_ctrl_seg(%p, %u)", conn, ctrl);
+
+	seg = tcp_segment_make_ctrl(ctrl);
+	tcp_tqueue_seg(conn, seg);
+}
+
+void tcp_tqueue_seg(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	tcp_segment_t *rt_seg;
+	tcp_tqueue_entry_t *tqe;
+
+	log_msg(LVL_DEBUG, "%s: tcp_tqueue_seg(%p, %p)", conn->name, conn,
+	    seg);
+
+	/*
+	 * Add segment to retransmission queue
+	 */
+
+	if (seg->len > 0) {
+		rt_seg = tcp_segment_dup(seg);
+		if (rt_seg == NULL) {
+			log_msg(LVL_ERROR, "Memory allocation failed.");
+			/* XXX Handle properly */
+			return;
+		}
+
+		tqe = calloc(1, sizeof(tcp_tqueue_entry_t));
+		if (tqe == NULL) {
+			log_msg(LVL_ERROR, "Memory allocation failed.");
+			/* XXX Handle properly */
+			return;
+		}
+
+		tqe->conn = conn;
+		tqe->seg = rt_seg;
+		rt_seg->seq = conn->snd_nxt;
+
+		list_append(&tqe->link, &conn->retransmit.list);
+
+		/* Set retransmission timer */
+		tcp_tqueue_timer_set(conn);
+	}
+
+	tcp_prepare_transmit_segment(conn, seg);
+}
+
+void tcp_prepare_transmit_segment(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	/*
+	 * Always send ACK once we have received SYN, except for RST segments.
+	 * (Spec says we should always send ACK once connection has been
+	 * established.)
+	 */
+	if (tcp_conn_got_syn(conn) && (seg->ctrl & CTL_RST) == 0)
+		seg->ctrl |= CTL_ACK;
+
+	seg->seq = conn->snd_nxt;
+	conn->snd_nxt += seg->len;
+
+	tcp_conn_transmit_segment(conn, seg);
+}
+
+/** Transmit data from the send buffer.
+ *
+ * @param conn	Connection
+ */
+void tcp_tqueue_new_data(tcp_conn_t *conn)
+{
+	size_t avail_wnd;
+	size_t xfer_seqlen;
+	size_t snd_buf_seqlen;
+	size_t data_size;
+	tcp_control_t ctrl;
+	bool send_fin;
+
+	tcp_segment_t *seg;
+
+	log_msg(LVL_DEBUG, "%s: tcp_tqueue_new_data()", conn->name);
+
+	/* Number of free sequence numbers in send window */
+	avail_wnd = (conn->snd_una + conn->snd_wnd) - conn->snd_nxt;
+	snd_buf_seqlen = conn->snd_buf_used + (conn->snd_buf_fin ? 1 : 0);
+
+	xfer_seqlen = min(snd_buf_seqlen, avail_wnd);
+	log_msg(LVL_DEBUG, "%s: snd_buf_seqlen = %zu, SND.WND = %zu, "
+	    "xfer_seqlen = %zu", conn->name, snd_buf_seqlen, conn->snd_wnd,
+	    xfer_seqlen);
+
+	if (xfer_seqlen == 0)
+		return;
+
+	/* XXX Do not always send immediately */
+
+	send_fin = conn->snd_buf_fin && xfer_seqlen == snd_buf_seqlen;
+	data_size = xfer_seqlen - (send_fin ? 1 : 0);
+
+	if (send_fin) {
+		log_msg(LVL_DEBUG, "%s: Sending out FIN.", conn->name);
+		/* We are sending out FIN */
+		ctrl = CTL_FIN;
+		tcp_conn_fin_sent(conn);
+	} else {
+		ctrl = 0;
+	}
+
+	seg = tcp_segment_make_data(ctrl, conn->snd_buf, data_size);
+	if (seg == NULL) {
+		log_msg(LVL_ERROR, "Memory allocation failure.");
+		return;
+	}
+
+	/* Remove data from send buffer */
+	memmove(conn->snd_buf, conn->snd_buf + data_size,
+	    conn->snd_buf_used - data_size);
+	conn->snd_buf_used -= data_size;
+
+	if (send_fin)
+		conn->snd_buf_fin = false;
+
+	tcp_tqueue_seg(conn, seg);
+}
+
+/** Remove ACKed segments from retransmission queue and possibly transmit
+ * more data.
+ *
+ * This should be called when SND.UNA is updated due to incoming ACK.
+ */
+void tcp_tqueue_ack_received(tcp_conn_t *conn)
+{
+	link_t *cur, *next;
+
+	log_msg(LVL_DEBUG, "%s: tcp_tqueue_ack_received(%p)", conn->name,
+	    conn);
+
+	cur = conn->retransmit.list.head.next;
+
+	while (cur != &conn->retransmit.list.head) {
+		next = cur->next;
+
+		tcp_tqueue_entry_t *tqe = list_get_instance(cur,
+		    tcp_tqueue_entry_t, link);
+
+		if (seq_no_segment_acked(conn, tqe->seg, conn->snd_una)) {
+			/* Remove acknowledged segment */
+			list_remove(cur);
+
+			if ((tqe->seg->ctrl & CTL_FIN) != 0) {
+				log_msg(LVL_DEBUG, "Fin has been acked");
+				log_msg(LVL_DEBUG, "SND.UNA=%" PRIu32
+				    " SEG.SEQ=%" PRIu32 " SEG.LEN=%" PRIu32,
+				    conn->snd_una, tqe->seg->seq, tqe->seg->len);
+				/* Our FIN has been acked */
+				conn->fin_is_acked = true;
+			}
+
+			tcp_segment_delete(tqe->seg);
+			free(tqe);
+
+			/* Reset retransmission timer */
+			tcp_tqueue_timer_set(conn);
+		}
+
+		cur = next;
+	}
+
+	/* Clear retransmission timer if the queue is empty. */
+	if (list_empty(&conn->retransmit.list))
+		tcp_tqueue_timer_clear(conn);
+
+	/* Possibly transmit more data */
+	tcp_tqueue_new_data(conn);
+}
+
+void tcp_conn_transmit_segment(tcp_conn_t *conn, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_conn_transmit_segment(%p, %p)",
+	    conn->name, conn, seg);
+
+	seg->wnd = conn->rcv_wnd;
+
+	if ((seg->ctrl & CTL_ACK) != 0)
+		seg->ack = conn->rcv_nxt;
+	else
+		seg->ack = 0;
+
+	tcp_transmit_segment(&conn->ident, seg);
+}
+
+void tcp_transmit_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "tcp_transmit_segment(f:(%x,%u),l:(%x,%u), %p)",
+	    sp->foreign.addr.ipv4, sp->foreign.port,
+	    sp->local.addr.ipv4, sp->local.port, seg);
+
+	log_msg(LVL_DEBUG, "SEG.SEQ=%" PRIu32 ", SEG.WND=%" PRIu32,
+	    seg->seq, seg->wnd);
+
+	tcp_segment_dump(seg);
+/*
+	tcp_pdu_prepare(conn, seg, &data, &len);
+	tcp_pdu_transmit(data, len);
+*/
+//	tcp_rqueue_bounce_seg(sp, seg);
+//	tcp_ncsim_bounce_seg(sp, seg);
+
+	tcp_pdu_t *pdu;
+
+	if (tcp_pdu_encode(sp, seg, &pdu) != EOK) {
+		log_msg(LVL_WARN, "Not enough memory. Segment dropped.");
+		return;
+	}
+
+	tcp_transmit_pdu(pdu);
+	tcp_pdu_delete(pdu);
+}
+
+static void retransmit_timeout_func(void *arg)
+{
+	tcp_conn_t *conn = (tcp_conn_t *) arg;
+	tcp_tqueue_entry_t *tqe;
+	tcp_segment_t *rt_seg;
+	link_t *link;
+
+	log_msg(LVL_DEBUG, "### %s: retransmit_timeout_func(%p)", conn->name, conn);
+
+	if (conn->cstate == st_closed) {
+		log_msg(LVL_DEBUG, "Connection already closed.");
+		return;
+	}
+
+	link = list_first(&conn->retransmit.list);
+	if (link == NULL) {
+		log_msg(LVL_DEBUG, "Nothing to retransmit");
+		return;
+	}
+
+	tqe = list_get_instance(link, tcp_tqueue_entry_t, link);
+
+	rt_seg = tcp_segment_dup(tqe->seg);
+	if (rt_seg == NULL) {
+		log_msg(LVL_ERROR, "Memory allocation failed.");
+		/* XXX Handle properly */
+		return;
+	}
+
+	log_msg(LVL_DEBUG, "### %s: retransmitting segment", conn->name);
+	tcp_conn_transmit_segment(tqe->conn, rt_seg);
+
+	/* Reset retransmission timer */
+	tcp_tqueue_timer_set(tqe->conn);
+}
+
+/** Set or re-set retransmission timer */
+static void tcp_tqueue_timer_set(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_set()", conn->name);
+
+	(void) retransmit_timeout_func;
+	fibril_timer_set(conn->retransmit.timer, RETRANSMIT_TIMEOUT,
+	    retransmit_timeout_func, (void *) conn);
+}
+
+/** Clear retransmission timer */
+static void tcp_tqueue_timer_clear(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_clear()", conn->name);
+
+	fibril_timer_clear(conn->retransmit.timer);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/tqueue.h
===================================================================
--- uspace/srv/net/tl/tcp/tqueue.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/tqueue.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP transmission queue
+ */
+
+#ifndef TQUEUE_H
+#define TQUEUE_H
+
+#include "std.h"
+#include "tcp_type.h"
+
+extern int tcp_tqueue_init(tcp_tqueue_t *, tcp_conn_t *);
+extern void tcp_tqueue_clear(tcp_tqueue_t *);
+extern void tcp_tqueue_fini(tcp_tqueue_t *);
+extern void tcp_tqueue_ctrl_seg(tcp_conn_t *, tcp_control_t);
+extern void tcp_tqueue_seg(tcp_conn_t *, tcp_segment_t *);
+extern void tcp_tqueue_new_data(tcp_conn_t *);
+extern void tcp_tqueue_ack_received(tcp_conn_t *);
+extern void tcp_prepare_transmit_segment(tcp_conn_t *, tcp_segment_t *);
+extern void tcp_conn_transmit_segment(tcp_conn_t *, tcp_segment_t *);
+extern void tcp_transmit_segment(tcp_sockpair_t *, tcp_segment_t *);
+extern void tcp_header_setup(tcp_conn_t *, tcp_segment_t *, tcp_header_t *);
+extern void tcp_phdr_setup(tcp_conn_t *, tcp_segment_t *, tcp_phdr_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tl/tcp/ucall.c
===================================================================
--- uspace/srv/net/tl/tcp/ucall.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/ucall.c	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+
+/**
+ * @file TCP entry points (close to those defined in the RFC)
+ */
+
+#include <fibril_synch.h>
+#include <io/log.h>
+#include <macros.h>
+#include <mem.h>
+#include "conn.h"
+#include "tcp_type.h"
+#include "tqueue.h"
+#include "ucall.h"
+
+/*
+ * User calls
+ */
+
+/** OPEN user call
+ *
+ * @param lsock		Local socket
+ * @param fsock		Foreign socket
+ * @param acpass	Active/passive
+ * @param conn		Connection
+ *
+ * Unlike in the spec we allow specifying the local address. This means
+ * the implementation does not need to magically guess it, especially
+ * considering there can be more than one local address.
+ *
+ * XXX We should be able to call active open on an existing listening
+ * connection.
+ * XXX We should be able to get connection structure immediately, before
+ * establishment.
+ */
+tcp_error_t tcp_uc_open(tcp_sock_t *lsock, tcp_sock_t *fsock, acpass_t acpass,
+    tcp_conn_t **conn)
+{
+	tcp_conn_t *nconn;
+
+	log_msg(LVL_DEBUG, "tcp_uc_open(%p, %p, %s, %p)",
+	    lsock, fsock, acpass == ap_active ? "active" : "passive",
+	    conn);
+
+	nconn = tcp_conn_new(lsock, fsock);
+	tcp_conn_add(nconn);
+
+	if (acpass == ap_active) {
+		/* Synchronize (initiate) connection */
+		tcp_conn_sync(nconn);
+	}
+
+	/* Wait for connection to be established or reset */
+	log_msg(LVL_DEBUG, "tcp_uc_open: Wait for connection.");
+	fibril_mutex_lock(&nconn->cstate_lock);
+	while (nconn->cstate == st_listen ||
+	    nconn->cstate == st_syn_sent ||
+	    nconn->cstate == st_syn_received) {
+		fibril_condvar_wait(&nconn->cstate_cv, &nconn->cstate_lock);
+	}
+
+	if (nconn->cstate != st_established) {
+		log_msg(LVL_DEBUG, "tcp_uc_open: Connection was reset.");
+		assert(nconn->cstate == st_closed);
+		fibril_mutex_unlock(&nconn->cstate_lock);
+		return TCP_ERESET;
+	}
+
+	fibril_mutex_unlock(&nconn->cstate_lock);
+	log_msg(LVL_DEBUG, "tcp_uc_open: Connection was established.");
+
+	*conn = nconn;
+	return TCP_EOK;
+}
+
+/** SEND user call */
+tcp_error_t tcp_uc_send(tcp_conn_t *conn, void *data, size_t size,
+    xflags_t flags)
+{
+	size_t buf_free;
+	size_t xfer_size;
+
+	log_msg(LVL_DEBUG, "%s: tcp_uc_send()", conn->name);
+
+	if (conn->cstate == st_closed)
+		return TCP_ENOTEXIST;
+
+	if (conn->cstate == st_listen) {
+		/* Change connection to active */
+		tcp_conn_sync(conn);
+	}
+
+	if (conn->snd_buf_fin)
+		return TCP_ECLOSING;
+
+	while (size > 0) {
+		buf_free = conn->snd_buf_size - conn->snd_buf_used;
+		while (buf_free == 0 && !conn->reset)
+			tcp_tqueue_new_data(conn);
+
+		if (conn->reset)
+			return TCP_ERESET;
+
+		xfer_size = min(size, buf_free);
+
+		/* Copy data to buffer */
+		memcpy(conn->snd_buf + conn->snd_buf_used, data, xfer_size);
+		data += xfer_size;
+		conn->snd_buf_used += xfer_size;
+		size -= xfer_size;
+	}
+
+	tcp_tqueue_new_data(conn);
+
+	return TCP_EOK;
+}
+
+/** RECEIVE user call */
+tcp_error_t tcp_uc_receive(tcp_conn_t *conn, void *buf, size_t size,
+    size_t *rcvd, xflags_t *xflags)
+{
+	size_t xfer_size;
+
+	log_msg(LVL_DEBUG, "%s: tcp_uc_receive()", conn->name);
+
+	if (conn->cstate == st_closed)
+		return TCP_ENOTEXIST;
+
+	fibril_mutex_lock(&conn->rcv_buf_lock);
+
+	/* Wait for data to become available */
+	while (conn->rcv_buf_used == 0 && !conn->rcv_buf_fin && !conn->reset) {
+		log_msg(LVL_DEBUG, "tcp_uc_receive() - wait for data");
+		fibril_condvar_wait(&conn->rcv_buf_cv, &conn->rcv_buf_lock);
+	}
+
+	if (conn->rcv_buf_used == 0) {
+		fibril_mutex_unlock(&conn->rcv_buf_lock);
+
+		*rcvd = 0;
+		*xflags = 0;
+
+		if (conn->rcv_buf_fin) {
+			/* End of data, peer closed connection */
+			return TCP_ECLOSING;
+		} else {
+			/* Connection was reset */
+			assert(conn->reset);
+			return TCP_ERESET;
+		}
+	}
+
+	/* Copy data from receive buffer to user buffer */
+	xfer_size = min(size, conn->rcv_buf_used);
+	memcpy(buf, conn->rcv_buf, xfer_size);
+	*rcvd = xfer_size;
+
+	/* Remove data from receive buffer */
+	memmove(conn->rcv_buf, conn->rcv_buf + xfer_size, conn->rcv_buf_used -
+	    xfer_size);
+	conn->rcv_buf_used -= xfer_size;
+	conn->rcv_wnd += xfer_size;
+
+	fibril_mutex_unlock(&conn->rcv_buf_lock);
+
+	/* TODO */
+	*xflags = 0;
+
+	/* Send new size of receive window */
+	tcp_tqueue_ctrl_seg(conn, CTL_ACK);
+
+	log_msg(LVL_DEBUG, "%s: tcp_uc_receive() - returning %zu bytes",
+	    conn->name, xfer_size);
+
+	return TCP_EOK;
+}
+
+/** CLOSE user call */
+tcp_error_t tcp_uc_close(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "%s: tcp_uc_close()", conn->name);
+
+	if (conn->cstate == st_closed)
+		return TCP_ENOTEXIST;
+
+	if (conn->snd_buf_fin)
+		return TCP_ECLOSING;
+
+	conn->snd_buf_fin = true;
+	tcp_tqueue_new_data(conn);
+
+	return TCP_EOK;
+}
+
+/** ABORT user call */
+void tcp_uc_abort(tcp_conn_t *conn)
+{
+	log_msg(LVL_DEBUG, "tcp_uc_abort()");
+}
+
+/** STATUS user call */
+void tcp_uc_status(tcp_conn_t *conn, tcp_conn_status_t *cstatus)
+{
+	log_msg(LVL_DEBUG, "tcp_uc_status()");
+}
+
+
+/*
+ * Arriving segments
+ */
+
+/** Segment arrived */
+void tcp_as_segment_arrived(tcp_sockpair_t *sp, tcp_segment_t *seg)
+{
+	tcp_conn_t *conn;
+
+	log_msg(LVL_DEBUG, "tcp_as_segment_arrived(f:(%x,%u), l:(%x,%u))",
+	    sp->foreign.addr.ipv4, sp->foreign.port,
+	    sp->local.addr.ipv4, sp->local.port);
+
+	conn = tcp_conn_find(sp);
+	if (conn != NULL && conn->cstate != st_closed) {
+		if (conn->ident.foreign.addr.ipv4 == TCP_IPV4_ANY)
+			conn->ident.foreign.addr.ipv4 = sp->foreign.addr.ipv4;
+		if (conn->ident.foreign.port == TCP_PORT_ANY)
+			conn->ident.foreign.port = sp->foreign.port;
+		if (conn->ident.local.addr.ipv4 == TCP_IPV4_ANY)
+			conn->ident.local.addr.ipv4 = sp->local.addr.ipv4;
+
+		tcp_conn_segment_arrived(conn, seg);
+	} else {
+		if (conn == NULL)
+			log_msg(LVL_WARN, "No connection found.");
+		else
+			log_msg(LVL_WARN, "Connection is closed.");
+		tcp_unexpected_segment(sp, seg);
+	}
+}
+
+/*
+ * Timeouts
+ */
+
+/** User timeout */
+void tcp_to_user(void)
+{
+	log_msg(LVL_DEBUG, "tcp_to_user()");
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/net/tl/tcp/ucall.h
===================================================================
--- uspace/srv/net/tl/tcp/ucall.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
+++ uspace/srv/net/tl/tcp/ucall.h	(revision 7aaed09d88be49fac8360d3017e3328ed9b0635c)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2011 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 tcp
+ * @{
+ */
+/** @file TCP user calls (close to those defined in the RFC)
+ */
+
+#ifndef UCALL_H
+#define UCALL_H
+
+#include <sys/types.h>
+#include "tcp_type.h"
+
+/*
+ * User calls
+ */
+extern tcp_error_t tcp_uc_open(tcp_sock_t *, tcp_sock_t *, acpass_t, tcp_conn_t **);
+extern tcp_error_t tcp_uc_send(tcp_conn_t *, void *, size_t, xflags_t);
+extern tcp_error_t tcp_uc_receive(tcp_conn_t *, void *, size_t, size_t *, xflags_t *);
+extern tcp_error_t tcp_uc_close(tcp_conn_t *);
+extern void tcp_uc_abort(tcp_conn_t *);
+extern void tcp_uc_status(tcp_conn_t *, tcp_conn_status_t *);
+
+/*
+ * Arriving segments
+ */
+extern void tcp_as_segment_arrived(tcp_sockpair_t *, tcp_segment_t *);
+
+/*
+ * Timeouts
+ */
+extern void tcp_to_user(void);
+
+#endif
+
+/** @}
+ */
