Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -95,6 +95,4 @@
 	srv/hw/char/i8042 \
 	srv/hw/char/s3c24xx_uart \
-	srv/hw/netif/ne2000 \
-	srv/net/netif/lo \
 	srv/net/il/arp \
 	srv/net/il/ip \
@@ -102,4 +100,6 @@
 	srv/net/tl/udp \
 	srv/net/tl/tcp \
+	srv/net/nil/eth \
+	srv/net/nil/nildummy \
 	srv/net/net \
 	drv/infrastructure/root \
@@ -117,6 +117,7 @@
 	drv/bus/usb/usbmast \
 	drv/bus/usb/usbmid \
-	drv/bus/usb/usbmouse \
-	drv/bus/usb/vhc
+	drv/bus/usb/vhc \
+	drv/nic/lo \
+	drv/nic/ne2k
 
 ifeq ($(CONFIG_PCC),y)
@@ -132,11 +133,4 @@
 	app/binutils
 endif
-
-## Networking
-#
-
-DIRS += \
-	srv/net/nil/eth \
-	srv/net/nil/nildummy
 
 ## Platform-specific hardware support
@@ -187,7 +181,7 @@
 	lib/softfloat \
 	lib/drv \
-	lib/packet \
 	lib/fb \
 	lib/net \
+	lib/nic \
 	lib/ext2 \
 	lib/usb \
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/Makefile.common	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -123,6 +123,6 @@
 
 LIBDRV_PREFIX = $(LIB_PREFIX)/drv
-LIBPACKET_PREFIX = $(LIB_PREFIX)/packet
 LIBNET_PREFIX = $(LIB_PREFIX)/net
+LIBNIC_PREFIX = $(LIB_PREFIX)/nic
 LIBMINIX_PREFIX = $(LIB_PREFIX)/minix
 
Index: uspace/app/bdsh/cmds/modules/cp/cp.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cp/cp.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/bdsh/cmds/modules/cp/cp.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -33,4 +33,6 @@
 #include <str.h>
 #include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
 #include "config.h"
 #include "util.h"
@@ -55,4 +57,37 @@
 };
 
+typedef enum {
+	TYPE_NONE,
+	TYPE_FILE,
+	TYPE_DIR
+} dentry_type_t;
+
+static int64_t copy_file(const char *src, const char *dest,
+    size_t blen, int vb);
+
+/** Get the type of a directory entry.
+ *
+ * @param path	Path of the directory entry.
+ *
+ * @return TYPE_DIR if the dentry is a directory.
+ * @return TYPE_FILE if the dentry is a file.
+ * @return TYPE_NONE if the dentry does not exists.
+ */
+static dentry_type_t get_type(const char *path)
+{
+	struct stat s;
+
+	int r = stat(path, &s);
+
+	if (r)
+		return TYPE_NONE;
+	else if (s.is_directory)
+		return TYPE_DIR;
+	else if (s.is_file)
+		return TYPE_FILE;
+
+	return TYPE_NONE;
+}
+
 static int strtoint(const char *s1)
 {
@@ -67,4 +102,218 @@
 	return (int) t1;
 }
+
+/** Get the last component of a path.
+ *
+ * e.g. /data/a  ---> a
+ *
+ * @param path	Pointer to the path.
+ *
+ * @return	Pointer to the last component or to the path itself.
+ */
+static char *get_last_path_component(char *path)
+{
+	char *ptr;
+
+	ptr = str_rchr(path, '/');
+	if (!ptr)
+		return path;
+	else
+		return ptr + 1;
+}
+
+/** Merge two paths together.
+ *
+ * e.g. (path1 = /data/dir, path2 = a/b) --> /data/dir/a/b
+ *
+ * @param path1		Path to which path2 will be appended.
+ * @param path1_size	Size of the path1 buffer.
+ * @param path2		Path that will be appended to path1.
+ */
+static void merge_paths(char *path1, size_t path1_size, char *path2)
+{
+	const char *delim = "/";
+
+	str_rtrim(path1, '/');
+	str_append(path1, path1_size, delim);
+	str_append(path1, path1_size, path2);
+}
+
+static int64_t do_copy(const char *src, const char *dest,
+    size_t blen, int vb, int recursive, int force)
+{
+	int r = -1;
+	char dest_path[PATH_MAX];
+	char src_path[PATH_MAX];
+	DIR *dir = NULL;
+	struct dirent *dp;
+
+	dentry_type_t src_type = get_type(src);
+	dentry_type_t dest_type = get_type(dest);
+
+	const size_t src_len = str_size(src);
+
+	if (src_type == TYPE_FILE) {
+		char *src_fname;
+
+		/* Initialize the src_path with the src argument */
+		str_cpy(src_path, src_len + 1, src);
+		str_rtrim(src_path, '/');
+		
+		/* Get the last component name from the src path */
+		src_fname = get_last_path_component(src_path);
+		
+		/* Initialize dest_path with the dest argument */
+		str_cpy(dest_path, PATH_MAX, dest);
+
+		if (dest_type == TYPE_DIR) {
+			/* e.g. cp file_name /data */
+			/* e.g. cp file_name /data/ */
+			
+			/* dest is a directory,
+			 * append the src filename to it.
+			 */
+			merge_paths(dest_path, PATH_MAX, src_fname);
+			dest_type = get_type(dest_path);
+		} else if (dest_type == TYPE_NONE) {
+			if (dest_path[str_size(dest_path) - 1] == '/') {
+				/* e.g. cp /textdemo /data/dirnotexists/ */
+
+				printf("The dest directory %s does not exists",
+				    dest_path);
+				goto exit;
+			}
+		}
+
+		if (dest_type == TYPE_DIR) {
+			printf("Cannot overwrite existing directory %s\n",
+			    dest_path);
+			goto exit;
+		} else if (dest_type == TYPE_FILE) {
+			/* e.g. cp file_name existing_file */
+
+			/* dest already exists, if force is set we will
+			 * try to remove it.
+			 */
+			if (force) {
+				if (unlink(dest_path)) {
+					printf("Unable to remove %s\n",
+					    dest_path);
+					goto exit;
+				}
+			} else {
+				printf("file already exists: %s\n", dest_path);
+				goto exit;
+			}
+		}
+
+		/* call copy_file and exit */
+		r = (copy_file(src, dest_path, blen, vb) < 0);
+
+	} else if (src_type == TYPE_DIR) {
+		/* e.g. cp -r /x/srcdir /y/destdir/ */
+
+		if (!recursive) {
+			printf("Cannot copy the %s directory without the "
+			    "-r option\n", src);
+			goto exit;
+		} else if (dest_type == TYPE_FILE) {
+			printf("Cannot overwrite a file with a directory\n");
+			goto exit;
+		}
+
+		char *src_dirname;
+
+		/* Initialize src_path with the content of src */
+		str_cpy(src_path, src_len + 1, src);
+		str_rtrim(src_path, '/');
+
+		src_dirname = get_last_path_component(src_path);
+
+		str_cpy(dest_path, PATH_MAX, dest);
+
+		switch (dest_type) {
+		case TYPE_DIR:
+			if (str_cmp(src_dirname, "..") &&
+			    str_cmp(src_dirname, ".")) {
+				/* The last component of src_path is
+				 * not '.' or '..'
+				 */
+				merge_paths(dest_path, PATH_MAX, src_dirname);
+
+				if (mkdir(dest_path, 0) == -1) {
+					printf("Unable to create "
+					    "dest directory %s\n", dest_path);
+					goto exit;
+				}
+			}
+			break;
+		default:
+		case TYPE_NONE:
+			/* dest does not exists, this means the user wants
+			 * to specify the name of the destination directory
+			 *
+			 * e.g. cp -r /src /data/new_dir_src
+			 */
+			if (mkdir(dest_path, 0)) {
+				printf("Unable to create "
+				    "dest directory %s\n", dest_path);
+				goto exit;
+			}
+			break;
+		}
+
+		dir = opendir(src);
+		if (!dir) {
+			/* Something strange is happening... */
+			printf("Unable to open src %s directory\n", src);
+			goto exit;
+		}
+
+		/* Copy every single directory entry of src into the
+		 * destination directory.
+		 */
+		while ((dp = readdir(dir))) {
+			struct stat src_s;
+			struct stat dest_s;
+
+			char src_dent[PATH_MAX];
+			char dest_dent[PATH_MAX];
+
+			str_cpy(src_dent, PATH_MAX, src);
+			merge_paths(src_dent, PATH_MAX, dp->d_name);
+
+			str_cpy(dest_dent, PATH_MAX, dest_path);
+			merge_paths(dest_dent, PATH_MAX, dp->d_name);
+
+			/* Check if we are copying a directory into itself */
+			stat(src_dent, &src_s);
+			stat(dest_path, &dest_s);
+
+			if (dest_s.index == src_s.index &&
+			    dest_s.fs_handle == src_s.fs_handle) {
+				printf("Cannot copy a directory "
+				    "into itself\n");
+				goto exit;
+			}
+
+			if (vb)
+				printf("copy %s %s\n", src_dent, dest_dent);
+
+			/* Recursively call do_copy() */
+			r = do_copy(src_dent, dest_dent, blen, vb, recursive,
+			    force);
+			if (r)
+				goto exit;
+
+		}
+	} else
+		printf("Unable to open source file %s\n", src);
+
+exit:
+	if (dir)
+		closedir(dir);
+	return r;
+}
+
 
 static int64_t copy_file(const char *src, const char *dest,
@@ -127,17 +376,16 @@
 	static char helpfmt[] =
 	    "Usage:  %s [options] <source> <dest>\n"
-	    "Options: (* indicates not yet implemented)\n"
+	    "Options:\n"
 	    "  -h, --help       A short option summary\n"
 	    "  -v, --version    Print version information and exit\n"
-	    "* -V, --verbose    Be annoyingly noisy about what's being done\n"
-	    "* -f, --force      Do not complain when <dest> exists\n"
-	    "* -r, --recursive  Copy entire directories\n"
-	    "  -b, --buffer ## Set the read buffer size to ##\n"
-	    "Currently, %s is under development, some options may not work.\n";
+	    "  -V, --verbose    Be annoyingly noisy about what's being done\n"
+	    "  -f, --force      Do not complain when <dest> exists\n"
+	    "  -r, --recursive  Copy entire directories\n"
+	    "  -b, --buffer ## Set the read buffer size to ##\n";
 	if (level == HELP_SHORT) {
 		printf("`%s' copies files and directories\n", cmdname);
 	} else {
 		help_cmd_cp(HELP_SHORT);
-		printf(helpfmt, cmdname, cmdname);
+		printf(helpfmt, cmdname);
 	}
 
@@ -148,5 +396,6 @@
 {
 	unsigned int argc, verbose = 0;
-	int buffer = 0;
+	int buffer = 0, recursive = 0;
+	int force = 0;
 	int c, opt_ind;
 	int64_t ret;
@@ -167,6 +416,8 @@
 			break;
 		case 'f':
+			force = 1;
 			break;
 		case 'r':
+			recursive = 1;
 			break;
 		case 'b':
@@ -194,10 +445,8 @@
 	}
 
-	ret = copy_file(argv[optind], argv[optind + 1], buffer, verbose);
-
-	if (verbose)
-		printf("%" PRId64 " bytes copied\n", ret);
-
-	if (ret >= 0)
+	ret = do_copy(argv[optind], argv[optind + 1], buffer, verbose,
+	    recursive, force);
+
+	if (ret == 0)
 		return CMD_SUCCESS;
 	else
Index: uspace/app/bdsh/cmds/modules/mkfile/mkfile.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mkfile/mkfile.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/bdsh/cmds/modules/mkfile/mkfile.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -54,4 +54,5 @@
 static struct option const long_options[] = {
 	{"size", required_argument, 0, 's'},
+	{"sparse", no_argument, 0, 'p'},
 	{"help", no_argument, 0, 'h'},
 	{0, 0, 0, 0}
@@ -69,4 +70,5 @@
 		"  -h, --help       A short option summary\n"
 		"  -s, --size sz    Size of the file\n"
+		"  -p, --sparse     Create a sparse file\n"
 		"\n"
 		"Size is a number followed by 'k', 'm' or 'g' for kB, MB, GB.\n"
@@ -115,7 +117,8 @@
 	ssize_t file_size;
 	ssize_t total_written;
-	ssize_t to_write, rc;
+	ssize_t to_write, rc, rc2 = 0;
 	char *file_name;
 	void *buffer;
+	bool create_sparse = false;
 
 	file_size = 0;
@@ -124,9 +127,12 @@
 
 	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
-		c = getopt_long(argc, argv, "s:h", long_options, &opt_ind);
+		c = getopt_long(argc, argv, "ps:h", long_options, &opt_ind);
 		switch (c) {
 		case 'h':
 			help_cmd_mkfile(HELP_LONG);
 			return CMD_SUCCESS;
+		case 'p':
+			create_sparse = true;
+			break;
 		case 's':
 			file_size = read_size(optarg);
@@ -154,4 +160,14 @@
 		printf("%s: failed to create file %s.\n", cmdname, file_name);
 		return CMD_FAILURE;
+	}
+
+	if (create_sparse && file_size > 0) {
+		const char byte = 0x00;
+
+		if ((rc2 = lseek(fd, file_size - 1, SEEK_SET)) < 0)
+			goto exit;
+
+		rc2 = write(fd, &byte, sizeof(char));
+		goto exit;
 	}
 
@@ -174,11 +190,12 @@
 	}
 
+	free(buffer);
+exit:
 	rc = close(fd);
-	if (rc != 0) {
+
+	if (rc != 0 || rc2 < 0) {
 		printf("%s: Error writing file (%zd).\n", cmdname, rc);
 		return CMD_FAILURE;
 	}
-
-	free(buffer);
 
 	return CMD_SUCCESS;
Index: uspace/app/bdsh/cmds/modules/mount/mount.c
===================================================================
--- uspace/app/bdsh/cmds/modules/mount/mount.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/bdsh/cmds/modules/mount/mount.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -27,9 +27,12 @@
  */
 
+#include <loc.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <vfs/vfs.h>
+#include <adt/list.h>
 #include <errno.h>
 #include <getopt.h>
+#include <inttypes.h>
 #include "config.h"
 #include "util.h"
@@ -43,4 +46,5 @@
 static struct option const long_options[] = {
 	{ "help", no_argument, 0, 'h' },
+	{ "instance", required_argument, 0, 'i' },
 	{ 0, 0, 0, 0 }
 };
@@ -61,4 +65,46 @@
 }
 
+static void print_mtab_list(void)
+{
+	LIST_INITIALIZE(mtab_list);
+	mtab_ent_t *old_ent = NULL;
+	char *svc_name;
+	int rc;
+
+	get_mtab_list(&mtab_list);
+
+	list_foreach(mtab_list, cur) {
+		mtab_ent_t *mtab_ent = list_get_instance(cur, mtab_ent_t,
+		    link);
+
+		if (old_ent)
+			free(old_ent);
+
+		old_ent = mtab_ent;
+
+		printf("%s", mtab_ent->fs_name);
+		if (mtab_ent->instance)
+			printf("/%d", mtab_ent->instance);
+
+		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(" (%s)", mtab_ent->opts);
+
+		putchar('\n');
+	}
+
+	if (old_ent)
+		free(old_ent);
+}
+
 /* Main entry point for mount, accepts an array of arguments */
 int cmd_mount(char **argv)
@@ -68,30 +114,47 @@
 	const char *dev = "";
 	int rc, c, opt_ind;
+	unsigned int instance = 0;
+	bool instance_set = false;
+	char **t_argv;
 
 	argc = cli_count_args(argv);
 
 	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
-		c = getopt_long(argc, argv, "h", long_options, &opt_ind);
+		c = getopt_long(argc, argv, "i:h", long_options, &opt_ind);
 		switch (c) {
 		case 'h':
 			help_cmd_mount(HELP_LONG);
 			return CMD_SUCCESS;
+		case 'i':
+			instance = (unsigned int) strtol(optarg, NULL, 10);
+			instance_set = true;
+			break;
 		}
 	}
 
-	if ((argc < 3) || (argc > 5)) {
+	if (instance_set) {
+		argc -= 2;
+		t_argv = &argv[2];
+	} else
+		t_argv = &argv[0];
+
+	if ((argc == 2) || (argc > 5)) {
 		printf("%s: invalid number of arguments. Try `mount --help'\n",
 		    cmdname);
 		return CMD_FAILURE;
 	}
+	if (argc == 1) {
+		print_mtab_list();
+		return CMD_SUCCESS;
+	}
 	if (argc > 3)
-		dev = argv[3];
+		dev = t_argv[3];
 	if (argc == 5)
-		mopts = argv[4];
+		mopts = t_argv[4];
 
-	rc = mount(argv[1], argv[2], dev, mopts, 0);
+	rc = mount(t_argv[1], t_argv[2], dev, mopts, 0, instance);
 	if (rc != EOK) {
 		printf("Unable to mount %s filesystem to %s on %s (rc=%d)\n",
-		    argv[1], argv[2], argv[3], rc);
+		    t_argv[1], t_argv[2], t_argv[3], rc);
 		return CMD_FAILURE;
 	}
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/init/init.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -121,5 +121,5 @@
 	
 	int rc = mount(fstype, ROOT_MOUNT_POINT, ROOT_DEVICE, opts,
-	    IPC_FLAG_BLOCKING);
+	    IPC_FLAG_BLOCKING, 0);
 	return mount_report("Root filesystem", ROOT_MOUNT_POINT, fstype,
 	    ROOT_DEVICE, rc);
@@ -138,5 +138,5 @@
 {
 	int rc = mount(LOCFS_FS_TYPE, LOCFS_MOUNT_POINT, "", "",
-	    IPC_FLAG_BLOCKING);
+	    IPC_FLAG_BLOCKING, 0);
 	return mount_report("Location service filesystem", LOCFS_MOUNT_POINT,
 	    LOCFS_FS_TYPE, NULL, rc);
@@ -261,5 +261,5 @@
 static bool mount_tmpfs(void)
 {
-	int rc = mount(TMPFS_FS_TYPE, TMPFS_MOUNT_POINT, "", "", 0);
+	int rc = mount(TMPFS_FS_TYPE, TMPFS_MOUNT_POINT, "", "", 0, 0);
 	return mount_report("Temporary filesystem", TMPFS_MOUNT_POINT,
 	    TMPFS_FS_TYPE, NULL, rc);
@@ -268,5 +268,5 @@
 static bool mount_data(void)
 {
-	int rc = mount(DATA_FS_TYPE, DATA_MOUNT_POINT, DATA_DEVICE, "wtcache", 0);
+	int rc = mount(DATA_FS_TYPE, DATA_MOUNT_POINT, DATA_DEVICE, "wtcache", 0, 0);
 	return mount_report("Data filesystem", DATA_MOUNT_POINT, DATA_FS_TYPE,
 	    DATA_DEVICE, rc);
@@ -305,4 +305,6 @@
 	srv_start("/srv/s3c24ser");
 	srv_start("/srv/s3c24ts");
+	
+	spawn("/srv/net");
 	
 	spawn("/srv/fb");
Index: uspace/app/locinfo/locinfo.c
===================================================================
--- uspace/app/locinfo/locinfo.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/locinfo/locinfo.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -89,4 +89,5 @@
 			}
 			printf("\t%s (%" PRIun ")\n", svc_name, svc_ids[j]);
+			free(svc_name);
 		}
 
Index: uspace/app/mkbd/main.c
===================================================================
--- uspace/app/mkbd/main.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/mkbd/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -69,5 +69,5 @@
 	int rc = usb_hid_report_init(*report);
 	if (rc != EOK) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		return rc;
@@ -79,5 +79,5 @@
 	    &report_desc_size);
 	if (rc != EOK) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		return rc;
@@ -85,5 +85,5 @@
 	
 	if (report_desc_size == 0) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		// TODO: other error code?
@@ -93,5 +93,5 @@
 	uint8_t *desc = (uint8_t *) malloc(report_desc_size);
 	if (desc == NULL) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		return ENOMEM;
@@ -103,5 +103,5 @@
 	    &actual_size);
 	if (rc != EOK) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		free(desc);
@@ -110,5 +110,5 @@
 	
 	if (actual_size != report_desc_size) {
-		usb_hid_free_report(*report);
+		usb_hid_report_deinit(*report);
 		*report = NULL;
 		free(desc);
Index: uspace/app/mkmfs/mkmfs.c
===================================================================
--- uspace/app/mkmfs/mkmfs.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/mkmfs/mkmfs.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,3 @@
 /*
- * Copyright (c) 2010 Jiri Svoboda
  * Copyright (c) 2011 Maurizio Lombardi
  * All rights reserved.
@@ -56,6 +55,6 @@
 #define USED	1
 
-#define UPPER(n, size) 			(((n) / (size)) + (((n) % (size)) != 0))
-#define NEXT_DENTRY(p, dirsize)		(p += (dirsize))
+#define UPPER(n, size) 		(((n) / (size)) + (((n) % (size)) != 0))
+#define NEXT_DENTRY(p, dirsize)	(p += (dirsize))
 
 typedef enum {
@@ -64,5 +63,5 @@
 } help_level_t;
 
-/*Generic MFS superblock*/
+/* Generic MFS superblock */
 struct mfs_sb_info {
 	uint64_t n_inodes;
@@ -84,5 +83,5 @@
 
 static void	help_cmd_mkmfs(help_level_t level);
-static int	num_of_set_bits(uint32_t n);
+static bool	is_power_of_two(uint32_t n);
 static int	init_superblock(struct mfs_sb_info *sb);
 static int	write_superblock(const struct mfs_sb_info *sbi);
@@ -118,9 +117,9 @@
 	struct mfs_sb_info sb;
 
-	/*Default is MinixFS V3*/
+	/* Default is MinixFS V3 */
 	sb.magic = MFS_MAGIC_V3;
 	sb.fs_version = 3;
 
-	/*Default block size is 4Kb*/
+	/* Default block size is 4Kb */
 	sb.block_size = MFS_MAX_BLOCKSIZE;
 	sb.dirsize = MFS3_DIRSIZE;
@@ -136,5 +135,6 @@
 
 	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
-		c = getopt_long(argc, argv, "lh12b:i:", long_options, &opt_ind);
+		c = getopt_long(argc, argv, "lh12b:i:",
+		    long_options, &opt_ind);
 		switch (c) {
 		case 'h':
@@ -169,17 +169,19 @@
 
 	if (sb.block_size < MFS_MIN_BLOCKSIZE || 
-			sb.block_size > MFS_MAX_BLOCKSIZE) {
+	    sb.block_size > MFS_MAX_BLOCKSIZE) {
 		printf(NAME ":Error! Invalid block size.\n");
 		exit(0);
-	} else if (num_of_set_bits(sb.block_size) != 1) {
-		/*Block size must be a power of 2.*/
+	} else if (!is_power_of_two(sb.block_size)) {
+		/* Block size must be a power of 2. */
 		printf(NAME ":Error! Invalid block size.\n");
 		exit(0);
 	} else if (sb.block_size > MFS_BLOCKSIZE && 
-			sb.fs_version != 3) {
-		printf(NAME ":Error! Block size > 1024 is supported by V3 filesystem only.\n");
+	    sb.fs_version != 3) {
+		printf(NAME ":Error! Block size > 1024 is "
+		    "supported by V3 filesystem only.\n");
 		exit(0);
 	} else if (sb.fs_version == 3 && sb.longnames) {
-		printf(NAME ":Error! Long filenames are supported by V1/V2 filesystem only.\n");
+		printf(NAME ":Error! Long filenames are supported "
+		    "by V1/V2 filesystem only.\n");
 		exit(0);
 	}
@@ -221,8 +223,9 @@
 	rc = block_get_nblocks(service_id, &sb.dev_nblocks);
 	if (rc != EOK) {
-		printf(NAME ": Warning, failed to obtain block device size.\n");
+		printf(NAME ": Warning, failed to obtain "
+		    "block device size.\n");
 	} else {
 		printf(NAME ": Block device has %" PRIuOFF64 " blocks.\n",
-				sb.dev_nblocks);
+		    sb.dev_nblocks);
 	}
 
@@ -232,10 +235,11 @@
 	}
 
-	/*Minimum block size is 1 Kb*/
+	/* Minimum block size is 1 Kb */
 	sb.dev_nblocks /= 2;
 
 	printf(NAME ": Creating Minix file system on device\n");
-
-	/*Initialize superblock*/
+	printf(NAME ": Writing superblock\n");
+
+	/* Initialize superblock */
 	if (init_superblock(&sb) != EOK) {
 		printf(NAME ": Error. Superblock initialization failed\n");
@@ -243,5 +247,7 @@
 	}
 
-	/*Initialize bitmaps*/
+	printf(NAME ": Initializing bitmaps\n");
+
+	/* Initialize bitmaps */
 	if (init_bitmaps(&sb) != EOK) {
 		printf(NAME ": Error. Bitmaps initialization failed\n");
@@ -249,5 +255,7 @@
 	}
 
-	/*Init inode table*/
+	printf(NAME ": Initializing the inode table\n");
+
+	/* Init inode table */
 	if (init_inode_table(&sb) != EOK) {
 		printf(NAME ": Error. Inode table initialization failed\n");
@@ -255,5 +263,7 @@
 	}
 
-	/*Make the root inode*/
+	printf(NAME ": Creating the root directory inode\n");
+
+	/* Make the root inode */
 	if (sb.fs_version == 1)
 		rc = make_root_ino(&sb);
@@ -266,5 +276,5 @@
 	}
 
-	/*Insert directory entries . and ..*/
+	/* Insert directory entries . and .. */
 	if (insert_dentries(&sb) != EOK) {
 		printf(NAME ": Error. Root directory initialization failed\n");
@@ -299,5 +309,5 @@
 
 	if (sb->fs_version != 3) {
-		/*Directory entries for V1/V2 filesystem*/
+		/* Directory entries for V1/V2 filesystem */
 		struct mfs_dentry *dentry = root_block;
 
@@ -306,10 +316,10 @@
 
 		dentry = (struct mfs_dentry *) NEXT_DENTRY(dentry_ptr,
-				sb->dirsize);
+		    sb->dirsize);
 
 		dentry->d_inum = MFS_ROOT_INO;
 		memcpy(dentry->d_name, "..\0", 3);
 	} else {
-		/*Directory entries for V3 filesystem*/
+		/* Directory entries for V3 filesystem */
 		struct mfs3_dentry *dentry = root_block;
 
@@ -318,5 +328,5 @@
 
 		dentry = (struct mfs3_dentry *) NEXT_DENTRY(dentry_ptr,
-				sb->dirsize);
+		    sb->dirsize);
 
 		dentry->d_inum = MFS_ROOT_INO;
@@ -389,5 +399,5 @@
 	ino_buf[MFS_ROOT_INO - 1].i_gid = 0;
 	ino_buf[MFS_ROOT_INO - 1].i_size = (sb->longnames ? MFSL_DIRSIZE :
-	MFS_DIRSIZE) * 2;
+	    MFS_DIRSIZE) * 2;
 	ino_buf[MFS_ROOT_INO - 1].i_mtime = sec;
 	ino_buf[MFS_ROOT_INO - 1].i_nlinks = 2;
@@ -411,5 +421,5 @@
 	int rc;
 
-	/*Compute offset of the first inode table block*/
+	/* Compute offset of the first inode table block */
 	const long itable_off = sb->zbmap_blocks + sb->ibmap_blocks + 2;
 
@@ -454,15 +464,17 @@
 
 	if (sb->longnames)
-		sb->magic = sb->fs_version == 1 ? MFS_MAGIC_V1L : MFS_MAGIC_V2L;
-
-	/*Compute the number of zones on disk*/
+		sb->magic = sb->fs_version == 1 ? MFS_MAGIC_V1L :
+		    MFS_MAGIC_V2L;
+
+	/* Compute the number of zones on disk */
 
 	if (sb->fs_version == 1) {
-		/*Valid only for MFS V1*/
+		/* Valid only for MFS V1 */
 		sb->n_zones = sb->dev_nblocks > UINT16_MAX ? 
-				UINT16_MAX : sb->dev_nblocks;
+		    UINT16_MAX : sb->dev_nblocks;
 		ind = MFS_BLOCKSIZE / sizeof(uint16_t);
 		ind2 = ind * ind;
-		sb->max_file_size = (V1_NR_DIRECT_ZONES + ind + ind2) * MFS_BLOCKSIZE;
+		sb->max_file_size = (V1_NR_DIRECT_ZONES + ind + ind2) *
+		    MFS_BLOCKSIZE;
 	} else {
 		/*Valid for MFS V2/V3*/
@@ -472,4 +484,5 @@
 		else
 			ptrsize = sizeof(uint32_t);
+
 		ind = sb->block_size / ptrsize;
 		ind2 = ind * ind;
@@ -477,5 +490,5 @@
 		sb->max_file_size = zones * sb->block_size;
 		sb->n_zones = sb->dev_nblocks > UINT32_MAX ?
-				UINT32_MAX : sb->dev_nblocks;
+		    UINT32_MAX : sb->dev_nblocks;
 
 		if (sb->fs_version == 3) {
@@ -487,5 +500,5 @@
 	}
 
-	/*Round up the number of inodes to fill block size*/
+	/* Round up the number of inodes to fill block size */
 	if (sb->n_inodes == 0)
 		inodes = sb->dev_nblocks / 3;
@@ -494,5 +507,6 @@
 
 	if (inodes % sb->ino_per_block)
-		inodes = ((inodes / sb->ino_per_block) + 1) * sb->ino_per_block;
+		inodes = ((inodes / sb->ino_per_block) + 1) *
+		    sb->ino_per_block;
 
 	if (sb->fs_version < 3)
@@ -501,21 +515,21 @@
 		sb->n_inodes = inodes > UINT32_MAX ? UINT32_MAX : inodes;
 
-	/*Compute inode bitmap size in blocks*/
+	/* Compute inode bitmap size in blocks */
 	sb->ibmap_blocks = UPPER(sb->n_inodes, sb->block_size * 8);
 
-	/*Compute inode table size*/
+	/* Compute inode table size */
 	sb->itable_size = sb->n_inodes / sb->ino_per_block;
 
-	/*Compute zone bitmap size in blocks*/
+	/* Compute zone bitmap size in blocks */
 	sb->zbmap_blocks = UPPER(sb->n_zones, sb->block_size * 8);
 
-	/*Compute first data zone position*/
+	/* Compute first data zone position */
 	sb->first_data_zone = 2 + sb->itable_size + 
-			sb->zbmap_blocks + sb->ibmap_blocks;
-
-	/*Set log2 of zone to block ratio to zero*/
+	    sb->zbmap_blocks + sb->ibmap_blocks;
+
+	/* Set log2 of zone to block ratio to zero */
 	sb->log2_zone_size = 0;
 
-	/*Check for errors*/
+	/* Check for errors */
 	if (sb->first_data_zone >= sb->n_zones) {
 		printf(NAME ": Error! Insufficient disk space");
@@ -523,5 +537,5 @@
 	}
 
-	/*Superblock is now ready to be written on disk*/
+	/* Superblock is now ready to be written on disk */
 	printf(NAME ": %d block size\n", sb->block_size);
 	printf(NAME ": %d inodes\n", (uint32_t) sb->n_inodes);
@@ -530,5 +544,5 @@
 	printf(NAME ": inode bitmap blocks = %ld\n", sb->ibmap_blocks);
 	printf(NAME ": zone bitmap blocks = %ld\n", sb->zbmap_blocks);
-	printf(NAME ": first data zone = %d\n", (uint32_t) sb->first_data_zone);
+	printf(NAME ": first data zone = %d\n", (uint32_t)sb->first_data_zone);
 	printf(NAME ": max file size = %u\n", sb->max_file_size);
 	printf(NAME ": long fnames = %s\n", sb->longnames ? "Yes" : "No");
@@ -645,5 +659,5 @@
 	for (i = 0; i < ibmap_nblocks; ++i) {
 		if ((rc = write_block(start_block + i,
-				1, (ibmap_buf8 + i * sb->block_size))) != EOK)
+		    1, (ibmap_buf8 + i * sb->block_size))) != EOK)
 			return rc;
 	}
@@ -653,5 +667,5 @@
 	for (i = 0; i < zbmap_nblocks; ++i) {
 		if ((rc = write_block(start_block + i,
-				1, (zbmap_buf8 + i * sb->block_size))) != EOK)
+		    1, (zbmap_buf8 + i * sb->block_size))) != EOK)
 			return rc;
 	}
@@ -692,5 +706,6 @@
 		uint8_t *data_ptr = (uint8_t *) data;
 
-		rc = block_write_direct(service_id, tmp_off << 2, size << 2, data_ptr);
+		rc = block_write_direct(service_id, tmp_off << 2,
+		    size << 2, data_ptr);
 
 		if (rc != EOK)
@@ -700,7 +715,9 @@
 		tmp_off++;
 
-		return block_write_direct(service_id, tmp_off << 2, size << 2, data_ptr);
-	}
-	return block_write_direct(service_id, off << shift, size << shift, data);
+		return block_write_direct(service_id, tmp_off << 2,
+		    size << 2, data_ptr);
+	}
+	return block_write_direct(service_id, off << shift,
+	    size << shift, data);
 }
 
@@ -711,18 +728,27 @@
 	} else {
 		printf("Usage: [options] device\n"
-				"-1         Make a Minix version 1 filesystem\n"
-				"-2         Make a Minix version 2 filesystem\n"
-				"-b ##      Specify the block size in bytes (V3 only),\n"
-				"           valid block size values are 1024, 2048 and 4096 bytes per block\n"
-				"-i ##      Specify the number of inodes for the filesystem\n"
-				"-l         Use 30-char long filenames (V1/V2 only)\n");
-	}
-}
-
-static int num_of_set_bits(uint32_t n)
-{
-	n = n - ((n >> 1) & 0x55555555);
-	n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
-	return (((n + (n >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+		    "-1         Make a Minix version 1 filesystem\n"
+		    "-2         Make a Minix version 2 filesystem\n"
+		    "-b ##      Specify the block size in bytes (V3 only),\n"
+		    "           valid block size values are 1024, 2048 and"
+				" 4096 bytes per block\n"
+		    "-i ##      Specify the number of inodes"
+				" for the filesystem\n"
+		    "-l         Use 30-char long filenames (V1/V2 only)\n");
+	}
+}
+
+/** Check if a given number is a power of two.
+ *
+ * @param n	The number to check.
+ *
+ * @return	true if it is a power of two, false otherwise.
+ */
+static bool is_power_of_two(uint32_t n)
+{
+	if (n == 0)
+		return false;
+
+	return (n & (n - 1)) == 0;
 }
 
Index: uspace/app/usbinfo/desctree.c
===================================================================
--- uspace/app/usbinfo/desctree.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/usbinfo/desctree.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -50,5 +50,5 @@
 
 static void browse_descriptor_tree_internal(usb_dp_parser_t *parser,
-    usb_dp_parser_data_t *data, uint8_t *root, size_t depth,
+    usb_dp_parser_data_t *data, const uint8_t *root, size_t depth,
     dump_descriptor_in_tree_t callback, void *arg)
 {
@@ -57,5 +57,5 @@
 	}
 	callback(root, depth, arg);
-	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	const uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
 	do {
 		browse_descriptor_tree_internal(parser, data, child, depth + 1,
Index: uspace/app/usbinfo/dump.c
===================================================================
--- uspace/app/usbinfo/dump.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/usbinfo/dump.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -110,10 +110,10 @@
 }
 
-static void dump_tree_descriptor(uint8_t *descriptor, size_t depth)
+static void dump_tree_descriptor(const uint8_t *descriptor, size_t depth)
 {
 	if (descriptor == NULL) {
 		return;
 	}
-	int type = (int) *(descriptor + 1);
+	int type = descriptor[1];
 	const char *name = "unknown";
 	switch (type) {
@@ -136,6 +136,7 @@
 }
 
-static void dump_tree_internal(usb_dp_parser_t *parser, usb_dp_parser_data_t *data,
-    uint8_t *root, size_t depth)
+static void dump_tree_internal(
+    usb_dp_parser_t *parser, usb_dp_parser_data_t *data,
+    const uint8_t *root, size_t depth)
 {
 	if (root == NULL) {
@@ -143,5 +144,5 @@
 	}
 	dump_tree_descriptor(root, depth);
-	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	const uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
 	do {
 		dump_tree_internal(parser, data, child, depth + 1);
@@ -152,5 +153,5 @@
 static void dump_tree(usb_dp_parser_t *parser, usb_dp_parser_data_t *data)
 {
-	uint8_t *ptr = data->data;
+	const uint8_t *ptr = data->data;
 	printf("Descriptor tree:\n");
 	dump_tree_internal(parser, data, ptr, 0);
Index: uspace/app/usbinfo/hid.c
===================================================================
--- uspace/app/usbinfo/hid.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/usbinfo/hid.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -55,5 +55,5 @@
 } descriptor_walk_context_t;
 
-static bool is_descriptor_kind(uint8_t *d, usb_descriptor_type_t t)
+static bool is_descriptor_kind(const uint8_t *d, usb_descriptor_type_t t)
 {
 	if (d == NULL) {
@@ -167,5 +167,5 @@
 
 	free(raw_report);
-	usb_hid_free_report(&report);
+	usb_hid_report_deinit(&report);
 }
 
@@ -180,5 +180,5 @@
  * @param arg Custom argument, passed as descriptor_walk_context_t.
  */
-static void descriptor_walk_callback(uint8_t *raw_descriptor,
+static void descriptor_walk_callback(const uint8_t *raw_descriptor,
     size_t depth, void *arg)
 {
Index: uspace/app/usbinfo/info.c
===================================================================
--- uspace/app/usbinfo/info.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/usbinfo/info.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -51,6 +51,6 @@
 }
 
-static void dump_match_ids_from_interface(uint8_t *descriptor, size_t depth,
-    void *arg)
+static void dump_match_ids_from_interface(
+    const uint8_t *descriptor, size_t depth, void *arg)
 {
 	if (depth != 1) {
@@ -165,6 +165,6 @@
 
 
-static void dump_descriptor_tree_callback(uint8_t *descriptor,
-    size_t depth, void *arg)
+static void dump_descriptor_tree_callback(
+    const uint8_t *descriptor, size_t depth, void *arg)
 {
 	const char *indent = get_indent(depth + 1);
@@ -246,6 +246,6 @@
 }
 
-static void find_string_indexes_callback(uint8_t *descriptor,
-    size_t depth, void *arg)
+static void find_string_indexes_callback(
+    const uint8_t *descriptor, size_t depth, void *arg)
 {
 	size_t descriptor_length = descriptor[0];
Index: uspace/app/usbinfo/usbinfo.h
===================================================================
--- uspace/app/usbinfo/usbinfo.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/usbinfo/usbinfo.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -74,5 +74,5 @@
 void destroy_device(usbinfo_device_t *);
 
-typedef void (*dump_descriptor_in_tree_t)(uint8_t *, size_t, void *);
+typedef void (*dump_descriptor_in_tree_t)(const uint8_t *, size_t, void *);
 void browse_descriptor_tree(uint8_t *, size_t, usb_dp_descriptor_nesting_t *,
     dump_descriptor_in_tree_t, size_t, void *);
Index: uspace/app/vuhid/Makefile
===================================================================
--- uspace/app/vuhid/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/vuhid/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -47,5 +47,6 @@
 
 SOURCES_INTERFACES = \
-	hids/bootkbd.c
+	hids/bootkbd.c \
+	hids/logitech_wireless.c
 
 SOURCES = \
@@ -53,4 +54,5 @@
 	device.c \
 	ifaces.c \
+	life.c \
 	stdreq.c \
 	$(SOURCES_INTERFACES)
Index: uspace/app/vuhid/hids/bootkbd.c
===================================================================
--- uspace/app/vuhid/hids/bootkbd.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/vuhid/hids/bootkbd.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -93,34 +93,11 @@
 	     0, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
-static size_t in_data_count = sizeof(in_data)/INPUT_SIZE;
-// FIXME - locking
-static size_t in_data_position = 0;
-
-static int on_data_in(vuhid_interface_t *iface,
-    void *buffer, size_t buffer_size, size_t *act_buffer_size)
-{
-	static size_t last_pos = (size_t) -1;
-	size_t pos = in_data_position;
-	if (pos >= in_data_count) {
-		return EBADCHECKSUM;
-	}
-
-	if (last_pos == pos) {
-		return ENAK;
-	}
-
-	if (buffer_size > INPUT_SIZE) {
-		buffer_size = INPUT_SIZE;
-	}
-
-	if (act_buffer_size != NULL) {
-		*act_buffer_size = buffer_size;
-	}
-
-	memcpy(buffer, in_data + pos * INPUT_SIZE, buffer_size);
-	last_pos = pos;
-
-	return EOK;
-}
+static vuhid_interface_life_t boot_life = {
+	.data_in = in_data,
+	.data_in_count = sizeof(in_data)/INPUT_SIZE,
+	.data_in_pos_change_delay = 500,
+	.msg_born = "Boot keyboard comes to life...",
+	.msg_die = "Boot keyboard died."
+};
 
 static int on_data_out(vuhid_interface_t *iface,
@@ -141,17 +118,4 @@
 }
 
-
-static void live(vuhid_interface_t *iface)
-{
-	async_usleep(1000 * 1000 * 5);
-	usb_log_debug("Boot keyboard comes to life...\n");
-	while (in_data_position < in_data_count) {
-		async_usleep(1000 * 500);
-		in_data_position++;
-	}
-	usb_log_debug("Boot keyboard died.\n");
-}
-
-
 vuhid_interface_t vuhid_interface_bootkbd = {
 	.id = "boot",
@@ -164,11 +128,12 @@
 
 	.in_data_size = INPUT_SIZE,
-	.on_data_in = on_data_in,
+	.on_data_in = interface_live_on_data_in,
 
 	.out_data_size = 1,
 	.on_data_out = on_data_out,
 
-	.live = live,
+	.live = interface_life_live,
 
+	.interface_data = &boot_life,
 	.vuhid_data = NULL
 };
Index: uspace/app/vuhid/hids/logitech_wireless.c
===================================================================
--- uspace/app/vuhid/hids/logitech_wireless.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/app/vuhid/hids/logitech_wireless.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,99 @@
+/*
+ * 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 usbvirthid
+ * @{
+ */
+/** @file
+ * Logitech wireless mouse-keyboard combo simulation (see issue 349).
+ */
+#include "../virthid.h"
+#include <errno.h>
+#include <usb/debug.h>
+#include <usb/hid/hid.h>
+#include <usb/hid/usages/core.h>
+
+static uint8_t iface1_report_descriptor[] = {
+	0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x85, 0x02, 0x09, 0x01,
+	0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x10, 0x15, 0x00,
+	0x25, 0x01, 0x95, 0x10, 0x75, 0x01, 0x81, 0x02, 0x05, 0x01,
+	0x16, 0x01, 0xF8, 0x26, 0xFF, 0x07, 0x75, 0x0C, 0x95, 0x02,
+	0x09, 0x30, 0x09, 0x31, 0x81, 0x06, 0x15, 0x81, 0x25, 0x7F,
+	0x75, 0x08, 0x95, 0x01, 0x09, 0x38, 0x81, 0x06, 0x05, 0x0C,
+	0x0A, 0x38, 0x02, 0x95, 0x01, 0x81, 0x06, 0xC0, 0xC0, 0x05,
+	0x0C, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x03, 0x75, 0x10, 0x95,
+	0x02, 0x15, 0x01, 0x26, 0x8C, 0x02, 0x19, 0x01, 0x2A, 0x8C,
+	0x02, 0x81, 0x00, 0xC0, 0x05, 0x01, 0x09, 0x80, 0xA1, 0x01,
+	0x85, 0x04, 0x75, 0x02, 0x95, 0x01, 0x15, 0x01, 0x25, 0x03,
+	0x09, 0x82, 0x09, 0x81, 0x09, 0x83, 0x81, 0x60, 0x75, 0x06,
+	0x81, 0x03, 0xC0, 0x06, 0xBC, 0xFF, 0x09, 0x88, 0xA1, 0x01,
+	0x85, 0x08, 0x19, 0x01, 0x29, 0xFF, 0x15, 0x01, 0x26, 0xFF,
+	0x00, 0x75, 0x08, 0x95, 0x01, 0x81, 0x00, 0xC0
+};
+#define iface1_input_size 8
+static uint8_t iface1_in_data[] = {
+		/*0, 0, 0, 0, 0, 0, 0, 0,
+		0, 9, 0, 0, 0, 0, 0, 0,
+		0, 0, 9, 0, 0, 0, 0, 0,
+		0, 9, 9, 0, 0, 0, 0, 0,*/
+		0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static vuhid_interface_life_t iface1_life = {
+	.data_in = iface1_in_data,
+	.data_in_count = sizeof(iface1_in_data)/iface1_input_size,
+	.data_in_pos_change_delay = 50,
+	.msg_born = "Mouse of Logitech Unifying Receiver comes to life...",
+	.msg_die = "Mouse of Logitech Unifying Receiver disconnected."
+};
+
+
+vuhid_interface_t vuhid_interface_logitech_wireless_1 = {
+	.id = "lw1",
+	.name = "Logitech Unifying Receiver, interface 1 (mouse)",
+	.usb_subclass = USB_HID_SUBCLASS_BOOT,
+	.usb_protocol = USB_HID_PROTOCOL_MOUSE,
+
+	.report_descriptor = iface1_report_descriptor,
+	.report_descriptor_size = sizeof(iface1_report_descriptor),
+
+	.in_data_size = iface1_input_size,
+	.on_data_in = interface_live_on_data_in,
+
+	.out_data_size = 0,
+	.on_data_out = NULL,
+
+	.live = interface_life_live,
+
+	.interface_data = &iface1_life,
+	.vuhid_data = NULL
+};
+
+/**
+ * @}
+ */
Index: uspace/app/vuhid/ifaces.c
===================================================================
--- uspace/app/vuhid/ifaces.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/vuhid/ifaces.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -38,7 +38,9 @@
 
 extern vuhid_interface_t vuhid_interface_bootkbd;
+extern vuhid_interface_t vuhid_interface_logitech_wireless_1;
 
 vuhid_interface_t *available_hid_interfaces[] = {
 	&vuhid_interface_bootkbd,
+	&vuhid_interface_logitech_wireless_1,
 	NULL
 };
Index: uspace/app/vuhid/life.c
===================================================================
--- uspace/app/vuhid/life.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/app/vuhid/life.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,86 @@
+/*
+ * 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 usbvirthid
+ * @{
+ */
+/**
+ * @file
+ *
+ */
+#include <errno.h>
+#include <usb/debug.h>
+#include "virthid.h"
+
+
+void interface_life_live(vuhid_interface_t *iface)
+{
+	vuhid_interface_life_t *data = iface->interface_data;
+	data->data_in_pos = 0;
+	data->data_in_last_pos = (size_t) -1;
+	async_usleep(1000 * 1000 * 5);
+	usb_log_debug("%s\n", data->msg_born);
+	while (data->data_in_pos < data->data_in_count) {
+		async_usleep(1000 * data->data_in_pos_change_delay);
+		// FIXME: proper locking
+		data->data_in_pos++;
+	}
+	usb_log_debug("%s\n", data->msg_die);
+}
+
+
+
+int interface_live_on_data_in(vuhid_interface_t *iface,
+    void *buffer, size_t buffer_size, size_t *act_buffer_size)
+{
+	vuhid_interface_life_t *life = iface->interface_data;
+	size_t pos = life->data_in_pos;
+	if (pos >= life->data_in_count) {
+		return EBADCHECKSUM;
+	}
+
+	if (pos == life->data_in_last_pos) {
+		return ENAK;
+	}
+
+	if (buffer_size > iface->in_data_size) {
+		buffer_size = iface->in_data_size;
+	}
+
+	if (act_buffer_size != NULL) {
+		*act_buffer_size = buffer_size;
+	}
+
+	memcpy(buffer, life->data_in + pos * iface->in_data_size, buffer_size);
+	life->data_in_last_pos = pos;
+
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/app/vuhid/virthid.h
===================================================================
--- uspace/app/vuhid/virthid.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/app/vuhid/virthid.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -82,4 +82,27 @@
 
 typedef struct {
+	/** Buffer with data from device to the host. */
+	uint8_t *data_in;
+	/** Number of items in @c data_in.
+	 * The total size of @c data_in buffer shall be
+	 * <code>data_in_count * vuhid_interface_t.in_data_size</code>.
+	 */
+	size_t data_in_count;
+
+	/** Current position in the data buffer. */
+	size_t data_in_pos;
+	/** Previous position. */
+	size_t data_in_last_pos;
+
+	/** Delay between transition to "next" input buffer (in ms). */
+	size_t data_in_pos_change_delay;
+
+	/** Message to print when interface becomes alive. */
+	const char *msg_born;
+	/** Message to print when interface dies. */
+	const char *msg_die;
+} vuhid_interface_life_t;
+
+typedef struct {
 	uint8_t length;
 	uint8_t type;
@@ -94,4 +117,8 @@
 void wait_for_interfaces_death(usbvirt_device_t *);
 
+void interface_life_live(vuhid_interface_t *);
+int interface_live_on_data_in(vuhid_interface_t *, void *, size_t, size_t *);
+
+
 #endif
 /**
Index: uspace/dist/src/c/demos/tetris/screen.c
===================================================================
--- uspace/dist/src/c/demos/tetris/screen.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/dist/src/c/demos/tetris/screen.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -95,6 +95,6 @@
 {
 	console_flush(console);
-	console_set_rgb_color(console, 0xffffff,
-	    use_color ? color : 0x000000);
+	console_set_rgb_color(console, use_color ? color : 0x000000,
+	    0xffffff);
 }
 
@@ -153,5 +153,5 @@
 		return false;
 	
-	return (ccap >= CONSOLE_CCAP_RGB);
+	return ((ccap & CONSOLE_CAP_RGB) == CONSOLE_CAP_RGB);
 }
 
Index: uspace/doc/doxygroups.h
===================================================================
--- uspace/doc/doxygroups.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/doc/doxygroups.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -33,16 +33,16 @@
 
 		/**
-		 * @defgroup netif Network interface drivers
-		 * @ingroup net
-		 */
-
-			/**
-			 * @defgroup lo Loopback Service
-			 * @ingroup netif
-			 */
-
-			/**
-			 * @defgroup ne2000 NE2000 network interface service
-			 * @ingroup netif
+		 * @defgroup nic Network interface controllers
+		 * @ingroup net
+		 */
+
+			/**
+			 * @defgroup libnic Base NIC framework library
+			 * @ingroup nic
+			 */
+
+			/**
+			 * @defgroup nic_drivers Drivers using the NICF
+			 * @ingroup nic
 			 */
 
@@ -272,10 +272,4 @@
 
 	/**
-	 * @defgroup drvusbmouse USB mouse driver
-	 * @ingroup usb
-	 * @brief USB driver for mouse with boot protocol.
-	 */
-
-	/**
 	 * @defgroup drvusbmast USB mass storage driver
 	 * @ingroup usb
Index: uspace/drv/bus/isa/isa.c
===================================================================
--- uspace/drv/bus/isa/isa.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/isa/isa.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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.ma
===================================================================
--- uspace/drv/bus/isa/isa.ma	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/isa/isa.ma	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/pci/pciintel/pci.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -78,4 +78,7 @@
 #define PCI_BUS_FROM_FUN(fun) ((fun)->busptr)
 
+/** Max is 47, align to something nice. */
+#define ID_MAX_STR_LEN 50
+
 static hw_resource_list_t *pciintel_get_resources(ddf_fun_t *fnode)
 {
@@ -202,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 *);
@@ -208,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,
@@ -225,6 +228,5 @@
 	fibril_mutex_lock(&bus->conf_mutex);
 	
-	uint32_t conf_addr;
-	conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
+	const uint32_t conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
 	void *addr = bus->conf_data_port + (reg & 3);
 	
@@ -311,24 +313,76 @@
 void pci_fun_create_match_ids(pci_fun_t *fun)
 {
-	char *match_id_str;
 	int rc;
-	
-	asprintf(&match_id_str, "pci/ven=%04x&dev=%04x",
+	char match_id_str[ID_MAX_STR_LEN];
+
+	/* Vendor ID & Device ID, length(incl \0) 22 */
+	rc = snprintf(match_id_str, ID_MAX_STR_LEN, "pci/ven=%04x&dev=%04x",
 	    fun->vendor_id, fun->device_id);
-
-	if (match_id_str == NULL) {
-		ddf_msg(LVL_ERROR, "Out of memory creating match ID.");
-		return;
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
+		    str_error(rc));
 	}
 
 	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 90);
 	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed adding match ID: %s",
+		ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
+	}
+
+	/* Class, subclass, prog IF, revision, length(incl \0) 47 */
+	rc = snprintf(match_id_str, ID_MAX_STR_LEN,
+	    "pci/class=%02x&subclass=%02x&progif=%02x&revision=%02x",
+	    fun->class_code, fun->subclass_code, fun->prog_if, fun->revision);
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
 		    str_error(rc));
 	}
-	
-	free(match_id_str);
-	
-	/* TODO add more ids (with subsys ids, using class id etc.) */
+
+	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 70);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
+	}
+
+	/* Class, subclass, prog IF, length(incl \0) 35 */
+	rc = snprintf(match_id_str, ID_MAX_STR_LEN,
+	    "pci/class=%02x&subclass=%02x&progif=%02x",
+	    fun->class_code, fun->subclass_code, fun->prog_if);
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
+		    str_error(rc));
+	}
+
+	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 60);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
+	}
+
+	/* Class, subclass, length(incl \0) 25 */
+	rc = snprintf(match_id_str, ID_MAX_STR_LEN,
+	    "pci/class=%02x&subclass=%02x",
+	    fun->class_code, fun->subclass_code);
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
+		    str_error(rc));
+	}
+
+	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 50);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
+	}
+
+	/* Class, length(incl \0) 13 */
+	rc = snprintf(match_id_str, ID_MAX_STR_LEN, "pci/class=%02x",
+	    fun->class_code);
+	if (rc < 0) {
+		ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
+		    str_error(rc));
+	}
+
+	rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 40);
+	if (rc != EOK) {
+		ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
+	}
+
+	/* TODO add subsys ids, but those exist only in header type 0 */
 }
 
@@ -481,8 +535,4 @@
 		for (fnum = 0; multi && fnum < 8; fnum++) {
 			pci_fun_init(fun, bus_num, dnum, fnum);
-			fun->vendor_id = pci_conf_read_16(fun,
-			    PCI_VENDOR_ID);
-			fun->device_id = pci_conf_read_16(fun,
-			    PCI_DEVICE_ID);
 			if (fun->vendor_id == 0xffff) {
 				/*
@@ -511,4 +561,5 @@
 			
 			fnode = ddf_fun_create(bus->dnode, fun_inner, fun_name);
+			free(fun_name);
 			if (fnode == NULL) {
 				ddf_msg(LVL_ERROR, "Failed creating function.");
@@ -516,5 +567,4 @@
 			}
 			
-			free(fun_name);
 			fun->fnode = fnode;
 			
@@ -560,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;
@@ -567,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;
@@ -584,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;
@@ -594,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;
@@ -691,4 +741,10 @@
 	fun->dev = dev;
 	fun->fn = fn;
+	fun->vendor_id = pci_conf_read_16(fun, PCI_VENDOR_ID);
+	fun->device_id = pci_conf_read_16(fun, PCI_DEVICE_ID);
+	fun->class_code = pci_conf_read_8(fun, PCI_BASE_CLASS);
+	fun->subclass_code = pci_conf_read_8(fun, PCI_SUB_CLASS);
+	fun->prog_if = pci_conf_read_8(fun, PCI_PROG_IF);
+	fun->revision = pci_conf_read_8(fun, PCI_REVISION_ID);
 }
 
@@ -711,15 +767,11 @@
 bool pci_alloc_resource_list(pci_fun_t *fun)
 {
-	fun->hw_resources.resources =
-	    (hw_resource_t *) malloc(PCI_MAX_HW_RES * sizeof(hw_resource_t));
-	return fun->hw_resources.resources != NULL;
+	fun->hw_resources.resources = fun->resources;
+	return true;
 }
 
 void pci_clean_resource_list(pci_fun_t *fun)
 {
-	if (fun->hw_resources.resources != NULL) {
-		free(fun->hw_resources.resources);
-		fun->hw_resources.resources = NULL;
-	}
+	fun->hw_resources.resources = NULL;
 }
 
Index: uspace/drv/bus/pci/pciintel/pci.h
===================================================================
--- uspace/drv/bus/pci/pciintel/pci.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/pci/pciintel/pci.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -60,5 +60,10 @@
 	int vendor_id;
 	int device_id;
+	uint8_t class_code;
+	uint8_t subclass_code;
+	uint8_t prog_if;
+	uint8_t revision;
 	hw_resource_list_t hw_resources;
+	hw_resource_t resources[PCI_MAX_HW_RES];
 } pci_fun_t;
 
Index: uspace/drv/bus/usb/ehci/Makefile
===================================================================
--- uspace/drv/bus/usb/ehci/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ehci/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -42,5 +42,4 @@
 
 SOURCES = \
-	hc_iface.c \
 	main.c \
 	pci.c
Index: uspace/drv/bus/usb/ehci/ehci.h
===================================================================
--- uspace/drv/bus/usb/ehci/ehci.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ehci/ehci.ma	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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: uspace/drv/bus/usb/ehci/hc_iface.c
===================================================================
--- uspace/drv/bus/usb/ehci/hc_iface.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ehci/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/endpoint_list.c
===================================================================
--- uspace/drv/bus/usb/ohci/endpoint_list.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/endpoint_list.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -60,5 +60,5 @@
 	    name, instance->list_head, instance->list_head_pa);
 
-	ed_init(instance->list_head, NULL);
+	ed_init(instance->list_head, NULL, NULL);
 	list_initialize(&instance->endpoint_list);
 	fibril_mutex_initialize(&instance->guard);
@@ -73,5 +73,6 @@
  * Does not check whether this replaces an existing list.
  */
-void endpoint_list_set_next(endpoint_list_t *instance, endpoint_list_t *next)
+void endpoint_list_set_next(
+    const endpoint_list_t *instance, const endpoint_list_t *next)
 {
 	assert(instance);
Index: uspace/drv/bus/usb/ohci/endpoint_list.h
===================================================================
--- uspace/drv/bus/usb/ohci/endpoint_list.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/endpoint_list.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -68,5 +68,6 @@
 
 int endpoint_list_init(endpoint_list_t *instance, const char *name);
-void endpoint_list_set_next(endpoint_list_t *instance, endpoint_list_t *next);
+void endpoint_list_set_next(
+    const endpoint_list_t *instance, const endpoint_list_t *next);
 void endpoint_list_add_ep(endpoint_list_t *instance, ohci_endpoint_t *ep);
 void endpoint_list_remove_ep(endpoint_list_t *instance, ohci_endpoint_t *ep);
Index: uspace/drv/bus/usb/ohci/hc.c
===================================================================
--- uspace/drv/bus/usb/ohci/hc.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/hc.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -127,28 +127,31 @@
 	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...) \
 if (ret != EOK) { \
 	usb_log_error(message); \
-	usb_endpoint_manager_unregister_ep( \
-	    &instance->generic.ep_manager, hub_address, 0, USB_DIRECTION_BOTH);\
-	usb_device_manager_release( \
-	    &instance->generic.dev_manager, hub_address); \
+	usb_endpoint_manager_remove_ep( \
+	    &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);
+	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",
@@ -192,11 +195,10 @@
 	list_initialize(&instance->pending_batches);
 
-	ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
-	    bandwidth_count_usb11);
-	CHECK_RET_RETURN(ret, "Failed to initialize generic driver: %s.\n",
-	    str_error(ret));
+	hcd_init(&instance->generic, USB_SPEED_FULL,
+	    BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
 	instance->generic.private_data = instance;
 	instance->generic.schedule = hc_schedule;
 	instance->generic.ep_add_hook = ohci_endpoint_init;
+	instance->generic.ep_remove_hook = ohci_endpoint_fini;
 
 	ret = hc_init_memory(instance);
@@ -221,8 +223,14 @@
 }
 /*----------------------------------------------------------------------------*/
-void hc_enqueue_endpoint(hc_t *instance, endpoint_t *ep)
-{
+void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
+{
+	assert(instance);
+	assert(ep);
+
 	endpoint_list_t *list = &instance->lists[ep->transfer_type];
 	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
+	assert(list);
+	assert(ohci_ep);
+
 	/* Enqueue ep */
 	switch (ep->transfer_type) {
@@ -247,9 +255,15 @@
 }
 /*----------------------------------------------------------------------------*/
-void hc_dequeue_endpoint(hc_t *instance, endpoint_t *ep)
-{
+void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep)
+{
+	assert(instance);
+	assert(ep);
+
 	/* Dequeue ep */
 	endpoint_list_t *list = &instance->lists[ep->transfer_type];
 	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
+
+	assert(list);
+	assert(ohci_ep);
 	switch (ep->transfer_type) {
 	case USB_TRANSFER_CONTROL:
@@ -565,5 +579,5 @@
 
 	/*Init HCCA */
-	instance->hcca = malloc32(sizeof(hcca_t));
+	instance->hcca = hcca_get();
 	if (instance->hcca == NULL)
 		return ENOMEM;
@@ -571,6 +585,5 @@
 	usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
 
-	unsigned i = 0;
-	for (; i < 32; ++i) {
+	for (unsigned i = 0; i < 32; ++i) {
 		instance->hcca->int_ep[i] =
 		    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa;
Index: uspace/drv/bus/usb/ohci/hc.h
===================================================================
--- uspace/drv/bus/usb/ohci/hc.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/hc.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -86,6 +86,6 @@
 static inline void hc_fini(hc_t *instance) { /* TODO: implement*/ };
 
-void hc_enqueue_endpoint(hc_t *instance, endpoint_t *ep);
-void hc_dequeue_endpoint(hc_t *instance, endpoint_t *ep);
+void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep);
+void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep);
 
 void hc_interrupt(hc_t *instance, uint32_t status);
Index: uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -34,31 +34,59 @@
 #include "endpoint_descriptor.h"
 
-static unsigned direc[3] =
-    { ED_STATUS_D_IN, ED_STATUS_D_OUT, ED_STATUS_D_TRANSFER };
+/** USB direction to OHCI values translation table. */
+static const uint32_t dir[] = {
+	[USB_DIRECTION_IN] = ED_STATUS_D_IN,
+	[USB_DIRECTION_OUT] = ED_STATUS_D_OUT,
+	[USB_DIRECTION_BOTH] = ED_STATUS_D_TD,
+};
 
-void ed_init(ed_t *instance, endpoint_t *ep)
+/**
+ * Initialize ED.
+ *
+ * @param instance ED structure to initialize.
+ * @param ep Driver endpoint to use.
+ * @param td TD to put in the list.
+ *
+ * If @param ep is NULL, dummy ED is initalized with only skip flag set.
+ */
+void ed_init(ed_t *instance, const endpoint_t *ep, const td_t *td)
 {
 	assert(instance);
 	bzero(instance, sizeof(ed_t));
+
 	if (ep == NULL) {
+		/* Mark as dead, used for dummy EDs at the beginning of
+		 * endpoint lists. */
 		instance->status = ED_STATUS_K_FLAG;
 		return;
 	}
-	assert(ep);
+	/* Non-dummy ED must have TD assigned */
+	assert(td);
+
+	/* Status: address, endpoint nr, direction mask and max packet size. */
 	instance->status = 0
 	    | ((ep->address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT)
 	    | ((ep->endpoint & ED_STATUS_EN_MASK) << ED_STATUS_EN_SHIFT)
-	    | ((direc[ep->direction] & ED_STATUS_D_MASK) << ED_STATUS_D_SHIFT)
+	    | ((dir[ep->direction] & ED_STATUS_D_MASK) << ED_STATUS_D_SHIFT)
 	    | ((ep->max_packet_size & ED_STATUS_MPS_MASK)
 	        << ED_STATUS_MPS_SHIFT);
 
-
+	/* Low speed flag */
 	if (ep->speed == USB_SPEED_LOW)
 		instance->status |= ED_STATUS_S_FLAG;
+
+	/* Isochronous format flag */
 	if (ep->transfer_type == USB_TRANSFER_ISOCHRONOUS)
 		instance->status |= ED_STATUS_F_FLAG;
 
+	/* Set TD to the list */
+	const uintptr_t pa = addr_to_phys(td);
+	instance->td_head = pa & ED_TDHEAD_PTR_MASK;
+	instance->td_tail = pa & ED_TDTAIL_PTR_MASK;
+
+	/* Set toggle bit */
 	if (ep->toggle)
 		instance->td_head |= ED_TDHEAD_TOGGLE_CARRY;
+
 }
 /**
Index: uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.h
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -45,5 +45,14 @@
 #include "completion_codes.h"
 
+/**
+ * OHCI Endpoint Descriptor representation.
+ *
+ * See OHCI spec. Chapter 4.2, page 16 (pdf page 30) for details */
 typedef struct ed {
+	/**
+	 * Status field.
+	 *
+	 * See table 4-1, p. 17 OHCI spec (pdf page 31).
+	 */
 	volatile uint32_t status;
 #define ED_STATUS_FA_MASK (0x7f)   /* USB device address   */
@@ -51,20 +60,32 @@
 #define ED_STATUS_EN_MASK (0xf)    /* USB endpoint address */
 #define ED_STATUS_EN_SHIFT (7)
-#define ED_STATUS_D_MASK (0x3)     /* direction */
+#define ED_STATUS_D_MASK (0x3)     /* Direction */
 #define ED_STATUS_D_SHIFT (11)
 #define ED_STATUS_D_OUT (0x1)
 #define ED_STATUS_D_IN (0x2)
-#define ED_STATUS_D_TRANSFER (0x3)
+#define ED_STATUS_D_TD (0x3) /* Direction is specified by TD */
 
-#define ED_STATUS_S_FLAG (1 << 13) /* speed flag: 1 = low */
-#define ED_STATUS_K_FLAG (1 << 14) /* skip flag (no not execute this ED) */
-#define ED_STATUS_F_FLAG (1 << 15) /* format: 1 = isochronous*/
-#define ED_STATUS_MPS_MASK (0x3ff) /* max_packet_size*/
+#define ED_STATUS_S_FLAG (1 << 13) /* Speed flag: 1 = low */
+#define ED_STATUS_K_FLAG (1 << 14) /* Skip flag (no not execute this ED) */
+#define ED_STATUS_F_FLAG (1 << 15) /* Format: 1 = isochronous */
+#define ED_STATUS_MPS_MASK (0x3ff) /* Maximum packet size */
 #define ED_STATUS_MPS_SHIFT (16)
 
+	/**
+	 * Pointer to the last TD.
+	 *
+	 * OHCI hw never changes this field and uses it only for a reference.
+	 */
 	volatile uint32_t td_tail;
 #define ED_TDTAIL_PTR_MASK (0xfffffff0)
 #define ED_TDTAIL_PTR_SHIFT (0)
 
+	/**
+	 * Pointer to the first TD.
+	 *
+	 * Driver should not change this field if the ED is active.
+	 * This field is updated by OHCI hw and points to the next TD
+	 * to be executed.
+	 */
 	volatile uint32_t td_head;
 #define ED_TDHEAD_PTR_MASK (0xfffffff0)
@@ -75,4 +96,9 @@
 #define ED_TDHEAD_HALTED_FLAG (0x1)
 
+	/**
+	 * Pointer to the next ED.
+	 *
+	 * Driver should not change this field on active EDs.
+	 */
 	volatile uint32_t next;
 #define ED_NEXT_PTR_MASK (0xfffffff0)
@@ -80,33 +106,62 @@
 } __attribute__((packed)) ed_t;
 
-void ed_init(ed_t *instance, endpoint_t *ep);
+void ed_init(ed_t *instance, const endpoint_t *ep, const td_t *td);
 
-static inline void ed_set_td(ed_t *instance, td_t *td)
+/**
+ * Check for SKIP or HALTED flag being set.
+ * @param instance ED
+ * @return true if either SKIP or HALTED flag is set, false otherwise.
+ */
+static inline bool ed_inactive(const ed_t *instance)
 {
 	assert(instance);
-	uintptr_t pa = addr_to_phys(td);
-	instance->td_head =
-	    ((pa & ED_TDHEAD_PTR_MASK)
-	    | (instance->td_head & ~ED_TDHEAD_PTR_MASK));
+	return (instance->td_head & ED_TDHEAD_HALTED_FLAG)
+	    || (instance->status & ED_STATUS_K_FLAG);
+}
+
+/**
+ * Check whether this ED contains TD to be executed.
+ * @param instance ED
+ * @return true if there are pending TDs, false otherwise.
+ */
+static inline bool ed_transfer_pending(const ed_t *instance)
+{
+	assert(instance);
+	return (instance->td_head & ED_TDHEAD_PTR_MASK)
+	    != (instance->td_tail & ED_TDTAIL_PTR_MASK);
+}
+
+/**
+ * Set the last element of TD list
+ * @param instance ED
+ * @param instance TD to set as the last item.
+ */
+static inline void ed_set_tail_td(ed_t *instance, const td_t *td)
+{
+	assert(instance);
+	const uintptr_t pa = addr_to_phys(td);
 	instance->td_tail = pa & ED_TDTAIL_PTR_MASK;
 }
 
-static inline void ed_set_end_td(ed_t *instance, td_t *td)
-{
-	assert(instance);
-	uintptr_t pa = addr_to_phys(td);
-	instance->td_tail = pa & ED_TDTAIL_PTR_MASK;
-}
-
-static inline void ed_append_ed(ed_t *instance, ed_t *next)
+/**
+ * Set next ED in ED chain.
+ * @param instance ED to modify
+ * @param next ED to append
+ */
+static inline void ed_append_ed(ed_t *instance, const ed_t *next)
 {
 	assert(instance);
 	assert(next);
-	uint32_t pa = addr_to_phys(next);
+	const uint32_t pa = addr_to_phys(next);
 	assert((pa & ED_NEXT_PTR_MASK) << ED_NEXT_PTR_SHIFT == pa);
 	instance->next = pa;
 }
 
-static inline int ed_toggle_get(ed_t *instance)
+/**
+ * Get toggle bit value stored in this ED
+ * @param instance ED
+ * @return Toggle bit value
+ */
+static inline int ed_toggle_get(const ed_t *instance)
 {
 	assert(instance);
@@ -114,12 +169,16 @@
 }
 
-static inline void ed_toggle_set(ed_t *instance, int toggle)
+/**
+ * Set toggle bit value stored in this ED
+ * @param instance ED
+ * @param toggle Toggle bit value
+ */
+static inline void ed_toggle_set(ed_t *instance, bool toggle)
 {
 	assert(instance);
-	assert(toggle == 0 || toggle == 1);
-	if (toggle == 1) {
+	if (toggle) {
 		instance->td_head |= ED_TDHEAD_TOGGLE_CARRY;
 	} else {
-		/* clear halted flag when reseting toggle */
+		/* Clear halted flag when reseting toggle TODO: Why? */
 		instance->td_head &= ~ED_TDHEAD_TOGGLE_CARRY;
 		instance->td_head &= ~ED_TDHEAD_HALTED_FLAG;
Index: uspace/drv/bus/usb/ohci/hw_struct/hcca.h
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/hcca.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/hw_struct/hcca.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -36,4 +36,5 @@
 
 #include <stdint.h>
+#include <malloc.h>
 
 /** Host controller communication area.
@@ -48,4 +49,9 @@
 } __attribute__((packed, aligned)) hcca_t;
 
+static inline void * hcca_get(void)
+{
+	assert(sizeof(hcca_t) == 256);
+	return memalign(256, sizeof(hcca_t));
+}
 #endif
 /**
Index: uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -35,22 +35,42 @@
 #include "transfer_descriptor.h"
 
-static unsigned dp[3] =
-    { TD_STATUS_DP_IN, TD_STATUS_DP_OUT, TD_STATUS_DP_SETUP };
-static unsigned togg[2] = { TD_STATUS_T_0, TD_STATUS_T_1 };
+/** USB direction to OHCI TD values translation table */
+static const uint32_t dir[] = {
+	[USB_DIRECTION_IN] = TD_STATUS_DP_IN,
+	[USB_DIRECTION_OUT] = TD_STATUS_DP_OUT,
+	[USB_DIRECTION_BOTH] = TD_STATUS_DP_SETUP,
+};
 
-void td_init(td_t *instance,
-    usb_direction_t dir, const void *buffer, size_t size, int toggle)
+/**
+ * Initialize OHCI TD.
+ * @param instance TD structure to initialize.
+ * @param next Next TD in ED list.
+ * @param direction Used to determine PID, BOTH means setup PID.
+ * @param buffer Pointer to the first byte of transferred data.
+ * @param size Size of the buffer.
+ * @param toggle Toggle bit value, use 0/1 to set explicitly,
+ *        any other value means that ED toggle will be used.
+ */
+void td_init(td_t *instance, const td_t *next,
+    usb_direction_t direction, const void *buffer, size_t size, int toggle)
 {
 	assert(instance);
 	bzero(instance, sizeof(td_t));
+	/* Set PID and Error code */
 	instance->status = 0
-	    | ((dp[dir] & TD_STATUS_DP_MASK) << TD_STATUS_DP_SHIFT)
+	    | ((dir[direction] & TD_STATUS_DP_MASK) << TD_STATUS_DP_SHIFT)
 	    | ((CC_NOACCESS2 & TD_STATUS_CC_MASK) << TD_STATUS_CC_SHIFT);
+
 	if (toggle == 0 || toggle == 1) {
-		instance->status |= togg[toggle] << TD_STATUS_T_SHIFT;
+		/* Set explicit toggle bit */
+		instance->status |= TD_STATUS_T_USE_TD_FLAG;
+		instance->status |= toggle ? TD_STATUS_T_FLAG : 0;
 	}
+
+	/* Alow less data on input. */
 	if (dir == USB_DIRECTION_IN) {
 		instance->status |= TD_STATUS_ROUND_FLAG;
 	}
+
 	if (buffer != NULL) {
 		assert(size != 0);
@@ -58,4 +78,7 @@
 		instance->be = addr_to_phys(buffer + size - 1);
 	}
+
+	instance->next = addr_to_phys(next) & TD_NEXT_PTR_MASK;
+
 }
 /**
Index: uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -37,6 +37,6 @@
 #include <bool.h>
 #include <stdint.h>
+
 #include "../utils/malloc32.h"
-
 #include "completion_codes.h"
 
@@ -46,52 +46,64 @@
 #define OHCI_TD_MAX_TRANSFER (4 * 1024)
 
+/**
+ * Transfer Descriptor representation.
+ *
+ * See OHCI spec chapter 4.3.1 General Transfer Descriptor on page 19
+ * (pdf page 33) for details.
+ */
 typedef struct td {
+	/** Status field. Do not touch on active TDs. */
 	volatile uint32_t status;
 #define TD_STATUS_ROUND_FLAG (1 << 18)
-#define TD_STATUS_DP_MASK (0x3) /* direction/PID */
+#define TD_STATUS_DP_MASK (0x3) /* Direction/PID */
 #define TD_STATUS_DP_SHIFT (19)
 #define TD_STATUS_DP_SETUP (0x0)
 #define TD_STATUS_DP_OUT (0x1)
 #define TD_STATUS_DP_IN (0x2)
-#define TD_STATUS_DI_MASK (0x7) /* delay interrupt, wait DI frames before int */
+#define TD_STATUS_DI_MASK (0x7) /* Delay interrupt, wait n frames before irq */
 #define TD_STATUS_DI_SHIFT (21)
 #define TD_STATUS_DI_NO_INTERRUPT (0x7)
-#define TD_STATUS_T_MASK (0x3)  /* data toggle 1x = use ED toggle carry */
-#define TD_STATUS_T_SHIFT (24)
-#define TD_STATUS_T_0 (0x2)
-#define TD_STATUS_T_1 (0x3)
-#define TD_STATUS_T_ED (0)
-#define TD_STATUS_EC_MASK (0x3) /* error count */
+#define TD_STATUS_T_FLAG (1 << 24) /* Explicit toggle bit value for this TD */
+#define TD_STATUS_T_USE_TD_FLAG (1 << 25) /* 1 = use bit 24 as toggle bit */
+#define TD_STATUS_EC_MASK (0x3) /* Error count */
 #define TD_STATUS_EC_SHIFT (26)
-#define TD_STATUS_CC_MASK (0xf) /* condition code */
+#define TD_STATUS_CC_MASK (0xf) /* Condition code */
 #define TD_STATUS_CC_SHIFT (28)
 
-	volatile uint32_t cbp; /* current buffer ptr, data to be transfered */
+	/**
+	 * Current buffer pointer.
+	 * Phys address of the first byte to be transferred. */
+	volatile uint32_t cbp;
+
+	/** Pointer to the next TD in chain. 16-byte aligned. */
 	volatile uint32_t next;
 #define TD_NEXT_PTR_MASK (0xfffffff0)
 #define TD_NEXT_PTR_SHIFT (0)
 
-	volatile uint32_t be; /* buffer end, address of the last byte */
+	/**
+	 * Buffer end.
+	 * Phys address of the last byte of the transfer.
+	 * @note this does not have to be on the same page as cbp.
+	 */
+	volatile uint32_t be;
 } __attribute__((packed)) td_t;
 
-void td_init(td_t *instance,
+void td_init(td_t *instance, const td_t *next,
     usb_direction_t dir, const void *buffer, size_t size, int toggle);
 
-inline static void td_set_next(td_t *instance, td_t *next)
+/**
+ * Check TD for completion.
+ * @param instance TD structure.
+ * @return true if the TD was accessed and processed by hw, false otherwise.
+ */
+inline static bool td_is_finished(const td_t *instance)
 {
 	assert(instance);
-	instance->next = addr_to_phys(next) & TD_NEXT_PTR_MASK;
-}
-
-inline static bool td_is_finished(td_t *instance)
-{
-	assert(instance);
-	int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
-	/* something went wrong, error code is set */
+	const int cc =
+	    (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
+	/* This value is changed on transfer completion,
+	 * either to CC_NOERROR or and error code.
+	 * See OHCI spec 4.3.1.3.5 p. 23 (pdf 37) */
 	if (cc != CC_NOACCESS1 && cc != CC_NOACCESS2) {
-		return true;
-	}
-	/* everything done */
-	if (cc == CC_NOERROR && instance->cbp == 0) {
 		return true;
 	}
@@ -99,16 +111,29 @@
 }
 
-static inline int td_error(td_t *instance)
+/**
+ * Get error code that indicates transfer status.
+ * @param instance TD structure.
+ * @return Error code.
+ */
+static inline int td_error(const td_t *instance)
 {
 	assert(instance);
-	int cc = (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
+	const int cc =
+	    (instance->status >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
 	return cc_to_rc(cc);
 }
 
+/**
+ * Get remaining portion of buffer to be read/written
+ * @param instance TD structure
+ * @return size of remaining buffer.
+ */
 static inline size_t td_remain_size(td_t *instance)
 {
 	assert(instance);
+	/* Current buffer pointer is cleared on successful transfer */
 	if (instance->cbp == 0)
 		return 0;
+	/* Buffer end points to the last byte of transfer buffer, so add 1 */
 	return instance->be - instance->cbp + 1;
 }
Index: uspace/drv/bus/usb/ohci/main.c
===================================================================
--- uspace/drv/bus/usb/ohci/main.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/ohci.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -76,24 +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(manager, handle);
-	if (addr < 0) {
-		return addr;
-	}
 
 	if (address != NULL) {
-		*address = addr;
+		*address = dev_to_ohci(fun->dev)->hc.rh.address;
 	}
 
@@ -107,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)
 {
@@ -121,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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/ohci.ma	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/ohci_batch.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_batch.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/ohci_batch.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -52,7 +52,6 @@
 	if (!ohci_batch)
 		return;
-	unsigned i = 0;
 	if (ohci_batch->tds) {
-		for (; i< ohci_batch->td_count; ++i) {
+		for (unsigned i = 0; i < ohci_batch->td_count; ++i) {
 			if (i != ohci_batch->leave_td)
 				free32(ohci_batch->tds[i]);
@@ -60,5 +59,5 @@
 		free(ohci_batch->tds);
 	}
-	usb_transfer_batch_dispose(ohci_batch->usb_batch);
+	usb_transfer_batch_destroy(ohci_batch->usb_batch);
 	free32(ohci_batch->device_buffer);
 	free(ohci_batch);
@@ -107,6 +106,6 @@
 	ohci_batch->tds[0] = ohci_endpoint_get(usb_batch->ep)->td;
 	ohci_batch->leave_td = 0;
-	unsigned i = 1;
-	for (; i <= ohci_batch->td_count; ++i) {
+
+	for (unsigned i = 1; i <= ohci_batch->td_count; ++i) {
 		ohci_batch->tds[i] = malloc32(sizeof(td_t));
 		CHECK_NULL_DISPOSE_RET(ohci_batch->tds[i],
@@ -160,47 +159,82 @@
 	usb_log_debug("Batch %p checking %zu td(s) for completion.\n",
 	    ohci_batch->usb_batch, ohci_batch->td_count);
-	usb_log_debug2("ED: %x:%x:%x:%x.\n",
+	usb_log_debug2("ED: %08x:%08x:%08x:%08x.\n",
 	    ohci_batch->ed->status, ohci_batch->ed->td_head,
 	    ohci_batch->ed->td_tail, ohci_batch->ed->next);
 
-	size_t i = 0;
-	for (; i < ohci_batch->td_count; ++i) {
+	if (!ed_inactive(ohci_batch->ed) && ed_transfer_pending(ohci_batch->ed))
+		return false;
+
+	/* Now we may be sure that either the ED is inactive because of errors
+	 * or all transfer descriptors completed successfully */
+
+	/* Assume all data got through */
+	ohci_batch->usb_batch->transfered_size =
+	    ohci_batch->usb_batch->buffer_size;
+
+	/* Assume we will leave the last(unused) TD behind */
+	ohci_batch->leave_td = ohci_batch->td_count;
+
+	/* Check all TDs */
+	for (size_t i = 0; i < ohci_batch->td_count; ++i) {
 		assert(ohci_batch->tds[i] != NULL);
-		usb_log_debug("TD %zu: %x:%x:%x:%x.\n", i,
+		usb_log_debug("TD %zu: %08x:%08x:%08x:%08x.\n", i,
 		    ohci_batch->tds[i]->status, ohci_batch->tds[i]->cbp,
 		    ohci_batch->tds[i]->next, ohci_batch->tds[i]->be);
-		if (!td_is_finished(ohci_batch->tds[i])) {
-			return false;
-		}
+
+		/* If the TD got all its data through, it will report 0 bytes
+		 * remain, the sole exception is INPUT with data rounding flag
+		 * (short), i.e. every INPUT. Nice thing is that short packets
+		 * will correctly report remaining data, thus making
+		 * this computation correct (short packets need to be produced
+		 * by the last TD)
+		 * NOTE: This also works for CONTROL transfer as
+		 * the first TD will return 0 remain.
+		 * NOTE: Short packets don't break the assumption that
+		 * we leave the very last(unused) TD behind.
+		 */
+		ohci_batch->usb_batch->transfered_size
+		    -= td_remain_size(ohci_batch->tds[i]);
+
 		ohci_batch->usb_batch->error = td_error(ohci_batch->tds[i]);
 		if (ohci_batch->usb_batch->error != EOK) {
-			usb_log_debug("Batch %p found error TD(%zu):%x.\n",
+			usb_log_debug("Batch %p found error TD(%zu):%08x.\n",
 			    ohci_batch->usb_batch, i,
 			    ohci_batch->tds[i]->status);
-			/* Make sure TD queue is empty (one TD),
-			 * ED should be marked as halted */
-			ohci_batch->ed->td_tail =
-			    (ohci_batch->ed->td_head & ED_TDTAIL_PTR_MASK);
-			++i;
+
+			/* ED should be stopped because of errors */
+			assert((ohci_batch->ed->td_head & ED_TDHEAD_HALTED_FLAG) != 0);
+
+			/* Now we have a problem: we don't know what TD
+			 * the head pointer points to, the retiring rules
+			 * described in specs say it should be the one after
+			 * the failed one so set the tail pointer accordingly.
+			 * It will be the one TD we leave behind.
+			 */
+			ohci_batch->leave_td = i + 1;
+
+			/* Check TD assumption */
+			const uint32_t pa = addr_to_phys(
+			    ohci_batch->tds[ohci_batch->leave_td]);
+			assert((ohci_batch->ed->td_head & ED_TDTAIL_PTR_MASK)
+			    == pa);
+
+			ed_set_tail_td(ohci_batch->ed,
+			    ohci_batch->tds[ohci_batch->leave_td]);
+
+			/* Clear possible ED HALT */
+			ohci_batch->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
 			break;
 		}
 	}
-
-	assert(i <= ohci_batch->td_count);
-	ohci_batch->leave_td = i;
-
+	assert(ohci_batch->usb_batch->transfered_size <=
+	    ohci_batch->usb_batch->buffer_size);
+
+	/* Store the remaining TD */
 	ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->usb_batch->ep);
 	assert(ohci_ep);
 	ohci_ep->td = ohci_batch->tds[ohci_batch->leave_td];
-	assert(i > 0);
-	ohci_batch->usb_batch->transfered_size =
-	    ohci_batch->usb_batch->buffer_size;
-	for (--i;i < ohci_batch->td_count; ++i)
-		ohci_batch->usb_batch->transfered_size
-		    -= td_remain_size(ohci_batch->tds[i]);
-
-	/* Clear possible ED HALT */
-	ohci_batch->ed->td_head &= ~ED_TDHEAD_HALTED_FLAG;
-	/* just make sure that we are leaving the right TD behind */
+
+	/* Make sure that we are leaving the right TD behind */
 	const uint32_t pa = addr_to_phys(ohci_ep->td);
 	assert(pa == (ohci_batch->ed->td_head & ED_TDHEAD_PTR_MASK));
@@ -217,5 +251,5 @@
 {
 	assert(ohci_batch);
-	ed_set_end_td(ohci_batch->ed, ohci_batch->tds[ohci_batch->td_count]);
+	ed_set_tail_td(ohci_batch->ed, ohci_batch->tds[ohci_batch->td_count]);
 }
 /*----------------------------------------------------------------------------*/
@@ -234,5 +268,5 @@
 	assert(ohci_batch->usb_batch);
 	assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
-	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", ohci_batch->ed,
+	usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed,
 	    ohci_batch->ed->status, ohci_batch->ed->td_tail,
 	    ohci_batch->ed->td_head, ohci_batch->ed->next);
@@ -247,14 +281,14 @@
 	const usb_direction_t status_dir = reverse_dir[dir];
 
-	/* setup stage */
-	td_init(ohci_batch->tds[0], USB_DIRECTION_BOTH, buffer,
-		ohci_batch->usb_batch->setup_size, toggle);
-	td_set_next(ohci_batch->tds[0], ohci_batch->tds[1]);
-	usb_log_debug("Created CONTROL SETUP TD: %x:%x:%x:%x.\n",
+	/* Setup stage */
+	td_init(
+	    ohci_batch->tds[0], ohci_batch->tds[1], USB_DIRECTION_BOTH,
+	    buffer, ohci_batch->usb_batch->setup_size, toggle);
+	usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x.\n",
 	    ohci_batch->tds[0]->status, ohci_batch->tds[0]->cbp,
 	    ohci_batch->tds[0]->next, ohci_batch->tds[0]->be);
 	buffer += ohci_batch->usb_batch->setup_size;
 
-	/* data stage */
+	/* Data stage */
 	size_t td_current = 1;
 	size_t remain_size = ohci_batch->usb_batch->buffer_size;
@@ -265,9 +299,8 @@
 		toggle = 1 - toggle;
 
-		td_init(ohci_batch->tds[td_current], data_dir, buffer,
-		    transfer_size, toggle);
-		td_set_next(ohci_batch->tds[td_current],
-		    ohci_batch->tds[td_current + 1]);
-		usb_log_debug("Created CONTROL DATA TD: %x:%x:%x:%x.\n",
+		td_init(ohci_batch->tds[td_current],
+		    ohci_batch->tds[td_current + 1],
+		    data_dir, buffer, transfer_size, toggle);
+		usb_log_debug("Created CONTROL DATA TD: %08x:%08x:%08x:%08x.\n",
 		    ohci_batch->tds[td_current]->status,
 		    ohci_batch->tds[td_current]->cbp,
@@ -281,10 +314,9 @@
 	}
 
-	/* status stage */
+	/* Status stage */
 	assert(td_current == ohci_batch->td_count - 1);
-	td_init(ohci_batch->tds[td_current], status_dir, NULL, 0, 1);
-	td_set_next(ohci_batch->tds[td_current],
-	    ohci_batch->tds[td_current + 1]);
-	usb_log_debug("Created CONTROL STATUS TD: %x:%x:%x:%x.\n",
+	td_init(ohci_batch->tds[td_current], ohci_batch->tds[td_current + 1],
+	    status_dir, NULL, 0, 1);
+	usb_log_debug("Created CONTROL STATUS TD: %08x:%08x:%08x:%08x.\n",
 	    ohci_batch->tds[td_current]->status,
 	    ohci_batch->tds[td_current]->cbp,
@@ -312,5 +344,5 @@
 	assert(ohci_batch->usb_batch);
 	assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
-	usb_log_debug("Using ED(%p): %x:%x:%x:%x.\n", ohci_batch->ed,
+	usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed,
 	    ohci_batch->ed->status, ohci_batch->ed->td_tail,
 	    ohci_batch->ed->td_head, ohci_batch->ed->next);
@@ -323,10 +355,9 @@
 		    ? OHCI_TD_MAX_TRANSFER : remain_size;
 
-		td_init(ohci_batch->tds[td_current], dir, buffer,
-		    transfer_size, -1);
-		td_set_next(ohci_batch->tds[td_current],
-		    ohci_batch->tds[td_current + 1]);
-
-		usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
+		td_init(
+		    ohci_batch->tds[td_current], ohci_batch->tds[td_current + 1],
+		    dir, buffer, transfer_size, -1);
+
+		usb_log_debug("Created DATA TD: %08x:%08x:%08x:%08x.\n",
 		    ohci_batch->tds[td_current]->status,
 		    ohci_batch->tds[td_current]->cbp,
Index: uspace/drv/bus/usb/ohci/ohci_endpoint.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_endpoint.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/ohci_endpoint.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -62,23 +62,8 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Disposes hcd endpoint structure
- *
- * @param[in] hcd_ep endpoint structure
- */
-static void ohci_endpoint_fini(endpoint_t *ep)
-{
-	ohci_endpoint_t *instance = ep->hc_data.data;
-	hc_dequeue_endpoint(instance->hcd->private_data, ep);
-	if (instance) {
-		free32(instance->ed);
-		free32(instance->td);
-		free(instance);
-	}
-}
-/*----------------------------------------------------------------------------*/
 /** Creates new hcd endpoint representation.
  *
  * @param[in] ep USBD endpoint structure
- * @return pointer to a new hcd endpoint structure, NULL on failure.
+ * @return Error code.
  */
 int ohci_endpoint_init(hcd_t *hcd, endpoint_t *ep)
@@ -102,11 +87,28 @@
 	}
 
-	ed_init(ohci_ep->ed, ep);
-	ed_set_td(ohci_ep->ed, ohci_ep->td);
+	ed_init(ohci_ep->ed, ep, ohci_ep->td);
 	endpoint_set_hc_data(
-	    ep, ohci_ep, ohci_endpoint_fini, ohci_ep_toggle_get, ohci_ep_toggle_set);
-	ohci_ep->hcd = hcd;
+	    ep, ohci_ep, ohci_ep_toggle_get, ohci_ep_toggle_set);
 	hc_enqueue_endpoint(hcd->private_data, ep);
 	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Disposes hcd endpoint structure
+ *
+ * @param[in] hcd driver using this instance.
+ * @param[in] ep endpoint structure.
+ */
+void ohci_endpoint_fini(hcd_t *hcd, endpoint_t *ep)
+{
+	assert(hcd);
+	assert(ep);
+	ohci_endpoint_t *instance = ohci_endpoint_get(ep);
+	hc_dequeue_endpoint(hcd->private_data, ep);
+	if (instance) {
+		free32(instance->ed);
+		free32(instance->td);
+		free(instance);
+	}
+	endpoint_clear_hc_data(ep);
 }
 /**
Index: uspace/drv/bus/usb/ohci/ohci_endpoint.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_endpoint.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/ohci_endpoint.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -51,9 +51,8 @@
 	/** Linked list used by driver software */
 	link_t link;
-	/** Device using this ep */
-	hcd_t *hcd;
 } ohci_endpoint_t;
 
 int ohci_endpoint_init(hcd_t *hcd, endpoint_t *ep);
+void ohci_endpoint_fini(hcd_t *hcd, endpoint_t *ep);
 
 /** Get and convert assigned ohci_endpoint_t structure
@@ -61,5 +60,5 @@
  * @return Pointer to assigned hcd endpoint structure
  */
-static inline ohci_endpoint_t * ohci_endpoint_get(endpoint_t *ep)
+static inline ohci_endpoint_t * ohci_endpoint_get(const endpoint_t *ep)
 {
 	assert(ep);
Index: uspace/drv/bus/usb/ohci/ohci_regs.h
===================================================================
--- uspace/drv/bus/usb/ohci/ohci_regs.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/ohci_regs.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -26,5 +26,5 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/** @addtogroup drvusbohcihc
+/** @addtogroup drvusbohci
  * @{
  */
Index: uspace/drv/bus/usb/ohci/pci.c
===================================================================
--- uspace/drv/bus/usb/ohci/pci.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/pci.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -85,6 +85,5 @@
 	bool irq_found = false;
 
-	size_t i;
-	for (i = 0; i < hw_resources.count; i++) {
+	for (size_t i = 0; i < hw_resources.count; i++) {
 		hw_resource_t *res = &hw_resources.resources[i];
 		switch (res->type) {
Index: uspace/drv/bus/usb/ohci/root_hub.c
===================================================================
--- uspace/drv/bus/usb/ohci/root_hub.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/root_hub.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -35,6 +35,9 @@
 #include <errno.h>
 #include <str_error.h>
+#include <fibril_synch.h>
 
 #include <usb/debug.h>
+#include <usb/dev/request.h>
+#include <usb/classes/hub.h>
 
 #include "root_hub.h"
@@ -43,7 +46,4 @@
 #include <usb/dev/driver.h>
 #include "ohci_regs.h"
-
-#include <usb/dev/request.h>
-#include <usb/classes/hub.h>
 
 /**
@@ -108,11 +108,13 @@
 static void create_serialized_hub_descriptor(rh_t *instance);
 static void rh_init_descriptors(rh_t *instance);
-static uint16_t create_interrupt_mask(rh_t *instance);
-static int get_status(rh_t *instance, usb_transfer_batch_t *request);
-static int get_descriptor(rh_t *instance, usb_transfer_batch_t *request);
-static int set_feature(rh_t *instance, usb_transfer_batch_t *request);
-static int clear_feature(rh_t *instance, usb_transfer_batch_t *request);
-static int set_feature_port(rh_t *instance, uint16_t feature, uint16_t port);
-static int clear_feature_port(rh_t *instance, uint16_t feature, uint16_t port);
+static uint16_t create_interrupt_mask(const rh_t *instance);
+static int get_status(const rh_t *instance, usb_transfer_batch_t *request);
+static int get_descriptor(const rh_t *instance, usb_transfer_batch_t *request);
+static int set_feature(const rh_t *instance, usb_transfer_batch_t *request);
+static int clear_feature(const rh_t *instance, usb_transfer_batch_t *request);
+static int set_feature_port(
+    const rh_t *instance, uint16_t feature, uint16_t port);
+static int clear_feature_port(
+    const rh_t *instance, uint16_t feature, uint16_t port);
 static int control_request(rh_t *instance, usb_transfer_batch_t *request);
 static inline void interrupt_request(
@@ -153,9 +155,11 @@
 	instance->unfinished_interrupt_transfer = NULL;
 
-#ifdef OHCI_POWER_SWITCH_no
+#if defined OHCI_POWER_SWITCH_no
 	/* Set port power mode to no power-switching. (always on) */
 	instance->registers->rh_desc_a |= RHDA_NPS_FLAG;
+
 	/* Set to no over-current reporting */
 	instance->registers->rh_desc_a |= RHDA_NOCP_FLAG;
+
 #elif defined OHCI_POWER_SWITCH_ganged
 	/* Set port power mode to no ganged power-switching. */
@@ -163,4 +167,5 @@
 	instance->registers->rh_desc_a &= ~RHDA_PSM_FLAG;
 	instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER;
+
 	/* Set to global over-current */
 	instance->registers->rh_desc_a &= ~RHDA_NOCP_FLAG;
@@ -174,7 +179,9 @@
 	instance->registers->rh_desc_b &= (RHDB_PCC_MASK << RHDB_PCC_SHIFT);
 	instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER;
+
 	/* Return control to per port state */
 	instance->registers->rh_desc_b |=
 		((1 << (instance->port_count + 1)) - 1) << RHDB_PCC_SHIFT;
+
 	/* Set per port over-current */
 	instance->registers->rh_desc_a &= ~RHDA_NOCP_FLAG;
@@ -182,4 +189,5 @@
 #endif
 
+	fibril_mutex_initialize(&instance->guard);
 	rh_init_descriptors(instance);
 
@@ -209,13 +217,16 @@
 	case USB_TRANSFER_INTERRUPT:
 		usb_log_debug("Root hub got INTERRUPT packet\n");
+		fibril_mutex_lock(&instance->guard);
+		assert(instance->unfinished_interrupt_transfer == NULL);
 		const uint16_t mask = create_interrupt_mask(instance);
 		if (mask == 0) {
 			usb_log_debug("No changes..\n");
-			assert(instance->unfinished_interrupt_transfer == NULL);
 			instance->unfinished_interrupt_transfer = request;
+			fibril_mutex_unlock(&instance->guard);
 			return;
 		}
 		usb_log_debug("Processing changes...\n");
 		interrupt_request(request, mask, instance->interrupt_mask_size);
+		fibril_mutex_unlock(&instance->guard);
 		break;
 
@@ -224,5 +235,5 @@
 		usb_transfer_batch_finish_error(request, NULL, 0, EINVAL);
 	}
-	usb_transfer_batch_dispose(request);
+	usb_transfer_batch_destroy(request);
 }
 /*----------------------------------------------------------------------------*/
@@ -237,14 +248,15 @@
 	assert(instance);
 
-	if (!instance->unfinished_interrupt_transfer)
-		return;
-
-	usb_log_debug("Finalizing interrupt transfer\n");
-	const uint16_t mask = create_interrupt_mask(instance);
-	interrupt_request(instance->unfinished_interrupt_transfer,
-	    mask, instance->interrupt_mask_size);
-	usb_transfer_batch_dispose(instance->unfinished_interrupt_transfer);
-
-	instance->unfinished_interrupt_transfer = NULL;
+	fibril_mutex_lock(&instance->guard);
+	if (instance->unfinished_interrupt_transfer) {
+		usb_log_debug("Finalizing interrupt transfer\n");
+		const uint16_t mask = create_interrupt_mask(instance);
+		interrupt_request(instance->unfinished_interrupt_transfer,
+		    mask, instance->interrupt_mask_size);
+		usb_transfer_batch_destroy(
+		    instance->unfinished_interrupt_transfer);
+		instance->unfinished_interrupt_transfer = NULL;
+	}
+	fibril_mutex_unlock(&instance->guard);
 }
 /*----------------------------------------------------------------------------*/
@@ -342,5 +354,5 @@
  * @return Mask of changes.
  */
-uint16_t create_interrupt_mask(rh_t *instance)
+uint16_t create_interrupt_mask(const rh_t *instance)
 {
 	assert(instance);
@@ -351,6 +363,5 @@
 		mask |= 1;
 	}
-	size_t port = 1;
-	for (; port <= instance->port_count; ++port) {
+	for (size_t port = 1; port <= instance->port_count; ++port) {
 		/* Write-clean bits are those that indicate change */
 		if (RHPS_CHANGE_WC_MASK
@@ -373,5 +384,5 @@
  * @return error code
  */
-int get_status(rh_t *instance, usb_transfer_batch_t *request)
+int get_status(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -419,5 +430,5 @@
  * @return Error code
  */
-int get_descriptor(rh_t *instance, usb_transfer_batch_t *request)
+int get_descriptor(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -497,5 +508,5 @@
  * @return error code
  */
-int set_feature_port(rh_t *instance, uint16_t feature, uint16_t port)
+int set_feature_port(const rh_t *instance, uint16_t feature, uint16_t port)
 {
 	assert(instance);
@@ -536,5 +547,5 @@
  * @return error code
  */
-int clear_feature_port(rh_t *instance, uint16_t feature, uint16_t port)
+int clear_feature_port(const rh_t *instance, uint16_t feature, uint16_t port)
 {
 	assert(instance);
@@ -593,5 +604,5 @@
  * @return error code
  */
-int set_feature(rh_t *instance, usb_transfer_batch_t *request)
+int set_feature(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -629,5 +640,5 @@
  * @return error code
  */
-int clear_feature(rh_t *instance, usb_transfer_batch_t *request)
+int clear_feature(const rh_t *instance, usb_transfer_batch_t *request)
 {
 	assert(instance);
@@ -636,5 +647,7 @@
 	const usb_device_request_setup_packet_t *setup_request =
 	    (usb_device_request_setup_packet_t *) request->setup_buffer;
+
 	request->transfered_size = 0;
+
 	switch (setup_request->request_type)
 	{
@@ -648,6 +661,7 @@
 		/*
 		 * Chapter 11.16.2 specifies that only C_HUB_LOCAL_POWER and
-		 * C_HUB_OVER_CURRENT are supported. C_HUB_OVER_CURRENT is represented
-		 * by OHCI RHS_OCIC_FLAG. C_HUB_LOCAL_POWER is not supported
+		 * C_HUB_OVER_CURRENT are supported.
+		 * C_HUB_OVER_CURRENT is represented by OHCI RHS_OCIC_FLAG.
+		 * C_HUB_LOCAL_POWER is not supported
 		 * as root hubs do not support local power status feature.
 		 * (OHCI pg. 127) */
@@ -721,4 +735,5 @@
 		    "additional data\n");
 		return clear_feature(instance, request);
+
 	case USB_DEVREQ_SET_FEATURE:
 		usb_log_debug2("Processing request without "
Index: uspace/drv/bus/usb/ohci/root_hub.h
===================================================================
--- uspace/drv/bus/usb/ohci/root_hub.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/root_hub.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -47,4 +47,5 @@
  */
 typedef struct rh {
+	fibril_mutex_t guard;
 	/** pointer to ohci driver registers */
 	ohci_regs_t *registers;
Index: uspace/drv/bus/usb/ohci/utils/malloc32.h
===================================================================
--- uspace/drv/bus/usb/ohci/utils/malloc32.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/ohci/utils/malloc32.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -41,4 +41,10 @@
 #include <as.h>
 
+/* Generic TDs and EDs require 16byte alignment,
+ * Isochronous TD require 32byte alignment,
+ * buffers do not have to be aligned.
+ */
+#define OHCI_ALIGN 32
+
 /** Get physical address translation
  *
@@ -62,5 +68,5 @@
  */
 static inline void * malloc32(size_t size)
-	{ return memalign(size, size); }
+	{ return memalign(OHCI_ALIGN, size); }
 /*----------------------------------------------------------------------------*/
 /** Physical mallocator simulator
@@ -69,5 +75,5 @@
  */
 static inline void free32(void *addr)
-	{ if (addr) free(addr); }
+	{ free(addr); }
 #endif
 /**
Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -192,23 +192,17 @@
 	    "Device registers at %p (%zuB) accessible.\n", io, reg_size);
 
-	ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
-	    bandwidth_count_usb11);
-	CHECK_RET_RETURN(ret, "Failed to initialize HCD generic driver: %s.\n",
+	ret = hc_init_mem_structures(instance);
+	CHECK_RET_RETURN(ret,
+	    "Failed to initialize UHCI memory structures: %s.\n",
 	    str_error(ret));
+
+#undef CHECK_RET_RETURN
+
+	hcd_init(&instance->generic, USB_SPEED_FULL,
+	    BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
 
 	instance->generic.private_data = instance;
 	instance->generic.schedule = hc_schedule;
 	instance->generic.ep_add_hook = NULL;
-
-#undef CHECK_RET_DEST_FUN_RETURN
-
-	ret = hc_init_mem_structures(instance);
-	if (ret != EOK) {
-		usb_log_error(
-		    "Failed to initialize UHCI memory structures: %s.\n",
-		    str_error(ret));
-		hcd_destroy(&instance->generic);
-		return ret;
-	}
 
 	hc_init_hw(instance);
@@ -299,6 +293,6 @@
 	const uint32_t queue = LINK_POINTER_QH(
 	        addr_to_phys(instance->transfers_interrupt.queue_head));
-	unsigned i = 0;
-	for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
+
+	for (unsigned i = 0; i < UHCI_FRAME_LIST_COUNT; ++i) {
 		instance->frame_list[i] = queue;
 	}
Index: uspace/drv/bus/usb/uhci/main.c
===================================================================
--- uspace/drv/bus/usb/uhci/main.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/uhci/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/pci.c
===================================================================
--- uspace/drv/bus/usb/uhci/pci.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/uhci/pci.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -82,6 +82,5 @@
 	bool irq_found = false;
 
-	size_t i;
-	for (i = 0; i < hw_resources.count; i++) {
+	for (size_t i = 0; i < hw_resources.count; i++) {
 		const hw_resource_t *res = &hw_resources.resources[i];
 		switch (res->type) {
Index: uspace/drv/bus/usb/uhci/uhci.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/uhci/uhci.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -89,29 +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(manager, handle);
-
-	if (addr < 0) {
-		return addr;
-	}
-
-	if (address != NULL) {
-		*address = addr;
-	}
-
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
 /** Gets handle of the respective hc.
  *
@@ -134,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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/uhci/uhci.ma	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/uhci_batch.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_batch.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/uhci/uhci_batch.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -48,5 +48,5 @@
 {
 	if (uhci_batch) {
-		usb_transfer_batch_dispose(uhci_batch->usb_batch);
+		usb_transfer_batch_destroy(uhci_batch->usb_batch);
 		free32(uhci_batch->device_buffer);
 		free(uhci_batch);
@@ -167,6 +167,6 @@
 	    uhci_batch->td_count);
 	uhci_batch->usb_batch->transfered_size = 0;
-	size_t i = 0;
-	for (;i < uhci_batch->td_count; ++i) {
+
+	for (size_t i = 0;i < uhci_batch->td_count; ++i) {
 		if (td_is_active(&uhci_batch->tds[i])) {
 			return false;
Index: uspace/drv/bus/usb/uhci/utils/malloc32.h
===================================================================
--- uspace/drv/bus/usb/uhci/utils/malloc32.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/uhci/utils/malloc32.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -62,10 +62,11 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Physical mallocator simulator
+/** DMA malloc simulator
  *
  * @param[in] size Size of the required memory space
- * @return Address of the alligned and big enough memory place, NULL on failure.
+ * @return Address of the aligned and big enough memory place, NULL on failure.
  */
-static inline void * malloc32(size_t size) {
+static inline void * malloc32(size_t size)
+{
 	/* This works only when the host has less than 4GB of memory as
 	 * physical address needs to fit into 32 bits */
@@ -83,13 +84,10 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Physical mallocator simulator
+/** DMA malloc simulator
  *
  * @param[in] addr Address of the place allocated by malloc32
  */
-static inline void free32(void *addr) {
-	if (!addr)
-		return;
-	free(addr);
-}
+static inline void free32(void *addr)
+	{ free(addr); }
 /*----------------------------------------------------------------------------*/
 /** Create 4KB page mapping
Index: uspace/drv/bus/usb/uhcirh/main.c
===================================================================
--- uspace/drv/bus/usb/uhcirh/main.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/uhcirh/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/uhcirh/port.c
===================================================================
--- uspace/drv/bus/usb/uhcirh/port.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/uhcirh/port.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -37,13 +37,15 @@
 #include <str_error.h>
 #include <async.h>
+#include <devman.h>
 
 #include <usb/usb.h>    /* usb_address_t */
-#include <usb/dev/hub.h>    /* usb_hc_new_device_wrapper */
 #include <usb/debug.h>
 
 #include "port.h"
 
+#define MAX_ERROR_COUNT 5
+
 static int uhci_port_check(void *port);
-static int uhci_port_reset_enable(int portno, void *arg);
+static int uhci_port_reset_enable(void *arg);
 static int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed);
 static int uhci_port_remove_device(uhci_port_t *port);
@@ -100,5 +102,6 @@
 	port->number = number;
 	port->wait_period_usec = usec;
-	port->attached_device = 0;
+	port->attached_device.fun = NULL;
+	port->attached_device.address = -1;
 	port->rh = rh;
 
@@ -150,4 +153,17 @@
 	assert(instance);
 
+	unsigned allowed_failures = MAX_ERROR_COUNT;
+#define CHECK_RET_FAIL(ret, msg...) \
+	if (ret != EOK) { \
+		usb_log_error(msg); \
+		if (!(allowed_failures-- > 0)) { \
+			usb_log_fatal( \
+			   "Maximum number of failures reached, " \
+			   "bailing out.\n"); \
+			return ret; \
+		} \
+		continue; \
+	} else (void)0
+
 	while (1) {
 		async_usleep(instance->wait_period_usec);
@@ -167,21 +183,15 @@
 		    instance->id_string, port_status);
 
+		int ret = usb_hc_connection_open(&instance->hc_connection);
+		CHECK_RET_FAIL(ret, "%s: Failed to connect to HC %s.\n",
+		    instance->id_string, str_error(ret));
+
 		/* Remove any old device */
-		if (instance->attached_device) {
-			usb_log_debug2("%s: Removing device.\n",
-			    instance->id_string);
+		if (instance->attached_device.fun) {
 			uhci_port_remove_device(instance);
 		}
 
-		int ret =
-		    usb_hc_connection_open(&instance->hc_connection);
-		if (ret != EOK) {
-			usb_log_error("%s: Failed to connect to HC.",
-			    instance->id_string);
-			continue;
-		}
-
 		if ((port_status & STATUS_CONNECTED) != 0) {
-			/* New device */
+			/* New device, this will take care of WC bits */
 			const usb_speed_t speed =
 			    ((port_status & STATUS_LOW_SPEED) != 0) ?
@@ -196,8 +206,6 @@
 
 		ret = usb_hc_connection_close(&instance->hc_connection);
-		if (ret != EOK) {
-			usb_log_error("%s: Failed to disconnect.",
-			    instance->id_string);
-		}
+		CHECK_RET_FAIL(ret, "%s: Failed to disconnect from hc: %s.\n",
+		    instance->id_string, str_error(ret));
 	}
 	return EOK;
@@ -212,5 +220,5 @@
  * Resets and enables the ub port.
  */
-int uhci_port_reset_enable(int portno, void *arg)
+int uhci_port_reset_enable(void *arg)
 {
 	uhci_port_t *port = arg;
@@ -256,11 +264,11 @@
 	usb_log_debug("%s: Detected new device.\n", port->id_string);
 
-	int ret, count = 0;
-	usb_address_t dev_addr;
+	int ret, count = MAX_ERROR_COUNT;
 	do {
 		ret = usb_hc_new_device_wrapper(port->rh, &port->hc_connection,
-		    speed, uhci_port_reset_enable, port->number, port,
-		    &dev_addr, &port->attached_device, NULL, NULL, NULL);
-	} while (ret != EOK && ++count < 4);
+		    speed, uhci_port_reset_enable, port,
+		    &port->attached_device.address, NULL, NULL,
+		    &port->attached_device.fun);
+	} while (ret != EOK && count-- > 0);
 
 	if (ret != EOK) {
@@ -271,6 +279,7 @@
 	}
 
-	usb_log_info("New device at port %u, address %d (handle %" PRIun ").\n",
-	    port->number, dev_addr, port->attached_device);
+	usb_log_info("%s: New device, address %d (handle %" PRIun ").\n",
+	    port->id_string, port->attached_device.address,
+	    port->attached_device.fun->handle);
 	return EOK;
 }
@@ -278,17 +287,42 @@
 /** Remove device.
  *
- * @param[in] port Memory structure to use.
- * @return Error code.
- *
- * Does not work, DDF does not support device removal.
- * Does not even free used USB address (it would be dangerous if tis driver
- * is still running).
+ * @param[in] port Port instance to use.
+ * @return Error code.
  */
 int uhci_port_remove_device(uhci_port_t *port)
 {
-	usb_log_error("%s: Don't know how to remove device %" PRIun ".\n",
-	    port->id_string, port->attached_device);
-	port->attached_device = 0;
-	return ENOTSUP;
+	assert(port);
+	/* There is nothing to remove. */
+	if (port->attached_device.fun == NULL) {
+		usb_log_warning("%s: Removed a ghost device.\n",
+		    port->id_string);
+		assert(port->attached_device.address == -1);
+		return EOK;
+	}
+
+	usb_log_debug("%s: Removing device.\n", port->id_string);
+
+	/* Stop driver first */
+	int ret = ddf_fun_unbind(port->attached_device.fun);
+	if (ret != EOK) {
+		usb_log_error("%s: Failed to remove child function: %s.\n",
+		   port->id_string, str_error(ret));
+		return ret;
+	}
+	ddf_fun_destroy(port->attached_device.fun);
+	port->attached_device.fun = NULL;
+
+	/* Driver stopped, free used address */
+	ret = usb_hc_unregister_device(&port->hc_connection,
+	    port->attached_device.address);
+	if (ret != EOK) {
+		usb_log_error("%s: Failed to unregister address of removed "
+		    "device: %s.\n", port->id_string, str_error(ret));
+		return ret;
+	}
+	port->attached_device.address = -1;
+
+	usb_log_info("%s: Removed attached device.\n", port->id_string);
+	return EOK;
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/uhcirh/port.h
===================================================================
--- uspace/drv/bus/usb/uhcirh/port.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/uhcirh/port.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -39,4 +39,5 @@
 #include <ddf/driver.h>
 #include <usb/hc.h> /* usb_hc_connection_t */
+#include <usb/dev/hub.h>
 
 typedef uint16_t port_status_t;
@@ -62,5 +63,5 @@
 	usb_hc_connection_t hc_connection;
 	ddf_dev_t *rh;
-	devman_handle_t attached_device;
+	usb_hub_attached_device_t attached_device;
 	fid_t checker;
 } uhci_port_t;
Index: uspace/drv/bus/usb/usbflbk/main.c
===================================================================
--- uspace/drv/bus/usb/usbflbk/main.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbflbk/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -46,5 +46,5 @@
  * @return Error code.
  */
-static int usbfallback_add_device(usb_device_t *dev)
+static int usbfallback_device_add(usb_device_t *dev)
 {
 	int rc;
@@ -64,4 +64,6 @@
 	}
 
+	dev->driver_data = ctl_fun;
+
 	usb_log_info("Pretending to control %s `%s'" \
 	    " (node `%s', handle %" PRIun ").\n",
@@ -72,11 +74,33 @@
 }
 
+/** Callback when new device is removed and recognized as gone by DDF.
+ *
+ * @param dev Representation of a generic DDF device.
+ * @return Error code.
+ */
+static int usbfallback_device_gone(usb_device_t *dev)
+{
+	assert(dev);
+	ddf_fun_t *ctl_fun = dev->driver_data;
+	const int ret = ddf_fun_unbind(ctl_fun);
+	if (ret != EOK) {
+		usb_log_error("Failed to unbind %s.\n", ctl_fun->name);
+		return ret;
+	}
+	ddf_fun_destroy(ctl_fun);
+	dev->driver_data = NULL;
+
+	return EOK;
+}
+
 /** USB fallback driver ops. */
-static usb_driver_ops_t usbfallback_driver_ops = {
-	.add_device = usbfallback_add_device,
+static const usb_driver_ops_t usbfallback_driver_ops = {
+	.device_add = usbfallback_device_add,
+	.device_rem = usbfallback_device_gone,
+	.device_gone = usbfallback_device_gone,
 };
 
 /** USB fallback driver. */
-static usb_driver_t usbfallback_driver = {
+static const usb_driver_t usbfallback_driver = {
 	.name = NAME,
 	.ops = &usbfallback_driver_ops,
Index: uspace/drv/bus/usb/usbhid/generic/hiddev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/generic/hiddev.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/generic/hiddev.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -48,8 +48,10 @@
 /*----------------------------------------------------------------------------*/
 
-usb_endpoint_description_t usb_hid_generic_poll_endpoint_description = {
+const usb_endpoint_description_t usb_hid_generic_poll_endpoint_description = {
 	.transfer_type = USB_TRANSFER_INTERRUPT,
 	.direction = USB_DIRECTION_IN,
 	.interface_class = USB_CLASS_HID,
+	.interface_subclass = -1,
+	.interface_protocol = -1,
 	.flags = 0
 };
@@ -59,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,
@@ -80,36 +75,32 @@
 	.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)
 {
 	usb_log_debug2("Generic HID: Get event length (fun: %p, "
 	    "fun->driver_data: %p.\n", fun, fun->driver_data);
-	
+
 	if (fun == NULL || fun->driver_data == NULL) {
 		return 0;
 	}
 
-	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",
 	    hid_dev, hid_dev->max_input_report_size);
-	
+
 	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)
 {
 	usb_log_debug2("Generic HID: Get event.\n");
-	
+
 	if (fun == NULL || fun->driver_data == NULL || buffer == NULL
 	    || act_size == NULL || event_nr == NULL) {
@@ -118,68 +109,62 @@
 	}
 
-	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
 	}
-	
+
 	/*! @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;
 	*event_nr = usb_hid_report_number(hid_dev);
-	
+
 	usb_log_debug2("OK\n");
-	
-	return EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 static size_t usb_generic_get_report_descriptor_length(ddf_fun_t *fun)
 {
 	usb_log_debug("Generic HID: Get report descriptor length.\n");
-	
+
 	if (fun == NULL || fun->driver_data == NULL) {
 		usb_log_debug("No function");
 		return EINVAL;
 	}
-	
-	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)
 {
 	usb_log_debug2("Generic HID: Get report descriptor.\n");
-	
+
 	if (fun == NULL || fun->driver_data == NULL) {
 		usb_log_debug("No function");
 		return EINVAL;
 	}
-	
-	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) {
 		return EINVAL;
 	}
-	
+
 	memcpy(desc, hid_dev->report_desc, hid_dev->report_desc_size);
 	*actual_size = hid_dev->report_desc_size;
-	
-	return EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 static int usb_generic_hid_client_connected(ddf_fun_t *fun)
 {
@@ -187,11 +172,29 @@
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
-static int usb_generic_hid_create_function(usb_hid_dev_t *hid_dev)
-{	
+/*----------------------------------------------------------------------------*/
+void usb_generic_hid_deinit(usb_hid_dev_t *hid_dev, void *data)
+{
+	ddf_fun_t *fun = data;
+	if (fun == NULL)
+		return;
+
+	if (ddf_fun_unbind(fun) != EOK) {
+		usb_log_error("Failed to unbind generic hid fun.\n");
+		return;
+	}
+	usb_log_debug2("%s unbound.\n", fun->name);
+	/* We did not allocate this, so leave this alone
+	 * the device would take care of it */
+	fun->driver_data = NULL;
+	ddf_fun_destroy(fun);
+}
+/*----------------------------------------------------------------------------*/
+int usb_generic_hid_init(usb_hid_dev_t *hid_dev, void **data)
+{
+	if (hid_dev == NULL) {
+		return EINVAL;
+	}
+
 	/* 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, 
@@ -201,7 +204,9 @@
 		return ENOMEM;
 	}
-	
+
+	/* 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;
-	fun->driver_data = hid_dev;
 
 	int rc = ddf_fun_bind(fun);
@@ -209,31 +214,19 @@
 		usb_log_error("Could not bind DDF function: %s.\n",
 		    str_error(rc));
+		fun->driver_data = NULL;
 		ddf_fun_destroy(fun);
 		return rc;
 	}
-	
+
 	usb_log_debug("HID function created. Handle: %" PRIun "\n", fun->handle);
-	
-	return EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-
-int usb_generic_hid_init(usb_hid_dev_t *hid_dev, void **data)
-{
-	if (hid_dev == NULL) {
-		return EINVAL;
-	}
-	
-	return usb_generic_hid_create_function(hid_dev);
-}
-
-/*----------------------------------------------------------------------------*/
-
+	*data = fun;
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 bool usb_generic_hid_polling_callback(usb_hid_dev_t *hid_dev, void *data)
 {
 	return true;
 }
-
 /**
  * @}
Index: uspace/drv/bus/usb/usbhid/generic/hiddev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/generic/hiddev.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/generic/hiddev.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -41,5 +41,6 @@
 struct usb_hid_dev;
 
-usb_endpoint_description_t usb_hid_generic_poll_endpoint_description;
+extern const usb_endpoint_description_t
+    usb_hid_generic_poll_endpoint_description;
 
 const char *HID_GENERIC_FUN_NAME;
@@ -50,4 +51,6 @@
 int usb_generic_hid_init(struct usb_hid_dev *hid_dev, void **data);
 
+void usb_generic_hid_deinit(struct usb_hid_dev *hid_dev, void *data);
+
 bool usb_generic_hid_polling_callback(struct usb_hid_dev *hid_dev, void *data);
 
Index: uspace/drv/bus/usb/usbhid/kbd/conv.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/conv.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/kbd/conv.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -87,5 +87,5 @@
 	[0x26] = KC_9,
 	[0x27] = KC_0,
-	
+
 	[0x28] = KC_ENTER,
 	[0x29] = KC_ESCAPE,
@@ -109,5 +109,5 @@
 
 	[0x39] = KC_CAPS_LOCK,
-	
+
 	[0x3a] = KC_F1,
 	[0x3b] = KC_F2,
@@ -122,5 +122,5 @@
 	[0x44] = KC_F11,
 	[0x45] = KC_F12,
-	
+
 	[0x46] = KC_PRTSCR,
 	[0x47] = KC_SCROLL_LOCK,
@@ -136,7 +136,7 @@
 	[0x51] = KC_DOWN,
 	[0x52] = KC_UP,
-	
+
 	//[0x64] = // some funny key
-	
+
 	[0xe0] = KC_LCTRL,
 	[0xe1] = KC_LSHIFT,
@@ -147,5 +147,5 @@
 	[0xe6] = KC_RALT,
 	//[0xe7] = KC_R	// TODO: right GUI
-	
+
 	[0x53] = KC_NUM_LOCK,
 	[0x54] = KC_NSLASH,
@@ -165,5 +165,5 @@
 	[0x62] = KC_N0,
 	[0x63] = KC_NPERIOD
-	
+
 };
 
@@ -186,5 +186,5 @@
 
 	key = map[scancode];
-	
+
 	return key;
 }
Index: uspace/drv/bus/usb/usbhid/kbd/kbddev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbddev.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/kbd/kbddev.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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,7 +87,6 @@
 
 /*----------------------------------------------------------------------------*/
-
 /** Keyboard polling endpoint description for boot protocol class. */
-usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description = {
+const usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description = {
 	.transfer_type = USB_TRANSFER_INTERRUPT,
 	.direction = USB_DIRECTION_IN,
@@ -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) {
@@ -237,35 +233,35 @@
 
 	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    hid_dev->report, NULL, kbd_dev->led_path, 
+	    &hid_dev->report, NULL, kbd_dev->led_path,
 	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
 	    USB_HID_REPORT_TYPE_OUTPUT);
-	
+
 	while (field != NULL) {
-		
-		if ((field->usage == USB_HID_LED_NUM_LOCK) 
+
+		if ((field->usage == USB_HID_LED_NUM_LOCK)
 		    && (kbd_dev->mods & KM_NUM_LOCK)){
 			field->value = 1;
 		}
 
-		if ((field->usage == USB_HID_LED_CAPS_LOCK) 
+		if ((field->usage == USB_HID_LED_CAPS_LOCK)
 		    && (kbd_dev->mods & KM_CAPS_LOCK)){
 			field->value = 1;
 		}
 
-		if ((field->usage == USB_HID_LED_SCROLL_LOCK) 
+		if ((field->usage == USB_HID_LED_SCROLL_LOCK)
 		    && (kbd_dev->mods & KM_SCROLL_LOCK)){
 			field->value = 1;
 		}
-		
-		field = usb_hid_report_get_sibling(hid_dev->report, field,
-		    kbd_dev->led_path,  
-	    	USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
-			USB_HID_REPORT_TYPE_OUTPUT);
-	}
-	
+
+		field = usb_hid_report_get_sibling(
+		    &hid_dev->report, field, kbd_dev->led_path,
+		USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+		    USB_HID_REPORT_TYPE_OUTPUT);
+	}
+
 	// TODO: what about the Report ID?
-	int rc = usb_hid_report_output_translate(hid_dev->report, 0,
+	int rc = usb_hid_report_output_translate(&hid_dev->report, 0,
 	    kbd_dev->output_buffer, kbd_dev->output_size);
-	
+
 	if (rc != EOK) {
 		usb_log_warning("Error translating LED output to output report"
@@ -273,14 +269,16 @@
 		return;
 	}
-	
-	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);
@@ -300,13 +297,15 @@
 		return;
 	}
-	
+
 	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,10 +340,8 @@
  * @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;
-	
+
 	/*
 	 * First of all, check if the kbd have reported phantom state.
@@ -356,53 +352,54 @@
 	 * 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;
 	}
-	
+
 	/*
 	 * Key releases
 	 */
 	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);
 		}
 	}
-	
+
 	/*
 	 * Key presses
 	 */
 	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);
 		}
 	}
-	
+
 	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                                                      */
@@ -432,28 +428,36 @@
 static void usb_kbd_process_data(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev)
 {
-	assert(hid_dev->report != NULL);
 	assert(hid_dev != NULL);
 	assert(kbd_dev != NULL);
-	
+
 	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, 
-	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+	    &hid_dev->report, NULL, path,
+	    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
 	    USB_HID_REPORT_TYPE_INPUT);
 	unsigned i = 0;
-	
+
 	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;
@@ -463,74 +467,36 @@
 		}
 		usb_log_debug2("Saved %u. key usage %d\n", i, kbd_dev->keys[i]);
-		
+
 		++i;
-		field = usb_hid_report_get_sibling(hid_dev->report, field, path, 
-		    USB_HID_PATH_COMPARE_END 
-		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+		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_REPORT_TYPE_INPUT);
 	}
-	
+
 	usb_hid_report_path_free(path);
-	
+
 	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_fatal("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_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev)
-{
-	assert(hid_dev != NULL);
-	assert(hid_dev->usb_dev != NULL);
+static int usb_kbd_create_function(usb_kbd_t *kbd_dev)
+{
 	assert(kbd_dev != NULL);
-	
+	assert(kbd_dev->hid_dev != NULL);
+	assert(kbd_dev->hid_dev->usb_dev != NULL);
+
 	/* Create the exposed function. */
 	usb_log_debug("Creating DDF function %s...\n", HID_KBD_FUN_NAME);
-	ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
-	    HID_KBD_FUN_NAME);
+	ddf_fun_t *fun = ddf_fun_create(kbd_dev->hid_dev->usb_dev->ddf_dev,
+	    fun_exposed, HID_KBD_FUN_NAME);
 	if (fun == NULL) {
 		usb_log_error("Could not create DDF function node.\n");
 		return ENOMEM;
 	}
-	
-	/*
-	 * 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;
@@ -540,12 +506,13 @@
 		usb_log_error("Could not bind DDF function: %s.\n",
 		    str_error(rc));
+		fun->driver_data = NULL; /* We did not allocate this. */
 		ddf_fun_destroy(fun);
 		return rc;
 	}
-	
+
 	usb_log_debug("%s function created. Handle: %" PRIun "\n",
 	    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,11 +521,18 @@
 		    "Could not add DDF function to category %s: %s.\n",
 		    HID_KBD_CLASS_NAME, str_error(rc));
-		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;
 	}
-	
+	kbd_dev->fun = fun;
+
 	return EOK;
 }
-
 /*----------------------------------------------------------------------------*/
 /* API functions                                                              */
@@ -587,186 +561,167 @@
 {
 	usb_log_debug("Initializing HID/KBD structure...\n");
-	
+
 	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);
-	
+
 	usb_log_debug("Size of the input report: %zu\n", kbd_dev->key_count);
-	
-	kbd_dev->keys = (int32_t *)calloc(kbd_dev->key_count, sizeof(int32_t));
-	
+
+	kbd_dev->keys = calloc(kbd_dev->key_count, sizeof(int32_t));
 	if (kbd_dev->keys == NULL) {
-		usb_log_fatal("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_fatal("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_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;
 	}
-	
+
 	usb_log_debug("Output buffer size: %zu\n", kbd_dev->output_size);
-	
+
 	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);
-	
-	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", 
+	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",
 	    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;
-	
-	kbd_dev->repeat_mtx = (fibril_mutex_t *)(
-	    malloc(sizeof(fibril_mutex_t)));
-	if (kbd_dev->repeat_mtx == NULL) {
-		usb_log_fatal("No memory!\n");
-		free(kbd_dev->keys);
-		usb_hid_report_output_free(kbd_dev->output_buffer);
-		free(kbd_dev);
-		return ENOMEM;
-	}
-	
-	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(hid_dev, 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);
-	
+
 	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);
 }
-
 /*----------------------------------------------------------------------------*/
 /**
@@ -780,60 +735,55 @@
 		return;
 	}
-	
-	// hangup session to the console
-	async_hangup(kbd_dev->console_sess);
-	
-	if (kbd_dev->repeat_mtx != NULL) {
-		//assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
-		// FIXME - the fibril_mutex_is_locked may not cause
-		// fibril scheduling
-		while (fibril_mutex_is_locked(kbd_dev->repeat_mtx)) {}
-		free(kbd_dev->repeat_mtx);
-	}
-	
-	// free all buffers
-	if (kbd_dev->keys != NULL) {
-		free(kbd_dev->keys);
-	}
-	if (kbd_dev->keys_old != NULL) {
-		free(kbd_dev->keys_old);
-	}
-	if (kbd_dev->led_data != NULL) {
-		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);
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
+
+	/* 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));
+	// FIXME - the fibril_mutex_is_locked may not cause
+	// fibril scheduling
+	while (fibril_mutex_is_locked(&kbd_dev->repeat_mtx)) {}
+
+	/* Free all buffers. */
+	free(kbd_dev->keys);
+	free(kbd_dev->keys_old);
+	free(kbd_dev->led_data);
+
+	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 = (usb_kbd_t *)data;
+		usb_kbd_t *kbd_dev = data;
 		if (usb_kbd_is_initialized(kbd_dev)) {
-			usb_kbd_mark_unusable(kbd_dev);
-		} else {
-			usb_kbd_destroy(kbd_dev);
-		}
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
+			kbd_dev->initialized = USB_KBD_STATUS_TO_DESTROY;
+			/* Wait for autorepeat */
+			async_usleep(CHECK_DELAY);
+		}
+		usb_kbd_destroy(kbd_dev);
+	}
+}
+/*----------------------------------------------------------------------------*/
 int usb_kbd_set_boot_protocol(usb_hid_dev_t *hid_dev)
 {
-	int rc = usb_hid_parse_report_descriptor(hid_dev->report, 
-	    USB_KBD_BOOT_REPORT_DESCRIPTOR, 
-	    USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE);
-	
+	assert(hid_dev);
+	int rc = usb_hid_parse_report_descriptor(
+	    &hid_dev->report, USB_KBD_BOOT_REPORT_DESCRIPTOR,
+	    sizeof(USB_KBD_BOOT_REPORT_DESCRIPTOR));
+
 	if (rc != EOK) {
 		usb_log_error("Failed to parse boot report descriptor: %s\n",
@@ -841,8 +791,8 @@
 		return rc;
 	}
-	
-	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe, 
+
+	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe,
 	    hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
-	
+
 	if (rc != EOK) {
 		usb_log_warning("Failed to set boot protocol to the device: "
@@ -850,8 +800,7 @@
 		return rc;
 	}
-	
+
 	return EOK;
 }
-
 /**
  * @}
Index: uspace/drv/bus/usb/usbhid/kbd/kbddev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbddev.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/kbd/kbddev.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -75,33 +75,33 @@
 	/** Currently pressed modifiers (bitmap). */
 	uint8_t modifiers;
-	
+
 	/** Currently active modifiers including locks. Sent to the console. */
 	unsigned mods;
-	
+
 	/** Currently active lock keys. */
 	unsigned lock_keys;
-	
+
 	/** IPC session to the console device (for sending key events). */
 	async_sess_t *console_sess;
-	
+
 	/** @todo What is this actually? */
 	ddf_dev_ops_t ops;
-	
+
 	/** Information for auto-repeat of keys. */
 	usb_kbd_repeat_t repeat;
-	
+
 	/** Mutex for accessing the information about auto-repeat. */
-	fibril_mutex_t *repeat_mtx;
-	
+	fibril_mutex_t repeat_mtx;
+
 	uint8_t *output_buffer;
-	
+
 	size_t output_size;
-	
+
 	size_t led_output_size;
-	
+
 	usb_hid_report_path_t *led_path;
-	
+
 	int32_t *led_data;
-	
+
 	/** State of the structure (for checking before use). 
 	 * 
@@ -111,9 +111,12 @@
 	 */
 	int initialized;
+
+	/** DDF function */
+	ddf_fun_t *fun;
 } usb_kbd_t;
 
 /*----------------------------------------------------------------------------*/
 
-usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description;
+extern const usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description;
 
 const char *HID_KBD_FUN_NAME;
@@ -132,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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/kbd/kbdrepeat.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -45,9 +45,4 @@
 #include "kbddev.h"
 
-
-/** Delay between auto-repeat state checks when no key is being repeated. */
-static unsigned int CHECK_DELAY = 10000;
-
-/*----------------------------------------------------------------------------*/
 /**
  * Main loop handling the auto-repeat of keys.
@@ -60,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.
  */
@@ -73,24 +68,21 @@
 {
 	unsigned int delay = 0;
-	
+
 	usb_log_debug("Starting autorepeat loop.\n");
 
 	while (true) {
-		// check if the kbd structure is usable
+		/* Check if the kbd structure is usable. */
 		if (!usb_kbd_is_initialized(kbd)) {
-			if (usb_kbd_is_ready_to_destroy(kbd)) {
-				usb_kbd_destroy(kbd);
-			}
+			usb_log_warning("kbd not ready, exiting autorepeat.\n");
 			return;
 		}
-		
-		fibril_mutex_lock(kbd->repeat_mtx);
+
+		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;
@@ -109,10 +101,8 @@
 			delay = CHECK_DELAY;
 		}
-		fibril_mutex_unlock(kbd->repeat_mtx);
-		
+		fibril_mutex_unlock(&kbd->repeat_mtx);
 		async_usleep(delay);
 	}
 }
-
 /*----------------------------------------------------------------------------*/
 /**
@@ -120,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.
@@ -130,17 +120,16 @@
 {
 	usb_log_debug("Autorepeat fibril spawned.\n");
-	
+
 	if (arg == NULL) {
 		usb_log_error("No device!\n");
 		return EINVAL;
 	}
-	
-	usb_kbd_t *kbd = (usb_kbd_t *)arg;
-	
+
+	usb_kbd_t *kbd = arg;
+
 	usb_kbd_repeat_loop(kbd);
-	
+
 	return EOK;
 }
-
 /*----------------------------------------------------------------------------*/
 /**
@@ -156,9 +145,8 @@
 void usb_kbd_repeat_start(usb_kbd_t *kbd, unsigned int key)
 {
-	fibril_mutex_lock(kbd->repeat_mtx);
+	fibril_mutex_lock(&kbd->repeat_mtx);
 	kbd->repeat.key_new = key;
-	fibril_mutex_unlock(kbd->repeat_mtx);
+	fibril_mutex_unlock(&kbd->repeat_mtx);
 }
-
 /*----------------------------------------------------------------------------*/
 /**
@@ -166,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).
  *
@@ -174,11 +162,10 @@
 void usb_kbd_repeat_stop(usb_kbd_t *kbd, unsigned int key)
 {
-	fibril_mutex_lock(kbd->repeat_mtx);
+	fibril_mutex_lock(&kbd->repeat_mtx);
 	if (key == kbd->repeat.key_new) {
 		kbd->repeat.key_new = 0;
 	}
-	fibril_mutex_unlock(kbd->repeat_mtx);
+	fibril_mutex_unlock(&kbd->repeat_mtx);
 }
-
 /**
  * @}
Index: uspace/drv/bus/usb/usbhid/kbd/kbdrepeat.h
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbdrepeat.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/kbd/kbdrepeat.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -37,4 +37,7 @@
 #define USB_HID_KBDREPEAT_H_
 
+/** Delay between auto-repeat state checks when no key is being repeated. */
+#define CHECK_DELAY 10000
+
 struct usb_kbd_t;
 
Index: uspace/drv/bus/usb/usbhid/main.c
===================================================================
--- uspace/drv/bus/usb/usbhid/main.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -46,72 +46,47 @@
 #include "usbhid.h"
 
-/*----------------------------------------------------------------------------*/
-
 #define NAME "usbhid"
 
 /**
- * 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.
- *
- * @retval EOK if successful.
- * @retval ENOMEM if there
- * @return Other error code inherited from one of functions usb_kbd_init(),
- *         ddf_fun_bind() and ddf_fun_add_to_class().
+ * @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);
-	
-	/* 
-	 * Initialize device (get and process descriptors, get address, etc.)
-	 */
-	usb_log_debug("Initializing USB/HID device...\n");
-	
-	usb_hid_dev_t *hid_dev = usb_hid_new();
+	usb_log_debug("%s\n", __FUNCTION__);
+
+	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");
-		usb_hid_destroy(hid_dev);
+		usb_hid_deinit(hid_dev);
 		return rc;
-	}	
-	
+	}
+
 	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. */
@@ -120,82 +95,76 @@
 	   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,
 	   /* Custom argument. */
 	   hid_dev);
-	
-	
+
 	if (rc != EOK) {
 		usb_log_error("Failed to start polling fibril for `%s'.\n",
 		    dev->ddf_dev->name);
+		usb_hid_deinit(hid_dev);
 		return rc;
 	}
+	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.
- *
- * @retval EOK if successful. 
- * @retval EREFUSED if the device is not supported.
- */
-static int usb_hid_add_device(usb_device_t *dev)
-{
-	usb_log_debug("usb_hid_add_device()\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);
 
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
+/**
+ * Callback for a device about to be removed from the driver.
+ *
+ * @param dev Structure representing the device.
+ * @return Error code.
+ */
+static int usb_hid_device_rem(usb_device_t *dev)
+{
+	// TODO: Stop device polling
+	// TODO: Call deinit (stops autorepeat too)
+	return ENOTSUP;
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Callback for removing a device from the driver.
+ *
+ * @param dev Structure representing the device.
+ * @return Error code.
+ */
+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 = 100;
+	/* Wait for fail. */
+	while (hid_dev->running && tries--) {
+		async_usleep(100000);
+	}
+	if (hid_dev->running) {
+		usb_log_error("Can't remove hid, still running.\n");
+		return EBUSY;
+	}
 
+	usb_hid_deinit(hid_dev);
+	usb_log_debug2("%s destruction complete.\n", dev->ddf_dev->name);
+	return EOK;
+}
 /*----------------------------------------------------------------------------*/
-
-/* Currently, the framework supports only device adding. Once the framework
- * supports unplug, more callbacks will be added. */
-static usb_driver_ops_t usb_hid_driver_ops = {
-        .add_device = usb_hid_add_device,
+/** USB generic driver callbacks */
+static const usb_driver_ops_t usb_hid_driver_ops = {
+	.device_add = usb_hid_device_add,
+	.device_rem = usb_hid_device_rem,
+	.device_gone = usb_hid_device_gone,
 };
-
-
-/* The driver itself. */
-static usb_driver_t usb_hid_driver = {
+/*----------------------------------------------------------------------------*/
+/** The driver itself. */
+static const usb_driver_t usb_hid_driver = {
         .name = NAME,
         .ops = &usb_hid_driver_ops,
         .endpoints = usb_hid_endpoints
 };
-
 /*----------------------------------------------------------------------------*/
-
 int main(int argc, char *argv[])
 {
@@ -206,5 +175,4 @@
 	return usb_driver_main(&usb_hid_driver);
 }
-
 /**
  * @}
Index: uspace/drv/bus/usb/usbhid/mouse/mousedev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -55,9 +55,9 @@
 #define ARROWS_PER_SINGLE_WHEEL 3
 
-#define NAME  "mouse"
-
-/*----------------------------------------------------------------------------*/
-
-usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {
+#define NAME "mouse"
+
+/*----------------------------------------------------------------------------*/
+
+const usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {
 	.transfer_type = USB_TRANSFER_INTERRUPT,
 	.direction = USB_DIRECTION_IN,
@@ -75,14 +75,7 @@
 /** Default idle rate for mouses. */
 static const uint8_t IDLE_RATE = 0;
-static const size_t USB_MOUSE_BUTTON_COUNT = 3;
-
-/*----------------------------------------------------------------------------*/
-
-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)
@@ -124,22 +117,19 @@
     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;
-	
+
 	async_sess_t *sess =
 	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
@@ -147,44 +137,16 @@
 		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);
 }
 
@@ -200,9 +162,8 @@
 		return;
 	}
-	
-	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);
@@ -247,5 +208,5 @@
 {
 	assert(mouse_dev != NULL);
-	
+
 	if (mouse_dev->mouse_sess == NULL) {
 		usb_log_warning(NAME " No console session.\n");
@@ -253,83 +214,107 @@
 	}
 
-	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,
-	    hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_Y);
-	int wheel = get_mouse_axis_move_value(hid_dev->report_id,
-	    hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
+	const int shift_x = get_mouse_axis_move_value(hid_dev->report_id,
+	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_X);
+	const int shift_y = get_mouse_axis_move_value(hid_dev->report_id,
+	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_Y);
+	const int wheel = get_mouse_axis_move_value(hid_dev->report_id,
+	    &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
 
 	if ((shift_x != 0) || (shift_y != 0)) {
-		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);
-	}
-	
+		async_exch_t *exch =
+		    async_exchange_begin(mouse_dev->mouse_sess);
+		if (exch != NULL) {
+			async_req_2_0(exch, MOUSEEV_MOVE_EVENT, shift_x, shift_y);
+			async_exchange_end(exch);
+		}
+	}
+
 	if (wheel != 0)
 		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);
-	
+
 	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
-	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
-	    USB_HID_REPORT_TYPE_INPUT);
+	    &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
+	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, USB_HID_REPORT_TYPE_INPUT);
 
 	while (field != NULL) {
 		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;
+			}
 		}
-		
+
 		field = usb_hid_report_get_sibling(
-		    hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
-		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
+		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
 		    USB_HID_REPORT_TYPE_INPUT);
 	}
-	
+
 	usb_hid_report_path_free(path);
 
 	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)
 {
 	assert(hid_dev != NULL);
 	assert(mouse != NULL);
-	
+
 	/* 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;
 	}
-	
+
 	fun->ops = &mouse->ops;
 	fun->driver_data = mouse;
@@ -337,12 +322,13 @@
 	int 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->driver_data = NULL;
 		ddf_fun_destroy(fun);
 		return rc;
 	}
-	
-	usb_log_debug("Adding DDF function to category %s...\n", 
-	    HID_MOUSE_CATEGORY);
+
+	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) {
@@ -350,20 +336,24 @@
 		    "Could not add DDF function to category %s: %s.\n",
 		    HID_MOUSE_CATEGORY, str_error(rc));
-		ddf_fun_destroy(fun);
-		return rc;
-	}
-	
+		FUN_UNBIND_DESTROY(fun);
+		return rc;
+	}
+	mouse->mouse_fun = fun;
+
 	/*
 	 * 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;
 	}
-	
+
 	/*
 	 * Store the initialized HID device and HID ops
@@ -375,10 +365,14 @@
 	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;
 	}
-	
+
 	usb_log_debug("Adding DDF function to category %s...\n", 
 	    HID_MOUSE_WHEEL_CATEGORY);
@@ -388,8 +382,12 @@
 		    "Could not add DDF function to category %s: %s.\n",
 		    HID_MOUSE_WHEEL_CATEGORY, str_error(rc));
-		ddf_fun_destroy(fun);
-		return rc;
-	}
-	
+
+		FUN_UNBIND_DESTROY(mouse->mouse_fun);
+		mouse->mouse_fun = NULL;
+		FUN_UNBIND_DESTROY(fun);
+		return rc;
+	}
+	mouse->wheel_fun = fun;
+
 	return EOK;
 }
@@ -397,8 +395,48 @@
 /*----------------------------------------------------------------------------*/
 
+/** Get highest index of a button mentioned in given report.
+ *
+ * @param report HID report.
+ * @param report_id Report id we are interested in.
+ * @return Highest button mentioned in the report.
+ * @retval 1 No button was mentioned.
+ *
+ */
+static size_t usb_mouse_get_highest_button(usb_hid_report_t *report, uint8_t report_id)
+{
+	size_t highest_button = 0;
+
+	usb_hid_report_path_t *path = usb_hid_report_path();
+	usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0);
+	usb_hid_report_path_set_report_id(path, report_id);
+
+	usb_hid_report_field_t *field = NULL;
+
+	/* Break from within. */
+	while (1) {
+		field = usb_hid_report_get_sibling(
+		    report, field, path,
+		    USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
+		    USB_HID_REPORT_TYPE_INPUT);
+		/* No more buttons? */
+		if (field == NULL) {
+			break;
+		}
+
+		size_t current_button = field->usage - field->usage_minimum;
+		if (current_button > highest_button) {
+			highest_button = current_button;
+		}
+	}
+
+	usb_hid_report_path_free(path);
+
+	return highest_button;
+}
+/*----------------------------------------------------------------------------*/
 int usb_mouse_init(usb_hid_dev_t *hid_dev, void **data)
 {
 	usb_log_debug("Initializing HID/Mouse structure...\n");
-	
+
 	if (hid_dev == NULL) {
 		usb_log_error("Failed to init keyboard structure: no structure"
@@ -406,6 +444,6 @@
 		return EINVAL;
 	}
-	
-	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 "
@@ -413,65 +451,89 @@
 		return ENOMEM;
 	}
-	
-	mouse_dev->buttons = (int32_t *)calloc(USB_MOUSE_BUTTON_COUNT, 
-	    sizeof(int32_t));
-	
+
+	// FIXME: This may not be optimal since stupid hardware vendor may
+	// use buttons 1, 2, 3 and 6000 and we would allocate array of
+	// 6001*4B and use only 4 items in it.
+	// Since I doubt that hardware producers would do that, I think
+	// that the current solution is good enough.
+	/* Adding 1 because we will be accessing buttons[highest]. */
+	mouse_dev->buttons_count = 1 + usb_mouse_get_highest_button(
+	    &hid_dev->report, hid_dev->report_id);
+	mouse_dev->buttons = calloc(mouse_dev->buttons_count, sizeof(int32_t));
+
 	if (mouse_dev->buttons == NULL) {
-		usb_log_fatal("No memory!\n");
+		usb_log_error(NAME ": out of memory, giving up on device!\n");
 		free(mouse_dev);
 		return ENOMEM;
 	}
-	
-	// 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((usb_mouse_t *)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);
-	
+	int rc = usb_hid_parse_report_descriptor(
+	    &hid_dev->report, USB_MOUSE_BOOT_REPORT_DESCRIPTOR,
+	    sizeof(USB_MOUSE_BOOT_REPORT_DESCRIPTOR));
+
 	if (rc != EOK) {
 		usb_log_error("Failed to parse boot report descriptor: %s\n",
@@ -479,8 +541,8 @@
 		return rc;
 	}
-	
-	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe, 
+
+	rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe,
 	    hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
-	
+
 	if (rc != EOK) {
 		usb_log_warning("Failed to set boot protocol to the device: "
@@ -488,5 +550,5 @@
 		return rc;
 	}
-	
+
 	return EOK;
 }
Index: uspace/drv/bus/usb/usbhid/mouse/mousedev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -49,13 +49,19 @@
 	async_sess_t *mouse_sess;
 	async_sess_t *wheel_sess;
-	
+
+	/* Mouse buttons statuses. */
 	int32_t *buttons;
-	
+	size_t buttons_count;
+
 	ddf_dev_ops_t ops;
+	/* DDF mouse function */
+	ddf_fun_t *mouse_fun;
+	/* DDF mouse function */
+	ddf_fun_t *wheel_fun;
 } usb_mouse_t;
 
 /*----------------------------------------------------------------------------*/
 
-usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description;
+extern const usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description;
 
 const char *HID_MOUSE_FUN_NAME;
Index: uspace/drv/bus/usb/usbhid/multimedia/multimedia.c
===================================================================
--- uspace/drv/bus/usb/usbhid/multimedia/multimedia.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/multimedia/multimedia.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -64,5 +64,5 @@
 	//int32_t *keys;
 	/** Count of stored keys (i.e. number of keys in the report). */
-	//size_t key_count;	
+	//size_t key_count;
 	/** IPC session to the console device (for sending key events). */
 	async_sess_t *console_sess;
@@ -71,5 +71,5 @@
 
 /*----------------------------------------------------------------------------*/
-/** 
+/**
  * Default handler for IPC methods not handled by DDF.
  *
@@ -86,12 +86,11 @@
 {
 	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 =
 	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
@@ -107,11 +106,8 @@
 		async_answer_0(icallid, EINVAL);
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static ddf_dev_ops_t multimedia_ops = {
 	.default_handler = default_connection_handler
 };
-
 /*----------------------------------------------------------------------------*/
 /**
@@ -125,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);
@@ -151,38 +146,54 @@
 		return;
 	}
-	
+
 	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);
-}
-
-/*----------------------------------------------------------------------------*/
-
-static int usb_multimedia_create_function(usb_hid_dev_t *hid_dev, 
-    usb_multimedia_t *multim_dev)
-{
+	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;
+	}
+
+	usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
+
 	/* Create the exposed function. */
-	ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
-	    NAME);
+	ddf_fun_t *fun = ddf_fun_create(
+	    hid_dev->usb_dev->ddf_dev, fun_exposed, NAME);
 	if (fun == NULL) {
 		usb_log_error("Could not create DDF function node.\n");
 		return ENOMEM;
 	}
-	
+
 	fun->ops = &multimedia_ops;
-	fun->driver_data = multim_dev;   // TODO: maybe change to hid_dev->data
-	
+
+	usb_multimedia_t *multim_dev =
+	    ddf_fun_data_alloc(fun, sizeof(usb_multimedia_t));
+	if (multim_dev == NULL) {
+		ddf_fun_destroy(fun);
+		return ENOMEM;
+	}
+
+	multim_dev->console_sess = NULL;
+
+	//todo Autorepeat?
+
 	int rc = ddf_fun_bind(fun);
 	if (rc != EOK) {
 		usb_log_error("Could not bind DDF function: %s.\n",
 		    str_error(rc));
-		// TODO: Can / should I destroy the DDF function?
 		ddf_fun_destroy(fun);
 		return rc;
 	}
-	
-	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");
 	if (rc != EOK) {
@@ -190,109 +201,95 @@
 		    "Could not add DDF function to category 'keyboard': %s.\n",
 		    str_error(rc));
-		// TODO: Can / should I destroy the DDF function?
-		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 = fun;
+
+	usb_log_debug(NAME " HID/multimedia structure initialized.\n");
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
-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? */
-	}
-	
-	usb_log_debug(NAME " Initializing HID/multimedia structure...\n");
-	
-	usb_multimedia_t *multim_dev = (usb_multimedia_t *)malloc(
-	    sizeof(usb_multimedia_t));
-	if (multim_dev == NULL) {
-		return ENOMEM;
-	}
-	
-	multim_dev->console_sess = NULL;
-	
-	/*! @todo Autorepeat */
-	
-	// save the KBD device structure into the HID device structure
-	*data = multim_dev;
-	
-	usb_log_debug(NAME " HID/multimedia device structure initialized.\n");
-	
-	int rc = usb_multimedia_create_function(hid_dev, multim_dev);
-	if (rc != EOK)
-		return rc;
-	
-	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);
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-
+	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", 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);
 
 	usb_hid_report_field_t *field = usb_hid_report_get_sibling(
-	    hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END 
-	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY, 
+	    &hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
+	    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
 	    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, 
+		    &hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
+		    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
 		    USB_HID_REPORT_TYPE_INPUT);
-	}	
+	}
 
 	usb_hid_report_path_free(path);
-	
+
 	return true;
 }
-
 /**
  * @}
Index: uspace/drv/bus/usb/usbhid/subdrivers.c
===================================================================
--- uspace/drv/bus/usb/usbhid/subdrivers.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/subdrivers.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -42,16 +42,16 @@
 #include "generic/hiddev.h"
 
-static usb_hid_subdriver_usage_t path_kbd[] = {
-	{USB_HIDUT_PAGE_GENERIC_DESKTOP, 
-	 USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD}, 
+static const usb_hid_subdriver_usage_t path_kbd[] = {
+	{USB_HIDUT_PAGE_GENERIC_DESKTOP,
+	 USB_HIDUT_USAGE_GENERIC_DESKTOP_KEYBOARD},
 	{0, 0}
 };
 
-static usb_hid_subdriver_usage_t path_mouse[] = {
+static const usb_hid_subdriver_usage_t path_mouse[] = {
 	{USB_HIDUT_PAGE_GENERIC_DESKTOP, USB_HIDUT_USAGE_GENERIC_DESKTOP_MOUSE},
 	{0, 0}
 };
 
-static usb_hid_subdriver_usage_t multim_key_path[] = {
+static const usb_hid_subdriver_usage_t multim_key_path[] = {
 	{USB_HIDUT_PAGE_CONSUMER, USB_HIDUT_USAGE_CONSUMER_CONSUMER_CONTROL},
 	{0, 0}
@@ -71,5 +71,4 @@
 			.poll_end = NULL
 		},
-		
 	},
 	{
@@ -99,6 +98,8 @@
 		}
 	},
-	{NULL, -1, 0, -1, -1, {NULL, NULL, NULL, NULL, NULL}}
 };
+
+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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/subdrivers.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -64,19 +64,19 @@
 	 */
 	const usb_hid_subdriver_usage_t *usage_path;
-	
+
 	/** Report ID for which the path should apply. */
 	int report_id;
-	
+
 	/** Compare type for the Usage path. */
 	int compare;
-	
+
 	/** Vendor ID (set to -1 if not specified). */
 	int vendor_id;
-	
+
 	/** Product ID (set to -1 if not specified). */
 	int product_id;
-	
+
 	/** Subdriver for controlling this device. */
-	usb_hid_subdriver_t subdriver;
+	const usb_hid_subdriver_t subdriver;
 } usb_hid_subdriver_mapping_t;
 
@@ -84,4 +84,5 @@
 
 extern const usb_hid_subdriver_mapping_t usb_hid_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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/usbhid.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -51,8 +51,6 @@
 #include "subdrivers.h"
 
-/*----------------------------------------------------------------------------*/
-
 /* Array of endpoints expected on the device, NULL terminated. */
-usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1] = {
+const usb_endpoint_description_t *usb_hid_endpoints[] = {
 	&usb_hid_kbd_poll_endpoint_description,
 	&usb_hid_mouse_poll_endpoint_description,
@@ -60,129 +58,75 @@
 	NULL
 };
-
-static const int USB_HID_MAX_SUBDRIVERS = 10;
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int usb_hid_set_boot_kbd_subdriver(usb_hid_dev_t *hid_dev)
 {
-	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
-	
-	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
-	    sizeof(usb_hid_subdriver_t));
+	assert(hid_dev != NULL);
+	assert(hid_dev->subdriver_count == 0);
+
+	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
 	if (hid_dev->subdrivers == NULL) {
 		return ENOMEM;
 	}
-	
-	assert(hid_dev->subdriver_count >= 0);
-	
-	// set the init callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].init = usb_kbd_init;
-	
-	// set the polling callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll = 
-	    usb_kbd_polling_callback;
-	
-	// set the polling ended callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll_end = NULL;
-	
-	// set the deinit callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].deinit = usb_kbd_deinit;
-	
-	// set subdriver count
-	++hid_dev->subdriver_count;
-	
+	hid_dev->subdriver_count = 1;
+	// TODO 0 should be keyboard, but find a better way
+	hid_dev->subdrivers[0] = usb_hid_subdrivers[0].subdriver;
+
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int usb_hid_set_boot_mouse_subdriver(usb_hid_dev_t *hid_dev)
 {
-	assert(hid_dev != NULL && hid_dev->subdriver_count == 0);
-	
-	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
-	    sizeof(usb_hid_subdriver_t));
+	assert(hid_dev != NULL);
+	assert(hid_dev->subdriver_count == 0);
+
+	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
 	if (hid_dev->subdrivers == NULL) {
 		return ENOMEM;
 	}
-	
-	assert(hid_dev->subdriver_count >= 0);
-	
-	// set the init callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].init = usb_mouse_init;
-	
-	// set the polling callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll = 
-	    usb_mouse_polling_callback;
-	
-	// set the polling ended callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll_end = NULL;
-	
-	// set the deinit callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].deinit = usb_mouse_deinit;
-	
-	// set subdriver count
-	++hid_dev->subdriver_count;
-	
+	hid_dev->subdriver_count = 1;
+	// TODO 2 should be mouse, but find a better way
+	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);
-	
-	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc(
-	    sizeof(usb_hid_subdriver_t));
+	assert(hid_dev != NULL);
+	assert(hid_dev->subdriver_count == 0);
+
+	hid_dev->subdrivers = malloc(sizeof(usb_hid_subdriver_t));
 	if (hid_dev->subdrivers == NULL) {
 		return ENOMEM;
 	}
-	
-	assert(hid_dev->subdriver_count >= 0);
-	
-	// set the init callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].init =
-	    usb_generic_hid_init;
-	
-	// set the polling callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll = 
-	    usb_generic_hid_polling_callback;
-	
-	// set the polling ended callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].poll_end = NULL;
-	
-	// set the deinit callback
-	hid_dev->subdrivers[hid_dev->subdriver_count].deinit = NULL;
-	
-	// set subdriver count
-	++hid_dev->subdriver_count;
-	
+	hid_dev->subdriver_count = 1;
+
+	/* Set generic hid subdriver routines */
+	hid_dev->subdrivers[0].init = usb_generic_hid_init;
+	hid_dev->subdrivers[0].poll = usb_generic_hid_polling_callback;
+	hid_dev->subdrivers[0].poll_end = NULL;
+	hid_dev->subdrivers[0].deinit = usb_generic_hid_deinit;
+
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
-static bool usb_hid_ids_match(usb_hid_dev_t *hid_dev, 
+/*----------------------------------------------------------------------------*/
+static bool usb_hid_ids_match(const usb_hid_dev_t *hid_dev,
     const usb_hid_subdriver_mapping_t *mapping)
 {
 	assert(hid_dev != NULL);
 	assert(hid_dev->usb_dev != NULL);
-	
-	return (hid_dev->usb_dev->descriptors.device.vendor_id 
+
+	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, 
+/*----------------------------------------------------------------------------*/
+static bool usb_hid_path_matches(usb_hid_dev_t *hid_dev,
     const usb_hid_subdriver_mapping_t *mapping)
 {
 	assert(hid_dev != NULL);
 	assert(mapping != NULL);
-	
+
 	usb_hid_report_path_t *usage_path = usb_hid_report_path();
 	if (usage_path == NULL) {
@@ -190,9 +134,9 @@
 		return false;
 	}
-	int i = 0;
-	while (mapping->usage_path[i].usage != 0 
-	    || mapping->usage_path[i].usage_page != 0) {
-		if (usb_hid_report_path_append_item(usage_path, 
-		    mapping->usage_path[i].usage_page, 
+
+	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,
 		    mapping->usage_path[i].usage) != EOK) {
 			usb_log_debug("Failed to append to usage path.\n");
@@ -200,11 +144,8 @@
 			return false;
 		}
-		++i;
-	}
-	
-	assert(hid_dev->report != NULL);
-	
+	}
+
 	usb_log_debug("Compare flags: %d\n", mapping->compare);
-	
+
 	bool matches = false;
 	uint8_t report_id = mapping->report_id;
@@ -212,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,
@@ -218,9 +158,9 @@
 		}
 
-		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);
 
@@ -229,87 +169,71 @@
 			break;
 		}
-		
+
 		report_id = usb_hid_get_next_report_id(
-		    hid_dev->report, report_id,
-		    USB_HID_REPORT_TYPE_INPUT);
+		    &hid_dev->report, report_id, USB_HID_REPORT_TYPE_INPUT);
 	} while (!matches && report_id != 0);
-	
+
 	usb_hid_report_path_free(usage_path);
-	
+
 	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) {
+/*----------------------------------------------------------------------------*/
+static int usb_hid_save_subdrivers(usb_hid_dev_t *hid_dev,
+    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;
 		return EOK;
 	}
-	
-	// add one generic HID subdriver per device
-	
-	hid_dev->subdrivers = (usb_hid_subdriver_t *)malloc((count + 1) * 
-	    sizeof(usb_hid_subdriver_t));
+
+	/* +1 for generic hid subdriver */
+	hid_dev->subdrivers = calloc((count + 1), sizeof(usb_hid_subdriver_t));
 	if (hid_dev->subdrivers == NULL) {
 		return ENOMEM;
 	}
-	
-	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];
+	}
+
+	/* Add one generic HID subdriver per device */
 	hid_dev->subdrivers[count].init = usb_generic_hid_init;
 	hid_dev->subdrivers[count].poll = usb_generic_hid_polling_callback;
-	hid_dev->subdrivers[count].deinit = NULL;
+	hid_dev->subdrivers[count].deinit = usb_generic_hid_deinit;
 	hid_dev->subdrivers[count].poll_end = NULL;
-	
+
 	hid_dev->subdriver_count = count + 1;
-	
+
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
 static int usb_hid_find_subdrivers(usb_hid_dev_t *hid_dev)
 {
 	assert(hid_dev != NULL);
-	
+
 	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,
@@ -317,174 +241,144 @@
 			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;
-		}
-		
+		}
+
 		if (matched) {
 			usb_log_debug("Subdriver matched.\n");
 			subdrivers[count++] = &mapping->subdriver;
 		}
-		
-		mapping = &usb_hid_subdrivers[++i];
-	}
-	
-	// we have all subdrivers determined, save them into the hid device
+	}
+
+	/* We have all subdrivers determined, save them into the hid device */
 	return usb_hid_save_subdrivers(hid_dev, subdrivers, count);
 }
-
-/*----------------------------------------------------------------------------*/
-
-static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, usb_device_t *dev)
-{
-	assert(hid_dev != NULL && dev != NULL);
-	
-	int rc = EOK;
-	
-	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");
-		rc = ENOTSUP;
-	}
-	
-	return rc;
-}
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
+static int usb_hid_check_pipes(usb_hid_dev_t *hid_dev, const usb_device_t *dev)
+{
+	assert(hid_dev);
+	assert(dev);
+
+	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)
 {
-	assert(hid_dev != NULL && hid_dev->report != NULL);
-	
+	assert(hid_dev != NULL);
+
 	uint8_t report_id = 0;
-	size_t size;
-	
 	size_t max_size = 0;
-	
+
 	do {
 		usb_log_debug("Getting size of the report.\n");
-		size = usb_hid_report_byte_size(hid_dev->report, report_id, 
-		    USB_HID_REPORT_TYPE_INPUT);
+		const size_t size =
+		    usb_hid_report_byte_size(&hid_dev->report, report_id,
+		        USB_HID_REPORT_TYPE_INPUT);
 		usb_log_debug("Report ID: %u, size: %zu\n", report_id, size);
 		max_size = (size > max_size) ? size : max_size;
 		usb_log_debug("Getting next report ID\n");
-		report_id = usb_hid_get_next_report_id(hid_dev->report, 
+		report_id = usb_hid_get_next_report_id(&hid_dev->report,
 		    report_id, USB_HID_REPORT_TYPE_INPUT);
 	} while (report_id != 0);
-	
+
 	usb_log_debug("Max size of input report: %zu\n", max_size);
-	
-	hid_dev->max_input_report_size = max_size;
+
 	assert(hid_dev->input_report == NULL);
-	
-	hid_dev->input_report = malloc(max_size);
+
+	hid_dev->input_report = calloc(1, max_size);
 	if (hid_dev->input_report == NULL) {
 		return ENOMEM;
 	}
-	memset(hid_dev->input_report, 0, max_size);
-	
+	hid_dev->max_input_report_size = max_size;
+
 	return EOK;
 }
-
-/*----------------------------------------------------------------------------*/
-
-usb_hid_dev_t *usb_hid_new(void)
-{
-	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)calloc(1,
-	    sizeof(usb_hid_dev_t));
-	
-	if (hid_dev == NULL) {
-		usb_log_fatal("No memory!\n");
-		return NULL;
-	}
-	
-	hid_dev->report = (usb_hid_report_t *)(malloc(sizeof(
-	    usb_hid_report_t)));
-	if (hid_dev->report == NULL) {
-		usb_log_fatal("No memory!\n");
-		free(hid_dev);
-		return NULL;
-	}
-	
-	hid_dev->poll_pipe_index = -1;
-	
-	return hid_dev;
-}
-
-/*----------------------------------------------------------------------------*/
-
+/*----------------------------------------------------------------------------*/
+/*
+ * 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);
+
 	/* The USB device should already be initialized, save it in structure */
 	hid_dev->usb_dev = dev;
-	
-	rc = usb_hid_check_pipes(hid_dev, dev);
+	hid_dev->poll_pipe_index = -1;
+
+	int rc = usb_hid_check_pipes(hid_dev, dev);
 	if (rc != EOK) {
 		return rc;
 	}
-		
+
 	/* 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:
@@ -492,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;
@@ -499,51 +393,60 @@
 			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;
 		default:
-			assert(hid_dev->poll_pipe_index 
+			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) {
@@ -552,24 +455,19 @@
 		}
 	}
-	
-	
+
 	return rc;
 }
-
-/*----------------------------------------------------------------------------*/
-
-bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer, 
+/*----------------------------------------------------------------------------*/
+bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer,
     size_t buffer_size, void *arg)
 {
-	int i;
-	
 	if (dev == NULL || arg == NULL || buffer == NULL) {
 		usb_log_error("Missing arguments to polling callback.\n");
 		return false;
 	}
-	
-	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
-	
+	usb_hid_dev_t *hid_dev = arg;
+
 	assert(hid_dev->input_report != NULL);
+
 	usb_log_debug("New data [%zu/%zu]: %s\n", buffer_size,
 	    hid_dev->max_input_report_size,
@@ -582,83 +480,62 @@
 		usb_hid_new_report(hid_dev);
 	}
-	
-	// parse the input report
-	
-	int rc = usb_hid_parse_report(hid_dev->report, buffer, buffer_size, 
-	    &hid_dev->report_id);
-	
+
+	/* Parse the input report */
+	const int rc = usb_hid_parse_report(
+	    &hid_dev->report, buffer, buffer_size, &hid_dev->report_id);
 	if (rc != EOK) {
 		usb_log_warning("Error in usb_hid_parse_report():"
 		    "%s\n", str_error(rc));
-	}	
-	
+	}
+
 	bool cont = false;
-	
-	// continue if at least one of the subdrivers want to continue
-	for (i = 0; i < hid_dev->subdriver_count; ++i) {
-		if (hid_dev->subdrivers[i].poll != NULL
-		    && hid_dev->subdrivers[i].poll(hid_dev, 
-		        hid_dev->subdrivers[i].data)) {
-			cont = true;
-		}
-	}
-	
+	/* Continue if at least one of the subdrivers want to continue */
+	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
+		if (hid_dev->subdrivers[i].poll != NULL) {
+			cont = cont || hid_dev->subdrivers[i].poll(
+			    hid_dev, hid_dev->subdrivers[i].data);
+		}
+	}
+
 	return cont;
 }
-
-/*----------------------------------------------------------------------------*/
-
-void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, 
-     void *arg)
-{
-	int i; 
-	
-	if (dev == NULL || arg == NULL) {
-		return;
-	}
-	
-	usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)arg;
-	
-	for (i = 0; i < hid_dev->subdriver_count; ++i) {
+/*----------------------------------------------------------------------------*/
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, void *arg)
+{
+	assert(dev);
+	assert(arg);
+
+	usb_hid_dev_t *hid_dev = arg;
+
+	for (unsigned i = 0; i < hid_dev->subdriver_count; ++i) {
 		if (hid_dev->subdrivers[i].poll_end != NULL) {
-			hid_dev->subdrivers[i].poll_end(hid_dev,
-			    hid_dev->subdrivers[i].data, reason);
-		}
-	}
-	
-	usb_hid_destroy(hid_dev);
-}
-
-/*----------------------------------------------------------------------------*/
-
+			hid_dev->subdrivers[i].poll_end(
+			    hid_dev, hid_dev->subdrivers[i].data, reason);
+		}
+	}
+
+	hid_dev->running = false;
+}
+/*----------------------------------------------------------------------------*/
 void usb_hid_new_report(usb_hid_dev_t *hid_dev)
 {
 	++hid_dev->report_nr;
 }
-
-/*----------------------------------------------------------------------------*/
-
-int usb_hid_report_number(usb_hid_dev_t *hid_dev)
+/*----------------------------------------------------------------------------*/
+int usb_hid_report_number(const usb_hid_dev_t *hid_dev)
 {
 	return hid_dev->report_nr;
 }
-
-/*----------------------------------------------------------------------------*/
-
-void usb_hid_destroy(usb_hid_dev_t *hid_dev)
-{
-	int i;
-	
-	if (hid_dev == NULL) {
-		return;
-	}
-	
+/*----------------------------------------------------------------------------*/
+void usb_hid_deinit(usb_hid_dev_t *hid_dev)
+{
+	assert(hid_dev);
+	assert(hid_dev->subdrivers != NULL || hid_dev->subdriver_count == 0);
+
+
 	usb_log_debug("Subdrivers: %p, subdriver count: %d\n", 
 	    hid_dev->subdrivers, hid_dev->subdriver_count);
-	
-	assert(hid_dev->subdrivers != NULL 
-	    || hid_dev->subdriver_count == 0);
-	
-	for (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,
@@ -666,18 +543,12 @@
 		}
 	}
-	
-	// free the subdrivers info
-	if (hid_dev->subdrivers != NULL) {
-		free(hid_dev->subdrivers);
-	}
-
-	// destroy the parser
-	if (hid_dev->report != NULL) {
-		usb_hid_free_report(hid_dev->report);
-	}
-
-	if (hid_dev->report_desc != NULL) {
-		free(hid_dev->report_desc);
-	}
+
+	/* Free allocated structures */
+	free(hid_dev->subdrivers);
+	free(hid_dev->report_desc);
+
+	/* Destroy the parser */
+	usb_hid_report_deinit(&hid_dev->report);
+
 }
 
Index: uspace/drv/bus/usb/usbhid/usbhid.h
===================================================================
--- uspace/drv/bus/usb/usbhid/usbhid.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhid/usbhid.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -102,14 +102,14 @@
 	/** Structure holding generic USB device information. */
 	usb_device_t *usb_dev;
-	
+
 	/** Index of the polling pipe in usb_hid_endpoints array. */
-	int poll_pipe_index;
-	
+	unsigned poll_pipe_index;
+
 	/** Subdrivers. */
 	usb_hid_subdriver_t *subdrivers;
-	
+
 	/** Number of subdrivers. */
-	int subdriver_count;
-	
+	unsigned subdriver_count;
+
 	/** Report descriptor. */
 	uint8_t *report_desc;
@@ -117,16 +117,17 @@
 	/** Report descriptor size. */
 	size_t report_desc_size;
-	
+
 	/** HID Report parser. */
-	usb_hid_report_t *report;
-	
+	usb_hid_report_t report;
+
 	uint8_t report_id;
-	
+
 	uint8_t *input_report;
-	
+
 	size_t input_report_size;
 	size_t max_input_report_size;
-	
+
 	int report_nr;
+	volatile bool running;
 };
 
@@ -140,23 +141,20 @@
 };
 
-usb_endpoint_description_t *usb_hid_endpoints[USB_HID_POLL_EP_COUNT + 1];
+extern const usb_endpoint_description_t *usb_hid_endpoints[];
 
 /*----------------------------------------------------------------------------*/
 
-usb_hid_dev_t *usb_hid_new(void);
-
 int usb_hid_init(usb_hid_dev_t *hid_dev, usb_device_t *dev);
 
-bool usb_hid_polling_callback(usb_device_t *dev, uint8_t *buffer, 
-    size_t buffer_size, void *arg);
+void usb_hid_deinit(usb_hid_dev_t *hid_dev);
 
-void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, 
-     void *arg);
+bool usb_hid_polling_callback(usb_device_t *dev,
+    uint8_t *buffer, size_t buffer_size, void *arg);
+
+void usb_hid_polling_ended_callback(usb_device_t *dev, bool reason, void *arg);
 
 void usb_hid_new_report(usb_hid_dev_t *hid_dev);
 
-int usb_hid_report_number(usb_hid_dev_t *hid_dev);
-
-void usb_hid_destroy(usb_hid_dev_t *hid_dev);
+int usb_hid_report_number(const usb_hid_dev_t *hid_dev);
 
 #endif /* USB_HID_USBHID_H_ */
Index: uspace/drv/bus/usb/usbhub/Makefile
===================================================================
--- uspace/drv/bus/usb/usbhub/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhub/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,5 @@
 #
 # Copyright (c) 2010 Vojtech Horky
+# Copyright (c) 2011 Jan Vesely
 # All rights reserved.
 #
@@ -43,7 +44,6 @@
 SOURCES = \
 	main.c \
-	utils.c \
 	usbhub.c \
-	ports.c
+	port.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/bus/usb/usbhub/main.c
===================================================================
--- uspace/drv/bus/usb/usbhub/main.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhub/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -38,7 +39,7 @@
 #include <usb/dev/driver.h>
 #include <usb/classes/classes.h>
+#include <usb/debug.h>
 
 #include "usbhub.h"
-#include "usbhub_private.h"
 
 /** Hub status-change endpoint description.
@@ -46,5 +47,6 @@
  * For more information see section 11.15.1 of USB 1.1 specification.
  */
-static usb_endpoint_description_t hub_status_change_endpoint_description = {
+static const usb_endpoint_description_t hub_status_change_endpoint_description =
+{
 	.transfer_type = USB_TRANSFER_INTERRUPT,
 	.direction = USB_DIRECTION_IN,
@@ -55,25 +57,18 @@
 };
 
-/**
- * usb hub driver operations
- *
- * The most important one is add_device, which is set to usb_hub_add_device.
- */
-static usb_driver_ops_t usb_hub_driver_ops = {
-	.add_device = usb_hub_add_device
+/** USB hub driver operations. */
+static const usb_driver_ops_t usb_hub_driver_ops = {
+	.device_add = usb_hub_device_add,
+//	.device_rem = usb_hub_device_remove,
+	.device_gone = usb_hub_device_gone,
 };
 
-/**
- * hub endpoints, excluding control endpoint
- */
-static usb_endpoint_description_t *usb_hub_endpoints[] = {
+/** Hub endpoints, excluding control endpoint. */
+static const usb_endpoint_description_t *usb_hub_endpoints[] = {
 	&hub_status_change_endpoint_description,
-	NULL
+	NULL,
 };
-
-/**
- * static usb hub driver information
- */
-static usb_driver_t usb_hub_driver = {
+/** Static usb hub driver information. */
+static const usb_driver_t usb_hub_driver = {
 	.name = NAME,
 	.ops = &usb_hub_driver_ops,
@@ -81,9 +76,7 @@
 };
 
-
 int main(int argc, char *argv[])
 {
 	printf(NAME ": HelenOS USB hub driver.\n");
-
 	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
 
@@ -94,3 +87,2 @@
  * @}
  */
-
Index: uspace/drv/bus/usb/usbhub/port.c
===================================================================
--- uspace/drv/bus/usb/usbhub/port.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/drv/bus/usb/usbhub/port.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,512 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
+ * 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 drvusbhub
+ * @{
+ */
+/** @file
+ * Hub ports functions.
+ */
+
+#include <bool.h>
+#include <devman.h>
+#include <errno.h>
+#include <str_error.h>
+#include <inttypes.h>
+#include <fibril_synch.h>
+
+#include <usb/debug.h>
+#include <usb/dev/hub.h>
+
+#include "port.h"
+#include "usbhub.h"
+#include "status.h"
+
+/** Information for fibril for device discovery. */
+struct add_device_phase1 {
+	usb_hub_dev_t *hub;
+	usb_hub_port_t *port;
+	usb_speed_t speed;
+};
+
+static int usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub);
+static void usb_hub_port_reset_completed(usb_hub_port_t *port,
+    usb_port_status_t status);
+static int get_port_status(usb_hub_port_t *port, usb_port_status_t *status);
+static int enable_port_callback(void *arg);
+static int add_device_phase1_worker_fibril(void *arg);
+static int create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub,
+    usb_speed_t speed);
+
+int usb_hub_port_fini(usb_hub_port_t *port, usb_hub_dev_t *hub)
+{
+	assert(port);
+	if (port->attached_device.fun)
+		return usb_hub_port_device_gone(port, hub);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Clear feature on hub port.
+ *
+ * @param port Port structure.
+ * @param feature Feature selector.
+ * @return Operation result
+ */
+int usb_hub_port_clear_feature(
+    usb_hub_port_t *port, usb_hub_class_feature_t feature)
+{
+	assert(port);
+	const usb_device_request_setup_packet_t clear_request = {
+		.request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE,
+		.request = USB_DEVREQ_CLEAR_FEATURE,
+		.value = feature,
+		.index = port->port_number,
+		.length = 0,
+	};
+	return usb_pipe_control_write(port->control_pipe, &clear_request,
+	    sizeof(clear_request), NULL, 0);
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Set feature on hub port.
+ *
+ * @param port Port structure.
+ * @param feature Feature selector.
+ * @return Operation result
+ */
+int usb_hub_port_set_feature(
+    usb_hub_port_t *port, usb_hub_class_feature_t feature)
+{
+	assert(port);
+	const usb_device_request_setup_packet_t clear_request = {
+		.request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE,
+		.request = USB_DEVREQ_SET_FEATURE,
+		.index = port->port_number,
+		.value = feature,
+		.length = 0,
+	};
+	return usb_pipe_control_write(port->control_pipe, &clear_request,
+	    sizeof(clear_request), NULL, 0);
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Mark reset process as failed due to external reasons
+ *
+ * @param port Port structure
+ */
+void usb_hub_port_reset_fail(usb_hub_port_t *port)
+{
+	assert(port);
+	fibril_mutex_lock(&port->mutex);
+	port->reset_completed = true;
+	port->reset_okay = false;
+	fibril_condvar_broadcast(&port->reset_cv);
+	fibril_mutex_unlock(&port->mutex);
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Process interrupts on given port
+ *
+ * Accepts connection, over current and port reset change.
+ * @param port port structure
+ * @param hub hub representation
+ */
+void usb_hub_port_process_interrupt(usb_hub_port_t *port, usb_hub_dev_t *hub)
+{
+	assert(port);
+	assert(hub);
+	usb_log_debug("Interrupt at port %zu\n", port->port_number);
+
+	usb_port_status_t status;
+	const int opResult = get_port_status(port, &status);
+	if (opResult != EOK) {
+		usb_log_error("Failed to get port %zu status: %s.\n",
+		    port->port_number, str_error(opResult));
+		return;
+	}
+
+	/* Connection change */
+	if (status & USB_HUB_PORT_C_STATUS_CONNECTION) {
+		const bool connected =
+		    (status & USB_HUB_PORT_STATUS_CONNECTION) != 0;
+		usb_log_debug("Connection change on port %zu: device %s.\n",
+		    port->port_number, connected ? "attached" : "removed");
+
+		/* ACK the change */
+		const int opResult = usb_hub_port_clear_feature(port,
+		    USB_HUB_FEATURE_C_PORT_CONNECTION);
+		if (opResult != EOK) {
+			usb_log_warning("Failed to clear port-change-connection"
+			    " flag: %s.\n", str_error(opResult));
+		}
+
+		if (connected) {
+			const int opResult = create_add_device_fibril(port, hub,
+			    usb_port_speed(status));
+			if (opResult != EOK) {
+				usb_log_error(
+				    "Cannot handle change on port %zu: %s.\n",
+				    port->port_number, str_error(opResult));
+			}
+		} else {
+			/* If enabled change was reported leave the removal
+			 * to that handler, it shall ACK the change too. */
+			if (!(status & USB_HUB_PORT_C_STATUS_ENABLED)) {
+				usb_hub_port_device_gone(port, hub);
+			}
+		}
+	}
+
+	/* Enable change, ports are automatically disabled on errors. */
+	if (status & USB_HUB_PORT_C_STATUS_ENABLED) {
+		usb_log_info("Port %zu, disabled because of errors.\n",
+		   port->port_number);
+		usb_hub_port_device_gone(port, hub);
+		const int rc = usb_hub_port_clear_feature(port,
+		        USB_HUB_FEATURE_C_PORT_ENABLE);
+		if (rc != EOK) {
+			usb_log_error(
+			    "Failed to clear port %zu enable change feature: "
+			    "%s.\n", port->port_number, str_error(rc));
+		}
+
+	}
+
+	/* Suspend change */
+	if (status & USB_HUB_PORT_C_STATUS_SUSPEND) {
+		usb_log_error("Port %zu went to suspend state, this should"
+		    "NOT happen as we do not support suspend state!",
+		    port->port_number);
+		const int rc = usb_hub_port_clear_feature(port,
+		        USB_HUB_FEATURE_C_PORT_SUSPEND);
+		if (rc != EOK) {
+			usb_log_error(
+			    "Failed to clear port %zu suspend change feature: "
+			    "%s.\n", port->port_number, str_error(rc));
+		}
+	}
+
+	/* Over current */
+	if (status & USB_HUB_PORT_C_STATUS_OC) {
+		/* According to the USB specs:
+		 * 11.13.5 Over-current Reporting and Recovery
+		 * Hub device is responsible for putting port in power off
+		 * mode. USB system software is responsible for powering port
+		 * back on when the over-current condition is gone */
+		const int rc = usb_hub_port_clear_feature(port,
+		    USB_HUB_FEATURE_C_PORT_OVER_CURRENT);
+		if (rc != EOK) {
+			usb_log_error(
+			    "Failed to clear port %zu OC change feature: %s.\n",
+			    port->port_number, str_error(rc));
+		}
+		if (!(status & ~USB_HUB_PORT_STATUS_OC)) {
+			const int rc = usb_hub_port_set_feature(
+			    port, USB_HUB_FEATURE_PORT_POWER);
+			if (rc != EOK) {
+				usb_log_error(
+				    "Failed to set port %zu power after OC:"
+				    " %s.\n", port->port_number, str_error(rc));
+			}
+		}
+	}
+
+	/* Port reset, set on port reset complete. */
+	if (status & USB_HUB_PORT_C_STATUS_RESET) {
+		usb_hub_port_reset_completed(port, status);
+	}
+
+	usb_log_debug("Port %zu status 0x%08" PRIx32 "\n",
+	    port->port_number, status);
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * routine called when a device on port has been removed
+ *
+ * If the device on port had default address, it releases default address.
+ * Otherwise does not do anything, because DDF does not allow to remove device
+ * from it`s device tree.
+ * @param port port structure
+ * @param hub hub representation
+ */
+int usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub)
+{
+	assert(port);
+	assert(hub);
+	if (port->attached_device.address < 0) {
+		usb_log_warning(
+		    "Device on port %zu removed before being registered.\n",
+		    port->port_number);
+
+		/*
+		 * Device was removed before port reset completed.
+		 * We will announce a failed port reset to unblock the
+		 * port reset callback from new device wrapper.
+		 */
+		usb_hub_port_reset_fail(port);
+		return EOK;
+	}
+
+	fibril_mutex_lock(&port->mutex);
+	assert(port->attached_device.fun);
+	usb_log_debug("Removing device on port %zu.\n", port->port_number);
+	int ret = ddf_fun_unbind(port->attached_device.fun);
+	if (ret != EOK) {
+		usb_log_error("Failed to unbind child function on port"
+		    " %zu: %s.\n", port->port_number, str_error(ret));
+		fibril_mutex_unlock(&port->mutex);
+		return ret;
+	}
+
+	ddf_fun_destroy(port->attached_device.fun);
+	port->attached_device.fun = NULL;
+
+	ret = usb_hc_connection_open(&hub->connection);
+	if (ret == EOK) {
+		ret = usb_hc_unregister_device(&hub->connection,
+		    port->attached_device.address);
+		if (ret != EOK) {
+			usb_log_warning("Failed to unregister address of the "
+			    "removed device: %s.\n", str_error(ret));
+		}
+		ret = usb_hc_connection_close(&hub->connection);
+		if (ret != EOK) {
+			usb_log_warning("Failed to close hc connection %s.\n",
+			    str_error(ret));
+		}
+
+	} else {
+		usb_log_warning("Failed to open hc connection %s.\n",
+		    str_error(ret));
+	}
+
+	port->attached_device.address = -1;
+	fibril_mutex_unlock(&port->mutex);
+	usb_log_info("Removed device on port %zu.\n", port->port_number);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Process port reset change
+ *
+ * After this change port should be enabled, unless some problem occurred.
+ * This functions triggers second phase of enabling new device.
+ * @param port Port structure
+ * @param status Port status mask
+ */
+void usb_hub_port_reset_completed(usb_hub_port_t *port,
+    usb_port_status_t status)
+{
+	assert(port);
+	fibril_mutex_lock(&port->mutex);
+	/* Finalize device adding. */
+	port->reset_completed = true;
+	port->reset_okay = (status & USB_HUB_PORT_STATUS_ENABLED) != 0;
+
+	if (port->reset_okay) {
+		usb_log_debug("Port %zu reset complete.\n", port->port_number);
+	} else {
+		usb_log_warning(
+		    "Port %zu reset complete but port not enabled.\n",
+		    port->port_number);
+	}
+	fibril_condvar_broadcast(&port->reset_cv);
+	fibril_mutex_unlock(&port->mutex);
+
+	/* Clear the port reset change. */
+	int rc = usb_hub_port_clear_feature(port, USB_HUB_FEATURE_C_PORT_RESET);
+	if (rc != EOK) {
+		usb_log_error(
+		    "Failed to clear port %zu reset change feature: %s.\n",
+		    port->port_number, str_error(rc));
+	}
+}
+/*----------------------------------------------------------------------------*/
+/** Retrieve port status.
+ *
+ * @param[in] port Port structure
+ * @param[out] status Where to store the port status.
+ * @return Error code.
+ */
+static int get_port_status(usb_hub_port_t *port, usb_port_status_t *status)
+{
+	assert(port);
+	/* USB hub specific GET_PORT_STATUS request. See USB Spec 11.16.2.6
+	 * Generic GET_STATUS request cannot be used because of the difference
+	 * in status data size (2B vs. 4B)*/
+	const usb_device_request_setup_packet_t request = {
+		.request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS,
+		.request = USB_HUB_REQUEST_GET_STATUS,
+		.value = 0,
+		.index = port->port_number,
+		.length = sizeof(usb_port_status_t),
+	};
+	size_t recv_size;
+	usb_port_status_t status_tmp;
+
+	const int rc = usb_pipe_control_read(port->control_pipe,
+	    &request, sizeof(usb_device_request_setup_packet_t),
+	    &status_tmp, sizeof(status_tmp), &recv_size);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	if (recv_size != sizeof (status_tmp)) {
+		return ELIMIT;
+	}
+
+	if (status != NULL) {
+		*status = status_tmp;
+	}
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Callback for enabling a specific port.
+ *
+ * We wait on a CV until port is reseted.
+ * That is announced via change on interrupt pipe.
+ *
+ * @param port_no Port number (starting at 1).
+ * @param arg Custom argument, points to @c usb_hub_dev_t.
+ * @return Error code.
+ */
+static int enable_port_callback(void *arg)
+{
+	usb_hub_port_t *port = arg;
+	assert(port);
+	const int rc =
+	    usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET);
+	if (rc != EOK) {
+		usb_log_warning("Port reset failed: %s.\n", str_error(rc));
+		return rc;
+	}
+
+	/*
+	 * Wait until reset completes.
+	 */
+	fibril_mutex_lock(&port->mutex);
+	while (!port->reset_completed) {
+		fibril_condvar_wait(&port->reset_cv, &port->mutex);
+	}
+	fibril_mutex_unlock(&port->mutex);
+
+	return port->reset_okay ? EOK : ESTALL;
+}
+/*----------------------------------------------------------------------------*/
+/** Fibril for adding a new device.
+ *
+ * Separate fibril is needed because the port reset completion is announced
+ * via interrupt pipe and thus we cannot block here.
+ *
+ * @param arg Pointer to struct add_device_phase1.
+ * @return 0 Always.
+ */
+int add_device_phase1_worker_fibril(void *arg)
+{
+	struct add_device_phase1 *data = arg;
+	assert(data);
+
+	usb_address_t new_address;
+	ddf_fun_t *child_fun;
+
+	const int rc = usb_hc_new_device_wrapper(data->hub->usb_device->ddf_dev,
+	    &data->hub->connection, data->speed, enable_port_callback,
+	    data->port, &new_address, NULL, NULL, &child_fun);
+
+	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));
+	}
+
+
+	fibril_mutex_lock(&data->hub->pending_ops_mutex);
+	assert(data->hub->pending_ops_count > 0);
+	--data->hub->pending_ops_count;
+	fibril_condvar_signal(&data->hub->pending_ops_cv);
+	fibril_mutex_unlock(&data->hub->pending_ops_mutex);
+
+	free(arg);
+
+	return rc;
+}
+/*----------------------------------------------------------------------------*/
+/** Start device adding when connection change is detected.
+ *
+ * This fires a new fibril to complete the device addition.
+ *
+ * @param hub Hub where the change occured.
+ * @param port Port index (starting at 1).
+ * @param speed Speed of the device.
+ * @return Error code.
+ */
+static int create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub,
+    usb_speed_t speed)
+{
+	assert(hub);
+	assert(port);
+	struct add_device_phase1 *data
+	    = malloc(sizeof(struct add_device_phase1));
+	if (data == NULL) {
+		return ENOMEM;
+	}
+	data->hub = hub;
+	data->port = port;
+	data->speed = speed;
+
+	fibril_mutex_lock(&port->mutex);
+	port->reset_completed = false;
+	fibril_mutex_unlock(&port->mutex);
+
+	fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data);
+	if (fibril == 0) {
+		free(data);
+		return ENOMEM;
+	}
+	fibril_mutex_lock(&hub->pending_ops_mutex);
+	++hub->pending_ops_count;
+	fibril_mutex_unlock(&hub->pending_ops_mutex);
+	fibril_add_ready(fibril);
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/usbhub/port.h
===================================================================
--- uspace/drv/bus/usb/usbhub/port.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/drv/bus/usb/usbhub/port.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * Copyright (c) 2011 Jan Vesely
+ * 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 drvusbhub
+ * @{
+ */
+/** @file
+ * Hub ports related functions.
+ */
+#ifndef DRV_USBHUB_PORT_H
+#define DRV_USBHUB_PORT_H
+
+#include <usb/dev/driver.h>
+#include <usb/dev/hub.h>
+#include <usb/classes/hub.h>
+
+typedef struct usb_hub_dev usb_hub_dev_t;
+
+/** Information about single port on a hub. */
+typedef struct {
+	/* Port number as reported in descriptors. */
+	size_t port_number;
+	/** Device communication pipe. */
+	usb_pipe_t *control_pipe;
+	/** Mutex needed not only by CV for checking port reset. */
+	fibril_mutex_t mutex;
+	/** CV for waiting to port reset completion. */
+	fibril_condvar_t reset_cv;
+	/** Whether port reset is completed.
+	 * Guarded by @c reset_mutex.
+	 */
+	bool reset_completed;
+	/** Whether to announce the port reset as successful. */
+	bool reset_okay;
+
+	/** Information about attached device. */
+	usb_hub_attached_device_t attached_device;
+} usb_hub_port_t;
+
+/** Initialize hub port information.
+ *
+ * @param port Port to be initialized.
+ */
+static inline void usb_hub_port_init(usb_hub_port_t *port, size_t port_number,
+    usb_pipe_t *control_pipe)
+{
+	assert(port);
+	port->attached_device.address = -1;
+	port->attached_device.fun = NULL;
+	port->port_number = port_number;
+	port->control_pipe = control_pipe;
+	fibril_mutex_initialize(&port->mutex);
+	fibril_condvar_initialize(&port->reset_cv);
+}
+int usb_hub_port_fini(usb_hub_port_t *port, usb_hub_dev_t *hub);
+int usb_hub_port_clear_feature(
+    usb_hub_port_t *port, usb_hub_class_feature_t feature);
+int usb_hub_port_set_feature(
+    usb_hub_port_t *port, usb_hub_class_feature_t feature);
+void usb_hub_port_reset_fail(usb_hub_port_t *port);
+void usb_hub_port_process_interrupt(usb_hub_port_t *port, usb_hub_dev_t *hub);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/usbhub/port_status.h
===================================================================
--- uspace/drv/bus/usb/usbhub/port_status.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,360 +1,0 @@
-/*
- * Copyright (c) 2010 Matus Dekanek
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/** @addtogroup drvusbhub
- * @{
- */
-
-#ifndef HUB_PORT_STATUS_H
-#define	HUB_PORT_STATUS_H
-
-#include <bool.h>
-#include <sys/types.h>
-#include <usb/dev/request.h>
-#include "usbhub_private.h"
-
-/**
- * structure holding port status and changes flags.
- * should not be accessed directly, use supplied getter/setter methods.
- *
- * For more information refer to table 11-15 in
- * "Universal Serial Bus Specification Revision 1.1"
- *
- */
-typedef uint32_t usb_port_status_t;
-
-/**
- * structure holding hub status and changes flags.
- * should not be accessed directly, use supplied getter/setter methods.
- *
- * For more information refer to table 11.16.2.5 in
- * "Universal Serial Bus Specification Revision 1.1"
- *
- */
-typedef uint32_t usb_hub_status_t;
-
-/**
- * set values in request to be it a port status request
- * @param request
- * @param port
- */
-static inline void usb_hub_set_port_status_request(
-    usb_device_request_setup_packet_t *request, uint16_t port) {
-	request->index = port;
-	request->request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS;
-	request->request = USB_HUB_REQUEST_GET_STATUS;
-	request->value = 0;
-	request->length = 4;
-}
-
-/**
- * set values in request to be it a port status request
- * @param request
- * @param port
- */
-static inline void usb_hub_set_hub_status_request(
-    usb_device_request_setup_packet_t *request) {
-	request->index = 0;
-	request->request_type = USB_HUB_REQ_TYPE_GET_HUB_STATUS;
-	request->request = USB_HUB_REQUEST_GET_STATUS;
-	request->value = 0;
-	request->length = 4;
-}
-
-/**
- * create request for usb hub port status
- * @param port
- * @return
- */
-static inline usb_device_request_setup_packet_t *
-usb_hub_create_port_status_request(uint16_t port) {
-	usb_device_request_setup_packet_t *result =
-	    malloc(sizeof (usb_device_request_setup_packet_t));
-	usb_hub_set_port_status_request(result, port);
-	return result;
-}
-
-/**
- * set the device request to be a port feature enable request
- * @param request
- * @param port
- * @param feature_selector
- */
-static inline void usb_hub_set_enable_port_feature_request(
-    usb_device_request_setup_packet_t *request, uint16_t port,
-    uint16_t feature_selector) {
-	request->index = port;
-	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
-	request->request = USB_HUB_REQUEST_SET_FEATURE;
-	request->value = feature_selector;
-	request->length = 0;
-}
-
-/**
- * set the device request to be a port feature clear request
- * @param request
- * @param port
- * @param feature_selector
- */
-static inline void usb_hub_set_disable_port_feature_request(
-    usb_device_request_setup_packet_t *request, uint16_t port,
-    uint16_t feature_selector
-    ) {
-	request->index = port;
-	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
-	request->request = USB_HUB_REQUEST_CLEAR_FEATURE;
-	request->value = feature_selector;
-	request->length = 0;
-}
-
-/**
- * set the device request to be a port enable request
- * @param request
- * @param port
- */
-static inline void usb_hub_set_enable_port_request(
-    usb_device_request_setup_packet_t *request, uint16_t port
-    ) {
-	request->index = port;
-	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
-	request->request = USB_HUB_REQUEST_SET_FEATURE;
-	request->value = USB_HUB_FEATURE_C_PORT_ENABLE;
-	request->length = 0;
-}
-
-/**
- * enable specified port
- * @param port
- * @return
- */
-static inline usb_device_request_setup_packet_t *
-usb_hub_create_enable_port_request(uint16_t port) {
-	usb_device_request_setup_packet_t *result =
-	    malloc(sizeof (usb_device_request_setup_packet_t));
-	usb_hub_set_enable_port_request(result, port);
-	return result;
-}
-
-/**
- * set the device request to be a port disable request
- * @param request
- * @param port
- */
-static inline void usb_hub_set_disable_port_request(
-    usb_device_request_setup_packet_t *request, uint16_t port
-    ) {
-	request->index = port;
-	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
-	request->request = USB_HUB_REQUEST_SET_FEATURE;
-	request->value = USB_HUB_FEATURE_C_PORT_SUSPEND;
-	request->length = 0;
-}
-
-/**
- * disable specified port
- * @param port
- * @return
- */
-static inline usb_device_request_setup_packet_t *
-usb_hub_create_disable_port_request(uint16_t port) {
-	usb_device_request_setup_packet_t *result =
-	    malloc(sizeof (usb_device_request_setup_packet_t));
-	usb_hub_set_disable_port_request(result, port);
-	return result;
-}
-
-/**
- * set the device request to be a port disable request
- * @param request
- * @param port
- */
-static inline void usb_hub_set_reset_port_request(
-    usb_device_request_setup_packet_t *request, uint16_t port
-    ) {
-	request->index = port;
-	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
-	request->request = USB_HUB_REQUEST_SET_FEATURE;
-	request->value = USB_HUB_FEATURE_PORT_RESET;
-	request->length = 0;
-}
-
-/**
- * disable specified port
- * @param port
- * @return
- */
-static inline usb_device_request_setup_packet_t *
-usb_hub_create_reset_port_request(uint16_t port) {
-	usb_device_request_setup_packet_t *result =
-	    malloc(sizeof (usb_device_request_setup_packet_t));
-	usb_hub_set_reset_port_request(result, port);
-	return result;
-}
-
-/**
- * set the device request to be a port disable request
- * @param request
- * @param port
- */
-static inline void usb_hub_set_power_port_request(
-    usb_device_request_setup_packet_t *request, uint16_t port
-    ) {
-	request->index = port;
-	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
-	request->request = USB_HUB_REQUEST_SET_FEATURE;
-	request->value = USB_HUB_FEATURE_PORT_POWER;
-	request->length = 0;
-}
-
-/**
- * set the device request to be a port disable request
- * @param request
- * @param port
- */
-static inline void usb_hub_unset_power_port_request(
-    usb_device_request_setup_packet_t *request, uint16_t port
-    ) {
-	request->index = port;
-	request->request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE;
-	request->request = USB_HUB_REQUEST_CLEAR_FEATURE;
-	request->value = USB_HUB_FEATURE_PORT_POWER;
-	request->length = 0;
-}
-
-/**
- * get i`th bit of port status
- * 
- * @param status
- * @param idx
- * @return
- */
-static inline bool usb_port_is_status(usb_port_status_t status, int idx) {
-	return (status & (1 << idx)) != 0;
-}
-
-/**
- * set i`th bit of port status
- * 
- * @param status
- * @param idx
- * @param value
- */
-static inline void usb_port_status_set_bit(
-    usb_port_status_t * status, int idx, bool value) {
-	(*status) = value ?
-	    ((*status) | (1 << (idx))) :
-	    ((*status)&(~(1 << (idx))));
-}
-
-/**
- * get i`th bit of hub status
- * 
- * @param status
- * @param idx
- * @return
- */
-static inline bool usb_hub_is_status(usb_hub_status_t status, int idx) {
-	return (status & (1 << idx)) != 0;
-}
-
-/**
- * set i`th bit of hub status
- * 
- * @param status
- * @param idx
- * @param value
- */
-static inline void usb_hub_status_set_bit(
-    usb_hub_status_t *status, int idx, bool value) {
-	(*status) = value ?
-	    ((*status) | (1 << (idx))) :
-	    ((*status)&(~(1 << (idx))));
-}
-
-/**
- * low speed device on the port indicator
- * 
- * @param status
- * @return true if low speed device is attached
- */
-static inline bool usb_port_low_speed(usb_port_status_t status) {
-	return usb_port_is_status(status, 9);
-}
-
-/**
- * set low speed device connected bit in port status
- * 
- * @param status
- * @param low_speed value of the bit
- */
-static inline void usb_port_set_low_speed(usb_port_status_t *status, bool low_speed) {
-	usb_port_status_set_bit(status, 9, low_speed);
-}
-
-//high speed device attached
-
-/**
- * high speed device on the port indicator
- *
- * @param status
- * @return true if high speed device is on port
- */
-static inline bool usb_port_high_speed(usb_port_status_t status) {
-	return usb_port_is_status(status, 10);
-}
-
-/**
- * set high speed device bit in port status
- *
- * @param status
- * @param high_speed value of the bit
- */
-static inline void usb_port_set_high_speed(usb_port_status_t *status, bool high_speed) {
-	usb_port_status_set_bit(status, 10, high_speed);
-}
-
-/**
- * speed getter for port status
- *
- * @param status
- * @return speed of usb device (for more see usb specification)
- */
-static inline usb_speed_t usb_port_speed(usb_port_status_t status) {
-	if (usb_port_low_speed(status))
-		return USB_SPEED_LOW;
-	if (usb_port_high_speed(status))
-		return USB_SPEED_HIGH;
-	return USB_SPEED_FULL;
-}
-
-
-
-#endif	/* HUB_PORT_STATUS_H */
-
-/**
- * @}
- */
Index: uspace/drv/bus/usb/usbhub/ports.c
===================================================================
--- uspace/drv/bus/usb/usbhub/ports.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,465 +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 drvusbhub
- * @{
- */
-/** @file
- * Hub ports functions.
- */
-
-#include <bool.h>
-#include <errno.h>
-#include <str_error.h>
-#include <inttypes.h>
-#include <fibril_synch.h>
-
-#include <usb/debug.h>
-
-#include "ports.h"
-#include "usbhub.h"
-#include "usbhub_private.h"
-#include "port_status.h"
-
-/** Information for fibril for device discovery. */
-struct add_device_phase1 {
-	usb_hub_info_t *hub;
-	size_t port;
-	usb_speed_t speed;
-};
-
-/**
- * count of port status changes that are not explicitly handled by
- * any function here and must be cleared by hand
- */
-static const unsigned int non_handled_changes_count = 2;
-
-/**
- * port status changes that are not explicitly handled by
- * any function here and must be cleared by hand
- */
-static const int non_handled_changes[] = {
-	USB_HUB_FEATURE_C_PORT_ENABLE,
-	USB_HUB_FEATURE_C_PORT_SUSPEND
-};
-
-static void usb_hub_removed_device(
-    usb_hub_info_t *hub, uint16_t port);
-
-static void usb_hub_port_reset_completed(usb_hub_info_t *hub,
-    uint16_t port, uint32_t status);
-
-static void usb_hub_port_over_current(usb_hub_info_t *hub,
-    uint16_t port, uint32_t status);
-
-static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port,
-    usb_port_status_t *status);
-
-static int enable_port_callback(int port_no, void *arg);
-
-static int add_device_phase1_worker_fibril(void *arg);
-
-static int create_add_device_fibril(usb_hub_info_t *hub, size_t port,
-    usb_speed_t speed);
-
-/**
- * Process interrupts on given hub port
- *
- * Accepts connection, over current and port reset change.
- * @param hub hub representation
- * @param port port number, starting from 1
- */
-void usb_hub_process_port_interrupt(usb_hub_info_t *hub,
-    uint16_t port) {
-	usb_log_debug("Interrupt at port %zu\n", (size_t) port);
-	//determine type of change
-	//usb_pipe_t *pipe = hub->control_pipe;
-
-	int opResult;
-
-	usb_port_status_t status;
-	opResult = get_port_status(&hub->usb_device->ctrl_pipe, port, &status);
-	if (opResult != EOK) {
-		usb_log_error("Failed to get port %zu status: %s.\n",
-		    (size_t) port, str_error(opResult));
-		return;
-	}
-	//connection change
-	if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_CONNECTION)) {
-		bool device_connected = usb_port_is_status(status,
-		    USB_HUB_FEATURE_PORT_CONNECTION);
-		usb_log_debug("Connection change on port %zu: %s.\n",
-		    (size_t) port,
-		    device_connected ? "device attached" : "device removed");
-
-		if (device_connected) {
-			opResult = create_add_device_fibril(hub, port,
-			    usb_port_speed(status));
-			if (opResult != EOK) {
-				usb_log_error(
-				    "Cannot handle change on port %zu: %s.\n",
-				    (size_t) port, str_error(opResult));
-			}
-		} else {
-			usb_hub_removed_device(hub, port);
-		}
-	}
-	//over current
-	if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT)) {
-		//check if it was not auto-resolved
-		usb_log_debug("Overcurrent change on port\n");
-		usb_hub_port_over_current(hub, port, status);
-	}
-	//port reset
-	if (usb_port_is_status(status, USB_HUB_FEATURE_C_PORT_RESET)) {
-		usb_hub_port_reset_completed(hub, port, status);
-	}
-	usb_log_debug("Port %d status 0x%08" PRIx32 "\n", (int) port, status);
-
-	usb_port_status_set_bit(
-	    &status, USB_HUB_FEATURE_C_PORT_CONNECTION, false);
-	usb_port_status_set_bit(
-	    &status, USB_HUB_FEATURE_C_PORT_RESET, false);
-	usb_port_status_set_bit(
-	    &status, USB_HUB_FEATURE_C_PORT_OVER_CURRENT, false);
-
-	//clearing not yet handled changes	
-	unsigned int feature_idx;
-	for (feature_idx = 0;
-	    feature_idx < non_handled_changes_count;
-	    ++feature_idx) {
-		unsigned int bit_idx = non_handled_changes[feature_idx];
-		if (status & (1 << bit_idx)) {
-			usb_log_info(
-			    "There was not yet handled change on port %d: %d"
-			    ";clearing it\n",
-			    port, bit_idx);
-			int opResult = usb_hub_clear_port_feature(
-			    hub->control_pipe,
-			    port, bit_idx);
-			if (opResult != EOK) {
-				usb_log_warning(
-				    "Could not clear port flag %d: %s\n",
-				    bit_idx, str_error(opResult)
-				    );
-			}
-			usb_port_status_set_bit(
-			    &status, bit_idx, false);
-		}
-	}
-	if (status >> 16) {
-		usb_log_info("There is still some unhandled change %X\n",
-		    status);
-	}
-}
-
-/**
- * routine called when a device on port has been removed
- *
- * If the device on port had default address, it releases default address.
- * Otherwise does not do anything, because DDF does not allow to remove device
- * from it`s device tree.
- * @param hub hub representation
- * @param port port number, starting from 1
- */
-static void usb_hub_removed_device(
-    usb_hub_info_t *hub, uint16_t port) {
-
-	int opResult = usb_hub_clear_port_feature(hub->control_pipe,
-	    port, USB_HUB_FEATURE_C_PORT_CONNECTION);
-	if (opResult != EOK) {
-		usb_log_warning("Could not clear port-change-connection flag\n");
-	}
-	/** \TODO remove device from device manager - not yet implemented in
-	 * devide manager
-	 */
-
-	//close address
-
-	usb_hub_port_t *the_port = hub->ports + port;
-
-	fibril_mutex_lock(&hub->port_mutex);
-
-	if (the_port->attached_device.address >= 0) {
-		usb_log_warning("Device unplug on `%s' (port %zu): " \
-		    "not implemented.\n", hub->usb_device->ddf_dev->name,
-		    (size_t) port);
-		the_port->attached_device.address = -1;
-		the_port->attached_device.handle = 0;
-	} else {
-		usb_log_warning("Device removed before being registered.\n");
-
-		/*
-		 * Device was removed before port reset completed.
-		 * We will announce a failed port reset to unblock the
-		 * port reset callback from new device wrapper.
-		 */
-		fibril_mutex_lock(&the_port->reset_mutex);
-		the_port->reset_completed = true;
-		the_port->reset_okay = false;
-		fibril_condvar_broadcast(&the_port->reset_cv);
-		fibril_mutex_unlock(&the_port->reset_mutex);
-	}
-
-	fibril_mutex_unlock(&hub->port_mutex);
-}
-
-/**
- * Process port reset change
- *
- * After this change port should be enabled, unless some problem occured.
- * This functions triggers second phase of enabling new device.
- * @param hub
- * @param port
- * @param status
- */
-static void usb_hub_port_reset_completed(usb_hub_info_t *hub,
-    uint16_t port, uint32_t status) {
-	usb_log_debug("Port %zu reset complete.\n", (size_t) port);
-	if (usb_port_is_status(status, USB_HUB_FEATURE_PORT_ENABLE)) {
-		/* Finalize device adding. */
-		usb_hub_port_t *the_port = hub->ports + port;
-		fibril_mutex_lock(&the_port->reset_mutex);
-		the_port->reset_completed = true;
-		the_port->reset_okay = true;
-		fibril_condvar_broadcast(&the_port->reset_cv);
-		fibril_mutex_unlock(&the_port->reset_mutex);
-	} else {
-		usb_log_warning(
-		    "Port %zu reset complete but port not enabled.\n",
-		    (size_t) port);
-	}
-	/* Clear the port reset change. */
-	int rc = usb_hub_clear_port_feature(hub->control_pipe,
-	    port, USB_HUB_FEATURE_C_PORT_RESET);
-	if (rc != EOK) {
-		usb_log_error("Failed to clear port %d reset feature: %s.\n",
-		    port, str_error(rc));
-	}
-}
-
-/**
- * Process over current condition on port.
- *
- * Turn off the power on the port.
- *
- * @param hub hub representation
- * @param port port number, starting from 1
- */
-static void usb_hub_port_over_current(usb_hub_info_t *hub,
-    uint16_t port, uint32_t status) {
-	int opResult;
-	if (usb_port_is_status(status, USB_HUB_FEATURE_PORT_OVER_CURRENT)) {
-		opResult = usb_hub_clear_port_feature(hub->control_pipe,
-		    port, USB_HUB_FEATURE_PORT_POWER);
-		if (opResult != EOK) {
-			usb_log_error("Cannot power off port %d; %s\n",
-			    port, str_error(opResult));
-		}
-	} else {
-		opResult = usb_hub_set_port_feature(hub->control_pipe,
-		    port, USB_HUB_FEATURE_PORT_POWER);
-		if (opResult != EOK) {
-			usb_log_error("Cannot power on port %d; %s\n",
-			    port, str_error(opResult));
-		}
-	}
-}
-
-/** Retrieve port status.
- *
- * @param[in] ctrl_pipe Control pipe to use.
- * @param[in] port Port number (starting at 1).
- * @param[out] status Where to store the port status.
- * @return Error code.
- */
-static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port,
-    usb_port_status_t *status) {
-	size_t recv_size;
-	usb_device_request_setup_packet_t request;
-	usb_port_status_t status_tmp;
-
-	usb_hub_set_port_status_request(&request, port);
-	int rc = usb_pipe_control_read(ctrl_pipe,
-	    &request, sizeof (usb_device_request_setup_packet_t),
-	    &status_tmp, sizeof (status_tmp), &recv_size);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	if (recv_size != sizeof (status_tmp)) {
-		return ELIMIT;
-	}
-
-	if (status != NULL) {
-		*status = status_tmp;
-	}
-
-	return EOK;
-}
-
-/** Callback for enabling a specific port.
- *
- * We wait on a CV until port is reseted.
- * That is announced via change on interrupt pipe.
- *
- * @param port_no Port number (starting at 1).
- * @param arg Custom argument, points to @c usb_hub_info_t.
- * @return Error code.
- */
-static int enable_port_callback(int port_no, void *arg) {
-	usb_hub_info_t *hub = arg;
-	int rc;
-	usb_device_request_setup_packet_t request;
-	usb_hub_port_t *my_port = hub->ports + port_no;
-
-	usb_hub_set_reset_port_request(&request, port_no);
-	rc = usb_pipe_control_write(hub->control_pipe,
-	    &request, sizeof (request), NULL, 0);
-	if (rc != EOK) {
-		usb_log_warning("Port reset failed: %s.\n", str_error(rc));
-		return rc;
-	}
-
-	/*
-	 * Wait until reset completes.
-	 */
-	fibril_mutex_lock(&my_port->reset_mutex);
-	while (!my_port->reset_completed) {
-		fibril_condvar_wait(&my_port->reset_cv, &my_port->reset_mutex);
-	}
-	fibril_mutex_unlock(&my_port->reset_mutex);
-
-	if (my_port->reset_okay) {
-		return EOK;
-	} else {
-		return ESTALL;
-	}
-}
-
-/** Fibril for adding a new device.
- *
- * Separate fibril is needed because the port reset completion is announced
- * via interrupt pipe and thus we cannot block here.
- *
- * @param arg Pointer to struct add_device_phase1.
- * @return 0 Always.
- */
-static int add_device_phase1_worker_fibril(void *arg) {
-	struct add_device_phase1 *data
-	    = (struct add_device_phase1 *) arg;
-
-	usb_address_t new_address;
-	devman_handle_t child_handle;
-
-	int rc = usb_hc_new_device_wrapper(data->hub->usb_device->ddf_dev,
-	    &data->hub->connection, data->speed,
-	    enable_port_callback, (int) data->port, data->hub,
-	    &new_address, &child_handle,
-	    NULL, NULL, NULL);
-
-	if (rc != EOK) {
-		usb_log_error("Failed registering device on port %zu: %s.\n",
-		    data->port, str_error(rc));
-		goto leave;
-	}
-
-	fibril_mutex_lock(&data->hub->port_mutex);
-	data->hub->ports[data->port].attached_device.handle = child_handle;
-	data->hub->ports[data->port].attached_device.address = new_address;
-	fibril_mutex_unlock(&data->hub->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,
-	    new_address, child_handle);
-
-leave:
-	free(arg);
-
-	fibril_mutex_lock(&data->hub->pending_ops_mutex);
-	assert(data->hub->pending_ops_count > 0);
-	data->hub->pending_ops_count--;
-	fibril_condvar_signal(&data->hub->pending_ops_cv);
-	fibril_mutex_unlock(&data->hub->pending_ops_mutex);
-
-
-	return EOK;
-}
-
-/** Start device adding when connection change is detected.
- *
- * This fires a new fibril to complete the device addition.
- *
- * @param hub Hub where the change occured.
- * @param port Port index (starting at 1).
- * @param speed Speed of the device.
- * @return Error code.
- */
-static int create_add_device_fibril(usb_hub_info_t *hub, size_t port,
-    usb_speed_t speed) {
-	struct add_device_phase1 *data
-	    = malloc(sizeof (struct add_device_phase1));
-	if (data == NULL) {
-		return ENOMEM;
-	}
-	data->hub = hub;
-	data->port = port;
-	data->speed = speed;
-
-	usb_hub_port_t *the_port = hub->ports + port;
-
-	fibril_mutex_lock(&the_port->reset_mutex);
-	the_port->reset_completed = false;
-	fibril_mutex_unlock(&the_port->reset_mutex);
-
-	int rc = usb_hub_clear_port_feature(hub->control_pipe, port,
-	    USB_HUB_FEATURE_C_PORT_CONNECTION);
-	if (rc != EOK) {
-		free(data);
-		usb_log_warning("Failed to clear port change flag: %s.\n",
-		    str_error(rc));
-		return rc;
-	}
-
-	fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data);
-	if (fibril == 0) {
-		free(data);
-		return ENOMEM;
-	}
-	fibril_mutex_lock(&hub->pending_ops_mutex);
-	hub->pending_ops_count++;
-	fibril_mutex_unlock(&hub->pending_ops_mutex);
-	fibril_add_ready(fibril);
-
-	return EOK;
-}
-
-/**
- * @}
- */
Index: uspace/drv/bus/usb/usbhub/ports.h
===================================================================
--- uspace/drv/bus/usb/usbhub/ports.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,80 +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 drvusbhub
- * @{
- */
-/** @file
- * Hub ports related functions.
- */
-#ifndef DRV_USBHUB_PORTS_H
-#define DRV_USBHUB_PORTS_H
-
-#include <usb/dev/driver.h>
-#include <usb/dev/hub.h>
-
-typedef struct usb_hub_info_t usb_hub_info_t;
-
-/** Information about single port on a hub. */
-typedef struct {
-	/** Mutex needed by CV for checking port reset. */
-	fibril_mutex_t reset_mutex;
-	/** CV for waiting to port reset completion. */
-	fibril_condvar_t reset_cv;
-	/** Whether port reset is completed.
-	 * Guarded by @c reset_mutex.
-	 */
-	bool reset_completed;
-	/** Whether to announce the port reset as successful. */
-	bool reset_okay;
-
-	/** Information about attached device. */
-	usb_hc_attached_device_t attached_device;
-} usb_hub_port_t;
-
-/** Initialize hub port information.
- *
- * @param port Port to be initialized.
- */
-static inline void usb_hub_port_init(usb_hub_port_t *port) {
-	port->attached_device.address = -1;
-	port->attached_device.handle = 0;
-	fibril_mutex_initialize(&port->reset_mutex);
-	fibril_condvar_initialize(&port->reset_cv);
-}
-
-
-void usb_hub_process_port_interrupt(usb_hub_info_t *hub,
-	uint16_t port);
-
-
-
-#endif
-/**
- * @}
- */
Index: uspace/drv/bus/usb/usbhub/status.h
===================================================================
--- uspace/drv/bus/usb/usbhub/status.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/drv/bus/usb/usbhub/status.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2010 Matus Dekanek
+ * Copyright (c) 2011 Jan Vesely
+ * 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 drvusbhub
+ * @{
+ */
+
+#ifndef HUB_STATUS_H
+#define	HUB_STATUS_H
+
+#include <bool.h>
+#include <sys/types.h>
+#include <usb/dev/request.h>
+
+/**
+ * structure holding port status and changes flags.
+ * should not be accessed directly, use supplied getter/setter methods.
+ *
+ * For more information refer to table 11-15 in
+ * "Universal Serial Bus Specification Revision 1.1"
+ *
+ */
+typedef uint32_t usb_port_status_t;
+#define USB_HUB_PORT_STATUS_CONNECTION \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_CONNECTION)))
+#define USB_HUB_PORT_STATUS_ENABLED \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_ENABLE)))
+#define USB_HUB_PORT_STATUS_SUSPEND \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_SUSPEND)))
+#define USB_HUB_PORT_STATUS_OC \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_OVER_CURRENT)))
+#define USB_HUB_PORT_STATUS_RESET \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_RESET)))
+#define USB_HUB_PORT_STATUS_POWER \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_POWER)))
+#define USB_HUB_PORT_STATUS_LOW_SPEED \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_LOW_SPEED)))
+#define USB_HUB_PORT_STATUS_HIGH_SPEED \
+    (uint32_usb2host(1 << 10))
+
+#define USB_HUB_PORT_C_STATUS_CONNECTION \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_CONNECTION)))
+#define USB_HUB_PORT_C_STATUS_ENABLED \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_ENABLE)))
+#define USB_HUB_PORT_C_STATUS_SUSPEND \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_SUSPEND)))
+#define USB_HUB_PORT_C_STATUS_OC \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_OVER_CURRENT)))
+#define USB_HUB_PORT_C_STATUS_RESET \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_RESET)))
+
+/**
+ * structure holding hub status and changes flags.
+ *
+ * For more information refer to table 11.16.2.5 in
+ * "Universal Serial Bus Specification Revision 1.1"
+ *
+ */
+typedef uint32_t usb_hub_status_t;
+#define USB_HUB_STATUS_OVER_CURRENT \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_HUB_OVER_CURRENT)))
+#define USB_HUB_STATUS_LOCAL_POWER \
+    (uint32_usb2host(1 << (USB_HUB_FEATURE_HUB_LOCAL_POWER)))
+
+#define USB_HUB_STATUS_C_OVER_CURRENT \
+    (uint32_usb2host(1 << (16 + USB_HUB_FEATURE_C_HUB_OVER_CURRENT)))
+#define USB_HUB_STATUS_C_LOCAL_POWER \
+    (uint32_usb2host(1 << (16 + USB_HUB_FEATURE_C_HUB_LOCAL_POWER)))
+
+
+/**
+ * speed getter for port status
+ *
+ * @param status
+ * @return speed of usb device (for more see usb specification)
+ */
+static inline usb_speed_t usb_port_speed(usb_port_status_t status)
+{
+	if ((status & USB_HUB_PORT_STATUS_LOW_SPEED) != 0)
+		return USB_SPEED_LOW;
+	if ((status & USB_HUB_PORT_STATUS_HIGH_SPEED) != 0)
+		return USB_SPEED_HIGH;
+	return USB_SPEED_FULL;
+}
+
+#endif	/* HUB_STATUS_H */
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/usbhub/usbhub.c
===================================================================
--- uspace/drv/bus/usb/usbhub/usbhub.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhub/usbhub.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Matus Dekanek
+ * Copyright (c) 2011 Jan Vesely
  * All rights reserved.
  *
@@ -38,6 +39,10 @@
 #include <str_error.h>
 #include <inttypes.h>
-
-#include <usb_iface.h>
+#include <stdio.h>
+
+#include <usb/usb.h>
+#include <usb/debug.h>
+#include <usb/dev/pipes.h>
+#include <usb/classes/classes.h>
 #include <usb/ddfiface.h>
 #include <usb/descriptor.h>
@@ -46,98 +51,169 @@
 #include <usb/classes/hub.h>
 #include <usb/dev/poll.h>
-#include <stdio.h>
+#include <usb_iface.h>
 
 #include "usbhub.h"
-#include "usbhub_private.h"
-#include "port_status.h"
-#include <usb/usb.h>
-#include <usb/dev/pipes.h>
-#include <usb/classes/classes.h>
-
-
-static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev);
-
-static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info);
-
-static int usb_hub_set_configuration(usb_hub_info_t *hub_info);
-
-static int usb_hub_start_hub_fibril(usb_hub_info_t *hub_info);
-
-static int usb_process_hub_over_current(usb_hub_info_t *hub_info,
+#include "status.h"
+
+#define HUB_FNC_NAME "hub"
+
+/** Standard get hub global status request */
+static const usb_device_request_setup_packet_t get_hub_status_request = {
+	.request_type = USB_HUB_REQ_TYPE_GET_HUB_STATUS,
+	.request = USB_HUB_REQUEST_GET_STATUS,
+	.index = 0,
+	.value = 0,
+	.length = sizeof(usb_hub_status_t),
+};
+
+static int usb_set_first_configuration(usb_device_t *usb_device);
+static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev);
+static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
     usb_hub_status_t status);
-
-static int usb_process_hub_local_power_change(usb_hub_info_t *hub_info,
-    usb_hub_status_t status);
-
-static void usb_hub_process_global_interrupt(usb_hub_info_t *hub_info);
-
+static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev);
 static void usb_hub_polling_terminated_callback(usb_device_t *device,
     bool was_error, void *data);
 
-
-//*********************************************
-//
-//  hub driver code, initialization
-//
-//*********************************************
-
-/**
- * Initialize hub device driver fibril
- *
- * Creates hub representation and fibril that periodically checks hub`s status.
+/**
+ * Initialize hub device driver structure.
+ *
+ * Creates hub representation and fibril that periodically checks hub's status.
  * Hub representation is passed to the fibril.
  * @param usb_dev generic usb device information
  * @return error code
  */
-int usb_hub_add_device(usb_device_t *usb_dev) {
-	if (!usb_dev) return EINVAL;
-	usb_hub_info_t *hub_info = usb_hub_info_create(usb_dev);
-	//create hc connection
+int usb_hub_device_add(usb_device_t *usb_dev)
+{
+	assert(usb_dev);
+	/* Create driver soft-state structure */
+	usb_hub_dev_t *hub_dev =
+	    usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));
+	if (hub_dev == NULL) {
+		usb_log_error("Failed to create hub driver structure.\n");
+		return ENOMEM;
+	}
+	hub_dev->usb_device = usb_dev;
+	hub_dev->pending_ops_count = 0;
+	hub_dev->running = false;
+	fibril_mutex_initialize(&hub_dev->pending_ops_mutex);
+	fibril_condvar_initialize(&hub_dev->pending_ops_cv);
+
+	/* Create hc connection */
 	usb_log_debug("Initializing USB wire abstraction.\n");
 	int opResult = usb_hc_connection_initialize_from_device(
-	    &hub_info->connection,
-	    hub_info->usb_device->ddf_dev);
-	if (opResult != EOK) {
-		usb_log_error("Could not initialize connection to device, "
-		    " %s\n",
-		    str_error(opResult));
-		free(hub_info);
+	    &hub_dev->connection, hub_dev->usb_device->ddf_dev);
+	if (opResult != EOK) {
+		usb_log_error("Could not initialize connection to device: %s\n",
+		    str_error(opResult));
 		return opResult;
 	}
 
-	//set hub configuration
-	opResult = usb_hub_set_configuration(hub_info);
-	if (opResult != EOK) {
-		usb_log_error("Could not set hub configuration, %s\n",
-		    str_error(opResult));
-		free(hub_info);
+	/* Set hub's first configuration. (There should be only one) */
+	opResult = usb_set_first_configuration(usb_dev);
+	if (opResult != EOK) {
+		usb_log_error("Could not set hub configuration: %s\n",
+		    str_error(opResult));
 		return opResult;
 	}
-	//get port count and create attached_devs
-	opResult = usb_hub_process_hub_specific_info(hub_info);
+
+	/* Get port count and create attached_devices. */
+	opResult = usb_hub_process_hub_specific_info(hub_dev);
 	if (opResult != EOK) {
 		usb_log_error("Could process hub specific info, %s\n",
 		    str_error(opResult));
-		free(hub_info);
 		return opResult;
 	}
 
-	usb_log_debug("Creating 'hub' function in DDF.\n");
-	ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
-	    fun_exposed, "hub");
-	assert(hub_fun != NULL);
-	hub_fun->ops = NULL;
-
-	opResult = ddf_fun_bind(hub_fun);
-	assert(opResult == EOK);
-	opResult = ddf_fun_add_to_category(hub_fun, "hub");
-	assert(opResult == EOK);
-
-	opResult = usb_hub_start_hub_fibril(hub_info);
-	if (opResult != EOK)
-		free(hub_info);
-	return opResult;
-}
-
+	/* Create hub control function. */
+	usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");
+	hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev,
+	    fun_exposed, HUB_FNC_NAME);
+	if (hub_dev->hub_fun == NULL) {
+		usb_log_error("Failed to create hub function.\n");
+		return ENOMEM;
+	}
+
+	/* Bind hub control function. */
+	opResult = ddf_fun_bind(hub_dev->hub_fun);
+	if (opResult != EOK) {
+		usb_log_error("Failed to bind hub function: %s.\n",
+		   str_error(opResult));
+		ddf_fun_destroy(hub_dev->hub_fun);
+		return opResult;
+	}
+
+	/* Start hub operation. */
+	opResult = usb_device_auto_poll(hub_dev->usb_device, 0,
+	    hub_port_changes_callback, ((hub_dev->port_count + 1 + 8) / 8),
+	    usb_hub_polling_terminated_callback, hub_dev);
+	if (opResult != EOK) {
+		/* Function is already bound */
+		ddf_fun_unbind(hub_dev->hub_fun);
+		ddf_fun_destroy(hub_dev->hub_fun);
+		usb_log_error("Failed to create polling fibril: %s.\n",
+		    str_error(opResult));
+		return opResult;
+	}
+	hub_dev->running = true;
+	usb_log_info("Controlling hub '%s' (%zu ports).\n",
+	    hub_dev->usb_device->ddf_dev->name, hub_dev->port_count);
+
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Turn off power to all ports.
+ *
+ * @param usb_dev generic usb device information
+ * @return error code
+ */
+int usb_hub_device_remove(usb_device_t *usb_dev)
+{
+	return ENOTSUP;
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Remove all attached devices
+ * @param usb_dev generic usb device information
+ * @return error code
+ */
+int usb_hub_device_gone(usb_device_t *usb_dev)
+{
+	assert(usb_dev);
+	usb_hub_dev_t *hub = usb_dev->driver_data;
+	assert(hub);
+	unsigned tries = 10;
+	while (hub->running) {
+		async_usleep(100000);
+		if (!tries--) {
+			usb_log_error("Can't remove hub, still running.\n");
+			return EINPROGRESS;
+		}
+	}
+
+	assert(!hub->running);
+
+	for (size_t port = 0; port < hub->port_count; ++port) {
+		if (hub->ports[port].attached_device.fun) {
+			const int ret =
+			    usb_hub_port_fini(&hub->ports[port], hub);
+			if (ret != EOK)
+				return ret;
+		}
+	}
+	free(hub->ports);
+
+	const int ret = ddf_fun_unbind(hub->hub_fun);
+	if (ret != EOK) {
+		usb_log_error("Failed to unbind '%s' function: %s.\n",
+		   HUB_FNC_NAME, str_error(ret));
+		return ret;
+	}
+	ddf_fun_destroy(hub->hub_fun);
+
+	usb_log_info("USB hub driver, stopped and cleaned.\n");
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 /** Callback for polling hub for changes.
  *
@@ -145,92 +221,60 @@
  * @param change_bitmap Bitmap of changed ports.
  * @param change_bitmap_size Size of the bitmap in bytes.
- * @param arg Custom argument, points to @c usb_hub_info_t.
+ * @param arg Custom argument, points to @c usb_hub_dev_t.
  * @return Whether to continue polling.
  */
 bool hub_port_changes_callback(usb_device_t *dev,
-    uint8_t *change_bitmap, size_t change_bitmap_size, void *arg) {
+    uint8_t *change_bitmap, size_t change_bitmap_size, void *arg)
+{
 	usb_log_debug("hub_port_changes_callback\n");
-	usb_hub_info_t *hub = (usb_hub_info_t *) arg;
-
-	/* FIXME: check that we received enough bytes. */
+	usb_hub_dev_t *hub = arg;
+	assert(hub);
+
+	/* It is an error condition if we didn't receive enough data */
 	if (change_bitmap_size == 0) {
-		goto leave;
-	}
-
-	bool change;
-	change = ((uint8_t*) change_bitmap)[0] & 1;
+		return false;
+	}
+
+	/* Lowest bit indicates global change */
+	const bool change = change_bitmap[0] & 1;
 	if (change) {
-		usb_hub_process_global_interrupt(hub);
-	}
-
-	size_t port;
-	for (port = 1; port < hub->port_count + 1; port++) {
-		bool change = (change_bitmap[port / 8] >> (port % 8)) % 2;
+		usb_hub_global_interrupt(hub);
+	}
+
+	/* N + 1 bit indicates change on port N */
+	for (size_t port = 0; port < hub->port_count + 1; port++) {
+		const size_t bit = port + 1;
+		const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1;
 		if (change) {
-			usb_hub_process_port_interrupt(hub, port);
-		}
-	}
-leave:
-	/* FIXME: proper interval. */
-	async_usleep(1000 * 250);
-
+			usb_hub_port_process_interrupt(&hub->ports[port], hub);
+		}
+	}
 	return true;
 }
-
-
-//*********************************************
-//
-//  support functions
-//
-//*********************************************
-
-/**
- * create usb_hub_info_t structure
- *
- * Does only basic copying of known information into new structure.
- * @param usb_dev usb device structure
- * @return basic usb_hub_info_t structure
- */
-static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev) {
-	usb_hub_info_t * result = malloc(sizeof (usb_hub_info_t));
-	if (!result) return NULL;
-	result->usb_device = usb_dev;
-	result->status_change_pipe = usb_dev->pipes[0].pipe;
-	result->control_pipe = &usb_dev->ctrl_pipe;
-	result->is_default_address_used = false;
-
-	result->ports = NULL;
-	result->port_count = (size_t) - 1;
-	fibril_mutex_initialize(&result->port_mutex);
-
-	fibril_mutex_initialize(&result->pending_ops_mutex);
-	fibril_condvar_initialize(&result->pending_ops_cv);
-	result->pending_ops_count = 0;
-	return result;
-}
-
-/**
- * Load hub-specific information into hub_info structure and process if needed
- *
- * Particularly read port count and initialize structure holding port
- * information. If there are non-removable devices, start initializing them.
+/*----------------------------------------------------------------------------*/
+/**
+ * Load hub-specific information into hub_dev structure and process if needed
+ *
+ * Read port count and initialize structures holding per port information.
+ * If there are any non-removable devices, start initializing them.
  * This function is hub-specific and should be run only after the hub is
- * configured using usb_hub_set_configuration function.
- * @param hub_info hub representation
+ * configured using usb_set_first_configuration function.
+ * @param hub_dev hub representation
  * @return error code
  */
-int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info)
-{
-	// get hub descriptor
+static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev)
+{
+	assert(hub_dev);
+
+	/* Get hub descriptor. */
 	usb_log_debug("Retrieving descriptor\n");
-	uint8_t serialized_descriptor[USB_HUB_MAX_DESCRIPTOR_SIZE];
-	int opResult;
-
+	usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
+
+	usb_hub_descriptor_header_t descriptor;
 	size_t received_size;
-	opResult = usb_request_get_descriptor(hub_info->control_pipe,
+	int opResult = usb_request_get_descriptor(control_pipe,
 	    USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
-	    USB_DESCTYPE_HUB, 0, 0, serialized_descriptor,
-	    USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
-
+	    USB_DESCTYPE_HUB, 0, 0, &descriptor,
+	    sizeof(usb_hub_descriptor_header_t), &received_size);
 	if (opResult != EOK) {
 		usb_log_error("Failed to receive hub descriptor: %s.\n",
@@ -238,216 +282,155 @@
 		return opResult;
 	}
-	usb_log_debug2("Parsing descriptor\n");
-	usb_hub_descriptor_t descriptor;
-	opResult = usb_deserialize_hub_desriptor(
-	        serialized_descriptor, received_size, &descriptor);
-	if (opResult != EOK) {
-		usb_log_error("Could not parse descriptor: %s\n",
-		    str_error(opResult));
-		return opResult;
-	}
-	usb_log_debug("Setting port count to %d.\n", descriptor.ports_count);
-	hub_info->port_count = descriptor.ports_count;
-
-	hub_info->ports =
-	    malloc(sizeof(usb_hub_port_t) * (hub_info->port_count + 1));
-	if (!hub_info->ports) {
+
+	usb_log_debug("Setting port count to %d.\n", descriptor.port_count);
+	hub_dev->port_count = descriptor.port_count;
+
+	hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t));
+	if (!hub_dev->ports) {
 		return ENOMEM;
 	}
 
-	size_t port;
-	for (port = 0; port < hub_info->port_count + 1; ++port) {
-		usb_hub_port_init(&hub_info->ports[port]);
-	}
-
-	const bool is_power_switched =
-	    !(descriptor.hub_characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG);
-	if (is_power_switched) {
-		usb_log_debug("Hub power switched\n");
-		const bool per_port_power = descriptor.hub_characteristics
-		    & HUB_CHAR_POWER_PER_PORT_FLAG;
-
-		for (port = 1; port <= hub_info->port_count; ++port) {
-			usb_log_debug("Powering port %zu.\n", port);
-			opResult = usb_hub_set_port_feature(
-			    hub_info->control_pipe,
-			    port, USB_HUB_FEATURE_PORT_POWER);
-			if (opResult != EOK) {
-				usb_log_error("Cannot power on port %zu: %s.\n",
-				    port, str_error(opResult));
-			} else {
-				if (!per_port_power) {
-					usb_log_debug(
-					    "Ganged power switching mode, "
-					    "one port is enough.\n");
-					break;
-				}
+	for (size_t port = 0; port < hub_dev->port_count; ++port) {
+		usb_hub_port_init(
+		    &hub_dev->ports[port], port + 1, control_pipe);
+	}
+
+	hub_dev->power_switched =
+	    !(descriptor.characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG);
+	hub_dev->per_port_power =
+	    descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG;
+
+	if (!hub_dev->power_switched) {
+		usb_log_info(
+		   "Power switching not supported, ports always powered.\n");
+		return EOK;
+	}
+
+	usb_log_info("Hub port power switching enabled.\n");
+
+	for (size_t port = 0; port < hub_dev->port_count; ++port) {
+		usb_log_debug("Powering port %zu.\n", port);
+		const int ret = usb_hub_port_set_feature(
+		    &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
+
+		if (ret != EOK) {
+			usb_log_error("Cannot power on port %zu: %s.\n",
+			    hub_dev->ports[port].port_number, str_error(ret));
+		} else {
+			if (!hub_dev->per_port_power) {
+				usb_log_debug("Ganged power switching, "
+				    "one port is enough.\n");
+				break;
 			}
 		}
-
-	} else {
-		usb_log_debug("Power not switched, not going to be powered\n");
 	}
 	return EOK;
 }
-
-/**
- * Set configuration of hub
+/*----------------------------------------------------------------------------*/
+/**
+ * Set configuration of and USB device
  *
  * Check whether there is at least one configuration and sets the first one.
  * This function should be run prior to running any hub-specific action.
- * @param hub_info hub representation
+ * @param usb_device usb device representation
  * @return error code
  */
-static int usb_hub_set_configuration(usb_hub_info_t *hub_info) {
-	//device descriptor
-	usb_standard_device_descriptor_t *std_descriptor
-	    = &hub_info->usb_device->descriptors.device;
-	usb_log_debug("Hub has %d configurations\n",
-	    std_descriptor->configuration_count);
-	if (std_descriptor->configuration_count < 1) {
+static int usb_set_first_configuration(usb_device_t *usb_device)
+{
+	assert(usb_device);
+	/* Get number of possible configurations from device descriptor */
+	const size_t configuration_count =
+	    usb_device->descriptors.device.configuration_count;
+	usb_log_debug("Hub has %zu configurations.\n", configuration_count);
+
+	if (configuration_count < 1) {
 		usb_log_error("There are no configurations available\n");
 		return EINVAL;
 	}
 
+	if (usb_device->descriptors.configuration_size
+	    < sizeof(usb_standard_configuration_descriptor_t)) {
+	    usb_log_error("Configuration descriptor is not big enough"
+	        " to fit standard configuration descriptor.\n");
+	    return EOVERFLOW;
+	}
+
+	// TODO: Make sure that the cast is correct
 	usb_standard_configuration_descriptor_t *config_descriptor
 	    = (usb_standard_configuration_descriptor_t *)
-	    hub_info->usb_device->descriptors.configuration;
-
-	/* Set configuration. */
-	int opResult = usb_request_set_configuration(
-	    &hub_info->usb_device->ctrl_pipe,
-	    config_descriptor->configuration_number);
-
+	    usb_device->descriptors.configuration;
+
+	/* Set configuration. Use the configuration that was in
+	 * usb_device->descriptors.configuration i.e. The first one. */
+	const int opResult = usb_request_set_configuration(
+	    &usb_device->ctrl_pipe, config_descriptor->configuration_number);
 	if (opResult != EOK) {
 		usb_log_error("Failed to set hub configuration: %s.\n",
 		    str_error(opResult));
-		return opResult;
-	}
-	usb_log_debug("\tUsed configuration %d\n",
-	    config_descriptor->configuration_number);
-
-	return EOK;
-}
-
-/**
- * create and start fibril with hub control loop
- *
- * Before the fibril is started, the control pipe and host controller
- * connection of the hub is open.
- *
- * @param hub_info hub representing structure
- * @return error code
- */
-static int usb_hub_start_hub_fibril(usb_hub_info_t *hub_info) {
-	int rc;
-
-	rc = usb_device_auto_poll(hub_info->usb_device, 0,
-	    hub_port_changes_callback, ((hub_info->port_count + 1) / 8) + 1,
-	    usb_hub_polling_terminated_callback, hub_info);
-	if (rc != EOK) {
-		usb_log_error("Failed to create polling fibril: %s.\n",
-		    str_error(rc));
-		free(hub_info);
-		return rc;
-	}
-
-	usb_log_info("Controlling hub `%s' (%zu ports).\n",
-	    hub_info->usb_device->ddf_dev->name, hub_info->port_count);
-	return EOK;
-}
-
-//*********************************************
-//
-//  change handling functions
-//
-//*********************************************
-
-/**
- * process hub over current change
+	} else {
+		usb_log_debug("\tUsed configuration %d\n",
+		    config_descriptor->configuration_number);
+	}
+	return opResult;
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Process hub over current change
  *
  * This means either to power off the hub or power it on.
- * @param hub_info hub instance
+ * @param hub_dev hub instance
  * @param status hub status bitmask
  * @return error code
  */
-static int usb_process_hub_over_current(usb_hub_info_t *hub_info,
-    usb_hub_status_t status) {
-	int opResult;
-	if (usb_hub_is_status(status, USB_HUB_FEATURE_HUB_OVER_CURRENT)) {
-		//poweroff all ports
-		unsigned int port;
-		for (port = 1; port <= hub_info->port_count; ++port) {
-			opResult = usb_hub_clear_port_feature(
-			    hub_info->control_pipe, port,
-			    USB_HUB_FEATURE_PORT_POWER);
-			if (opResult != EOK) {
-				usb_log_warning(
-				    "Cannot power off port %d;  %s\n",
-				    port, str_error(opResult));
-			}
-		}
-	} else {
-		//power all ports
-		unsigned int port;
-		for (port = 1; port <= hub_info->port_count; ++port) {
-			opResult = usb_hub_set_port_feature(
-			    hub_info->control_pipe, port,
-			    USB_HUB_FEATURE_PORT_POWER);
-			if (opResult != EOK) {
-				usb_log_warning(
-				    "Cannot power off port %d;  %s\n",
-				    port, str_error(opResult));
-			}
-		}
-	}
-	return opResult;
-}
-
-/**
- * process hub local power change
- *
- * This change is ignored.
- * @param hub_info hub instance
- * @param status hub status bitmask
- * @return error code
- */
-static int usb_process_hub_local_power_change(usb_hub_info_t *hub_info,
-    usb_hub_status_t status) {
-	int opResult = EOK;
-	opResult = usb_hub_clear_feature(hub_info->control_pipe,
-	    USB_HUB_FEATURE_C_HUB_LOCAL_POWER);
-	if (opResult != EOK) {
-		usb_log_error("Cannnot clear hub power change flag: "
-		    "%s\n",
-		    str_error(opResult));
-	}
-	return opResult;
-}
-
-/**
- * process hub interrupts
- *
- * The change can be either in the over-current condition or
- * local-power change.
- * @param hub_info hub instance
- */
-static void usb_hub_process_global_interrupt(usb_hub_info_t *hub_info) {
+static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
+    usb_hub_status_t status)
+{
+	if (status & USB_HUB_STATUS_OVER_CURRENT) {
+		/* Hub should remove power from all ports if it detects OC */
+		usb_log_warning("Detected hub over-current condition, "
+		    "all ports should be powered off.");
+		return;
+	}
+
+	/* Ports are always powered. */
+	if (!hub_dev->power_switched)
+		return;
+
+	/* Over-current condition is gone, it is safe to turn the ports on. */
+	for (size_t port = 0; port < hub_dev->port_count; ++port) {
+		const int ret = usb_hub_port_set_feature(
+		    &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
+		if (ret != EOK) {
+			usb_log_warning("HUB OVER-CURRENT GONE: Cannot power on"
+			    " port %zu: %s\n", hub_dev->ports[port].port_number,
+			    str_error(ret));
+		} else {
+			if (!hub_dev->per_port_power)
+				return;
+		}
+	}
+
+}
+/*----------------------------------------------------------------------------*/
+/**
+ * Process hub interrupts.
+ *
+ * The change can be either in the over-current condition or local-power change.
+ * @param hub_dev hub instance
+ */
+static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev)
+{
+	assert(hub_dev);
+	assert(hub_dev->usb_device);
 	usb_log_debug("Global interrupt on a hub\n");
-	usb_pipe_t *pipe = hub_info->control_pipe;
-	int opResult;
-
-	usb_port_status_t status;
+	usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe;
+
+	usb_hub_status_t status;
 	size_t rcvd_size;
-	usb_device_request_setup_packet_t request;
-	//int opResult;
-	usb_hub_set_hub_status_request(&request);
-	//endpoint 0
-
-	opResult = usb_pipe_control_read(
-	    pipe,
-	    &request, sizeof (usb_device_request_setup_packet_t),
-	    &status, 4, &rcvd_size
-	    );
+	/* NOTE: We can't use standard USB GET_STATUS request, because
+	 * hubs reply is 4byte instead of 2 */
+	const int opResult = usb_pipe_control_read(control_pipe,
+	    &get_hub_status_request, sizeof(get_hub_status_request),
+	    &status, sizeof(usb_hub_status_t), &rcvd_size);
 	if (opResult != EOK) {
 		usb_log_error("Could not get hub status: %s\n",
@@ -455,30 +438,60 @@
 		return;
 	}
-	if (rcvd_size != sizeof (usb_port_status_t)) {
+	if (rcvd_size != sizeof(usb_hub_status_t)) {
 		usb_log_error("Received status has incorrect size\n");
 		return;
 	}
-	//port reset
-	if (
-	    usb_hub_is_status(status, 16 + USB_HUB_FEATURE_C_HUB_OVER_CURRENT)) {
-		usb_process_hub_over_current(hub_info, status);
-	}
-	if (
-	    usb_hub_is_status(status, 16 + USB_HUB_FEATURE_C_HUB_LOCAL_POWER)) {
-		usb_process_hub_local_power_change(hub_info, status);
-	}
-}
-
+
+	/* Handle status changes */
+	if (status & USB_HUB_STATUS_C_OVER_CURRENT) {
+		usb_hub_over_current(hub_dev, status);
+		/* Ack change in hub OC flag */
+		const int ret = usb_request_clear_feature(
+		    &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS,
+		    USB_REQUEST_RECIPIENT_DEVICE,
+		    USB_HUB_FEATURE_C_HUB_OVER_CURRENT, 0);
+		if (ret != EOK) {
+			usb_log_error("Failed to clear hub over-current "
+			    "change flag: %s.\n", str_error(opResult));
+		}
+	}
+
+	if (status & USB_HUB_STATUS_C_LOCAL_POWER) {
+		/* NOTE: Handling this is more complicated.
+		 * If the transition is from bus power to local power, all
+		 * is good and we may signal the parent hub that we don't
+		 * need the power.
+		 * If the transition is from local power to bus power
+		 * the hub should turn off all the ports and devices need
+		 * to be reinitialized taking into account the limited power
+		 * that is now available.
+		 * There is no support for power distribution in HelenOS,
+		 * (or other OSes/hub devices that I've seen) so this is not
+		 * implemented.
+		 * Just ACK the change.
+		 */
+		const int ret = usb_request_clear_feature(
+		    control_pipe, USB_REQUEST_TYPE_CLASS,
+		    USB_REQUEST_RECIPIENT_DEVICE,
+		    USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0);
+		if (opResult != EOK) {
+			usb_log_error("Failed to clear hub power change "
+			    "flag: %s.\n", str_error(ret));
+		}
+	}
+}
+/*----------------------------------------------------------------------------*/
 /**
  * callback called from hub polling fibril when the fibril terminates
  *
- * Should perform a cleanup - deletes hub_info.
+ * Does not perform cleanup, just marks the hub as not running.
  * @param device usb device afected
  * @param was_error indicates that the fibril is stoped due to an error
- * @param data pointer to usb_hub_info_t structure
+ * @param data pointer to usb_hub_dev_t structure
  */
 static void usb_hub_polling_terminated_callback(usb_device_t *device,
-    bool was_error, void *data) {
-	usb_hub_info_t * hub = data;
+    bool was_error, void *data)
+{
+	usb_hub_dev_t *hub = data;
 	assert(hub);
 
@@ -494,15 +507,7 @@
 	 */
 	if (hub->pending_ops_count > 0) {
-		fibril_mutex_lock(&hub->port_mutex);
-		size_t port;
-		for (port = 0; port < hub->port_count; port++) {
-			usb_hub_port_t *the_port = hub->ports + port;
-			fibril_mutex_lock(&the_port->reset_mutex);
-			the_port->reset_completed = true;
-			the_port->reset_okay = false;
-			fibril_condvar_broadcast(&the_port->reset_cv);
-			fibril_mutex_unlock(&the_port->reset_mutex);
-		}
-		fibril_mutex_unlock(&hub->port_mutex);
+		for (size_t port = 0; port < hub->port_count; ++port) {
+			usb_hub_port_reset_fail(&hub->ports[port]);
+		}
 	}
 	/* And now wait for them. */
@@ -512,14 +517,6 @@
 	}
 	fibril_mutex_unlock(&hub->pending_ops_mutex);
-
-	usb_device_destroy(hub->usb_device);
-
-	free(hub->ports);
-	free(hub);
-}
-
-
-
-
+	hub->running = false;
+}
 /**
  * @}
Index: uspace/drv/bus/usb/usbhub/usbhub.h
===================================================================
--- uspace/drv/bus/usb/usbhub/usbhub.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbhub/usbhub.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Vojtech Horky
  * All rights reserved.
  *
@@ -26,5 +27,4 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 /** @addtogroup drvusbhub
  * @{
@@ -49,44 +49,16 @@
 #define NAME "usbhub"
 
-#include "ports.h"
+#include "port.h"
 
 /** Information about attached hub. */
-struct usb_hub_info_t {
+struct usb_hub_dev {
 	/** Number of ports. */
 	size_t port_count;
-
-	/** attached device handles, for each port one */
+	/** Port structures, one for each port */
 	usb_hub_port_t *ports;
-
-	fibril_mutex_t port_mutex;
-
-	/** connection to hcd */
+	/** Connection to hcd */
 	usb_hc_connection_t connection;
-
-	/** default address is used indicator
-	 *
-	 * If default address is requested by this device, it cannot
-	 * be requested by the same hub again, otherwise a deadlock will occur.
-	 */
-	bool is_default_address_used;
-
-	/** convenience pointer to status change pipe
-	 *
-	 * Status change pipe is initialized in usb_device structure. This is
-	 * pointer into this structure, so that it does not have to be
-	 * searched again and again for the 'right pipe'.
-	 */
-	usb_pipe_t * status_change_pipe;
-
-	/** convenience pointer to control pipe
-	 *
-	 * Control pipe is initialized in usb_device structure. This is
-	 * pointer into this structure, so that it does not have to be
-	 * searched again and again for the 'right pipe'.
-	 */
-	usb_pipe_t * control_pipe;
-
-	/** generic usb device data*/
-	usb_device_t * usb_device;
+	/** Generic usb device data*/
+	usb_device_t *usb_device;
 
 	/** Number of pending operations on the mutex to prevent shooting
@@ -101,8 +73,17 @@
 	/** Condition variable for pending_ops_count. */
 	fibril_condvar_t pending_ops_cv;
-
+	/** Pointer to devman usbhub function. */
+	ddf_fun_t *hub_fun;
+	/** Status indicator */
+	bool running;
+	/** Hub supports port power switching. */
+	bool power_switched;
+	/** Each port is switched individually. */
+	bool per_port_power;
 };
 
-int usb_hub_add_device(usb_device_t *usb_dev);
+int usb_hub_device_add(usb_device_t *usb_dev);
+int usb_hub_device_remove(usb_device_t *usb_dev);
+int usb_hub_device_gone(usb_device_t *usb_dev);
 
 bool hub_port_changes_callback(usb_device_t *dev,
Index: uspace/drv/bus/usb/usbhub/usbhub_private.h
===================================================================
--- uspace/drv/bus/usb/usbhub/usbhub_private.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,181 +1,0 @@
-/*
- * Copyright (c) 2010 Matus Dekanek
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbhub
- * @{
- */
-/** @file
- * @brief Hub driver private definitions
- */
-
-#ifndef USBHUB_PRIVATE_H
-#define	USBHUB_PRIVATE_H
-
-#include "usbhub.h"
-
-#include <adt/list.h>
-#include <bool.h>
-#include <ddf/driver.h>
-#include <fibril_synch.h>
-
-#include <usb/classes/hub.h>
-#include <usb/usb.h>
-#include <usb/debug.h>
-#include <usb/dev/request.h>
-
-//************
-//
-// convenience define for malloc
-//
-//************
-
-
-usb_hub_info_t * usb_create_hub_info(ddf_dev_t * device);
-
-/**
- * Set the device request to be a get hub descriptor request.
- * @warning the size is allways set to USB_HUB_MAX_DESCRIPTOR_SIZE
- * @param request
- * @param addr
- */
-static inline void usb_hub_set_descriptor_request(
-    usb_device_request_setup_packet_t * request
-    ) {
-	request->index = 0;
-	request->request_type = USB_HUB_REQ_TYPE_GET_DESCRIPTOR;
-	request->request = USB_HUB_REQUEST_GET_DESCRIPTOR;
-	request->value_high = USB_DESCTYPE_HUB;
-	request->value_low = 0;
-	request->length = USB_HUB_MAX_DESCRIPTOR_SIZE;
-}
-
-/**
- * Clear feature on hub port.
- *
- * @param hc Host controller telephone
- * @param address Hub address
- * @param port_index Port
- * @param feature Feature selector
- * @return Operation result
- */
-static inline int usb_hub_clear_port_feature(usb_pipe_t *pipe,
-    int port_index,
-    usb_hub_class_feature_t feature) {
-
-	usb_device_request_setup_packet_t clear_request = {
-		.request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE,
-		.request = USB_DEVREQ_CLEAR_FEATURE,
-		.length = 0,
-		.index = port_index
-	};
-	clear_request.value = feature;
-	return usb_pipe_control_write(pipe, &clear_request,
-	    sizeof (clear_request), NULL, 0);
-}
-
-/**
- * Clear feature on hub port.
- *
- * @param hc Host controller telephone
- * @param address Hub address
- * @param port_index Port
- * @param feature Feature selector
- * @return Operation result
- */
-static inline int usb_hub_set_port_feature(usb_pipe_t *pipe,
-    int port_index,
-    usb_hub_class_feature_t feature) {
-
-	usb_device_request_setup_packet_t clear_request = {
-		.request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE,
-		.request = USB_DEVREQ_SET_FEATURE,
-		.length = 0,
-		.index = port_index
-	};
-	clear_request.value = feature;
-	return usb_pipe_control_write(pipe, &clear_request,
-	    sizeof (clear_request), NULL, 0);
-}
-
-/**
- * Clear feature on hub port.
- *
- * @param pipe pipe to hub control endpoint
- * @param feature Feature selector
- * @return Operation result
- */
-static inline int usb_hub_clear_feature(usb_pipe_t *pipe,
-    usb_hub_class_feature_t feature) {
-
-	usb_device_request_setup_packet_t clear_request = {
-		.request_type = USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE,
-		.request = USB_DEVREQ_CLEAR_FEATURE,
-		.length = 0,
-		.index = 0
-	};
-	clear_request.value = feature;
-	return usb_pipe_control_write(pipe, &clear_request,
-	    sizeof (clear_request), NULL, 0);
-}
-
-/**
- * Clear feature on hub port.
- *
- * @param pipe pipe to hub control endpoint
- * @param feature Feature selector
- * @return Operation result
- */
-static inline int usb_hub_set_feature(usb_pipe_t *pipe,
-    usb_hub_class_feature_t feature) {
-
-	usb_device_request_setup_packet_t clear_request = {
-		.request_type = USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE,
-		.request = USB_DEVREQ_SET_FEATURE,
-		.length = 0,
-		.index = 0
-	};
-	clear_request.value = feature;
-	return usb_pipe_control_write(pipe, &clear_request,
-	    sizeof (clear_request), NULL, 0);
-}
-
-
-void * usb_create_serialized_hub_descriptor(usb_hub_descriptor_t * descriptor);
-
-void usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor,
-    void * serialized_descriptor);
-
-int usb_deserialize_hub_desriptor(
-    void *serialized_descriptor, size_t size, usb_hub_descriptor_t *descriptor);
-
-
-#endif	/* USBHUB_PRIVATE_H */
-
-/**
- * @}
- */
Index: uspace/drv/bus/usb/usbhub/utils.c
===================================================================
--- uspace/drv/bus/usb/usbhub/utils.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,155 +1,0 @@
-/*
- * Copyright (c) 2010 Matus Dekanek
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup drvusbhub
- * @{
- */
-/** @file
- * @brief various utilities
- */
-#include <ddf/driver.h>
-#include <bool.h>
-#include <errno.h>
-
-#include <usbhc_iface.h>
-#include <usb/descriptor.h>
-#include <usb/classes/hub.h>
-
-#include "usbhub.h"
-#include "usbhub_private.h"
-#include "port_status.h"
-
-
-size_t USB_HUB_MAX_DESCRIPTOR_SIZE = 71;
-
-//*********************************************
-//
-//  various utils
-//
-//*********************************************
-
-//hub descriptor utils
-
-/**
- * create uint8_t array with serialized descriptor
- *
- * @param descriptor
- * @return newly created serializd descriptor pointer
- */
-void * usb_create_serialized_hub_descriptor(usb_hub_descriptor_t *descriptor) {
-	//base size
-	size_t size = 7;
-	//variable size according to port count
-	size_t var_size = (descriptor->ports_count + 7) / 8;
-	size += 2 * var_size;
-	uint8_t * result = malloc(size);
-	//size
-	if (result)
-		usb_serialize_hub_descriptor(descriptor, result);
-	return result;
-}
-
-/**
- * serialize descriptor into given buffer
- *
- * The buffer size is not checked.
- * @param descriptor
- * @param serialized_descriptor
- */
-void usb_serialize_hub_descriptor(usb_hub_descriptor_t *descriptor,
-    void * serialized_descriptor) {
-	//base size
-	uint8_t * sdescriptor = serialized_descriptor;
-	size_t size = 7;
-	//variable size according to port count
-	size_t var_size = (descriptor->ports_count + 7) / 8;
-	size += 2 * var_size;
-	//size
-	sdescriptor[0] = size;
-	//descriptor type
-	sdescriptor[1] = USB_DESCTYPE_HUB;
-	sdescriptor[2] = descriptor->ports_count;
-	/// @fixme handling of endianness??
-	sdescriptor[3] = descriptor->hub_characteristics / 256;
-	sdescriptor[4] = descriptor->hub_characteristics % 256;
-	sdescriptor[5] = descriptor->pwr_on_2_good_time;
-	sdescriptor[6] = descriptor->current_requirement;
-
-	size_t i;
-	for (i = 0; i < var_size; ++i) {
-		sdescriptor[7 + i] = descriptor->devices_removable[i];
-	}
-	for (i = 0; i < var_size; ++i) {
-		sdescriptor[7 + var_size + i] = 255;
-	}
-}
-
-/*----------------------------------------------------------------------------*/
-/**
- * Deserialize descriptor into given pointer
- *
- * @param serialized_descriptor
- * @param descriptor
- * @return
- */
-int usb_deserialize_hub_desriptor(
-    void *serialized_descriptor, size_t size, usb_hub_descriptor_t *descriptor)
-{
-	uint8_t * sdescriptor = serialized_descriptor;
-
-	if (sdescriptor[1] != USB_DESCTYPE_HUB) {
-		usb_log_error("Trying to deserialize wrong descriptor %x\n",
-		    sdescriptor[1]);
-		return EINVAL;
-	}
-	if (size < 7) {
-		usb_log_error("Serialized descriptor too small.\n");
-		return EOVERFLOW;
-	}
-
-	descriptor->ports_count = sdescriptor[2];
-	descriptor->hub_characteristics = sdescriptor[3] + 256 * sdescriptor[4];
-	descriptor->pwr_on_2_good_time = sdescriptor[5];
-	descriptor->current_requirement = sdescriptor[6];
-	const size_t var_size = (descriptor->ports_count + 7) / 8;
-	//descriptor->devices_removable = (uint8_t*) malloc(var_size);
-
-	if (size < (7 + var_size)) {
-		usb_log_error("Serialized descriptor too small.\n");
-		return EOVERFLOW;
-	}
-	size_t i = 0;
-	for (; i < var_size; ++i) {
-		descriptor->devices_removable[i] = sdescriptor[7 + i];
-	}
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-/**
- * @}
- */
Index: uspace/drv/bus/usb/usbmast/bo_trans.c
===================================================================
--- uspace/drv/bus/usb/usbmast/bo_trans.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbmast/bo_trans.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbmast/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -55,5 +55,5 @@
 #define GET_BULK_OUT(dev) ((dev)->pipes[BULK_OUT_EP].pipe)
 
-static usb_endpoint_description_t bulk_in_ep = {
+static const usb_endpoint_description_t bulk_in_ep = {
 	.transfer_type = USB_TRANSFER_BULK,
 	.direction = USB_DIRECTION_IN,
@@ -63,5 +63,5 @@
 	.flags = 0
 };
-static usb_endpoint_description_t bulk_out_ep = {
+static const usb_endpoint_description_t bulk_out_ep = {
 	.transfer_type = USB_TRANSFER_BULK,
 	.direction = USB_DIRECTION_OUT,
@@ -72,5 +72,5 @@
 };
 
-usb_endpoint_description_t *mast_endpoints[] = {
+static const usb_endpoint_description_t *mast_endpoints[] = {
 	&bulk_in_ep,
 	&bulk_out_ep,
@@ -82,10 +82,46 @@
     void *arg);
 
+/** Callback when a device is removed from the system.
+ *
+ * @param dev Representation of USB device.
+ * @return Error code.
+ */
+static int usbmast_device_gone(usb_device_t *dev)
+{
+	usbmast_dev_t *mdev = dev->driver_data;
+	assert(mdev);
+
+	for (size_t i = 0; i < mdev->lun_count; ++i) {
+		const int rc = ddf_fun_unbind(mdev->luns[i]);
+		if (rc != EOK) {
+			usb_log_error("Failed to unbind LUN function %zu: "
+			    "%s\n", i, str_error(rc));
+			return rc;
+		}
+		ddf_fun_destroy(mdev->luns[i]);
+		mdev->luns[i] = NULL;
+	}
+	free(mdev->luns);
+	return EOK;
+}
+
+/** Callback when a device is about to be removed.
+ *
+ * @param dev Representation of USB device.
+ * @return Error code.
+ */
+static int usbmast_device_remove(usb_device_t *dev)
+{
+	//TODO: flush buffers, or whatever.
+	//TODO: remove device
+	return ENOTSUP;
+}
+
 /** Callback when new device is attached and recognized as a mass storage.
  *
- * @param dev Representation of a the USB device.
+ * @param dev Representation of USB device.
  * @return Error code.
  */
-static int usbmast_add_device(usb_device_t *dev)
+static int usbmast_device_add(usb_device_t *dev)
 {
 	int rc;
@@ -94,9 +130,8 @@
 
 	/* Allocate softstate */
-	mdev = calloc(1, sizeof(usbmast_dev_t));
+	mdev = usb_device_data_alloc(dev, sizeof(usbmast_dev_t));
 	if (mdev == NULL) {
 		usb_log_error("Failed allocating softstate.\n");
-		rc = ENOMEM;
-		goto error;
+		return ENOMEM;
 	}
 
@@ -104,17 +139,22 @@
 	mdev->usb_dev = dev;
 
-	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_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,
+	    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");
-	mdev->luns = usb_masstor_get_lun_count(mdev);
-
-	for (i = 0; i < mdev->luns; i++) {
+	mdev->lun_count = usb_masstor_get_lun_count(mdev);
+	mdev->luns = calloc(mdev->lun_count, sizeof(ddf_fun_t*));
+	if (mdev->luns == NULL) {
+		rc = ENOMEM;
+		usb_log_error("Failed allocating luns table.\n");
+		goto error;
+	}
+
+	for (i = 0; i < mdev->lun_count; i++) {
 		rc = usbmast_fun_create(mdev, i);
 		if (rc != EOK)
@@ -124,7 +164,16 @@
 	return EOK;
 error:
-	/* XXX Destroy functions */
-	if (mdev != NULL)
-		free(mdev);
+	/* Destroy functions */
+	for (size_t i = 0; i < mdev->lun_count; ++i) {
+		if (mdev->luns[i] == NULL)
+			continue;
+		const int rc = ddf_fun_unbind(mdev->luns[i]);
+		if (rc != EOK) {
+			usb_log_warning("Failed to unbind LUN function %zu: "
+			    "%s.\n", i, str_error(rc));
+		}
+		ddf_fun_destroy(mdev->luns[i]);
+	}
+	free(mdev->luns);
 	return rc;
 }
@@ -158,8 +207,6 @@
 	}
 
-	free(fun_name);
-
 	/* Allocate soft state */
-	mfun = ddf_dev_data_alloc(mdev->ddf_dev, sizeof(usbmast_fun_t));
+	mfun = ddf_fun_data_alloc(fun, sizeof(usbmast_fun_t));
 	if (mfun == NULL) {
 		usb_log_error("Failed allocating softstate.\n");
@@ -168,12 +215,10 @@
 	}
 
+	mfun->ddf_fun = fun;
 	mfun->mdev = mdev;
 	mfun->lun = lun;
 
-	fun_name = NULL;
-
 	/* Set up a connection handler. */
 	fun->conn_handler = usbmast_bd_connection;
-	fun->driver_data = mfun;
 
 	usb_log_debug("Inquire...\n");
@@ -219,4 +264,7 @@
 		goto error;
 	}
+
+	free(fun_name);
+	mdev->luns[lun] = fun;
 
 	return EOK;
@@ -300,10 +348,12 @@
 
 /** USB mass storage driver ops. */
-static usb_driver_ops_t usbmast_driver_ops = {
-	.add_device = usbmast_add_device,
+static const usb_driver_ops_t usbmast_driver_ops = {
+	.device_add = usbmast_device_add,
+	.device_rem = usbmast_device_remove,
+	.device_gone = usbmast_device_gone,
 };
 
 /** USB mass storage driver. */
-static usb_driver_t usbmast_driver = {
+static const usb_driver_t usbmast_driver = {
 	.name = NAME,
 	.ops = &usbmast_driver_ops,
Index: uspace/drv/bus/usb/usbmast/usbmast.h
===================================================================
--- uspace/drv/bus/usb/usbmast/usbmast.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbmast/usbmast.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -41,5 +41,5 @@
 
 /** Mass storage device. */
-typedef struct {
+typedef struct usbmast_dev {
 	/** DDF device */
 	ddf_dev_t *ddf_dev;
@@ -47,6 +47,9 @@
 	usb_device_t *usb_dev;
 	/** Number of LUNs */
-	unsigned luns;
+	unsigned lun_count;
+	/** LUN functions */
+	ddf_fun_t **luns;
 } usbmast_dev_t;
+
 
 /** Mass storage function.
Index: uspace/drv/bus/usb/usbmid/dump.c
===================================================================
--- uspace/drv/bus/usb/usbmid/dump.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbmid/dump.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -47,10 +47,10 @@
  * @param depth Nesting depth.
  */
-static void dump_tree_descriptor(uint8_t *data, size_t depth)
+static void dump_tree_descriptor(const uint8_t *data, size_t depth)
 {
 	if (data == NULL) {
 		return;
 	}
-	int type = (int) *(data + 1);
+	const int type = data[1];
 	if (type == USB_DESCTYPE_INTERFACE) {
 		usb_standard_interface_descriptor_t *descriptor
@@ -71,6 +71,7 @@
  * @param depth Nesting depth.
  */
-static void dump_tree_internal(usb_dp_parser_t *parser, usb_dp_parser_data_t *data,
-    uint8_t *root, size_t depth)
+static void dump_tree_internal(
+    usb_dp_parser_t *parser, usb_dp_parser_data_t *data,
+    const uint8_t *root, size_t depth)
 {
 	if (root == NULL) {
@@ -78,5 +79,5 @@
 	}
 	dump_tree_descriptor(root, depth);
-	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	const uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
 	do {
 		dump_tree_internal(parser, data, child, depth + 1);
@@ -92,5 +93,5 @@
 static void dump_tree(usb_dp_parser_t *parser, usb_dp_parser_data_t *data)
 {
-	uint8_t *ptr = data->data;
+	const uint8_t *ptr = data->data;
 	dump_tree_internal(parser, data, ptr, 0);
 }
Index: uspace/drv/bus/usb/usbmid/explore.c
===================================================================
--- uspace/drv/bus/usb/usbmid/explore.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbmid/explore.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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;
@@ -73,8 +72,8 @@
  * @param list List where to add the interfaces.
  */
-static void create_interfaces(uint8_t *config_descriptor,
+static void create_interfaces(const uint8_t *config_descriptor,
     size_t config_descriptor_size, list_t *list)
 {
-	usb_dp_parser_data_t data = {
+	const usb_dp_parser_data_t data = {
 		.data = config_descriptor,
 		.size = config_descriptor_size,
@@ -82,47 +81,43 @@
 	};
 
-	usb_dp_parser_t parser = {
+	static const usb_dp_parser_t parser = {
 		.nesting = usb_dp_standard_descriptor_nesting
 	};
 
-	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
+	const uint8_t *interface_ptr =
+	    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,18 +134,19 @@
 	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 ;-). */
-	uint8_t *config_descriptor_raw = dev->descriptors.configuration;
+	/* Shortcuts to save on typing ;-). */
+	const void *config_descriptor_raw = dev->descriptors.configuration;
 	size_t config_descriptor_size = dev->descriptors.configuration_size;
-	usb_standard_configuration_descriptor_t *config_descriptor =
-	    (usb_standard_configuration_descriptor_t *) config_descriptor_raw;
+	const usb_standard_configuration_descriptor_t *config_descriptor =
+	    config_descriptor_raw;
 
 	/* Select the first configuration */
@@ -163,32 +159,40 @@
 	}
 
-	/* Create control function */
-	ddf_fun_t *ctl_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, "ctl");
-	if (ctl_fun == NULL) {
+	/* Create driver soft-state. */
+	usb_mid_t *usb_mid = usb_device_data_alloc(dev, sizeof(usb_mid_t));
+	if (!usb_mid) {
+		usb_log_error("Failed to create USB MID structure.\n");
+		return false;
+	}
+
+	/* Create control function. */
+	usb_mid->ctl_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, "ctl");
+	if (usb_mid->ctl_fun == NULL) {
 		usb_log_error("Failed to create control function.\n");
 		return false;
 	}
-
-	ctl_fun->ops = &mid_device_ops;
-
-	rc = ddf_fun_bind(ctl_fun);
+	usb_mid->ctl_fun->ops = &mid_device_ops;
+
+	/* Bind control function. */
+	rc = ddf_fun_bind(usb_mid->ctl_fun);
 	if (rc != EOK) {
 		usb_log_error("Failed to bind control function: %s.\n",
 		    str_error(rc));
-		return false;
-	}
+		ddf_fun_destroy(usb_mid->ctl_fun);
+		return false;
+	}
+
 
 	/* Create interface children. */
-	list_t interface_list;
-	list_initialize(&interface_list);
+	list_initialize(&usb_mid->interface_list);
 	create_interfaces(config_descriptor_raw, config_descriptor_size,
-	    &interface_list);
-
-	list_foreach(interface_list, link) {
-		usbmid_interface_t *iface = list_get_instance(link,
-		    usbmid_interface_t, link);
+	    &usb_mid->interface_list);
+
+	/* Start child function for every interface. */
+	list_foreach(usb_mid->interface_list, 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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbmid/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -49,5 +49,5 @@
  * @return Error code.
  */
-static int usbmid_add_device(usb_device_t *dev)
+static int usbmid_device_add(usb_device_t *dev)
 {
 	usb_log_info("Taking care of new MID `%s'.\n", dev->ddf_dev->name);
@@ -65,12 +65,114 @@
 	return EOK;
 }
+/*----------------------------------------------------------------------------*/
+/** Callback when a MID device is about to be removed from the host.
+ *
+ * @param dev USB device representing the removed device.
+ * @return Error code.
+ */
+static int usbmid_device_remove(usb_device_t *dev)
+{
+	assert(dev);
+	usb_mid_t *usb_mid = dev->driver_data;
+	assert(usb_mid);
+
+	/* 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("Removing child for interface %d (%s).\n",
+		    iface->interface_no,
+		    usb_str_class(iface->interface->interface_class));
+
+		/* 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;
+}
+/*----------------------------------------------------------------------------*/
+/** Callback when a MID device was removed from the host.
+ *
+ * @param dev USB device representing the removed device.
+ * @return Error code.
+ */
+static int usbmid_device_gone(usb_device_t *dev)
+{
+	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 */
+	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);
+
+	/* Now remove all other functions */
+	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("Child for interface %d (%s) gone.\n",
+		    iface->interface_no,
+		    usb_str_class(iface->interface->interface_class));
+
+		const int pret = usbmid_interface_destroy(iface);
+		if (pret != EOK) {
+			usb_log_error("Failed to remove child for interface "
+			    "%d (%s): %s\n",
+			    iface->interface_no,
+			    usb_str_class(iface->interface->interface_class),
+			    str_error(pret));
+			ret = pret;
+		}
+	}
+	return ret;
+}
 
 /** USB MID driver ops. */
-static usb_driver_ops_t mid_driver_ops = {
-	.add_device = usbmid_add_device,
+static const usb_driver_ops_t mid_driver_ops = {
+	.device_add = usbmid_device_add,
+	.device_rem = usbmid_device_remove,
+	.device_gone = usbmid_device_gone,
 };
 
 /** USB MID driver. */
-static usb_driver_t mid_driver = {
+static const usb_driver_t mid_driver = {
 	.name = NAME,
 	.ops = &mid_driver_ops,
Index: uspace/drv/bus/usb/usbmid/usbmid.c
===================================================================
--- uspace/drv/bus/usb/usbmid/usbmid.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbmid/usbmid.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -45,13 +45,5 @@
 
 /** Callback for DDF USB interface. */
-static int usb_iface_get_address_impl(ddf_fun_t *fun, devman_handle_t handle,
-    usb_address_t *address)
-{
-	return usb_iface_get_address_hub_impl(fun, handle, address);
-}
-
-/** 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);
@@ -69,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_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,
 };
 
@@ -79,4 +71,19 @@
 };
 
+int usbmid_interface_destroy(usbmid_interface_t *mid_iface)
+{
+	assert(mid_iface);
+	assert_link_not_used(&mid_iface->link);
+	const int ret = ddf_fun_unbind(mid_iface->fun);
+	if (ret != EOK) {
+		return ret;
+	}
+	/* NOTE: usbmid->interface points somewhere, but we did not
+	 * allocate that space, so don't touch */
+	ddf_fun_destroy(mid_iface->fun);
+	/* NOTE: mid_iface is invalid at this point, it was assigned to
+	 * mid_iface->fun->driver_data and freed in ddf_fun_destroy */
+	return EOK;
+}
 
 /** Spawn new child device from one interface.
@@ -102,48 +109,37 @@
 	 * 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) {
-		goto error_leave;
+		return ENOMEM;
 	}
 
 	/* Create the device. */
 	child = ddf_fun_create(parent->ddf_dev, fun_inner, child_name);
+	free(child_name);
 	if (child == NULL) {
-		rc = ENOMEM;
-		goto error_leave;
+		return ENOMEM;
 	}
 
-	iface->fun = child;
-
-	child->driver_data = iface;
-	child->ops = &child_device_ops;
-
 	rc = usb_device_create_match_ids_from_interface(device_descriptor,
-	    interface_descriptor,
-	    &child->match_ids);
+	    interface_descriptor, &child->match_ids);
 	if (rc != EOK) {
-		goto error_leave;
+		ddf_fun_destroy(child);
+		return rc;
 	}
 
 	rc = ddf_fun_bind(child);
 	if (rc != EOK) {
-		goto error_leave;
+		/* This takes care of match_id deallocation as well. */
+		ddf_fun_destroy(child);
+		return rc;
 	}
 
+	iface->fun = child;
+	child->driver_data = iface;
+	child->ops = &child_device_ops;
+
 	return EOK;
-
-error_leave:
-	if (child != NULL) {
-		child->name = 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/drv/bus/usb/usbmid/usbmid.h
===================================================================
--- uspace/drv/bus/usb/usbmid/usbmid.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/usbmid/usbmid.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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;
@@ -58,4 +58,10 @@
 } usbmid_interface_t;
 
+/** Container to hold all the function pointers */
+typedef struct usb_mid {
+	ddf_fun_t *ctl_fun;
+	list_t interface_list;
+} usb_mid_t;
+
 bool usbmid_explore_device(usb_device_t *);
 int usbmid_spawn_interface_child(usb_device_t *, usbmid_interface_t *,
@@ -63,4 +69,10 @@
     const usb_standard_interface_descriptor_t *);
 void usbmid_dump_descriptors(uint8_t *, size_t);
+int usbmid_interface_destroy(usbmid_interface_t *mid_iface);
+
+static inline usbmid_interface_t * usbmid_interface_from_link(link_t *item)
+{
+	return list_get_instance(item, usbmid_interface_t, link);
+}
 
 #endif
Index: uspace/drv/bus/usb/usbmouse/Makefile
===================================================================
--- uspace/drv/bus/usb/usbmouse/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,50 +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.
-#
-
-USPACE_PREFIX = ../../../..
-
-LIBS = \
-	$(LIBUSBHID_PREFIX)/libusbhid.a \
-	$(LIBUSBDEV_PREFIX)/libusbdev.a \
-	$(LIBUSB_PREFIX)/libusb.a \
-	$(LIBDRV_PREFIX)/libdrv.a
-
-EXTRA_CFLAGS += \
-	-I$(LIBUSB_PREFIX)/include \
-	-I$(LIBUSBDEV_PREFIX)/include \
-	-I$(LIBUSBHID_PREFIX)/include \
-	-I$(LIBDRV_PREFIX)/include
-
-BINARY = usbmouse
-
-SOURCES = \
-	init.c \
-	main.c \
-	mouse.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/bus/usb/usbmouse/init.c
===================================================================
--- uspace/drv/bus/usb/usbmouse/init.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,141 +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 drvusbmouse
- * @{
- */
-/**
- * @file
- * Initialization routines for USB mouse driver.
- */
-
-#include "mouse.h"
-#include <usb/debug.h>
-#include <usb/classes/classes.h>
-#include <usb/hid/hid.h>
-#include <usb/dev/request.h>
-#include <usb/hid/request.h>
-#include <errno.h>
-
-/** Mouse polling endpoint description for boot protocol subclass. */
-usb_endpoint_description_t poll_endpoint_description = {
-	.transfer_type = USB_TRANSFER_INTERRUPT,
-	.direction = USB_DIRECTION_IN,
-	.interface_class = USB_CLASS_HID,
-	.interface_subclass = USB_HID_SUBCLASS_BOOT,
-	.interface_protocol = USB_HID_PROTOCOL_MOUSE,
-	.flags = 0
-};
-
-/** Default handler for IPC methods not handled by DDF.
- *
- * @param fun     Device function handling the call.
- * @param icallid Call ID.
- * @param icall   Call data.
- *
- */
-static void default_connection_handler(ddf_fun_t *fun, ipc_callid_t icallid,
-    ipc_call_t *icall)
-{
-	usb_mouse_t *mouse = (usb_mouse_t *) fun->driver_data;
-	assert(mouse != NULL);
-	
-	async_sess_t *callback =
-	    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
-	
-	if (callback) {
-		if (mouse->console_sess == NULL) {
-			mouse->console_sess = callback;
-			async_answer_0(icallid, EOK);
-		} else
-			async_answer_0(icallid, ELIMIT);
-	} else
-		async_answer_0(icallid, EINVAL);
-}
-
-/** Device ops for USB mouse. */
-static ddf_dev_ops_t mouse_ops = {
-	.default_handler = default_connection_handler
-};
-
-/** Create USB mouse device.
- *
- * The mouse device is stored into <code>dev-&gt;driver_data</code>.
- *
- * @param dev Generic device.
- * @return Error code.
- */
-int usb_mouse_create(usb_device_t *dev)
-{
-	usb_mouse_t *mouse = malloc(sizeof(usb_mouse_t));
-	if (mouse == NULL)
-		return ENOMEM;
-	
-	mouse->dev = dev;
-	mouse->console_sess = NULL;
-	
-	int rc;
-	
-	/* Create DDF function. */
-	mouse->mouse_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, "mouse");
-	if (mouse->mouse_fun == NULL) {
-		rc = ENOMEM;
-		goto leave;
-	}
-	
-	mouse->mouse_fun->ops = &mouse_ops;
-	
-	rc = ddf_fun_bind(mouse->mouse_fun);
-	if (rc != EOK)
-		goto leave;
-	
-	/* Add the function to mouse class. */
-	rc = ddf_fun_add_to_category(mouse->mouse_fun, "mouse");
-	if (rc != EOK)
-		goto leave;
-	
-	/* Set the boot protocol. */
-	rc = usbhid_req_set_protocol(&dev->ctrl_pipe, dev->interface_no,
-	    USB_HID_PROTOCOL_BOOT);
-	if (rc != EOK)
-		goto leave;
-	
-	/* Everything allright. */
-	dev->driver_data = mouse;
-	mouse->mouse_fun->driver_data = mouse;
-	
-	return EOK;
-	
-leave:
-	free(mouse);
-	return rc;
-}
-
-/**
- * @}
- */
Index: uspace/drv/bus/usb/usbmouse/main.c
===================================================================
--- uspace/drv/bus/usb/usbmouse/main.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,105 +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 drvusbmouse
- * @{
- */
-/**
- * @file
- * Main routines of USB boot protocol mouse driver.
- */
-
-#include "mouse.h"
-#include <usb/debug.h>
-#include <usb/dev/poll.h>
-#include <errno.h>
-#include <str_error.h>
-
-#define NAME  "usbmouse"
-
-/** Callback when new mouse device is attached and recognised by DDF.
- *
- * @param dev Representation of a generic DDF device.
- *
- * @return Error code.
- *
- */
-static int usbmouse_add_device(usb_device_t *dev)
-{
-	int rc = usb_mouse_create(dev);
-	if (rc != EOK) {
-		usb_log_error("Failed to initialize device driver: %s.\n",
-		    str_error(rc));
-		return rc;
-	}
-	
-	usb_log_debug("Polling pipe at endpoint %d.\n",
-	    dev->pipes[0].pipe->endpoint_no);
-	
-	rc = usb_device_auto_poll(dev, 0, usb_mouse_polling_callback,
-	    dev->pipes[0].pipe->max_packet_size,
-	    usb_mouse_polling_ended_callback, dev->driver_data);
-	
-	if (rc != EOK) {
-		usb_log_error("Failed to start polling fibril: %s.\n",
-		    str_error(rc));
-		return rc;
-	}
-	
-	usb_log_info("controlling new mouse (handle %" PRIun ").\n",
-	    dev->ddf_dev->handle);
-	
-	return EOK;
-}
-
-/** USB mouse driver ops. */
-static usb_driver_ops_t mouse_driver_ops = {
-	.add_device = usbmouse_add_device,
-};
-
-static usb_endpoint_description_t *endpoints[] = {
-	&poll_endpoint_description,
-	NULL
-};
-
-/** USB mouse driver. */
-static usb_driver_t mouse_driver = {
-	.name = NAME,
-	.ops = &mouse_driver_ops,
-	.endpoints = endpoints
-};
-
-int main(int argc, char *argv[])
-{
-	usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
-	return usb_driver_main(&mouse_driver);
-}
-
-/**
- * @}
- */
Index: uspace/drv/bus/usb/usbmouse/mouse.c
===================================================================
--- uspace/drv/bus/usb/usbmouse/mouse.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,131 +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 drvusbmouse
- * @{
- */
-/**
- * @file
- * Actual handling of USB mouse protocol.
- */
-
-#include <usb/debug.h>
-#include <errno.h>
-#include <str_error.h>
-#include <ipc/mouseev.h>
-#include <async.h>
-#include "mouse.h"
-
-/** Mouse polling callback.
- *
- * @param dev    Device that is being polled.
- * @param buffer Data buffer.
- * @param size   Buffer size in bytes.
- * @param arg    Pointer to usb_mouse_t.
- *
- * @return Always true.
- *
- */
-bool usb_mouse_polling_callback(usb_device_t *dev, uint8_t *buffer,
-    size_t size, void *arg)
-{
-	usb_mouse_t *mouse = (usb_mouse_t *) arg;
-	
-	usb_log_debug2("got buffer: %s.\n",
-	    usb_debug_str_buffer(buffer, size, 0));
-	
-	uint8_t butt = buffer[0];
-	char str_buttons[4] = {
-		butt & 1 ? '#' : '.',
-		butt & 2 ? '#' : '.',
-		butt & 4 ? '#' : '.',
-		0
-	};
-	
-	int shift_x = ((int) buffer[1]) - 127;
-	int shift_y = ((int) buffer[2]) - 127;
-	int wheel = ((int) buffer[3]) - 127;
-	
-	if (buffer[1] == 0)
-		shift_x = 0;
-	
-	if (buffer[2] == 0)
-		shift_y = 0;
-	
-	if (buffer[3] == 0)
-		wheel = 0;
-	
-	if (mouse->console_sess) {
-		if ((shift_x != 0) || (shift_y != 0)) {
-			// FIXME: guessed for QEMU
-			
-			async_exch_t *exch = async_exchange_begin(mouse->console_sess);
-			async_req_2_0(exch, MOUSEEV_MOVE_EVENT, -shift_x / 10, -shift_y / 10);
-			async_exchange_end(exch);
-		}
-		if (butt) {
-			// FIXME: proper button clicking
-			
-			async_exch_t *exch = async_exchange_begin(mouse->console_sess);
-			async_req_2_0(exch, MOUSEEV_BUTTON_EVENT, 1, 1);
-			async_req_2_0(exch, MOUSEEV_BUTTON_EVENT, 1, 0);
-			async_exchange_end(exch);
-		}
-	}
-	
-	usb_log_debug("buttons=%s  dX=%+3d  dY=%+3d  wheel=%+3d\n",
-	    str_buttons, shift_x, shift_y, wheel);
-	
-	/* Guess. */
-	async_usleep(1000);
-	
-	return true;
-}
-
-/** Callback when polling is terminated.
- *
- * @param dev              Device where the polling terminated.
- * @param recurring_errors Whether the polling was terminated due to
- *                         recurring errors.
- * @param arg              Pointer to usb_mouse_t.
- *
- */
-void usb_mouse_polling_ended_callback(usb_device_t *dev, bool recurring_errors,
-    void *arg)
-{
-	usb_mouse_t *mouse = (usb_mouse_t *) arg;
-	
-	async_hangup(mouse->console_sess);
-	mouse->console_sess = NULL;
-	
-	usb_device_destroy(dev);
-}
-
-/**
- * @}
- */
Index: uspace/drv/bus/usb/usbmouse/mouse.h
===================================================================
--- uspace/drv/bus/usb/usbmouse/mouse.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,74 +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 drvusbmouse
- * @{
- */
-/**
- * @file
- * Common definitions for USB mouse driver.
- */
-
-#ifndef USBMOUSE_MOUSE_H_
-#define USBMOUSE_MOUSE_H_
-
-#include <usb/dev/driver.h>
-#include <usb/dev/pipes.h>
-#include <time.h>
-#include <async.h>
-
-#define POLL_PIPE(dev) \
-	((dev)->pipes[0].pipe)
-
-/** Container for USB mouse device. */
-typedef struct {
-	/** Generic device container. */
-	usb_device_t *dev;
-	
-	/** Function representing the device. */
-	ddf_fun_t *mouse_fun;
-	
-	/** Polling interval in microseconds. */
-	suseconds_t poll_interval_us;
-	
-	/** Callback session to console (consumer). */
-	async_sess_t *console_sess;
-} usb_mouse_t;
-
-extern usb_endpoint_description_t poll_endpoint_description;
-
-extern int usb_mouse_create(usb_device_t *);
-extern bool usb_mouse_polling_callback(usb_device_t *, uint8_t *, size_t,
-    void *);
-extern void usb_mouse_polling_ended_callback(usb_device_t *, bool, void *);
-
-#endif
-
-/**
- * @}
- */
Index: uspace/drv/bus/usb/usbmouse/usbmouse.ma
===================================================================
--- uspace/drv/bus/usb/usbmouse/usbmouse.ma	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,1 +1,0 @@
-100 usb&interface&class=HID&subclass=0x01&protocol=0x02
Index: uspace/drv/bus/usb/vhc/connhost.c
===================================================================
--- uspace/drv/bus/usb/vhc/connhost.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/vhc/connhost.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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;
@@ -104,7 +96,6 @@
 {
 	VHC_DATA(vhc, fun);
-	bool found =
-	    usb_device_manager_find_by_address(&vhc->dev_manager, address, handle);
-	return found ? EOK : ENOENT;
+	return usb_device_manager_get_info_by_address(
+	    &vhc->dev_manager, address, handle, NULL);
 }
 
@@ -119,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;
@@ -137,24 +128,14 @@
  */
 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)
 {
-	/* TODO: Use usb_endpoint_manager_add_ep */
-	VHC_DATA(vhc, fun);
-
-	endpoint_t *ep = endpoint_get(
-	    address, endpoint, direction, transfer_type, USB_SPEED_FULL, 1);
-	if (ep == NULL) {
-		return ENOMEM;
-	}
-
-	int rc = usb_endpoint_manager_register_ep(&vhc->ep_manager, ep, 1);
-	if (rc != EOK) {
-		endpoint_destroy(ep);
-		return rc;
-	}
-
-	return EOK;
+	VHC_DATA(vhc, fun);
+
+	return usb_endpoint_manager_add_ep(&vhc->ep_manager,
+	    address, endpoint, direction, transfer_type, USB_SPEED_FULL, 1, 0,
+	    NULL, NULL);
+
 }
 
@@ -172,6 +153,6 @@
 	VHC_DATA(vhc, fun);
 
-	int rc = usb_endpoint_manager_unregister_ep(&vhc->ep_manager,
-	    address, endpoint, direction);
+	int rc = usb_endpoint_manager_remove_ep(&vhc->ep_manager,
+	    address, endpoint, direction, NULL, NULL);
 
 	return rc;
@@ -414,6 +395,6 @@
 	VHC_DATA(vhc, fun);
 
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&vhc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_IN, NULL);
+	endpoint_t *ep = usb_endpoint_manager_find_ep(&vhc->ep_manager,
+	    target.address, target.endpoint, USB_DIRECTION_IN);
 	if (ep == NULL) {
 		return ENOENT;
@@ -440,5 +421,7 @@
 	int rc = vhc_virtdev_add_transfer(vhc, transfer);
 	if (rc != EOK) {
-		free(transfer->setup_buffer);
+		if (transfer->setup_buffer != NULL) {
+			free(transfer->setup_buffer);
+		}
 		free(transfer);
 		return rc;
@@ -454,6 +437,6 @@
 	VHC_DATA(vhc, fun);
 
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&vhc->ep_manager,
-	    target.address, target.endpoint, USB_DIRECTION_OUT, NULL);
+	endpoint_t *ep = usb_endpoint_manager_find_ep(&vhc->ep_manager,
+	    target.address, target.endpoint, USB_DIRECTION_OUT);
 	if (ep == NULL) {
 		return ENOENT;
@@ -488,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");
@@ -506,15 +488,13 @@
 }
 
-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);
-	usb_address_t addr = usb_device_manager_find(&vhc->dev_manager, handle);
+	const usb_address_t addr =
+	    usb_device_manager_find_address(&vhc->dev_manager, handle);
 	if (addr < 0) {
 		return addr;
@@ -528,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,
 
@@ -540,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/hub.c
===================================================================
--- uspace/drv/bus/usb/vhc/hub.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/vhc/hub.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -81,5 +81,5 @@
 }
 
-static int pretend_port_rest(int unused, void *unused2)
+static int pretend_port_rest(void *unused2)
 {
 	return EOK;
@@ -114,8 +114,6 @@
 
 	ddf_fun_t *hub_dev;
-	rc = usb_hc_new_device_wrapper(hc_dev->dev, &hc_conn,
-	    USB_SPEED_FULL,
-	    pretend_port_rest, 0, NULL,
-	    NULL, NULL, &rh_ops, hc_dev, &hub_dev);
+	rc = usb_hc_new_device_wrapper(hc_dev->dev, &hc_conn, USB_SPEED_FULL,
+	    pretend_port_rest, NULL, NULL, &rh_ops, hc_dev, &hub_dev);
 	if (rc != EOK) {
 		usb_log_fatal("Failed to create root hub: %s.\n",
Index: uspace/drv/bus/usb/vhc/main.c
===================================================================
--- uspace/drv/bus/usb/vhc/main.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/vhc/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/bus/usb/vhc/vhc.ma	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,2 +1,1 @@
 10 usb&hc=vhc
-
Index: uspace/drv/char/ns8250/ns8250.c
===================================================================
--- uspace/drv/char/ns8250/ns8250.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/char/ns8250/ns8250.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/infrastructure/root/root.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/infrastructure/rootmac/rootmac.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/infrastructure/rootpc/rootpc.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/devices.def
===================================================================
--- uspace/drv/infrastructure/rootvirt/devices.def	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/infrastructure/rootvirt/devices.def	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -4,5 +4,13 @@
  * Unless the list is empty, the last item shall be followed by a comma.
  */
+
+/* Loopback network interface */
+{
+    .name = "lo",
+    .match_id = "virtual&loopback"
+},
+
 #ifdef CONFIG_TEST_DRIVERS
+
 {
 	.name = "test1",
@@ -25,6 +33,9 @@
 	.match_id = "virtual&test3"
 },
+
 #endif
+
 #ifdef CONFIG_RUN_VIRTUAL_USB_HC
+
 /* Virtual USB host controller. */
 {
@@ -32,3 +43,4 @@
 	.match_id = "usb&hc=vhc"
 },
+
 #endif
Index: uspace/drv/infrastructure/rootvirt/rootvirt.c
===================================================================
--- uspace/drv/infrastructure/rootvirt/rootvirt.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/infrastructure/rootvirt/rootvirt.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/lo/Makefile
===================================================================
--- uspace/drv/nic/lo/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/drv/nic/lo/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 = lo
+
+SOURCES = \
+	lo.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/nic/lo/lo.c
===================================================================
--- uspace/drv/nic/lo/lo.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/drv/nic/lo/lo.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup drv_lo
+ * @brief Loopback virtual device driver
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <async.h>
+#include <nic.h>
+#include <packet_client.h>
+
+#define NAME  "lo"
+
+static nic_address_t lo_addr = {
+	.address = {0, 0, 0, 0, 0, 0}
+};
+
+static ddf_dev_ops_t lo_dev_ops;
+
+static nic_device_info_t lo_info = {
+	.vendor_name = "HelenOS",
+	.model_name = "loopback",
+	.part_number = "N/A (virtual device)",
+	.serial_number = "N/A (virtual device)"
+};
+
+static void lo_write_packet(nic_t *nic_data, packet_t *packet)
+{
+	nic_report_send_ok(nic_data, 1, packet_get_data_length(packet));
+	nic_received_noneth_packet(nic_data, packet);
+}
+
+static int lo_set_address(ddf_fun_t *fun, const nic_address_t *address)
+{
+	printf("%s: Set loopback HW to " PRIMAC "\n", NAME,
+	    ARGSMAC(address->address));
+	return ENOTSUP;
+}
+
+static int lo_get_device_info(ddf_fun_t *fun, nic_device_info_t *info)
+{
+	assert(info);
+	memcpy(info, &lo_info, sizeof(nic_device_info_t));
+	return EOK;
+}
+
+static int lo_dev_add(ddf_dev_t *dev)
+{
+	nic_t *nic_data = nic_create_and_bind(dev);
+	if (nic_data == NULL) {
+		printf("%s: Failed to initialize\n", NAME);
+		return ENOMEM;
+	}
+	
+	dev->driver_data = nic_data;
+	nic_set_write_packet_handler(nic_data, lo_write_packet);
+	
+	int rc = nic_connect_to_services(nic_data);
+	if (rc != EOK) {
+		printf("%s: Failed to connect to services\n", NAME);
+		nic_unbind_and_destroy(dev);
+		return rc;
+	}
+	
+	rc = nic_register_as_ddf_fun(nic_data, &lo_dev_ops);
+	if (rc != EOK) {
+		printf("%s: Failed to register as DDF function\n", NAME);
+		nic_unbind_and_destroy(dev);
+		return rc;
+	}
+	
+	rc = nic_report_address(nic_data, &lo_addr);
+	if (rc != EOK) {
+		printf("%s: Failed to setup loopback address\n", NAME);
+		nic_unbind_and_destroy(dev);
+		return rc;
+	}
+	
+	printf("%s: Adding loopback device '%s'\n", NAME, dev->name);
+	return EOK;
+}
+
+static nic_iface_t lo_nic_iface;
+
+static driver_ops_t lo_driver_ops = {
+	.dev_add = lo_dev_add,
+};
+
+static driver_t lo_driver = {
+	.name = NAME,
+	.driver_ops = &lo_driver_ops
+};
+
+int main(int argc, char *argv[])
+{
+	nic_driver_init(NAME);
+	nic_driver_implement(&lo_driver_ops, &lo_dev_ops, &lo_nic_iface);
+	lo_nic_iface.set_address = lo_set_address;
+	lo_nic_iface.get_device_info = lo_get_device_info;
+	
+	return ddf_driver_main(&lo_driver);
+}
+
+/** @}
+ */
Index: uspace/drv/nic/lo/lo.ma
===================================================================
--- uspace/drv/nic/lo/lo.ma	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/drv/nic/lo/lo.ma	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,1 @@
+10 virtual&loopback
Index: uspace/drv/nic/ne2k/Makefile
===================================================================
--- uspace/drv/nic/ne2k/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/drv/nic/ne2k/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,38 @@
+#
+# 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 = ne2k
+
+SOURCES = \
+	dp8390.c \
+	ne2k.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/drv/nic/ne2k/dp8390.c
===================================================================
--- uspace/drv/nic/ne2k/dp8390.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/drv/nic/ne2k/dp8390.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Martin Decky
+ * 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.
+ */
+
+/*
+ * This code is based upon the NE2000 driver for MINIX,
+ * distributed according to a BSD-style license.
+ *
+ * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
+ * Copyright (c) 1992, 1994 Philip Homburg
+ * Copyright (c) 1996 G. Falzoni
+ *
+ */
+
+/**
+ * @addtogroup drv_ne2k
+ * @{
+ */
+
+/**
+ * @file
+ * @brief NE2000 driver core
+ *
+ * NE2000 (based on DP8390) network interface core implementation.
+ * Only the basic NE2000 PIO (ISA) interface is supported, remote
+ * DMA is completely absent from this code for simplicity.
+ *
+ */
+
+#include <assert.h>
+#include <byteorder.h>
+#include <errno.h>
+#include <stdio.h>
+#include <libarch/ddi.h>
+#include <net/packet.h>
+#include <packet_client.h>
+#include "dp8390.h"
+
+/** Page size */
+#define DP_PAGE  256
+
+/** 6 * DP_PAGE >= 1514 bytes */
+#define SQ_PAGES  6
+
+/** Type definition of the receive header
+ *
+ */
+typedef struct {
+	/** Copy of RSR */
+	uint8_t status;
+	
+	/** Pointer to next packet */
+	uint8_t next;
+	
+	/** Receive Byte Count Low */
+	uint8_t rbcl;
+	
+	/** Receive Byte Count High */
+	uint8_t rbch;
+} recv_header_t;
+
+/** Read a memory block word by word.
+ *
+ * @param[in]  port Source address.
+ * @param[out] buf  Destination buffer.
+ * @param[in]  size Memory block size in bytes.
+ *
+ */
+static void pio_read_buf_16(void *port, void *buf, size_t size)
+{
+	size_t i;
+	
+	for (i = 0; (i << 1) < size; i++)
+		*((uint16_t *) buf + i) = pio_read_16((ioport16_t *) (port));
+}
+
+/** Write a memory block word by word.
+ *
+ * @param[in] port Destination address.
+ * @param[in] buf  Source buffer.
+ * @param[in] size Memory block size in bytes.
+ *
+ */
+static void pio_write_buf_16(void *port, void *buf, size_t size)
+{
+	size_t i;
+	
+	for (i = 0; (i << 1) < size; i++)
+		pio_write_16((ioport16_t *) port, *((uint16_t *) buf + i));
+}
+
+static void ne2k_download(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
+{
+	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_RSAR0, addr & 0xff);
+	pio_write_8(ne2k->port + DP_RSAR1, (addr >> 8) & 0xff);
+	pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+	
+	if (esize != 0) {
+		pio_read_buf_16(ne2k->data_port, buf, esize);
+		size -= esize;
+		buf += esize;
+	}
+	
+	if (size) {
+		assert(size == 1);
+		
+		uint16_t word = pio_read_16(ne2k->data_port);
+		memcpy(buf, &word, 1);
+	}
+}
+
+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_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);
+	pio_write_8(ne2k->port + DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
+	
+	if (esize != 0) {
+		pio_write_buf_16(ne2k->data_port, buf, esize);
+		size -= esize;
+		buf += esize;
+	}
+	
+	if (size) {
+		assert(size == 1);
+		
+		uint16_t word = 0;
+		
+		memcpy(&word, buf, 1);
+		pio_write_16(ne2k->data_port, word);
+	}
+}
+
+static void ne2k_init(ne2k_t *ne2k)
+{
+	unsigned int i;
+	
+	/* Reset the ethernet card */
+	uint8_t val = pio_read_8(ne2k->port + NE2K_RESET);
+	usleep(2000);
+	pio_write_8(ne2k->port + NE2K_RESET, val);
+	usleep(2000);
+	
+	/* Reset the DP8390 */
+	pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
+	for (i = 0; i < NE2K_RETRY; i++) {
+		if (pio_read_8(ne2k->port + DP_ISR) != 0)
+			break;
+	}
+}
+
+/** Probe and initialize the network interface.
+ *
+ * @param[in,out] ne2k Network interface structure.
+ * @param[in]     port Device address.
+ * @param[in]     irq  Device interrupt vector.
+ *
+ * @return EOK on success.
+ * @return EXDEV if the network interface was not recognized.
+ *
+ */
+int ne2k_probe(ne2k_t *ne2k)
+{
+	unsigned int i;
+	
+	ne2k_init(ne2k);
+	
+	/* Check if the DP8390 is really there */
+	uint8_t val = pio_read_8(ne2k->port + DP_CR);
+	if ((val & (CR_STP | CR_DM_ABORT)) != (CR_STP | CR_DM_ABORT))
+		return EXDEV;
+	
+	/* Disable the receiver and init TCR and DCR */
+	pio_write_8(ne2k->port + DP_RCR, RCR_MON);
+	pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
+	pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
+	
+	/* Setup a transfer to get the MAC address */
+	pio_write_8(ne2k->port + DP_RBCR0, ETH_ADDR << 1);
+	pio_write_8(ne2k->port + DP_RBCR1, 0);
+	pio_write_8(ne2k->port + DP_RSAR0, 0);
+	pio_write_8(ne2k->port + DP_RSAR1, 0);
+	pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+	
+	for (i = 0; i < ETH_ADDR; i++)
+		ne2k->mac.address[i] = pio_read_16(ne2k->data_port);
+	
+	return EOK;
+}
+
+void ne2k_set_physical_address(ne2k_t *ne2k, const nic_address_t *address)
+{
+	memcpy(&ne2k->mac, address, sizeof(nic_address_t));
+	
+	pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_DM_ABORT | CR_STP);
+	
+	pio_write_8(ne2k->port + DP_RBCR0, ETH_ADDR << 1);
+	pio_write_8(ne2k->port + DP_RBCR1, 0);
+	pio_write_8(ne2k->port + DP_RSAR0, 0);
+	pio_write_8(ne2k->port + DP_RSAR1, 0);
+	pio_write_8(ne2k->port + DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
+
+	size_t i;
+	for (i = 0; i < ETH_ADDR; i++)
+		pio_write_16(ne2k->data_port, ne2k->mac.address[i]);
+
+	//pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_DM_ABORT | CR_STA);
+}
+
+/** Start the network interface.
+ *
+ * @param[in,out] ne2k Network interface structure.
+ *
+ * @return EOK on success.
+ * @return EXDEV if the network interface is disabled.
+ *
+ */
+int ne2k_up(ne2k_t *ne2k)
+{
+	if (!ne2k->probed)
+		return EXDEV;
+	
+	ne2k_init(ne2k);
+	
+	/*
+	 * Setup send queue. Use the first
+	 * SQ_PAGES of NE2000 memory for the send
+	 * buffer.
+	 */
+	ne2k->sq.dirty = false;
+	ne2k->sq.page = NE2K_START / DP_PAGE;
+	fibril_mutex_initialize(&ne2k->sq_mutex);
+	fibril_condvar_initialize(&ne2k->sq_cv);
+	
+	/*
+	 * Setup receive ring buffer. Use all the rest
+	 * of the NE2000 memory (except the first SQ_PAGES
+	 * reserved for the send buffer) for the receive
+	 * ring buffer.
+	 */
+	ne2k->start_page = ne2k->sq.page + SQ_PAGES;
+	ne2k->stop_page = ne2k->sq.page + NE2K_SIZE / DP_PAGE;
+	
+	/*
+	 * Initialization of the DP8390 following the mandatory procedure
+	 * in reference manual ("DP8390D/NS32490D NIC Network Interface
+	 * Controller", National Semiconductor, July 1995, Page 29).
+	 */
+	
+	/* Step 1: */
+	pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
+	
+	/* Step 2: */
+	pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
+	
+	/* Step 3: */
+	pio_write_8(ne2k->port + DP_RBCR0, 0);
+	pio_write_8(ne2k->port + DP_RBCR1, 0);
+	
+	/* Step 4: */
+	pio_write_8(ne2k->port + DP_RCR, ne2k->receive_configuration);
+	
+	/* Step 5: */
+	pio_write_8(ne2k->port + DP_TCR, TCR_INTERNAL);
+	
+	/* Step 6: */
+	pio_write_8(ne2k->port + DP_BNRY, ne2k->start_page);
+	pio_write_8(ne2k->port + DP_PSTART, ne2k->start_page);
+	pio_write_8(ne2k->port + DP_PSTOP, ne2k->stop_page);
+	
+	/* Step 7: */
+	pio_write_8(ne2k->port + DP_ISR, 0xff);
+	
+	/* Step 8: */
+	pio_write_8(ne2k->port + DP_IMR,
+	    IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
+	
+	/* Step 9: */
+	pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
+	
+	pio_write_8(ne2k->port + DP_PAR0, ne2k->mac.address[0]);
+	pio_write_8(ne2k->port + DP_PAR1, ne2k->mac.address[1]);
+	pio_write_8(ne2k->port + DP_PAR2, ne2k->mac.address[2]);
+	pio_write_8(ne2k->port + DP_PAR3, ne2k->mac.address[3]);
+	pio_write_8(ne2k->port + DP_PAR4, ne2k->mac.address[4]);
+	pio_write_8(ne2k->port + DP_PAR5, ne2k->mac.address[5]);
+	
+	pio_write_8(ne2k->port + DP_MAR0, 0);
+	pio_write_8(ne2k->port + DP_MAR1, 0);
+	pio_write_8(ne2k->port + DP_MAR2, 0);
+	pio_write_8(ne2k->port + DP_MAR3, 0);
+	pio_write_8(ne2k->port + DP_MAR4, 0);
+	pio_write_8(ne2k->port + DP_MAR5, 0);
+	pio_write_8(ne2k->port + DP_MAR6, 0);
+	pio_write_8(ne2k->port + DP_MAR7, 0);
+	
+	pio_write_8(ne2k->port + DP_CURR, ne2k->start_page + 1);
+	
+	/* Step 10: */
+	pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_DM_ABORT | CR_STA);
+	
+	/* Step 11: */
+	pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
+	
+	/* Reset counters by reading */
+	pio_read_8(ne2k->port + DP_CNTR0);
+	pio_read_8(ne2k->port + DP_CNTR1);
+	pio_read_8(ne2k->port + DP_CNTR2);
+	
+	/* Finish the initialization */
+	ne2k->up = true;
+	return EOK;
+}
+
+/** Stop the network interface.
+ *
+ * @param[in,out] ne2k Network interface structure.
+ *
+ */
+void ne2k_down(ne2k_t *ne2k)
+{
+	if ((ne2k->probed) && (ne2k->up)) {
+		pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
+		ne2k_init(ne2k);
+		ne2k->up = false;
+	}
+}
+
+static void ne2k_reset(ne2k_t *ne2k)
+{
+	unsigned int i;
+
+	fibril_mutex_lock(&ne2k->sq_mutex);
+
+	/* Stop the chip */
+	pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
+	pio_write_8(ne2k->port + DP_RBCR0, 0);
+	pio_write_8(ne2k->port + DP_RBCR1, 0);
+
+	for (i = 0; i < NE2K_RETRY; i++) {
+		if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RST) != 0)
+			break;
+	}
+
+	pio_write_8(ne2k->port + DP_TCR, TCR_1EXTERNAL | TCR_OFST);
+	pio_write_8(ne2k->port + DP_CR, CR_STA | CR_DM_ABORT);
+	pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
+
+	/* Acknowledge the ISR_RDC (remote DMA) interrupt */
+	for (i = 0; i < NE2K_RETRY; i++) {
+		if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RDC) != 0)
+			break;
+	}
+
+	uint8_t val = pio_read_8(ne2k->port + DP_ISR);
+	pio_write_8(ne2k->port + DP_ISR, val & ~ISR_RDC);
+
+	/*
+	 * Reset the transmit ring. If we were transmitting a frame,
+	 * we pretend that the packet is processed. Higher layers will
+	 * retransmit if the packet wasn't actually sent.
+	 */
+	ne2k->sq.dirty = false;
+
+	fibril_mutex_unlock(&ne2k->sq_mutex);
+}
+
+/** Send a frame.
+ *
+ * @param[in,out] ne2k   Network interface structure.
+ * @param[in]     packet Frame to be sent.
+ *
+ */
+void ne2k_send(nic_t *nic_data, packet_t *packet)
+{
+	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
+
+	assert(ne2k->probed);
+	assert(ne2k->up);
+
+	fibril_mutex_lock(&ne2k->sq_mutex);
+	
+	while (ne2k->sq.dirty) {
+		fibril_condvar_wait(&ne2k->sq_cv, &ne2k->sq_mutex);
+	}
+	void *buf = packet_get_data(packet);
+	size_t size = packet_get_data_length(packet);
+	
+	if ((size < ETH_MIN_PACK_SIZE) || (size > ETH_MAX_PACK_SIZE_TAGGED)) {
+		fibril_mutex_unlock(&ne2k->sq_mutex);
+		return;
+	}
+
+	/* Upload the frame to the ethernet card */
+	ne2k_upload(ne2k, buf, ne2k->sq.page * DP_PAGE, size);
+	ne2k->sq.dirty = true;
+	ne2k->sq.size = size;
+
+	/* Initialize the transfer */
+	pio_write_8(ne2k->port + DP_TPSR, ne2k->sq.page);
+	pio_write_8(ne2k->port + DP_TBCR0, size & 0xff);
+	pio_write_8(ne2k->port + DP_TBCR1, (size >> 8) & 0xff);
+	pio_write_8(ne2k->port + DP_CR, CR_TXP | CR_STA);
+	fibril_mutex_unlock(&ne2k->sq_mutex);
+
+	/* Relase packet */
+	nic_release_packet(nic_data, packet);
+}
+
+static nic_frame_t *ne2k_receive_frame(nic_t *nic_data, uint8_t page,
+	size_t length)
+{
+	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
+
+	nic_frame_t *frame = nic_alloc_frame(nic_data, length);
+	if (frame == NULL)
+		return NULL;
+	
+	void *buf = packet_suffix(frame->packet, length);
+	bzero(buf, length);
+	uint8_t last = page + length / DP_PAGE;
+	
+	if (last >= ne2k->stop_page) {
+		size_t left = (ne2k->stop_page - page) * DP_PAGE
+		    - sizeof(recv_header_t);
+		ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
+		    left);
+		ne2k_download(ne2k, buf + left, ne2k->start_page * DP_PAGE,
+		    length - left);
+	} else {
+		ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
+		    length);
+	}
+	return frame;
+}
+
+static void ne2k_receive(nic_t *nic_data)
+{
+	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
+	/*
+	 * Allocate memory for the list of received frames.
+	 * If the allocation fails here we still receive the
+	 * frames from the network, but they will be lost.
+	 */
+	nic_frame_list_t *frames = nic_alloc_frame_list();
+	size_t frames_count = 0;
+
+	/* We may block sending in this loop - after so many received frames there
+	 * must be some interrupt pending (for the frames not yet downloaded) and
+	 * we will continue in its handler. */
+	while (frames_count < 16) {
+		//TODO: isn't some locking necessary here?
+		uint8_t boundary = pio_read_8(ne2k->port + DP_BNRY) + 1;
+		
+		if (boundary == ne2k->stop_page)
+			boundary = ne2k->start_page;
+		
+		pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_STA);
+		uint8_t current = pio_read_8(ne2k->port + DP_CURR);
+		pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STA);
+		if (current == boundary)
+			/* No more frames to process */
+			break;
+		
+		recv_header_t header;
+		size_t size = sizeof(header);
+		size_t offset = boundary * DP_PAGE;
+		
+		/* Get the frame header */
+		pio_write_8(ne2k->port + DP_RBCR0, size & 0xff);
+		pio_write_8(ne2k->port + DP_RBCR1, (size >> 8) & 0xff);
+		pio_write_8(ne2k->port + DP_RSAR0, offset & 0xff);
+		pio_write_8(ne2k->port + DP_RSAR1, (offset >> 8) & 0xff);
+		pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
+		
+		pio_read_buf_16(ne2k->data_port, (void *) &header, size);
+
+		size_t length =
+		    (((size_t) header.rbcl) | (((size_t) header.rbch) << 8)) - size;
+		uint8_t next = header.next;
+		
+		if ((length < ETH_MIN_PACK_SIZE)
+		    || (length > ETH_MAX_PACK_SIZE_TAGGED)) {
+			next = current;
+		} else if ((header.next < ne2k->start_page)
+		    || (header.next > ne2k->stop_page)) {
+			next = current;
+		} else if (header.status & RSR_FO) {
+			/*
+			 * This is very serious, so we issue a warning and
+			 * reset the buffers.
+			 */
+			ne2k->overruns++;
+			next = current;
+		} else if ((header.status & RSR_PRX) && (ne2k->up)) {
+			if (frames != NULL) {
+				nic_frame_t *frame =
+					ne2k_receive_frame(nic_data, boundary, length);
+				if (frame != NULL) {
+					nic_frame_list_append(frames, frame);
+					frames_count++;
+				} else {
+					break;
+				}
+			} else
+				break;
+		}
+		
+		/*
+		 * Update the boundary pointer
+		 * to the value of the page
+		 * prior to the next packet to
+		 * be processed.
+		 */
+		if (next == ne2k->start_page)
+			next = ne2k->stop_page - 1;
+		else
+			next--;
+		pio_write_8(ne2k->port + DP_BNRY, next);
+	}
+	nic_received_frame_list(nic_data, frames);
+}
+
+void ne2k_interrupt(nic_t *nic_data, uint8_t isr, uint8_t tsr)
+{
+	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
+
+	if (isr & (ISR_PTX | ISR_TXE)) {
+		if (tsr & TSR_COL) {
+			nic_report_collisions(nic_data,
+				pio_read_8(ne2k->port + DP_NCR) & 15);
+		}
+
+		if (tsr & TSR_PTX) {
+			// TODO: fix number of sent bytes (but how?)
+			nic_report_send_ok(nic_data, 1, 0);
+		} else if (tsr & TSR_ABT) {
+			nic_report_send_error(nic_data, NIC_SEC_ABORTED, 1);
+		} else if (tsr & TSR_CRS) {
+			nic_report_send_error(nic_data, NIC_SEC_CARRIER_LOST, 1);
+		} else if (tsr & TSR_FU) {
+			ne2k->underruns++;
+			// if (ne2k->underruns < NE2K_ERL) {
+			// }
+		} else if (tsr & TSR_CDH) {
+			nic_report_send_error(nic_data, NIC_SEC_HEARTBEAT, 1);
+			// if (nic_data->stats.send_heartbeat_errors < NE2K_ERL) {
+			// }
+		} else if (tsr & TSR_OWC) {
+			nic_report_send_error(nic_data, NIC_SEC_WINDOW_ERROR, 1);
+		}
+
+		fibril_mutex_lock(&ne2k->sq_mutex);
+		if (ne2k->sq.dirty) {
+			/* Prepare the buffer for next packet */
+			ne2k->sq.dirty = false;
+			ne2k->sq.size = 0;
+			
+			/* Signal a next frame to be sent */
+			fibril_condvar_broadcast(&ne2k->sq_cv);
+		} else {
+			ne2k->misses++;
+			// if (ne2k->misses < NE2K_ERL) {
+			// }
+		}
+		fibril_mutex_unlock(&ne2k->sq_mutex);
+	}
+
+	if (isr & ISR_CNT) {
+		unsigned int errors;
+		for (errors = pio_read_8(ne2k->port + DP_CNTR0); errors > 0; --errors)
+			nic_report_receive_error(nic_data, NIC_REC_CRC, 1);
+		for (errors = pio_read_8(ne2k->port + DP_CNTR1); errors > 0; --errors)
+			nic_report_receive_error(nic_data, NIC_REC_FRAME_ALIGNMENT, 1);
+		for (errors = pio_read_8(ne2k->port + DP_CNTR2); errors > 0; --errors)
+			nic_report_receive_error(nic_data, NIC_REC_MISSED, 1);
+	}
+	if (isr & ISR_PRX) {
+		ne2k_receive(nic_data);
+	}
+	if (isr & ISR_RST) {
+		/*
+		 * The chip is stopped, and all arrived
+		 * frames are delivered.
+		 */
+		ne2k_reset(ne2k);
+	}
+	
+	/* Unmask interrupts to be processed in the next round */
+	pio_write_8(ne2k->port + DP_IMR,
+	    IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
+}
+
+void ne2k_set_accept_bcast(ne2k_t *ne2k, int accept)
+{
+	if (accept)
+		ne2k->receive_configuration |= RCR_AB;
+	else
+		ne2k->receive_configuration &= ~RCR_AB;
+	
+	pio_write_8(ne2k->port + DP_RCR, ne2k->receive_configuration);
+}
+
+void ne2k_set_accept_mcast(ne2k_t *ne2k, int accept)
+{
+	if (accept)
+		ne2k->receive_configuration |= RCR_AM;
+	else
+		ne2k->receive_configuration &= ~RCR_AM;
+	
+	pio_write_8(ne2k->port + DP_RCR, ne2k->receive_configuration);
+}
+
+void ne2k_set_promisc_phys(ne2k_t *ne2k, int promisc)
+{
+	if (promisc)
+		ne2k->receive_configuration |= RCR_PRO;
+	else
+		ne2k->receive_configuration &= ~RCR_PRO;
+	
+	pio_write_8(ne2k->port + DP_RCR, ne2k->receive_configuration);
+}
+
+void ne2k_set_mcast_hash(ne2k_t *ne2k, uint64_t hash)
+{
+	/* Select Page 1 and stop all transfers */
+	pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
+	
+	pio_write_8(ne2k->port + DP_MAR0, (uint8_t) hash);
+	pio_write_8(ne2k->port + DP_MAR1, (uint8_t) (hash >> 8));
+	pio_write_8(ne2k->port + DP_MAR2, (uint8_t) (hash >> 16));
+	pio_write_8(ne2k->port + DP_MAR3, (uint8_t) (hash >> 24));
+	pio_write_8(ne2k->port + DP_MAR4, (uint8_t) (hash >> 32));
+	pio_write_8(ne2k->port + DP_MAR5, (uint8_t) (hash >> 40));
+	pio_write_8(ne2k->port + DP_MAR6, (uint8_t) (hash >> 48));
+	pio_write_8(ne2k->port + DP_MAR7, (uint8_t) (hash >> 56));
+	
+	/* Select Page 0 and resume transfers */
+	pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_DM_ABORT | CR_STA);
+}
+
+/** @}
+ */
Index: uspace/drv/nic/ne2k/dp8390.h
===================================================================
--- uspace/drv/nic/ne2k/dp8390.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/drv/nic/ne2k/dp8390.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Martin Decky
+ * 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.
+ */
+
+/*
+ * This code is based upon the NE2000 driver for MINIX,
+ * distributed according to a BSD-style license.
+ *
+ * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
+ * Copyright (c) 1992, 1994 Philip Homburg
+ * Copyright (c) 1996 G. Falzoni
+ *
+ */
+
+/** @addtogroup drv_ne2k
+ *  @{
+ */
+
+/** @file
+ *  DP8390 network interface definitions.
+ */
+
+#ifndef __NET_NETIF_DP8390_H__
+#define __NET_NETIF_DP8390_H__
+
+#include <fibril_synch.h>
+#include <nic.h>
+#include <ddf/interrupt.h>
+
+/** Input/output size */
+#define NE2K_IO_SIZE  0x0020
+
+/* NE2000 implementation. */
+
+/** NE2000 Data Register */
+#define NE2K_DATA  0x0010
+
+/** NE2000 Reset register */
+#define NE2K_RESET  0x001f
+
+/** NE2000 data start */
+#define NE2K_START  0x4000
+
+/** NE2000 data size */
+#define NE2K_SIZE  0x4000
+
+/** NE2000 retry count */
+#define NE2K_RETRY  0x1000
+
+/** NE2000 error messages rate limiting */
+#define NE2K_ERL  10
+
+/** Minimum Ethernet packet size in bytes */
+#define ETH_MIN_PACK_SIZE  60
+
+/** Maximum Ethernet packet size in bytes */
+#define ETH_MAX_PACK_SIZE_TAGGED  1518
+
+/* National Semiconductor DP8390 Network Interface Controller. */
+
+/** Page 0, for reading */
+#define DP_CR     0x00  /**< Command Register */
+#define DP_CLDA0  0x01  /**< Current Local DMA Address 0 */
+#define DP_CLDA1  0x02  /**< Current Local DMA Address 1 */
+#define DP_BNRY   0x03  /**< Boundary Pointer */
+#define DP_TSR    0x04  /**< Transmit Status Register */
+#define DP_NCR    0x05  /**< Number of Collisions Register */
+#define DP_FIFO   0x06  /**< FIFO */
+#define DP_ISR    0x07  /**< Interrupt Status Register */
+#define DP_CRDA0  0x08  /**< Current Remote DMA Address 0 */
+#define DP_CRDA1  0x09  /**< Current Remote DMA Address 1 */
+#define DP_RSR    0x0c  /**< Receive Status Register */
+#define DP_CNTR0  0x0d  /**< Tally Counter 0 */
+#define DP_CNTR1  0x0e  /**< Tally Counter 1 */
+#define DP_CNTR2  0x0f  /**< Tally Counter 2 */
+
+/** Page 0, for writing */
+#define DP_PSTART  0x01  /**< Page Start Register*/
+#define DP_PSTOP   0x02  /**< Page Stop Register */
+#define DP_TPSR    0x04  /**< Transmit Page Start Register */
+#define DP_TBCR0   0x05  /**< Transmit Byte Count Register 0 */
+#define DP_TBCR1   0x06  /**< Transmit Byte Count Register 1 */
+#define DP_RSAR0   0x08  /**< Remote Start Address Register 0 */
+#define DP_RSAR1   0x09  /**< Remote Start Address Register 1 */
+#define DP_RBCR0   0x0a  /**< Remote Byte Count Register 0 */
+#define DP_RBCR1   0x0b  /**< Remote Byte Count Register 1 */
+#define DP_RCR     0x0c  /**< Receive Configuration Register */
+#define DP_TCR     0x0d  /**< Transmit Configuration Register */
+#define DP_DCR     0x0e  /**< Data Configuration Register */
+#define DP_IMR     0x0f  /**< Interrupt Mask Register */
+
+/** Page 1, read/write */
+#define DP_PAR0  0x01  /**< Physical Address Register 0 */
+#define DP_PAR1  0x02  /**< Physical Address Register 1 */
+#define DP_PAR2  0x03  /**< Physical Address Register 2 */
+#define DP_PAR3  0x04  /**< Physical Address Register 3 */
+#define DP_PAR4  0x05  /**< Physical Address Register 4 */
+#define DP_PAR5  0x06  /**< Physical Address Register 5 */
+#define DP_CURR  0x07  /**< Current Page Register */
+#define DP_MAR0  0x08  /**< Multicast Address Register 0 */
+#define DP_MAR1  0x09  /**< Multicast Address Register 1 */
+#define DP_MAR2  0x0a  /**< Multicast Address Register 2 */
+#define DP_MAR3  0x0b  /**< Multicast Address Register 3 */
+#define DP_MAR4  0x0c  /**< Multicast Address Register 4 */
+#define DP_MAR5  0x0d  /**< Multicast Address Register 5 */
+#define DP_MAR6  0x0e  /**< Multicast Address Register 6 */
+#define DP_MAR7  0x0f  /**< Multicast Address Register 7 */
+
+/* Bits in Command Register */
+#define CR_STP       0x01  /**< Stop (software reset) */
+#define CR_STA       0x02  /**< Start (activate NIC) */
+#define CR_TXP       0x04  /**< Transmit Packet */
+#define CR_DMA       0x38  /**< Mask for DMA control */
+#define CR_DM_NOP    0x00  /**< DMA: No Operation */
+#define CR_DM_RR     0x08  /**< DMA: Remote Read */
+#define CR_DM_RW     0x10  /**< DMA: Remote Write */
+#define CR_DM_SP     0x18  /**< DMA: Send Packet */
+#define CR_DM_ABORT  0x20  /**< DMA: Abort Remote DMA Operation */
+#define CR_PS        0xc0  /**< Mask for Page Select */
+#define CR_PS_P0     0x00  /**< Register Page 0 */
+#define CR_PS_P1     0x40  /**< Register Page 1 */
+#define CR_PS_P2     0x80  /**< Register Page 2 */
+#define CR_PS_T1     0xc0  /**< Test Mode Register Map */
+
+/* Bits in Interrupt State Register */
+#define ISR_PRX  0x01  /**< Packet Received with no errors */
+#define ISR_PTX  0x02  /**< Packet Transmitted with no errors */
+#define ISR_RXE  0x04  /**< Receive Error */
+#define ISR_TXE  0x08  /**< Transmit Error */
+#define ISR_OVW  0x10  /**< Overwrite Warning */
+#define ISR_CNT  0x20  /**< Counter Overflow */
+#define ISR_RDC  0x40  /**< Remote DMA Complete */
+#define ISR_RST  0x80  /**< Reset Status */
+
+/* Bits in Interrupt Mask Register */
+#define IMR_PRXE  0x01  /**< Packet Received Interrupt Enable */
+#define IMR_PTXE  0x02  /**< Packet Transmitted Interrupt Enable */
+#define IMR_RXEE  0x04  /**< Receive Error Interrupt Enable */
+#define IMR_TXEE  0x08  /**< Transmit Error Interrupt Enable */
+#define IMR_OVWE  0x10  /**< Overwrite Warning Interrupt Enable */
+#define IMR_CNTE  0x20  /**< Counter Overflow Interrupt Enable */
+#define IMR_RDCE  0x40  /**< DMA Complete Interrupt Enable */
+
+/* Bits in Data Configuration Register */
+#define DCR_WTS        0x01  /**< Word Transfer Select */
+#define DCR_BYTEWIDE   0x00  /**< WTS: byte wide transfers */
+#define DCR_WORDWIDE   0x01  /**< WTS: word wide transfers */
+#define DCR_BOS        0x02  /**< Byte Order Select */
+#define DCR_LTLENDIAN  0x00  /**< BOS: Little Endian */
+#define DCR_BIGENDIAN  0x02  /**< BOS: Big Endian */
+#define DCR_LAS        0x04  /**< Long Address Select */
+#define DCR_BMS        0x08  /**< Burst Mode Select */
+#define DCR_AR         0x10  /**< Autoinitialize Remote */
+#define DCR_FTS        0x60  /**< Fifo Threshold Select */
+#define DCR_2BYTES     0x00  /**< 2 bytes */
+#define DCR_4BYTES     0x40  /**< 4 bytes */
+#define DCR_8BYTES     0x20  /**< 8 bytes */
+#define DCR_12BYTES    0x60  /**< 12 bytes */
+
+/* Bits in Transmit Configuration Register */
+#define TCR_CRC        0x01  /**< Inhibit CRC */
+#define TCR_ELC        0x06  /**< Encoded Loopback Control */
+#define TCR_NORMAL     0x00  /**< ELC: Normal Operation */
+#define TCR_INTERNAL   0x02  /**< ELC: Internal Loopback */
+#define TCR_0EXTERNAL  0x04  /**< ELC: External Loopback LPBK=0 */
+#define TCR_1EXTERNAL  0x06  /**< ELC: External Loopback LPBK=1 */
+#define TCR_ATD        0x08  /**< Auto Transmit Disable */
+#define TCR_OFST       0x10  /**< Collision Offset Enable (be nice) */
+
+/* Bits in Interrupt Status Register */
+#define TSR_PTX  0x01  /**< Packet Transmitted (without error) */
+#define TSR_DFR  0x02  /**< Transmit Deferred (reserved) */
+#define TSR_COL  0x04  /**< Transmit Collided */
+#define TSR_ABT  0x08  /**< Transmit Aborted */
+#define TSR_CRS  0x10  /**< Carrier Sense Lost */
+#define TSR_FU   0x20  /**< FIFO Underrun */
+#define TSR_CDH  0x40  /**< CD Heartbeat */
+#define TSR_OWC  0x80  /**< Out of Window Collision */
+
+/* Bits in Receive Configuration Register */
+#define RCR_SEP  0x01  /**< Save Errored Packets */
+#define RCR_AR   0x02  /**< Accept Runt Packets */
+#define RCR_AB   0x04  /**< Accept Broadcast */
+#define RCR_AM   0x08  /**< Accept Multicast */
+#define RCR_PRO  0x10  /**< Physical Promiscuous */
+#define RCR_MON  0x20  /**< Monitor Mode */
+
+/* Bits in Receive Status Register */
+#define RSR_PRX  0x01  /**< Packet Received Intact */
+#define RSR_CRC  0x02  /**< CRC Error */
+#define RSR_FAE  0x04  /**< Frame Alignment Error */
+#define RSR_FO   0x08  /**< FIFO Overrun */
+#define RSR_MPA  0x10  /**< Missed Packet */
+#define RSR_PHY  0x20  /**< Multicast Address Match */
+#define RSR_DIS  0x40  /**< Receiver Disabled */
+#define RSR_DFR  0x80  /**< In later manuals: Deferring */
+
+typedef struct {
+	/* Device configuration */
+	void *base_port; /**< Port assigned from ISA configuration **/
+	void *port;
+	void *data_port;
+	int irq;
+	nic_address_t mac;
+	
+	uint8_t start_page;  /**< Ring buffer start page */
+	uint8_t stop_page;   /**< Ring buffer stop page */
+	
+	/* Send queue */
+	struct {
+		bool dirty;    /**< Buffer contains a packet */
+		size_t size;   /**< Packet size */
+		uint8_t page;  /**< Starting page of the buffer */
+	} sq;
+	fibril_mutex_t sq_mutex;
+	fibril_condvar_t sq_cv;
+	
+	/* Driver run-time variables */
+	bool probed;
+	bool up;
+
+	/* Irq code with assigned addresses for this device */
+	irq_code_t code;
+
+	/* Copy of the receive configuration register */
+	uint8_t receive_configuration;
+
+	/* Device statistics */
+	// TODO: shouldn't be these directly in device.h - nic_device_stats?
+	uint64_t misses;     /**< Receive frame misses */
+	uint64_t underruns;  /**< FIFO underruns */
+	uint64_t overruns;   /**< FIFO overruns */
+} ne2k_t;
+
+extern int ne2k_probe(ne2k_t *);
+extern int ne2k_up(ne2k_t *);
+extern void ne2k_down(ne2k_t *);
+extern void ne2k_send(nic_t *, packet_t *);
+extern void ne2k_interrupt(nic_t *, uint8_t, uint8_t);
+extern packet_t *ne2k_alloc_packet(nic_t *, size_t);
+
+extern void ne2k_set_accept_mcast(ne2k_t *, int);
+extern void ne2k_set_accept_bcast(ne2k_t *, int);
+extern void ne2k_set_promisc_phys(ne2k_t *, int);
+extern void ne2k_set_mcast_hash(ne2k_t *, uint64_t);
+extern void ne2k_set_physical_address(ne2k_t *, const nic_address_t *address);
+
+#endif
+
+/** @}
+ */
Index: uspace/drv/nic/ne2k/ne2k.c
===================================================================
--- uspace/drv/nic/ne2k/ne2k.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/drv/nic/ne2k/ne2k.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * 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.
+ */
+
+/**
+ * @addtogroup drv_ne2k
+ * @brief Novell NE2000 NIC driver
+ * @{
+ */
+/**
+ * @file
+ * @brief Bridge between NICF, DDF and business logic for the NIC
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <str_error.h>
+#include <async.h>
+#include "dp8390.h"
+
+#define NAME  "ne2k"
+
+/** Return the ISR from the interrupt call.
+ *
+ * @param[in] call The interrupt call.
+ *
+ */
+#define IRQ_GET_ISR(call)  ((int) IPC_GET_ARG2(call))
+
+/** Return the TSR from the interrupt call.
+ *
+ * @param[in] call The interrupt call.
+ *
+ */
+#define IRQ_GET_TSR(call)  ((int) IPC_GET_ARG3(call))
+
+#define DRIVER_DATA(dev) ((nic_t *) ((dev)->driver_data))
+#define NE2K(device) ((ne2k_t *) nic_get_specific(DRIVER_DATA(device)))
+
+/** NE2000 kernel interrupt command sequence.
+ *
+ */
+static irq_cmd_t ne2k_cmds_prototype[] = {
+	{
+		/* Read Interrupt Status Register */
+		.cmd = CMD_PIO_READ_8,
+		.addr = NULL,
+		.dstarg = 2
+	},
+	{
+		/* Mask supported interrupt causes */
+		.cmd = CMD_BTEST,
+		.value = (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW |
+		    ISR_CNT | ISR_RDC),
+		.srcarg = 2,
+		.dstarg = 3,
+	},
+	{
+		/* Predicate for accepting the interrupt */
+		.cmd = CMD_PREDICATE,
+		.value = 4,
+		.srcarg = 3
+	},
+	{
+		/*
+		 * Mask future interrupts via
+		 * Interrupt Mask Register
+		 */
+		.cmd = CMD_PIO_WRITE_8,
+		.addr = NULL,
+		.value = 0
+	},
+	{
+		/* Acknowledge the current interrupt */
+		.cmd = CMD_PIO_WRITE_A_8,
+		.addr = NULL,
+		.srcarg = 3
+	},
+	{
+		/* Read Transmit Status Register */
+		.cmd = CMD_PIO_READ_8,
+		.addr = NULL,
+		.dstarg = 3
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+static void ne2k_interrupt_handler(ddf_dev_t *dev, ipc_callid_t iid,
+	ipc_call_t *call);
+
+static int ne2k_register_interrupt(nic_t *nic_data)
+{
+	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
+
+	if (ne2k->code.cmdcount == 0) {
+		irq_cmd_t *ne2k_cmds = malloc(sizeof(ne2k_cmds_prototype));
+		if (ne2k_cmds == NULL) {
+			return ENOMEM;
+		}
+		memcpy(ne2k_cmds, ne2k_cmds_prototype, sizeof (ne2k_cmds_prototype));
+		ne2k_cmds[0].addr = ne2k->port + DP_ISR;
+		ne2k_cmds[3].addr = ne2k->port + DP_IMR;
+		ne2k_cmds[4].addr = ne2k_cmds[0].addr;
+		ne2k_cmds[5].addr = ne2k->port + DP_TSR;
+
+		ne2k->code.cmdcount = sizeof(ne2k_cmds_prototype) / sizeof(irq_cmd_t);
+		ne2k->code.cmds = ne2k_cmds;
+	}
+
+	int rc = register_interrupt_handler(nic_get_ddf_dev(nic_data),
+		ne2k->irq, ne2k_interrupt_handler, &ne2k->code);
+	return rc;
+}
+
+static ddf_dev_ops_t ne2k_dev_ops;
+
+static void ne2k_dev_cleanup(ddf_dev_t *dev)
+{
+	if (dev->driver_data != NULL) {
+		ne2k_t *ne2k = NE2K(dev);
+		if (ne2k) {
+			free(ne2k->code.cmds);
+		}
+		nic_unbind_and_destroy(dev);
+	}
+	if (dev->parent_sess != NULL) {
+		async_hangup(dev->parent_sess);
+		dev->parent_sess = NULL;
+	}
+}
+
+static int ne2k_dev_init(nic_t *nic_data)
+{
+	/* Get HW resources */
+	hw_res_list_parsed_t hw_res_parsed;
+	hw_res_list_parsed_init(&hw_res_parsed);
+	
+	int rc = nic_get_resources(nic_data, &hw_res_parsed);
+	
+	if (rc != EOK)
+		goto failed;
+	
+	if (hw_res_parsed.irqs.count == 0) {
+		rc = EINVAL;
+		goto failed;
+	}
+	
+	if (hw_res_parsed.io_ranges.count == 0) {
+		rc = EINVAL;
+		goto failed;
+	}
+	
+	if (hw_res_parsed.io_ranges.ranges[0].size < NE2K_IO_SIZE) {
+		rc = EINVAL;
+		goto failed;
+	}
+	
+	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
+	ne2k->irq = hw_res_parsed.irqs.irqs[0];
+	
+	ne2k->base_port = (void *) (uintptr_t)
+	    hw_res_parsed.io_ranges.ranges[0].address;
+	
+	hw_res_list_parsed_clean(&hw_res_parsed);
+	
+	/* Enable port I/O */
+	if (pio_enable(ne2k->base_port, NE2K_IO_SIZE, &ne2k->port) != EOK)
+		return EADDRNOTAVAIL;
+	
+	
+	ne2k->data_port = ne2k->port + NE2K_DATA;
+	ne2k->receive_configuration = RCR_AB | RCR_AM;
+	ne2k->probed = false;
+	ne2k->up = false;
+	
+	/* Find out whether the device is present. */
+	if (ne2k_probe(ne2k) != EOK)
+		return ENOENT;
+	
+	ne2k->probed = true;
+	
+	rc = ne2k_register_interrupt(nic_data);
+	if (rc != EOK)
+		return EINVAL;
+	
+	return EOK;
+	
+failed:
+	hw_res_list_parsed_clean(&hw_res_parsed);
+	return rc;
+}
+
+void ne2k_interrupt_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
+{
+	nic_t *nic_data = DRIVER_DATA(dev);
+	ne2k_interrupt(nic_data, IRQ_GET_ISR(*call), IRQ_GET_TSR(*call));
+
+	async_answer_0(iid, EOK);
+}
+
+static int ne2k_on_activating(nic_t *nic_data)
+{
+	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
+
+	if (!ne2k->up) {
+		int rc = ne2k_up(ne2k);
+		if (rc != EOK) {
+			return rc;
+		}
+
+		nic_enable_interrupt(nic_data, ne2k->irq);
+	}
+	return EOK;
+}
+
+static int ne2k_on_stopping(nic_t *nic_data)
+{
+	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
+
+	nic_disable_interrupt(nic_data, ne2k->irq);
+	ne2k->receive_configuration = RCR_AB | RCR_AM;
+	ne2k_down(ne2k);
+	return EOK;
+}
+
+static int ne2k_set_address(ddf_fun_t *fun, const nic_address_t *address)
+{
+	nic_t *nic_data = DRIVER_DATA(fun);
+	int rc = nic_report_address(nic_data, address);
+	if (rc != EOK) {
+		return EINVAL;
+	}
+	/* Note: some frame with previous physical address may slip to NIL here
+	 * (for a moment the filtering is not exact), but ethernet should be OK with
+	 * that. Some packet may also be lost, but this is not a problem.
+	 */
+	ne2k_set_physical_address((ne2k_t *) nic_get_specific(nic_data), address);
+	return EOK;
+}
+
+static int ne2k_on_unicast_mode_change(nic_t *nic_data,
+	nic_unicast_mode_t new_mode,
+	const nic_address_t *address_list, size_t address_count)
+{
+	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
+	switch (new_mode) {
+	case NIC_UNICAST_BLOCKED:
+		ne2k_set_promisc_phys(ne2k, false);
+		nic_report_hw_filtering(nic_data, 0, -1, -1);
+		return EOK;
+	case NIC_UNICAST_DEFAULT:
+		ne2k_set_promisc_phys(ne2k, false);
+		nic_report_hw_filtering(nic_data, 1, -1, -1);
+		return EOK;
+	case NIC_UNICAST_LIST:
+		ne2k_set_promisc_phys(ne2k, true);
+		nic_report_hw_filtering(nic_data, 0, -1, -1);
+		return EOK;
+	case NIC_UNICAST_PROMISC:
+		ne2k_set_promisc_phys(ne2k, true);
+		nic_report_hw_filtering(nic_data, 1, -1, -1);
+		return EOK;
+	default:
+		return ENOTSUP;
+	}
+}
+
+static int ne2k_on_multicast_mode_change(nic_t *nic_data,
+	nic_multicast_mode_t new_mode,
+	const nic_address_t *address_list, size_t address_count)
+{
+	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
+	switch (new_mode) {
+	case NIC_MULTICAST_BLOCKED:
+		ne2k_set_accept_mcast(ne2k, false);
+		nic_report_hw_filtering(nic_data, -1, 1, -1);
+		return EOK;
+	case NIC_MULTICAST_LIST:
+		ne2k_set_accept_mcast(ne2k, true);
+		ne2k_set_mcast_hash(ne2k,
+			nic_mcast_hash(address_list, address_count));
+		nic_report_hw_filtering(nic_data, -1, 0, -1);
+		return EOK;
+	case NIC_MULTICAST_PROMISC:
+		ne2k_set_accept_mcast(ne2k, true);
+		ne2k_set_mcast_hash(ne2k, 0xFFFFFFFFFFFFFFFFllu);
+		nic_report_hw_filtering(nic_data, -1, 1, -1);
+		return EOK;
+	default:
+		return ENOTSUP;
+	}
+}
+
+static int ne2k_on_broadcast_mode_change(nic_t *nic_data,
+	nic_broadcast_mode_t new_mode)
+{
+	ne2k_t *ne2k = (ne2k_t *) nic_get_specific(nic_data);
+	switch (new_mode) {
+	case NIC_BROADCAST_BLOCKED:
+		ne2k_set_accept_bcast(ne2k, false);
+		return EOK;
+	case NIC_BROADCAST_ACCEPTED:
+		ne2k_set_accept_bcast(ne2k, true);
+		return EOK;
+	default:
+		return ENOTSUP;
+	}
+}
+
+static int ne2k_dev_add(ddf_dev_t *dev)
+{
+	/* Allocate driver data for the device. */
+	nic_t *nic_data = nic_create_and_bind(dev);
+	if (nic_data == NULL)
+		return ENOMEM;
+	
+	nic_set_write_packet_handler(nic_data, ne2k_send);
+	nic_set_state_change_handlers(nic_data,
+		ne2k_on_activating, NULL, ne2k_on_stopping);
+	nic_set_filtering_change_handlers(nic_data,
+		ne2k_on_unicast_mode_change, ne2k_on_multicast_mode_change,
+		ne2k_on_broadcast_mode_change, NULL, NULL);
+	
+	ne2k_t *ne2k = malloc(sizeof(ne2k_t));
+	if (NULL != ne2k) {
+		memset(ne2k, 0, sizeof(ne2k_t));
+		nic_set_specific(nic_data, ne2k);
+	} else {
+		nic_unbind_and_destroy(dev);
+		return ENOMEM;
+	}
+	
+	int rc = ne2k_dev_init(nic_data);
+	if (rc != EOK) {
+		ne2k_dev_cleanup(dev);
+		return rc;
+	}
+	
+	rc = nic_report_address(nic_data, &ne2k->mac);
+	if (rc != EOK) {
+		ne2k_dev_cleanup(dev);
+		return rc;
+	}
+	
+	rc = nic_register_as_ddf_fun(nic_data, &ne2k_dev_ops);
+	if (rc != EOK) {
+		ne2k_dev_cleanup(dev);
+		return rc;
+	}
+	
+	rc = nic_connect_to_services(nic_data);
+	if (rc != EOK) {
+		ne2k_dev_cleanup(dev);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+static nic_iface_t ne2k_nic_iface = {
+	.set_address = ne2k_set_address
+};
+
+static driver_ops_t ne2k_driver_ops = {
+	.dev_add = ne2k_dev_add
+};
+
+static driver_t ne2k_driver = {
+	.name = NAME,
+	.driver_ops = &ne2k_driver_ops
+};
+
+int main(int argc, char *argv[])
+{
+	nic_driver_init(NAME);
+	nic_driver_implement(&ne2k_driver_ops, &ne2k_dev_ops, &ne2k_nic_iface);
+	
+	return ddf_driver_main(&ne2k_driver);
+}
+
+/** @}
+ */
Index: uspace/drv/nic/ne2k/ne2k.ma
===================================================================
--- uspace/drv/nic/ne2k/ne2k.ma	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/drv/nic/ne2k/ne2k.ma	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,1 @@
+10 isa/ne2k
Index: uspace/drv/test/test1/test1.c
===================================================================
--- uspace/drv/test/test1/test1.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/test/test1/test1.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/test/test2/test2.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/drv/test/test3/test3.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -67,5 +67,7 @@
 	generic/devman.c \
 	generic/device/hw_res.c \
+	generic/device/hw_res_parsed.c \
 	generic/device/char_dev.c \
+	generic/device/nic.c \
 	generic/elf/elf_load.c \
 	generic/event.c \
@@ -103,4 +105,5 @@
 	generic/adt/list.c \
 	generic/adt/hash_table.c \
+	generic/adt/hash_set.c \
 	generic/adt/dynamic_fifo.c \
 	generic/adt/measured_strings.c \
Index: uspace/lib/c/arch/ia64/include/ddi.h
===================================================================
--- uspace/lib/c/arch/ia64/include/ddi.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/arch/ia64/include/ddi.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -52,8 +52,12 @@
 static inline void pio_write_8(ioport8_t *port, uint8_t v)
 {
-	uintptr_t prt = (uintptr_t) port;
+	if (port < (ioport8_t *) IO_SPACE_BOUNDARY) {
+		uintptr_t prt = (uintptr_t) port;
 
-	*((ioport8_t *)(IA64_IOSPACE_ADDRESS +
-	    ((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
+		*((ioport8_t *)(IA64_IOSPACE_ADDRESS +
+		    ((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
+	} else {
+		*port = v;
+	}
 
 	asm volatile ("mf\n" ::: "memory");
@@ -62,8 +66,12 @@
 static inline void pio_write_16(ioport16_t *port, uint16_t v)
 {
-	uintptr_t prt = (uintptr_t) port;
+	if (port < (ioport16_t *) IO_SPACE_BOUNDARY) {
+		uintptr_t prt = (uintptr_t) port;
 
-	*((ioport16_t *)(IA64_IOSPACE_ADDRESS +
-	    ((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
+		*((ioport16_t *)(IA64_IOSPACE_ADDRESS +
+		    ((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
+	} else {
+		*port = v;
+	}
 
 	asm volatile ("mf\n" ::: "memory");
@@ -72,8 +80,12 @@
 static inline void pio_write_32(ioport32_t *port, uint32_t v)
 {
-	uintptr_t prt = (uintptr_t) port;
+	if (port < (ioport32_t *) IO_SPACE_BOUNDARY) {
+		uintptr_t prt = (uintptr_t) port;
 
-	*((ioport32_t *)(IA64_IOSPACE_ADDRESS +
-	    ((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
+		*((ioport32_t *)(IA64_IOSPACE_ADDRESS +
+		    ((prt & 0xfff) | ((prt >> 2) << 12)))) = v;
+	} else {
+		*port = v;
+	}
 
 	asm volatile ("mf\n" ::: "memory");
@@ -82,30 +94,54 @@
 static inline uint8_t pio_read_8(ioport8_t *port)
 {
-	uintptr_t prt = (uintptr_t) port;
+	uint8_t v;
 
 	asm volatile ("mf\n" ::: "memory");
 
-	return *((ioport8_t *)(IA64_IOSPACE_ADDRESS +
-	    ((prt & 0xfff) | ((prt >> 2) << 12))));
+	if (port < (ioport8_t *) IO_SPACE_BOUNDARY) {
+		uintptr_t prt = (uintptr_t) port;
+
+		v = *((ioport8_t *)(IA64_IOSPACE_ADDRESS +
+		    ((prt & 0xfff) | ((prt >> 2) << 12))));
+	} else {
+		v = *port;
+	}
+
+	return v;
 }
 
 static inline uint16_t pio_read_16(ioport16_t *port)
 {
-	uintptr_t prt = (uintptr_t) port;
+	uint16_t v;
 
 	asm volatile ("mf\n" ::: "memory");
 
-	return *((ioport16_t *)(IA64_IOSPACE_ADDRESS +
-	    ((prt & 0xfff) | ((prt >> 2) << 12))));
+	if (port < (ioport16_t *) IO_SPACE_BOUNDARY) {
+		uintptr_t prt = (uintptr_t) port;
+
+		v = *((ioport16_t *)(IA64_IOSPACE_ADDRESS +
+		    ((prt & 0xfff) | ((prt >> 2) << 12))));
+	} else {
+		v = *port;
+	}
+
+	return v;
 }
 
 static inline uint32_t pio_read_32(ioport32_t *port)
 {
-	uintptr_t prt = (uintptr_t) port;
+	uint32_t v;
 
 	asm volatile ("mf\n" ::: "memory");
 
-	return *((ioport32_t *)(IA64_IOSPACE_ADDRESS +
-	    ((prt & 0xfff) | ((prt >> 2) << 12))));
+	if (port < (ioport32_t *) port) {
+		uintptr_t prt = (uintptr_t) port;
+
+		v = *((ioport32_t *)(IA64_IOSPACE_ADDRESS +
+		    ((prt & 0xfff) | ((prt >> 2) << 12))));
+	} else {
+		v = *port;
+	}
+
+	return v;
 }
 
Index: uspace/lib/c/generic/adt/hash_set.c
===================================================================
--- uspace/lib/c/generic/adt/hash_set.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/c/generic/adt/hash_set.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * 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.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#include <adt/hash_set.h>
+#include <adt/list.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <assert.h>
+#include <str.h>
+
+/** Create chained hash set
+ *
+ * @param     h         Hash set structure to be initialized.
+ * @param[in] hash      Hash function
+ * @param[in] equals    Equals function
+ * @param[in] init_size Initial hash set size
+ *
+ * @return True on success
+ *
+ */
+int hash_set_init(hash_set_t *h, hash_set_hash hash, hash_set_equals equals,
+    size_t init_size)
+{
+	assert(h);
+	assert(hash);
+	assert(equals);
+	
+	if (init_size < HASH_SET_MIN_SIZE)
+		init_size = HASH_SET_MIN_SIZE;
+	
+	h->table = malloc(init_size * sizeof(link_t));
+	if (!h->table)
+		return false;
+	
+	for (size_t i = 0; i < init_size; i++)
+		list_initialize(&h->table[i]);
+	
+	h->size = init_size;
+	h->count = 0;
+	h->hash = hash;
+	h->equals = equals;
+	
+	return true;
+}
+
+/** Destroy a hash table instance.
+ *
+ * @param h Hash table to be destroyed.
+ *
+ */
+void hash_set_destroy(hash_set_t *h)
+{
+	assert(h);
+	free(h->table);
+}
+
+/** Rehash the internal table to new table
+ *
+ * @param h         Original hash set
+ * @param new_table Memory for the new table
+ * @param new_size  Size of the new table
+ */
+static void hash_set_rehash(hash_set_t *h, list_t *new_table,
+    size_t new_size)
+{
+	assert(new_size >= HASH_SET_MIN_SIZE);
+	
+	for (size_t bucket = 0; bucket < new_size; bucket++)
+		list_initialize(&new_table[bucket]);
+	
+	for (size_t bucket = 0; bucket < h->size; bucket++) {
+		link_t *cur;
+		link_t *next;
+		
+		for (cur = h->table[bucket].head.next;
+		    cur != &h->table[bucket].head;
+		    cur = next) {
+			next = cur->next;
+			list_append(cur, &new_table[h->hash(cur) % new_size]);
+		}
+	}
+	
+	list_t *old_table = h->table;
+	h->table = new_table;
+	free(old_table);
+	h->size = new_size;
+}
+
+/** Insert item into the set.
+ *
+ * If the set already contains equivalent object,
+ * the function fails.
+ *
+ * @param h    Hash table.
+ * @param key  Array of all keys necessary to compute hash index.
+ * @param item Item to be inserted into the hash table.
+ *
+ * @return True if the object was inserted
+ * @return Ffalse if the set already contained equivalent object.
+ *
+ */
+int hash_set_insert(hash_set_t *h, link_t *item)
+{
+	assert(item);
+	assert(h);
+	assert(h->hash);
+	assert(h->equals);
+	
+	unsigned long hash = h->hash(item);
+	unsigned long chain = hash % h->size;
+	
+	list_foreach(h->table[chain], cur) {
+		if (h->equals(cur, item))
+			return false;
+	}
+	
+	if (h->count + 1 > h->size) {
+		size_t new_size = h->size * 2;
+		list_t *temp = malloc(new_size * sizeof(list_t));
+		if (temp != NULL)
+			hash_set_rehash(h, temp, new_size);
+		
+		/*
+		 * If the allocation fails, just use the same
+		 * old table and try to rehash next time.
+		 */
+		chain = hash % h->size;
+	}
+	
+	h->count++;
+	list_append(item, &h->table[chain]);
+	
+	return true;
+}
+
+/** Search the hash set for a matching object and return it
+ *
+ * @param h    Hash set
+ * @param item The item that should equal to the matched object
+ *
+ * @return Matching item on success, NULL if there is no such item.
+ *
+ */
+link_t *hash_set_find(hash_set_t *h, const link_t *item)
+{
+	assert(h);
+	assert(h->hash);
+	assert(h->equals);
+	
+	unsigned long chain = h->hash(item) % h->size;
+	
+	list_foreach(h->table[chain], cur) {
+		if (h->equals(cur, item))
+			return cur;
+	}
+	
+	return NULL;
+}
+
+/** Remove first matching object from the hash set and return it
+ *
+ * @param h    Hash set.
+ * @param item The item that should be equal to the matched object
+ *
+ * @return The removed item or NULL if this is not found.
+ *
+ */
+link_t *hash_set_remove(hash_set_t *h, const link_t *item)
+{
+	assert(h);
+	assert(h->hash);
+	assert(h->equals);
+	
+	link_t *cur = hash_set_find(h, item);
+	if (cur) {
+		list_remove(cur);
+		
+		h->count--;
+		if (4 * h->count < h->size && h->size > HASH_SET_MIN_SIZE) {
+			size_t new_size = h->size / 2;
+			if (new_size < HASH_SET_MIN_SIZE)
+				/* possible e.g. if init_size == HASH_SET_MIN_SIZE + 1 */
+				new_size = HASH_SET_MIN_SIZE;
+			
+			list_t *temp = malloc(new_size * sizeof (list_t));
+			if (temp != NULL)
+				hash_set_rehash(h, temp, new_size);
+		}
+	}
+	
+	return cur;
+}
+
+/** Remove all elements for which the function returned non-zero
+ *
+ * The function can also destroy the element.
+ *
+ * @param h   Hash set.
+ * @param f   Function to be applied.
+ * @param arg Argument to be passed to the function.
+ *
+ */
+void hash_set_remove_selected(hash_set_t *h, int (*f)(link_t *, void *),
+    void *arg)
+{
+	assert(h);
+	assert(h->table);
+	
+	for (size_t bucket = 0; bucket < h->size; bucket++) {
+		link_t *prev = &h->table[bucket].head;
+		link_t *cur;
+		link_t *next;
+		
+		for (cur = h->table[bucket].head.next;
+		    cur != &h->table[bucket].head;
+		    cur = next) {
+			next = cur->next;
+			if (f(cur, arg)) {
+				prev->next = next;
+				next->prev = prev;
+				h->count--;
+			} else
+				prev = cur;
+		}
+	}
+	
+	if (4 * h->count < h->size && h->size > HASH_SET_MIN_SIZE) {
+		size_t new_size = h->size / 2;
+		if (new_size < HASH_SET_MIN_SIZE)
+			/* possible e.g. if init_size == HASH_SET_MIN_SIZE + 1 */
+			new_size = HASH_SET_MIN_SIZE;
+		
+		list_t *temp = malloc(new_size * sizeof (list_t));
+		if (temp != NULL)
+			hash_set_rehash(h, temp, new_size);
+	}
+}
+
+/** Apply function to all items in hash set
+ *
+ * @param h   Hash set.
+ * @param f   Function to be applied.
+ * @param arg Argument to be passed to the function.
+ *
+ */
+void hash_set_apply(hash_set_t *h, void (*f)(link_t *, void *), void *arg)
+{
+	assert(h);
+	assert(h->table);
+	
+	for (size_t bucket = 0; bucket < h->size; bucket++) {
+		link_t *cur;
+		link_t *next;
+		
+		for (cur = h->table[bucket].head.next;
+		    cur != &h->table[bucket].head;
+		    cur = next) {
+			
+			/*
+			 * The next pointer must be stored prior to the functor
+			 * call to allow using destructor as the functor (the
+			 * free function could overwrite the cur->next pointer).
+			 */
+			next = cur->next;
+			f(cur, arg);
+		}
+	}
+}
+
+/** Remove all elements from the set.
+ *
+ * The table is reallocated to the minimum size.
+ *
+ * @param h   Hash set
+ * @param f   Function (destructor?) applied to all element. Can be NULL.
+ * @param arg Argument to the destructor.
+ *
+ */
+void hash_set_clear(hash_set_t *h, void (*f)(link_t *, void *), void *arg)
+{
+	assert(h);
+	assert(h->table);
+	
+	for (size_t bucket = 0; bucket < h->size; bucket++) {
+		link_t *cur;
+		link_t *next;
+		
+		for (cur = h->table[bucket].head.next;
+		    cur != &h->table[bucket].head;
+		    cur = next) {
+			next = cur->next;
+			list_remove(cur);
+			if (f != NULL)
+				f(cur, arg);
+		}
+	}
+	
+	assert(h->size >= HASH_SET_MIN_SIZE);
+	list_t *new_table =
+	    realloc(h->table, HASH_SET_MIN_SIZE * sizeof(list_t));
+	
+	/* We are shrinking, therefore we shouldn't get NULL */
+	assert(new_table);
+	
+	if (h->table != new_table) {
+		/* Init the lists, pointers to itself are used in them */
+		for (size_t bucket = 0; bucket < HASH_SET_MIN_SIZE; ++bucket)
+			list_initialize(&new_table[bucket]);
+		
+		h->table = new_table;
+	}
+	
+	h->count = 0;
+	h->size = HASH_SET_MIN_SIZE;
+}
+
+/** Get hash set size
+ *
+ * @param hHash set
+ *
+ * @return Number of elements in the set.
+ *
+ */
+size_t hash_set_count(const hash_set_t *h)
+{
+	assert(h);
+	return h->count;
+}
+
+/** Check whether element is contained in the hash set
+ *
+ * @param h    Hash set
+ * @param item Item that should be equal to the matched object
+ *
+ * @return True if the hash set contains equal object
+ * @return False otherwise
+ *
+ */
+int hash_set_contains(const hash_set_t *h, const link_t *item)
+{
+	/*
+	 * The hash_set_find cannot accept constant hash set,
+	 * because we can modify the returned element. But in
+	 * this case we are using it safely.
+	 */
+	return hash_set_find((hash_set_t *) h, item) != NULL;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/adt/hash_table.c
===================================================================
--- uspace/lib/c/generic/adt/hash_table.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/generic/adt/hash_table.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -76,4 +76,24 @@
 	
 	return true;
+}
+
+/** Remove all elements from the hash table
+ *
+ * @param h Hash table to be cleared
+ */
+void hash_table_clear(hash_table_t *h)
+{
+	for (hash_count_t chain = 0; chain < h->entries; ++chain) {
+		link_t *cur;
+		link_t *next;
+		
+		for (cur = h->entry[chain].head.next;
+		    cur != &h->entry[chain].head;
+		    cur = next) {
+			next = cur->next;
+			list_remove(cur);
+			h->op->remove_callback(cur);
+		}
+	}
 }
 
@@ -190,5 +210,5 @@
 }
 
-/** Apply fucntion to all items in hash table.
+/** Apply function to all items in hash table.
  *
  * @param h   Hash table.
@@ -198,9 +218,17 @@
  */
 void hash_table_apply(hash_table_t *h, void (*f)(link_t *, void *), void *arg)
-{
-	hash_index_t bucket;
-	
-	for (bucket = 0; bucket < h->entries; bucket++) {
-		list_foreach(h->entry[bucket], cur) {
+{	
+	for (hash_index_t bucket = 0; bucket < h->entries; bucket++) {
+		link_t *cur;
+		link_t *next;
+
+		for (cur = h->entry[bucket].head.next; cur != &h->entry[bucket].head;
+		    cur = next) {
+			/*
+			 * The next pointer must be stored prior to the functor
+			 * call to allow using destructor as the functor (the
+			 * free function could overwrite the cur->next pointer).
+			 */
+			next = cur->next;
 			f(cur, arg);
 		}
Index: uspace/lib/c/generic/adt/list.c
===================================================================
--- uspace/lib/c/generic/adt/list.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/generic/adt/list.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -33,5 +33,5 @@
 /**
  * @file
- * @brief	Functions completing doubly linked circular list implementaion.
+ * @brief	Functions completing doubly linked circular list implementation.
  *
  * This file contains some of the functions implementing doubly linked circular lists.
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/generic/async.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1846,8 +1846,6 @@
 	
 	fibril_mutex_lock(&async_sess_mutex);
-	
+
 	int rc = async_hangup_internal(sess->phone);
-	if (rc == EOK)
-		free(sess);
 	
 	while (!list_empty(&sess->exch_list)) {
@@ -1861,4 +1859,6 @@
 		free(exch);
 	}
+
+	free(sess);
 	
 	fibril_mutex_unlock(&async_sess_mutex);
Index: uspace/lib/c/generic/ddi.c
===================================================================
--- uspace/lib/c/generic/ddi.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/generic/ddi.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -53,22 +53,24 @@
 }
 
-/** 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 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.
  *
- * @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 *pf, void *vp, 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) pf, (sysarg_t) vp,
+	    pages, flags);
 }
 
Index: uspace/lib/c/generic/device/hw_res_parsed.c
===================================================================
--- uspace/lib/c/generic/device/hw_res_parsed.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/c/generic/device/hw_res_parsed.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,203 @@
+/*
+ * 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 <device/hw_res_parsed.h>
+#include <malloc.h>
+#include <assert.h>
+#include <errno.h>
+
+static void hw_res_parse_add_irq(hw_res_list_parsed_t *out, hw_resource_t *res,
+    int flags)
+{
+	assert(res && (res->type == INTERRUPT));
+	
+	int irq = res->res.interrupt.irq;
+	size_t count = out->irqs.count;
+	int keep_duplicit = flags & HW_RES_KEEP_DUPLICIT;
+	
+	if (!keep_duplicit) {
+		for (size_t i = 0; i < count; i++) {
+			if (out->irqs.irqs[i] == irq)
+				return;
+		}
+	}
+	
+	out->irqs.irqs[count] = irq;
+	out->irqs.count++;
+}
+
+static void hw_res_parse_add_io_range(hw_res_list_parsed_t *out,
+    hw_resource_t *res, int flags)
+{
+	assert(res && (res->type == IO_RANGE));
+	
+	uint64_t address = res->res.io_range.address;
+	endianness_t endianness = res->res.io_range.endianness;
+	size_t size = res->res.io_range.size;
+	
+	if ((size == 0) && (!(flags & HW_RES_KEEP_ZERO_AREA)))
+		return;
+	
+	int keep_duplicit = flags & HW_RES_KEEP_DUPLICIT;
+	size_t count = out->io_ranges.count;
+	
+	if (!keep_duplicit) {
+		for (size_t i = 0; i < count; i++) {
+			uint64_t s_address = out->io_ranges.ranges[i].address;
+			size_t s_size = out->io_ranges.ranges[i].size;
+			
+			if ((address == s_address) && (size == s_size))
+				return;
+		}
+	}
+	
+	out->io_ranges.ranges[count].address = address;
+	out->io_ranges.ranges[count].endianness = endianness;
+	out->io_ranges.ranges[count].size = size;
+	out->io_ranges.count++;
+}
+
+static void hw_res_parse_add_mem_range(hw_res_list_parsed_t *out,
+    hw_resource_t *res, int flags)
+{
+	assert(res && (res->type == MEM_RANGE));
+	
+	uint64_t address = res->res.mem_range.address;
+	endianness_t endianness = res->res.mem_range.endianness;
+	size_t size = res->res.mem_range.size;
+	
+	if ((size == 0) && (!(flags & HW_RES_KEEP_ZERO_AREA)))
+		return;
+	
+	int keep_duplicit = flags & HW_RES_KEEP_DUPLICIT;
+	size_t count = out->mem_ranges.count;
+	
+	if (!keep_duplicit) {
+		for (size_t i = 0; i < count; ++i) {
+			uint64_t s_address = out->mem_ranges.ranges[i].address;
+			size_t s_size = out->mem_ranges.ranges[i].size;
+			
+			if ((address == s_address) && (size == s_size))
+				return;
+		}
+	}
+	
+	out->mem_ranges.ranges[count].address = address;
+	out->mem_ranges.ranges[count].endianness = endianness;
+	out->mem_ranges.ranges[count].size = size;
+	out->mem_ranges.count++;
+}
+
+/** Parse list of hardware resources
+ *
+ * @param      hw_resources Original structure resource
+ * @param[out] out          Output parsed resources
+ * @param      flags        Flags of the parsing.
+ *                          HW_RES_KEEP_ZERO_AREA for keeping
+ *                          zero-size areas, HW_RES_KEEP_DUPLICITIES
+ *                          for keep duplicit areas
+ *
+ * @return EOK if succeed, error code otherwise.
+ *
+ */
+int hw_res_list_parse(hw_resource_list_t *hw_resources,
+    hw_res_list_parsed_t *out, int flags)
+{
+	if ((!hw_resources) || (!out))
+		return EINVAL;
+	
+	size_t res_count = hw_resources->count;
+	hw_res_list_parsed_clean(out);
+	
+	out->irqs.irqs = malloc(res_count * sizeof(int));
+	out->io_ranges.ranges = malloc(res_count * sizeof(io_range_t));
+	out->mem_ranges.ranges = malloc(res_count * sizeof(mem_range_t));
+	
+	for (size_t i = 0; i < res_count; ++i) {
+		hw_resource_t *resource = &(hw_resources->resources[i]);
+		
+		switch (resource->type) {
+		case INTERRUPT:
+			hw_res_parse_add_irq(out, resource, flags);
+			break;
+		case IO_RANGE:
+			hw_res_parse_add_io_range(out, resource, flags);
+			break;
+		case MEM_RANGE:
+			hw_res_parse_add_mem_range(out, resource, flags);
+			break;
+		default:
+			return EINVAL;
+		}
+	}
+	
+	return EOK;
+};
+
+/** Get hw_resources from the parent device.
+ *
+ * The output must be inited, will be cleared
+ *
+ * @see get_hw_resources
+ * @see hw_resources_parse
+ *
+ * @param sess                Session to the parent device
+ * @param hw_resources_parsed Output list
+ * @param flags               Parsing flags
+ *
+ * @return EOK if succeed, error code otherwise
+ *
+ */
+int hw_res_get_list_parsed(async_sess_t *sess,
+    hw_res_list_parsed_t *hw_res_parsed, int flags)
+{
+	if (!hw_res_parsed)
+		return EBADMEM;
+	
+	hw_resource_list_t hw_resources;
+	hw_res_list_parsed_clean(hw_res_parsed);
+	bzero(&hw_resources, sizeof(hw_resource_list_t));
+	
+	int rc = hw_res_get_resource_list(sess, &hw_resources);
+	if (rc != EOK)
+		return rc;
+	
+	rc = hw_res_list_parse(&hw_resources, hw_res_parsed, flags);
+	hw_res_clean_resource_list(&hw_resources);
+	
+	return rc;
+};
+
+/** @}
+ */
Index: uspace/lib/c/generic/device/nic.c
===================================================================
--- uspace/lib/c/generic/device/nic.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/c/generic/device/nic.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,1271 @@
+/*
+ * 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.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/**
+ * @file
+ * @brief Client-side RPC stubs for DDF NIC
+ */
+
+#include <ipc/dev_iface.h>
+#include <assert.h>
+#include <device/nic.h>
+#include <errno.h>
+#include <async.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <ipc/services.h>
+
+/** Send a packet through the device
+ *
+ * @param[in] dev_sess
+ * @param[in] packet_id Id of the sent packet
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_send_message(async_sess_t *dev_sess, packet_id_t packet_id)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_SEND_MESSAGE, packet_id);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Connect the driver to the NET and NIL services
+ *
+ * @param[in] dev_sess
+ * @param[in] nil_service Service identifier for the NIL service
+ * @param[in] device_id
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_connect_to_nil(async_sess_t *dev_sess, services_t nil_service,
+    nic_device_id_t device_id)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_3_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_CONNECT_TO_NIL, nil_service, device_id);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Get the current state of the device
+ *
+ * @param[in]  dev_sess
+ * @param[out] state    Current state
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_state(async_sess_t *dev_sess, nic_device_state_t *state)
+{
+	assert(state);
+	
+	sysarg_t _state;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_STATE, &_state);
+	async_exchange_end(exch);
+	
+	*state = (nic_device_state_t) _state;
+	
+	return rc;
+}
+
+/** Request the device to change its state
+ *
+ * @param[in] dev_sess
+ * @param[in] state    New state
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_set_state(async_sess_t *dev_sess, nic_device_state_t state)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_SET_STATE, state);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Request the MAC address of the device
+ *
+ * @param[in]  dev_sess
+ * @param[out] address  Structure with buffer for the address
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_address(async_sess_t *dev_sess, nic_address_t *address)
+{
+	assert(address);
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	aid_t aid = async_send_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_ADDRESS, NULL);
+	int rc = async_data_read_start(exch, address, sizeof(nic_address_t));
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(aid, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Set the address of the device (e.g. MAC on Ethernet)
+ *
+ * @param[in] dev_sess
+ * @param[in] address  Pointer to the address
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_set_address(async_sess_t *dev_sess, const nic_address_t *address)
+{
+	assert(address);
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	aid_t aid = async_send_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_SET_ADDRESS, NULL);
+	int rc = async_data_write_start(exch, address, sizeof(nic_address_t));
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(aid, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Request statistic data about NIC operation.
+ *
+ * @param[in]  dev_sess
+ * @param[out] stats    Structure with the statistics
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_stats(async_sess_t *dev_sess, nic_device_stats_t *stats)
+{
+	assert(stats);
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_STATS);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	rc = async_data_read_start(exch, stats, sizeof(nic_device_stats_t));
+	
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Request information about the device.
+ *
+ * @see nic_device_info_t
+ *
+ * @param[in]  dev_sess
+ * @param[out] device_info Information about the device
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_device_info(async_sess_t *dev_sess, nic_device_info_t *device_info)
+{
+	assert(device_info);
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_DEVICE_INFO);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	rc = async_data_read_start(exch, device_info, sizeof(nic_device_info_t));
+	
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Request status of the cable (plugged/unplugged)
+ *
+ * @param[in]  dev_sess
+ * @param[out] cable_state Current cable state
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_cable_state(async_sess_t *dev_sess, nic_cable_state_t *cable_state)
+{
+	assert(cable_state);
+	
+	sysarg_t _cable_state;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_CABLE_STATE, &_cable_state);
+	async_exchange_end(exch);
+	
+	*cable_state = (nic_cable_state_t) _cable_state;
+	
+	return rc;
+}
+
+/** Request current operation mode.
+ *
+ * @param[in]  dev_sess
+ * @param[out] speed    Current operation speed in Mbps. Can be NULL.
+ * @param[out] duplex   Full duplex/half duplex. Can be NULL.
+ * @param[out] role     Master/slave/auto. Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_operation_mode(async_sess_t *dev_sess, int *speed,
+   nic_channel_mode_t *duplex, nic_role_t *role)
+{
+	sysarg_t _speed;
+	sysarg_t _duplex;
+	sysarg_t _role;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_OPERATION_MODE, &_speed, &_duplex, &_role);
+	async_exchange_end(exch);
+	
+	if (speed)
+		*speed = (int) _speed;
+	
+	if (duplex)
+		*duplex = (nic_channel_mode_t) _duplex;
+	
+	if (role)
+		*role = (nic_role_t) _role;
+	
+	return rc;
+}
+
+/** Set current operation mode.
+ *
+ * If the NIC has auto-negotiation enabled, this command
+ * disables auto-negotiation and sets the operation mode.
+ *
+ * @param[in] dev_sess
+ * @param[in] speed    Operation speed in Mbps
+ * @param[in] duplex   Full duplex/half duplex
+ * @param[in] role     Master/slave/auto (e.g. in Gbit Ethernet]
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_set_operation_mode(async_sess_t *dev_sess, int speed,
+    nic_channel_mode_t duplex, nic_role_t role)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_4_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_SET_OPERATION_MODE, (sysarg_t) speed, (sysarg_t) duplex,
+	    (sysarg_t) role);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Enable auto-negotiation.
+ *
+ * The advertisement argument can only limit some modes,
+ * it can never force the NIC to advertise unsupported modes.
+ *
+ * The allowed modes are defined in "net/eth_phys.h" in the C library.
+ *
+ * @param[in] dev_sess
+ * @param[in] advertisement Allowed advertised modes. Use 0 for all modes.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_autoneg_enable(async_sess_t *dev_sess, uint32_t advertisement)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_AUTONEG_ENABLE, (sysarg_t) advertisement);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Disable auto-negotiation.
+ *
+ * @param[in] dev_sess
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_autoneg_disable(async_sess_t *dev_sess)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_AUTONEG_DISABLE);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Probe current state of auto-negotiation.
+ *
+ * Modes are defined in the "net/eth_phys.h" in the C library.
+ *
+ * @param[in]  dev_sess
+ * @param[out] our_advertisement   Modes advertised by this NIC.
+ *                                 Can be NULL.
+ * @param[out] their_advertisement Modes advertised by the other side.
+ *                                 Can be NULL.
+ * @param[out] result              General state of auto-negotiation.
+ *                                 Can be NULL.
+ * @param[out]  their_result       State of other side auto-negotiation.
+ *                                 Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_autoneg_probe(async_sess_t *dev_sess, uint32_t *our_advertisement,
+    uint32_t *their_advertisement, nic_result_t *result,
+    nic_result_t *their_result)
+{
+	sysarg_t _our_advertisement;
+	sysarg_t _their_advertisement;
+	sysarg_t _result;
+	sysarg_t _their_result;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_4(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_AUTONEG_PROBE, &_our_advertisement, &_their_advertisement,
+	    &_result, &_their_result);
+	async_exchange_end(exch);
+	
+	if (our_advertisement)
+		*our_advertisement = (uint32_t) _our_advertisement;
+	
+	if (*their_advertisement)
+		*their_advertisement = (uint32_t) _their_advertisement;
+	
+	if (result)
+		*result = (nic_result_t) _result;
+	
+	if (their_result)
+		*their_result = (nic_result_t) _their_result;
+	
+	return rc;
+}
+
+/** Restart the auto-negotiation process.
+ *
+ * @param[in] dev_sess
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_autoneg_restart(async_sess_t *dev_sess)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_AUTONEG_RESTART);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Query party's sending and reception of the PAUSE frame.
+ *
+ * @param[in]  dev_sess
+ * @param[out] we_send    This NIC sends the PAUSE frame (true/false)
+ * @param[out] we_receive This NIC receives the PAUSE frame (true/false)
+ * @param[out] pause      The time set to transmitted PAUSE frames.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_pause(async_sess_t *dev_sess, nic_result_t *we_send,
+    nic_result_t *we_receive, uint16_t *pause)
+{
+	sysarg_t _we_send;
+	sysarg_t _we_receive;
+	sysarg_t _pause;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_PAUSE, &_we_send, &_we_receive, &_pause);
+	async_exchange_end(exch);
+	
+	if (we_send)
+		*we_send = _we_send;
+	
+	if (we_receive)
+		*we_receive = _we_receive;
+	
+	if (pause)
+		*pause = _pause;
+	
+	return rc;
+}
+
+/** Control sending and reception of the PAUSE frame.
+ *
+ * @param[in] dev_sess
+ * @param[in] allow_send    Allow sending the PAUSE frame (true/false)
+ * @param[in] allow_receive Allow reception of the PAUSE frame (true/false)
+ * @param[in] pause         Pause length in 512 bit units written
+ *                          to transmitted frames. The value 0 means
+ *                          auto value (the best). If the requested
+ *                          time cannot be set the driver is allowed
+ *                          to set the nearest supported value.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_set_pause(async_sess_t *dev_sess, int allow_send, int allow_receive,
+    uint16_t pause)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_4_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_SET_PAUSE, allow_send, allow_receive, pause);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Retrieve current settings of unicast frames reception.
+ *
+ * Note: In case of mode != NIC_UNICAST_LIST the contents of
+ * address_list and address_count are undefined.
+ *
+ * @param[in]   dev_sess
+ * @param[out]  mode          Current operation mode
+ * @param[in]   max_count     Maximal number of addresses that could
+ *                            be written into the list buffer.
+ * @param[out]  address_list  Buffer for the list (array). Can be NULL.
+ * @param[out]  address_count Number of addresses in the list before
+ *                            possible truncation due to the max_count.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_unicast_get_mode(async_sess_t *dev_sess, nic_unicast_mode_t *mode,
+    size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	assert(mode);
+	
+	sysarg_t _mode;
+	sysarg_t _address_count;
+	
+	if (!address_list)
+		max_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_2_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_UNICAST_GET_MODE, max_count, &_mode, &_address_count);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	*mode = (nic_unicast_mode_t) _mode;
+	if (address_count)
+		*address_count = (size_t) _address_count;
+	
+	if ((max_count) && (_address_count))
+		rc = async_data_read_start(exch, address_list,
+		    max_count * sizeof(nic_address_t));
+	
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Set which unicast frames are received.
+ *
+ * @param[in] dev_sess
+ * @param[in] mode          Current operation mode
+ * @param[in] address_list  The list of addresses. Can be NULL.
+ * @param[in] address_count Number of addresses in the list.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_unicast_set_mode(async_sess_t *dev_sess, nic_unicast_mode_t mode,
+    const nic_address_t *address_list, size_t address_count)
+{
+	if (address_list == NULL)
+		address_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	aid_t message_id = async_send_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_UNICAST_SET_MODE, (sysarg_t) mode, address_count, NULL);
+	
+	int rc;
+	if (address_count)
+		rc = async_data_write_start(exch, address_list,
+		    address_count * sizeof(nic_address_t));
+	else
+		rc = EOK;
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(message_id, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Retrieve current settings of multicast frames reception.
+ *
+ * Note: In case of mode != NIC_MULTICAST_LIST the contents of
+ * address_list and address_count are undefined.
+ *
+ * @param[in]  dev_sess
+ * @param[out] mode          Current operation mode
+ * @param[in]  max_count     Maximal number of addresses that could
+ *                           be written into the list buffer.
+ * @param[out] address_list  Buffer for the list (array). Can be NULL.
+ * @param[out] address_count Number of addresses in the list before
+ *                           possible truncation due to the max_count.
+ *                           Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_multicast_get_mode(async_sess_t *dev_sess, nic_multicast_mode_t *mode,
+    size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	assert(mode);
+	
+	sysarg_t _mode;
+	
+	if (!address_list)
+		max_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	sysarg_t ac;
+	int rc = async_req_2_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_MULTICAST_GET_MODE, max_count, &_mode, &ac);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	*mode = (nic_multicast_mode_t) _mode;
+	if (address_count)
+		*address_count = (size_t) ac;
+	
+	if ((max_count) && (ac))
+		rc = async_data_read_start(exch, address_list,
+		    max_count * sizeof(nic_address_t));
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Set which multicast frames are received.
+ *
+ * @param[in] dev_sess
+ * @param[in] mode          Current operation mode
+ * @param[in] address_list  The list of addresses. Can be NULL.
+ * @param[in] address_count Number of addresses in the list.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_multicast_set_mode(async_sess_t *dev_sess, nic_multicast_mode_t mode,
+    const nic_address_t *address_list, size_t address_count)
+{
+	if (address_list == NULL)
+		address_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	aid_t message_id = async_send_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_MULTICAST_SET_MODE, (sysarg_t) mode, address_count, NULL);
+	
+	int rc;
+	if (address_count)
+		rc = async_data_write_start(exch, address_list,
+		    address_count * sizeof(nic_address_t));
+	else
+		rc = EOK;
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(message_id, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Determine if broadcast packets are received.
+ *
+ * @param[in]  dev_sess
+ * @param[out] mode     Current operation mode
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_broadcast_get_mode(async_sess_t *dev_sess, nic_broadcast_mode_t *mode)
+{
+	assert(mode);
+	
+	sysarg_t _mode;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_BROADCAST_GET_MODE, &_mode);
+	async_exchange_end(exch);
+	
+	*mode = (nic_broadcast_mode_t) _mode;
+	
+	return rc;
+}
+
+/** Set whether broadcast packets are received.
+ *
+ * @param[in] dev_sess
+ * @param[in] mode     Current operation mode
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_broadcast_set_mode(async_sess_t *dev_sess, nic_broadcast_mode_t mode)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_BROADCAST_SET_MODE, mode);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Determine if defective (erroneous) packets are received.
+ *
+ * @param[in]  dev_sess
+ * @param[out] mode     Bitmask specifying allowed errors
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_defective_get_mode(async_sess_t *dev_sess, uint32_t *mode)
+{
+	assert(mode);
+	
+	sysarg_t _mode;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_DEFECTIVE_GET_MODE, &_mode);
+	async_exchange_end(exch);
+	
+	*mode = (uint32_t) _mode;
+	
+	return rc;
+}
+
+/** Set whether defective (erroneous) packets are received.
+ *
+ * @param[in]  dev_sess
+ * @param[out] mode     Bitmask specifying allowed errors
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_defective_set_mode(async_sess_t *dev_sess, uint32_t mode)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_DEFECTIVE_SET_MODE, mode);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Retrieve the currently blocked source MAC addresses.
+ *
+ * @param[in]  dev_sess
+ * @param[in]  max_count     Maximal number of addresses that could
+ *                           be written into the list buffer.
+ * @param[out] address_list  Buffer for the list (array). Can be NULL.
+ * @param[out] address_count Number of addresses in the list before
+ *                           possible truncation due to the max_count.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_blocked_sources_get(async_sess_t *dev_sess, size_t max_count,
+    nic_address_t *address_list, size_t *address_count)
+{
+	if (!address_list)
+		max_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	sysarg_t ac;
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_BLOCKED_SOURCES_GET, max_count, &ac);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	if (address_count)
+		*address_count = (size_t) ac;
+	
+	if ((max_count) && (ac))
+		rc = async_data_read_start(exch, address_list,
+		    max_count * sizeof(nic_address_t));
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Set which source MACs are blocked
+ *
+ * @param[in] dev_sess
+ * @param[in] address_list  The list of addresses. Can be NULL.
+ * @param[in] address_count Number of addresses in the list.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_blocked_sources_set(async_sess_t *dev_sess,
+    const nic_address_t *address_list, size_t address_count)
+{
+	if (address_list == NULL)
+		address_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	aid_t message_id = async_send_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_BLOCKED_SOURCES_SET, address_count, NULL);
+	
+	int rc;
+	if (address_count)
+		rc = async_data_write_start(exch, address_list,
+			address_count * sizeof(nic_address_t));
+	else
+		rc = EOK;
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(message_id, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Request current VLAN filtering mask.
+ *
+ * @param[in]  dev_sess
+ * @param[out] stats    Structure with the statistics
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_vlan_get_mask(async_sess_t *dev_sess, nic_vlan_mask_t *mask)
+{
+	assert(mask);
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_VLAN_GET_MASK);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	rc = async_data_read_start(exch, mask, sizeof(nic_vlan_mask_t));
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Set the mask used for VLAN filtering.
+ *
+ * If NULL, VLAN filtering is disabled.
+ *
+ * @param[in] dev_sess
+ * @param[in] mask     Pointer to mask structure or NULL to disable.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_vlan_set_mask(async_sess_t *dev_sess, const nic_vlan_mask_t *mask)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	aid_t message_id = async_send_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_VLAN_SET_MASK, mask != NULL, NULL);
+	
+	int rc;
+	if (mask != NULL)
+		rc = async_data_write_start(exch, mask, sizeof(nic_vlan_mask_t));
+	else
+		rc = EOK;
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(message_id, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Set VLAN (802.1q) tag.
+ *
+ * Set whether the tag is to be signaled in offload info and
+ * if the tag should be stripped from received frames and added
+ * to sent frames automatically. Not every combination of add
+ * and strip must be supported.
+ *
+ * @param[in] dev_sess
+ * @param[in] tag      VLAN priority (top 3 bits) and
+ *                     the VLAN tag (bottom 12 bits)
+ * @param[in] add      Add the VLAN tag automatically (boolean)
+ * @param[in] strip    Strip the VLAN tag automatically (boolean)
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_vlan_set_tag(async_sess_t *dev_sess, uint16_t tag, int add, int strip)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_4_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_VLAN_SET_TAG, (sysarg_t) tag, (sysarg_t) add, (sysarg_t) strip);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Add new Wake-On-LAN virtue.
+ *
+ * @param[in]  dev_sess
+ * @param[in]  type     Type of the virtue
+ * @param[in]  data     Data required for this virtue
+ *                      (depends on type)
+ * @param[in]  length   Length of the data
+ * @param[out] id       Identifier of the new virtue
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_virtue_add(async_sess_t *dev_sess, nic_wv_type_t type,
+    const void *data, size_t length, nic_wv_id_t *id)
+{
+	assert(id);
+	
+	bool send_data = ((data != NULL) && (length != 0));
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	ipc_call_t result;
+	aid_t message_id = async_send_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_VIRTUE_ADD, (sysarg_t) type, send_data, &result);
+	
+	sysarg_t res;
+	if (send_data) {
+		int rc = async_data_write_start(exch, data, length);
+		if (rc != EOK) {
+			async_exchange_end(exch);
+			async_wait_for(message_id, &res);
+			return rc;
+		}
+	}
+	
+	async_exchange_end(exch);
+	async_wait_for(message_id, &res);
+	
+	*id = IPC_GET_ARG1(result);
+	return (int) res;
+}
+
+/** Remove Wake-On-LAN virtue.
+ *
+ * @param[in] dev_sess
+ * @param[in] id       Virtue identifier
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_virtue_remove(async_sess_t *dev_sess, nic_wv_id_t id)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_VIRTUE_REMOVE, (sysarg_t) id);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Get information about virtue.
+ *
+ * @param[in]  dev_sess
+ * @param[in]  id         Virtue identifier
+ * @param[out] type       Type of the filter. Can be NULL.
+ * @param[out] max_length Size of the data buffer.
+ * @param[out] data       Buffer for data used when the
+ *                        virtue was created. Can be NULL.
+ * @param[out] length     Length of the data. Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_virtue_probe(async_sess_t *dev_sess, nic_wv_id_t id,
+    nic_wv_type_t *type, size_t max_length, void *data, size_t *length)
+{
+	sysarg_t _type;
+	sysarg_t _length;
+	
+	if (data == NULL)
+		max_length = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_3_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_VIRTUE_PROBE, (sysarg_t) id, max_length,
+	    &_type, &_length);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	if (type)
+		*type = _type;
+	
+	if (length)
+		*length = _length;
+	
+	if ((max_length) && (_length != 0))
+		rc = async_data_read_start(exch, data, max_length);
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Get a list of all virtues of the specified type.
+ *
+ * When NIC_WV_NONE is specified as the virtue type the function
+ * lists virtues of all types.
+ *
+ * @param[in]  dev_sess
+ * @param[in]  type      Type of the virtues
+ * @param[in]  max_count Maximum number of ids that can be
+ *                       written into the list buffer.
+ * @param[out] id_list   Buffer for to the list of virtue ids.
+ *                       Can be NULL.
+ * @param[out] id_count  Number of virtue identifiers in the list
+ *                       before possible truncation due to the
+ *                       max_count. Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_virtue_list(async_sess_t *dev_sess, nic_wv_type_t type,
+    size_t max_count, nic_wv_id_t *id_list, size_t *id_count)
+{
+	if (id_list == NULL)
+		max_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	sysarg_t count;
+	int rc = async_req_3_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_VIRTUE_LIST, (sysarg_t) type, max_count, &count);
+	
+	if (id_count)
+		*id_count = (size_t) count;
+	
+	if ((rc != EOK) || (!max_count)) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	rc = async_data_read_start(exch, id_list,
+	    max_count * sizeof(nic_wv_id_t));
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Get number of virtues that can be enabled yet.
+ *
+ * Count: < 0 => Virtue of this type can be never used
+ *        = 0 => No more virtues can be enabled
+ *        > 0 => #count virtues can be enabled yet
+ *
+ * @param[in]  dev_sess
+ * @param[in]  type     Virtue type
+ * @param[out] count    Number of virtues
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_virtue_get_caps(async_sess_t *dev_sess, nic_wv_type_t type,
+    int *count)
+{
+	assert(count);
+	
+	sysarg_t _count;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_VIRTUE_GET_CAPS, (sysarg_t) type, &_count);
+	async_exchange_end(exch);
+	
+	*count = (int) _count;
+	return rc;
+}
+
+/** Load the frame that issued the wakeup.
+ *
+ * The NIC can support only matched_type,  only part of the frame
+ * can be available or not at all. Sometimes even the type can be
+ * uncertain -- in this case the matched_type contains NIC_WV_NONE.
+ *
+ * Frame_length can be greater than max_length, but at most max_length
+ * bytes will be copied into the frame buffer.
+ *
+ * Note: Only the type of the filter can be detected, not the concrete
+ * filter, because the driver is probably not running when the wakeup
+ * is issued.
+ *
+ * @param[in]  dev_sess
+ * @param[out] matched_type Type of the filter that issued wakeup.
+ * @param[in]  max_length   Size of the buffer
+ * @param[out] frame        Buffer for the frame. Can be NULL.
+ * @param[out] frame_length Length of the stored frame. Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_load_info(async_sess_t *dev_sess, nic_wv_type_t *matched_type,
+    size_t max_length, uint8_t *frame, size_t *frame_length)
+{
+	assert(matched_type);
+	
+	sysarg_t _matched_type;
+	sysarg_t _frame_length;
+	
+	if (frame == NULL)
+		max_length = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_2_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_LOAD_INFO, max_length, &_matched_type, &_frame_length);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	*matched_type = (nic_wv_type_t) _matched_type;
+	if (frame_length)
+		*frame_length = (size_t) _frame_length;
+	
+	if ((max_length != 0) && (_frame_length != 0))
+		rc = async_data_read_start(exch, frame, max_length);
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Probe supported options and current setting of offload computations
+ *
+ * @param[in]  dev_sess
+ * @param[out] supported Supported offload options
+ * @param[out] active    Currently active offload options
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_offload_probe(async_sess_t *dev_sess, uint32_t *supported,
+    uint32_t *active)
+{
+	assert(supported);
+	assert(active);
+	
+	sysarg_t _supported;
+	sysarg_t _active;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_OFFLOAD_PROBE, &_supported, &_active);
+	async_exchange_end(exch);
+	
+	*supported = (uint32_t) _supported;
+	*active = (uint32_t) _active;
+	return rc;
+}
+
+/** Set which offload computations can be performed on the NIC.
+ *
+ * @param[in] dev_sess
+ * @param[in] mask     Mask for the options (only those set here will be set)
+ * @param[in] active   Which options should be enabled and which disabled
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_offload_set(async_sess_t *dev_sess, uint32_t mask, uint32_t active)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_3_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_AUTONEG_RESTART, (sysarg_t) mask, (sysarg_t) active);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Query the current interrupt/poll mode of the NIC
+ *
+ * @param[in]  dev_sess
+ * @param[out] mode     Current poll mode
+ * @param[out] period   Period used in periodic polling.
+ *                      Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_poll_get_mode(async_sess_t *dev_sess, nic_poll_mode_t *mode,
+    struct timeval *period)
+{
+	assert(mode);
+	
+	sysarg_t _mode;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_POLL_GET_MODE, period != NULL, &_mode);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	*mode = (nic_poll_mode_t) _mode;
+	
+	if (period != NULL)
+		rc = async_data_read_start(exch, period, sizeof(struct timeval));
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Set the interrupt/poll mode of the NIC.
+ *
+ * @param[in] dev_sess
+ * @param[in] mode     New poll mode
+ * @param[in] period   Period used in periodic polling. Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_poll_set_mode(async_sess_t *dev_sess, nic_poll_mode_t mode,
+    const struct timeval *period)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	aid_t message_id = async_send_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_POLL_SET_MODE, (sysarg_t) mode, period != NULL, NULL);
+	
+	int rc;
+	if (period)
+		rc = async_data_write_start(exch, period, sizeof(struct timeval));
+	else
+		rc = EOK;
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(message_id, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Request the driver to poll the NIC.
+ *
+ * @param[in] dev_sess
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_poll_now(async_sess_t *dev_sess)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE), NIC_POLL_NOW);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/malloc.c
===================================================================
--- uspace/lib/c/generic/malloc.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/generic/malloc.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -873,4 +873,7 @@
 void free(const void *addr)
 {
+	if (addr == NULL)
+		return;
+
 	futex_down(&malloc_futex);
 	
Index: uspace/lib/c/generic/net/packet.c
===================================================================
--- uspace/lib/c/generic/net/packet.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/generic/net/packet.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -36,4 +36,5 @@
  */
 
+#include <assert.h>
 #include <malloc.h>
 #include <mem.h>
@@ -44,29 +45,10 @@
 #include <sys/mman.h>
 
-#include <adt/generic_field.h>
+#include <adt/hash_table.h>
 #include <net/packet.h>
 #include <net/packet_header.h>
 
-/** Packet map page size. */
-#define PACKET_MAP_SIZE	100
-
-/** Returns the packet map page index.
- * @param[in] packet_id The packet identifier.
- */
-#define PACKET_MAP_PAGE(packet_id)	(((packet_id) - 1) / PACKET_MAP_SIZE)
-
-/** Returns the packet index in the corresponding packet map page.
- *  @param[in] packet_id The packet identifier.
- */
-#define PACKET_MAP_INDEX(packet_id)	(((packet_id) - 1) % PACKET_MAP_SIZE)
-
-/** Type definition of the packet map page. */
-typedef packet_t *packet_map_t[PACKET_MAP_SIZE];
-
-/** Packet map.
- * Maps packet identifiers to the packet references.
- * @see generic_field.h
- */
-GENERIC_FIELD_DECLARE(gpm, packet_map_t);
+/** Packet hash table size. */
+#define PACKET_HASH_TABLE_SIZE  128
 
 /** Packet map global data. */
@@ -75,8 +57,49 @@
 	fibril_rwlock_t lock;
 	/** Packet map. */
-	gpm_t packet_map;
+	hash_table_t packet_map;
+	/** Packet map operations */
+	hash_table_operations_t operations;
 } pm_globals;
 
-GENERIC_FIELD_IMPLEMENT(gpm, packet_map_t);
+typedef struct {
+	link_t link;
+	packet_t *packet;
+} pm_entry_t;
+
+/**
+ * Hash function for the packet mapping hash table
+ */
+static hash_index_t pm_hash(unsigned long key[])
+{
+	return (hash_index_t) key[0] % PACKET_HASH_TABLE_SIZE;
+}
+
+/**
+ * Key compare function for the packet mapping hash table
+ */
+static int pm_compare(unsigned long key[], hash_count_t keys, link_t *link)
+{
+	pm_entry_t *entry = list_get_instance(link, pm_entry_t, link);
+	return entry->packet->packet_id == key[0];
+}
+
+/**
+ * Remove callback for the packet mapping hash table
+ */
+static void pm_remove_callback(link_t *link)
+{
+	pm_entry_t *entry = list_get_instance(link, pm_entry_t, link);
+	free(entry);
+}
+
+/**
+ * Wrapper used when destroying the whole table
+ */
+static void pm_free_wrapper(link_t *link, void *ignored)
+{
+	pm_entry_t *entry = list_get_instance(link, pm_entry_t, link);
+	free(entry);
+}
+
 
 /** Initializes the packet map.
@@ -87,10 +110,18 @@
 int pm_init(void)
 {
-	int rc;
+	int rc = EOK;
 
 	fibril_rwlock_initialize(&pm_globals.lock);
 	
 	fibril_rwlock_write_lock(&pm_globals.lock);
-	rc = gpm_initialize(&pm_globals.packet_map);
+	
+	pm_globals.operations.hash = pm_hash;
+	pm_globals.operations.compare = pm_compare;
+	pm_globals.operations.remove_callback = pm_remove_callback;
+
+	if (!hash_table_create(&pm_globals.packet_map, PACKET_HASH_TABLE_SIZE, 1,
+	    &pm_globals.operations))
+		rc = ENOMEM;
+	
 	fibril_rwlock_write_unlock(&pm_globals.lock);
 	
@@ -100,27 +131,28 @@
 /** Finds the packet mapping.
  *
- * @param[in] packet_id	The packet identifier to be found.
- * @return		The found packet reference.
- * @return		NULL if the mapping does not exist.
+ * @param[in] packet_id Packet identifier to be found.
+ *
+ * @return The found packet reference.
+ * @return NULL if the mapping does not exist.
+ *
  */
 packet_t *pm_find(packet_id_t packet_id)
 {
-	packet_map_t *map;
-	packet_t *packet;
-
 	if (!packet_id)
 		return NULL;
-
+	
 	fibril_rwlock_read_lock(&pm_globals.lock);
-	if (packet_id > PACKET_MAP_SIZE * gpm_count(&pm_globals.packet_map)) {
-		fibril_rwlock_read_unlock(&pm_globals.lock);
-		return NULL;
-	}
-	map = gpm_get_index(&pm_globals.packet_map, PACKET_MAP_PAGE(packet_id));
-	if (!map) {
-		fibril_rwlock_read_unlock(&pm_globals.lock);
-		return NULL;
-	}
-	packet = (*map) [PACKET_MAP_INDEX(packet_id)];
+	
+	unsigned long key = packet_id;
+	link_t *link = hash_table_find(&pm_globals.packet_map, &key);
+	
+	packet_t *packet;
+	if (link != NULL) {
+		pm_entry_t *entry =
+		    hash_table_get_instance(link, pm_entry_t, link);
+		packet = entry->packet;
+	} else
+		packet = NULL;
+	
 	fibril_rwlock_read_unlock(&pm_globals.lock);
 	return packet;
@@ -129,67 +161,58 @@
 /** Adds the packet mapping.
  *
- * @param[in] packet	The packet to be remembered.
- * @return		EOK on success.
- * @return		EINVAL if the packet is not valid.
- * @return		EINVAL if the packet map is not initialized.
- * @return		ENOMEM if there is not enough memory left.
+ * @param[in] packet Packet to be remembered.
+ *
+ * @return EOK on success.
+ * @return EINVAL if the packet is not valid.
+ * @return ENOMEM if there is not enough memory left.
+ *
  */
 int pm_add(packet_t *packet)
 {
-	packet_map_t *map;
-	int rc;
-
 	if (!packet_is_valid(packet))
 		return EINVAL;
-
+	
 	fibril_rwlock_write_lock(&pm_globals.lock);
-
-	if (PACKET_MAP_PAGE(packet->packet_id) <
-	    gpm_count(&pm_globals.packet_map)) {
-		map = gpm_get_index(&pm_globals.packet_map,
-		    PACKET_MAP_PAGE(packet->packet_id));
-	} else {
-		do {
-			map = (packet_map_t *) malloc(sizeof(packet_map_t));
-			if (!map) {
-				fibril_rwlock_write_unlock(&pm_globals.lock);
-				return ENOMEM;
-			}
-			bzero(map, sizeof(packet_map_t));
-			rc = gpm_add(&pm_globals.packet_map, map);
-			if (rc < 0) {
-				fibril_rwlock_write_unlock(&pm_globals.lock);
-				free(map);
-				return rc;
-			}
-		} while (PACKET_MAP_PAGE(packet->packet_id) >=
-		    gpm_count(&pm_globals.packet_map));
+	
+	pm_entry_t *entry = malloc(sizeof(pm_entry_t));
+	if (entry == NULL) {
+		fibril_rwlock_write_unlock(&pm_globals.lock);
+		return ENOMEM;
 	}
-
-	(*map) [PACKET_MAP_INDEX(packet->packet_id)] = packet;
+	
+	entry->packet = packet;
+	
+	unsigned long key = packet->packet_id;
+	hash_table_insert(&pm_globals.packet_map, &key, &entry->link);
+	
 	fibril_rwlock_write_unlock(&pm_globals.lock);
+	
 	return EOK;
 }
 
-/** Releases the packet map. */
+/** Remove the packet mapping
+ *
+ * @param[in] packet The packet to be removed
+ *
+ */
+void pm_remove(packet_t *packet)
+{
+	assert(packet_is_valid(packet));
+	
+	fibril_rwlock_write_lock(&pm_globals.lock);
+	
+	unsigned long key = packet->packet_id;
+	hash_table_remove(&pm_globals.packet_map, &key, 1);
+	
+	fibril_rwlock_write_unlock(&pm_globals.lock);
+}
+
+/** Release the packet map. */
 void pm_destroy(void)
 {
-	int count;
-	int index;
-	packet_map_t *map;
-	packet_t *packet;
-
 	fibril_rwlock_write_lock(&pm_globals.lock);
-	count = gpm_count(&pm_globals.packet_map);
-	while (count > 0) {
-		map = gpm_get_index(&pm_globals.packet_map, count - 1);
-		for (index = PACKET_MAP_SIZE - 1; index >= 0; --index) {
-			packet = (*map)[index];
-			if (packet_is_valid(packet))
-				munmap(packet, packet->length);
-		}
-	}
-	gpm_destroy(&pm_globals.packet_map, free);
-	/* leave locked */
+	hash_table_apply(&pm_globals.packet_map, pm_free_wrapper, NULL);
+	hash_table_destroy(&pm_globals.packet_map);
+	/* Leave locked */
 }
 
@@ -199,46 +222,52 @@
  * The packet is inserted right before the packets of the same order value.
  *
- * @param[in,out] first	The first packet of the queue. Sets the first packet of
- *			the queue. The original first packet may be shifted by
- *			the new packet.
- * @param[in] packet	The packet to be added.
- * @param[in] order	The packet order value.
- * @param[in] metric	The metric value of the packet.
- * @return		EOK on success.
- * @return		EINVAL if the first parameter is NULL.
- * @return		EINVAL if the packet is not valid.
+ * @param[in,out] first First packet of the queue. Sets the first
+ *                      packet of the queue. The original first packet
+ *                      may be shifted by the new packet.
+ * @param[in] packet    Packet to be added.
+ * @param[in] order     Packet order value.
+ * @param[in] metric    Metric value of the packet.
+ *
+ * @return EOK on success.
+ * @return EINVAL if the first parameter is NULL.
+ * @return EINVAL if the packet is not valid.
+ *
  */
 int pq_add(packet_t **first, packet_t *packet, size_t order, size_t metric)
 {
-	packet_t *item;
-
-	if (!first || !packet_is_valid(packet))
+	if ((!first) || (!packet_is_valid(packet)))
 		return EINVAL;
-
+	
 	pq_set_order(packet, order, metric);
 	if (packet_is_valid(*first)) {
-		item = * first;
+		packet_t *cur = *first;
+		
 		do {
-			if (item->order < order) {
-				if (item->next) {
-					item = pm_find(item->next);
-				} else {
-					item->next = packet->packet_id;
-					packet->previous = item->packet_id;
+			if (cur->order < order) {
+				if (cur->next)
+					cur = pm_find(cur->next);
+				else {
+					cur->next = packet->packet_id;
+					packet->previous = cur->packet_id;
+					
 					return EOK;
 				}
 			} else {
-				packet->previous = item->previous;
-				packet->next = item->packet_id;
-				item->previous = packet->packet_id;
-				item = pm_find(packet->previous);
-				if (item)
-					item->next = packet->packet_id;
+				packet->previous = cur->previous;
+				packet->next = cur->packet_id;
+				
+				cur->previous = packet->packet_id;
+				cur = pm_find(packet->previous);
+				
+				if (cur)
+					cur->next = packet->packet_id;
 				else
 					*first = packet;
+				
 				return EOK;
 			}
-		} while (packet_is_valid(item));
+		} while (packet_is_valid(cur));
 	}
+	
 	*first = packet;
 	return EOK;
@@ -312,10 +341,11 @@
 
 	next = pm_find(packet->next);
-	if (next) {
+	if (next)
 		next->previous = packet->previous;
-		previous = pm_find(next->previous);
-		if (previous)
-			previous->next = next->packet_id;
-	}
+	
+	previous = pm_find(packet->previous);
+	if (previous)
+		previous->next = packet->next ;
+	
 	packet->previous = 0;
 	packet->next = 0;
Index: uspace/lib/c/generic/ns.c
===================================================================
--- uspace/lib/c/generic/ns.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/generic/ns.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -54,8 +54,9 @@
 	if (!exch)
 		return NULL;
+	
 	async_sess_t *sess =
 	    async_connect_me_to(mgmt, exch, service, arg2, arg3);
 	async_exchange_end(exch);
-
+	
 	if (!sess)
 		return NULL;
@@ -75,7 +76,12 @@
 {
 	async_exch_t *exch = async_exchange_begin(session_ns);
+	if (!exch)
+		return NULL;
 	async_sess_t *sess =
 	    async_connect_me_to_blocking(mgmt, exch, service, arg2, arg3);
 	async_exchange_end(exch);
+
+	if (!sess)
+		return NULL;
 	
 	/*
Index: uspace/lib/c/generic/str.c
===================================================================
--- uspace/lib/c/generic/str.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/generic/str.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -839,4 +839,58 @@
 	
 	return NULL;
+}
+
+/** Removes specified trailing characters from a string.
+ *
+ * @param str String to remove from.
+ * @param ch  Character to remove.
+ */
+void str_rtrim(char *str, wchar_t ch)
+{
+	size_t off = 0;
+	size_t pos = 0;
+	wchar_t c;
+	bool update_last_chunk = true;
+	char *last_chunk = NULL;
+
+	while ((c = str_decode(str, &off, STR_NO_LIMIT))) {
+		if (c != ch) {
+			update_last_chunk = true;
+			last_chunk = NULL;
+		} else if (update_last_chunk) {
+			update_last_chunk = false;
+			last_chunk = (str + pos);
+		}
+		pos = off;
+	}
+
+	if (last_chunk)
+		*last_chunk = '\0';
+}
+
+/** Removes specified leading characters from a string.
+ *
+ * @param str String to remove from.
+ * @param ch  Character to remove.
+ */
+void str_ltrim(char *str, wchar_t ch)
+{
+	wchar_t acc;
+	size_t off = 0;
+	size_t pos = 0;
+	size_t str_sz = str_size(str);
+
+	while ((acc = str_decode(str, &off, STR_NO_LIMIT)) != 0) {
+		if (acc != ch)
+			break;
+		else
+			pos = off;
+	}
+
+	if (pos > 0) {
+		memmove(str, &str[pos], str_sz - pos);
+		pos = str_sz - pos;
+		str[str_sz - pos] = '\0';
+	}
 }
 
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -143,5 +143,5 @@
 
 int mount(const char *fs_name, const char *mp, const char *fqsn,
-    const char *opts, unsigned int flags)
+    const char *opts, unsigned int flags, unsigned int instance)
 {
 	int null_id = -1;
@@ -181,5 +181,6 @@
 
 	sysarg_t rc_orig;
-	aid_t req = async_send_2(exch, VFS_IN_MOUNT, service_id, flags, NULL);
+	aid_t req = async_send_3(exch, VFS_IN_MOUNT, service_id, flags,
+	    instance, NULL);
 	sysarg_t rc = async_data_write_start(exch, (void *) mpa, mpa_size);
 	if (rc != EOK) {
@@ -830,4 +831,65 @@
 }
 
+int get_mtab_list(list_t *mtab_list)
+{
+	sysarg_t rc;
+	aid_t req;
+	size_t i;
+	sysarg_t num_mounted_fs;
+	
+	async_exch_t *exch = vfs_exchange_begin();
+
+	req = async_send_0(exch, VFS_IN_MTAB_GET, NULL);
+
+	/* Ask VFS how many filesystems are mounted */
+	rc = async_req_0_1(exch, VFS_IN_PING, &num_mounted_fs);
+	if (rc != EOK)
+		goto exit;
+
+	for (i = 0; i < num_mounted_fs; ++i) {
+		mtab_ent_t *mtab_ent;
+
+		mtab_ent = malloc(sizeof(mtab_ent_t));
+		if (!mtab_ent) {
+			rc = ENOMEM;
+			goto exit;
+		}
+
+		memset(mtab_ent, 0, sizeof(mtab_ent_t));
+
+		rc = async_data_read_start(exch, (void *) mtab_ent->mp,
+		    MAX_PATH_LEN);
+		if (rc != EOK)
+			goto exit;
+
+		rc = async_data_read_start(exch, (void *) mtab_ent->opts,
+			MAX_MNTOPTS_LEN);
+		if (rc != EOK)
+			goto exit;
+
+		rc = async_data_read_start(exch, (void *) mtab_ent->fs_name,
+			FS_NAME_MAXLEN);
+		if (rc != EOK)
+			goto exit;
+
+		sysarg_t p[2];
+
+		rc = async_req_0_2(exch, VFS_IN_PING, &p[0], &p[1]);
+		if (rc != EOK)
+			goto exit;
+
+		mtab_ent->instance = p[0];
+		mtab_ent->service_id = p[1];
+
+		link_initialize(&mtab_ent->link);
+		list_append(&mtab_ent->link, mtab_list);
+	}
+
+exit:
+	async_wait_for(req, &rc);
+	vfs_exchange_end(exch);
+	return rc;
+}
+
 /** @}
  */
Index: uspace/lib/c/include/adt/hash_set.h
===================================================================
--- uspace/lib/c/include/adt/hash_set.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/c/include/adt/hash_set.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2006 Jakub Jermar
+ * 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.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_HASH_SET_H_
+#define LIBC_HASH_SET_H_
+
+#include <adt/list.h>
+#include <unistd.h>
+
+#define HASH_SET_MIN_SIZE  8
+
+typedef unsigned long (*hash_set_hash)(const link_t *);
+typedef int (*hash_set_equals)(const link_t *, const link_t *);
+
+/** Hash table structure. */
+typedef struct {
+	list_t *table;
+	
+	/** Current table size */
+	size_t size;
+	
+	/**
+	 * Current number of entries. If count > size,
+	 * the table is rehashed into table with double
+	 * size. If (4 * count < size) && (size > min_size),
+	 * the table is rehashed into table with half the size.
+	 */
+	size_t count;
+	
+	/** Hash function */
+	hash_set_hash hash;
+	
+	/** Hash table item equals function */
+	hash_set_equals equals;
+} hash_set_t;
+
+extern int hash_set_init(hash_set_t *, hash_set_hash, hash_set_equals, size_t);
+extern int hash_set_insert(hash_set_t *, link_t *);
+extern link_t *hash_set_find(hash_set_t *, const link_t *);
+extern int hash_set_contains(const hash_set_t *, const link_t *);
+extern size_t hash_set_count(const hash_set_t *);
+extern link_t *hash_set_remove(hash_set_t *, const link_t *);
+extern void hash_set_remove_selected(hash_set_t *,
+    int (*)(link_t *, void *), void *);
+extern void hash_set_destroy(hash_set_t *);
+extern void hash_set_apply(hash_set_t *, void (*)(link_t *, void *), void *);
+extern void hash_set_clear(hash_set_t *, void (*)(link_t *, void *), void *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/adt/hash_table.h
===================================================================
--- uspace/lib/c/include/adt/hash_table.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/adt/hash_table.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -86,4 +86,5 @@
 extern bool hash_table_create(hash_table_t *, hash_count_t, hash_count_t,
     hash_table_operations_t *);
+extern void hash_table_clear(hash_table_t *);
 extern void hash_table_insert(hash_table_t *, unsigned long [], link_t *);
 extern link_t *hash_table_find(hash_table_t *, unsigned long []);
Index: uspace/lib/c/include/ddi.h
===================================================================
--- uspace/lib/c/include/ddi.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/ddi.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -41,5 +41,5 @@
 
 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 iospace_enable(task_id_t, void *, unsigned long);
 extern int pio_enable(void *, size_t, void **);
Index: uspace/lib/c/include/device/hw_res_parsed.h
===================================================================
--- uspace/lib/c/include/device/hw_res_parsed.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/c/include/device/hw_res_parsed.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,134 @@
+/*
+ * 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_HW_RES_PARSED_H_
+#define LIBC_DEVICE_HW_RES_PARSED_H_
+
+#include <device/hw_res.h>
+#include <str.h>
+
+/** Keep areas of the zero size in the list */
+#define HW_RES_KEEP_ZERO_AREA  0x1
+
+/** Keep duplicit entries */
+#define HW_RES_KEEP_DUPLICIT   0x2
+
+/** Address range structure */
+typedef struct addr_range {
+	/** Start address */
+	uint64_t address;
+	
+	/** Endianness */
+	endianness_t endianness;
+	
+	/** Area size */
+	size_t size;
+} addr_range_t;
+
+/** IO range type */
+typedef addr_range_t io_range_t;
+
+/** Memory range type */
+typedef addr_range_t mem_range_t;
+
+/** List of IRQs */
+typedef struct irq_list {
+	/** Irq count */
+	size_t count;
+	
+	/** Array of IRQs */
+	int *irqs;
+} irq_list_t;
+
+/** List of memory areas */
+typedef struct addr_range_list {
+	/** Areas count */
+	size_t count;
+	
+	/** Array of areas */
+	addr_range_t *ranges;
+} addr_range_list_t;
+
+/** List of IO mapped areas */
+typedef addr_range_list_t io_range_list_t;
+
+/** Memory range type */
+typedef addr_range_list_t mem_range_list_t;
+
+/** HW resources parsed according to resource type */
+typedef struct hw_resource_list_parsed {
+	/** List of IRQs */
+	irq_list_t irqs;
+	
+	/** List of memory areas */
+	mem_range_list_t mem_ranges;
+	
+	/** List of IO areas */
+	io_range_list_t io_ranges;
+} hw_res_list_parsed_t;
+
+/** Clean hw_resource_list_parsed_t structure
+ *
+ * All allocated memory will be released, data amd pointers set to 0.
+ *
+ * @param list The structure to clear
+ */
+static inline void hw_res_list_parsed_clean(hw_res_list_parsed_t *list)
+{
+	if (list == NULL)
+		return;
+	
+	free(list->irqs.irqs);
+	free(list->io_ranges.ranges);
+	free(list->mem_ranges.ranges);
+	
+	bzero(list, sizeof(hw_res_list_parsed_t));
+}
+
+/** Initialize the hw_resource_list_parsed_t structure
+ *
+ *  @param list The structure to initialize
+ */
+static inline void hw_res_list_parsed_init(hw_res_list_parsed_t *list)
+{
+	bzero(list, sizeof(hw_res_list_parsed_t));
+}
+
+extern int hw_res_list_parse(hw_resource_list_t *, hw_res_list_parsed_t *, int);
+extern int hw_res_get_list_parsed(async_sess_t *, hw_res_list_parsed_t *, int);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/device/nic.h
===================================================================
--- uspace/lib/c/include/device/nic.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/c/include/device/nic.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+ /** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_DEVICE_NIC_H_
+#define LIBC_DEVICE_NIC_H_
+
+#include <async.h>
+#include <net/device.h>
+#include <net/packet.h>
+#include <ipc/services.h>
+
+typedef enum {
+	NIC_SEND_MESSAGE = 0,
+	NIC_CONNECT_TO_NIL,
+	NIC_GET_STATE,
+	NIC_SET_STATE,
+	NIC_GET_ADDRESS,
+	NIC_SET_ADDRESS,
+	NIC_GET_STATS,
+	NIC_GET_DEVICE_INFO,
+	NIC_GET_CABLE_STATE,
+	NIC_GET_OPERATION_MODE,
+	NIC_SET_OPERATION_MODE,
+	NIC_AUTONEG_ENABLE,
+	NIC_AUTONEG_DISABLE,
+	NIC_AUTONEG_PROBE,
+	NIC_AUTONEG_RESTART,
+	NIC_GET_PAUSE,
+	NIC_SET_PAUSE,
+	NIC_UNICAST_GET_MODE,
+	NIC_UNICAST_SET_MODE,
+	NIC_MULTICAST_GET_MODE,
+	NIC_MULTICAST_SET_MODE,
+	NIC_BROADCAST_GET_MODE,
+	NIC_BROADCAST_SET_MODE,
+	NIC_DEFECTIVE_GET_MODE,
+	NIC_DEFECTIVE_SET_MODE,
+	NIC_BLOCKED_SOURCES_GET,
+	NIC_BLOCKED_SOURCES_SET,
+	NIC_VLAN_GET_MASK,
+	NIC_VLAN_SET_MASK,
+	NIC_VLAN_SET_TAG,
+	NIC_WOL_VIRTUE_ADD,
+	NIC_WOL_VIRTUE_REMOVE,
+	NIC_WOL_VIRTUE_PROBE,
+	NIC_WOL_VIRTUE_LIST,
+	NIC_WOL_VIRTUE_GET_CAPS,
+	NIC_WOL_LOAD_INFO,
+	NIC_OFFLOAD_PROBE,
+	NIC_OFFLOAD_SET,
+	NIC_POLL_GET_MODE,
+	NIC_POLL_SET_MODE,
+	NIC_POLL_NOW
+} nic_funcs_t;
+
+extern int nic_send_message(async_sess_t *, packet_id_t);
+extern int nic_connect_to_nil(async_sess_t *, services_t, nic_device_id_t);
+extern int nic_get_state(async_sess_t *, nic_device_state_t *);
+extern int nic_set_state(async_sess_t *, nic_device_state_t);
+extern int nic_get_address(async_sess_t *, nic_address_t *);
+extern int nic_set_address(async_sess_t *, const nic_address_t *);
+extern int nic_get_stats(async_sess_t *, nic_device_stats_t *);
+extern int nic_get_device_info(async_sess_t *, nic_device_info_t *);
+extern int nic_get_cable_state(async_sess_t *, nic_cable_state_t *);
+
+extern int nic_get_operation_mode(async_sess_t *, int *, nic_channel_mode_t *,
+    nic_role_t *);
+extern int nic_set_operation_mode(async_sess_t *, int, nic_channel_mode_t,
+    nic_role_t);
+extern int nic_autoneg_enable(async_sess_t *, uint32_t);
+extern int nic_autoneg_disable(async_sess_t *);
+extern int nic_autoneg_probe(async_sess_t *, uint32_t *, uint32_t *,
+    nic_result_t *, nic_result_t *);
+extern int nic_autoneg_restart(async_sess_t *);
+extern int nic_get_pause(async_sess_t *, nic_result_t *, nic_result_t *,
+    uint16_t *);
+extern int nic_set_pause(async_sess_t *, int, int, uint16_t);
+
+extern int nic_unicast_get_mode(async_sess_t *, nic_unicast_mode_t *, size_t,
+    nic_address_t *, size_t *);
+extern int nic_unicast_set_mode(async_sess_t *, nic_unicast_mode_t,
+    const nic_address_t *, size_t);
+extern int nic_multicast_get_mode(async_sess_t *, nic_multicast_mode_t *,
+    size_t, nic_address_t *, size_t *);
+extern int nic_multicast_set_mode(async_sess_t *, nic_multicast_mode_t,
+    const nic_address_t *, size_t);
+extern int nic_broadcast_get_mode(async_sess_t *, nic_broadcast_mode_t *);
+extern int nic_broadcast_set_mode(async_sess_t *, nic_broadcast_mode_t);
+extern int nic_defective_get_mode(async_sess_t *, uint32_t *);
+extern int nic_defective_set_mode(async_sess_t *, uint32_t);
+extern int nic_blocked_sources_get(async_sess_t *, size_t, nic_address_t *,
+    size_t *);
+extern int nic_blocked_sources_set(async_sess_t *, const nic_address_t *,
+    size_t);
+
+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_wol_virtue_add(async_sess_t *, nic_wv_type_t, const void *,
+    size_t, nic_wv_id_t *);
+extern int nic_wol_virtue_remove(async_sess_t *, nic_wv_id_t);
+extern int nic_wol_virtue_probe(async_sess_t *, nic_wv_id_t, nic_wv_type_t *,
+    size_t, void *, size_t *);
+extern int nic_wol_virtue_list(async_sess_t *, nic_wv_type_t, size_t,
+    nic_wv_id_t *, size_t *);
+extern int nic_wol_virtue_get_caps(async_sess_t *, nic_wv_type_t, int *);
+extern int nic_wol_load_info(async_sess_t *, nic_wv_type_t *, size_t, uint8_t *,
+    size_t *);
+
+extern int nic_offload_probe(async_sess_t *, uint32_t *, uint32_t *);
+extern int nic_offload_set(async_sess_t *, uint32_t, uint32_t);
+
+extern int nic_poll_get_mode(async_sess_t *, nic_poll_mode_t *,
+    struct timeval *);
+extern int nic_poll_set_mode(async_sess_t *, nic_poll_mode_t,
+    const struct timeval *);
+extern int nic_poll_now(async_sess_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -36,6 +36,10 @@
 typedef enum {
 	HW_RES_DEV_IFACE = 0,
+	/** Character device interface */
 	CHAR_DEV_IFACE,
-
+	
+	/** Network interface controller interface */
+	NIC_DEV_IFACE,
+	
 	/** Interface provided by any PCI device. */
 	PCI_DEV_IFACE,
Index: uspace/lib/c/include/ipc/devman.h
===================================================================
--- uspace/lib/c/include/ipc/devman.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/ipc/devman.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -146,4 +146,5 @@
 typedef enum {
 	DRIVER_DEV_ADD = IPC_FIRST_USER_METHOD,
+	DRIVER_DEV_ADDED,
 	DRIVER_DEV_REMOVE,
 	DRIVER_DEV_GONE,
Index: uspace/lib/c/include/ipc/il.h
===================================================================
--- uspace/lib/c/include/ipc/il.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/ipc/il.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -54,4 +54,10 @@
 	NET_IL_MTU_CHANGED,
 	
+	/**
+	 * Device address changed message
+	 * @see il_addr_changed_msg()
+	 */
+	NET_IL_ADDR_CHANGED,
+
 	/** Packet received message.
 	 * @see il_received_msg()
Index: uspace/lib/c/include/ipc/net.h
===================================================================
--- uspace/lib/c/include/ipc/net.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/ipc/net.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -277,5 +277,5 @@
  *
  */
-#define IPC_GET_DEVICE(call)  ((device_id_t) IPC_GET_ARG1(call))
+#define IPC_GET_DEVICE(call)  ((nic_device_id_t) IPC_GET_ARG1(call))
 
 /** Return the packet identifier message argument.
@@ -298,5 +298,33 @@
  *
  */
-#define IPC_GET_STATE(call)  ((device_state_t) IPC_GET_ARG2(call))
+#define IPC_GET_STATE(call)  ((nic_device_state_t) IPC_GET_ARG2(call))
+
+/** Return the device handle argument
+ *
+ * @param[in] call Message call structure
+ *
+ */
+#define IPC_GET_DEVICE_HANDLE(call) ((devman_handle_t) IPC_GET_ARG2(call))
+
+/** Return the device driver service message argument.
+ *
+ * @param[in] call Message call structure.
+ *
+ */
+#define IPC_GET_SERVICE(call)  ((services_t) IPC_GET_ARG3(call))
+
+/** Return the target service message argument.
+ *
+ * @param[in] call Message call structure.
+ *
+ */
+#define IPC_GET_TARGET(call)  ((services_t) IPC_GET_ARG3(call))
+
+/** Return the sender service message argument.
+ *
+ * @param[in] call Message call structure.
+ *
+ */
+#define IPC_GET_SENDER(call)  ((services_t) IPC_GET_ARG3(call))
 
 /** Return the maximum transmission unit message argument.
@@ -305,26 +333,5 @@
  *
  */
-#define IPC_GET_MTU(call)  ((size_t) IPC_GET_ARG2(call))
-
-/** Return the device driver service message argument.
- *
- * @param[in] call Message call structure.
- *
- */
-#define IPC_GET_SERVICE(call)  ((services_t) IPC_GET_ARG3(call))
-
-/** Return the target service message argument.
- *
- * @param[in] call Message call structure.
- *
- */
-#define IPC_GET_TARGET(call)  ((services_t) IPC_GET_ARG3(call))
-
-/** Return the sender service message argument.
- *
- * @param[in] call Message call structure.
- *
- */
-#define IPC_GET_SENDER(call)  ((services_t) IPC_GET_ARG3(call))
+#define IPC_GET_MTU(call)  ((size_t) IPC_GET_ARG3(call))
 
 /** Return the error service message argument.
Index: uspace/lib/c/include/ipc/net_net.h
===================================================================
--- uspace/lib/c/include/ipc/net_net.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/ipc/net_net.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -43,14 +43,18 @@
 /** Networking subsystem central module messages. */
 typedef enum {
-	/** Returns the general configuration
+	/** Return general configuration
 	 * @see net_get_conf_req()
 	 */
 	NET_NET_GET_CONF = NET_FIRST,
-	/** Returns the device specific configuration
+	/** Return device specific configuration
 	 * @see net_get_device_conf_req()
 	 */
 	NET_NET_GET_DEVICE_CONF,
-	/** Starts the networking stack. */
-	NET_NET_STARTUP,
+	/** Return number of mastered devices */
+	NET_NET_GET_DEVICES_COUNT,
+	/** Return names and device IDs of all devices */
+	NET_NET_GET_DEVICES,
+	/** Notify the networking service about a ready device */
+	NET_NET_DRIVER_READY
 } net_messages;
 
Index: uspace/lib/c/include/ipc/nil.h
===================================================================
--- uspace/lib/c/include/ipc/nil.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/ipc/nil.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -70,4 +70,8 @@
 	 */
 	NET_NIL_BROADCAST_ADDR,
+	/** Device has changed address
+	 * @see nil_addr_changed_msg()
+	 */
+	NET_NIL_ADDR_CHANGED
 } nil_messages;
 
Index: uspace/lib/c/include/ipc/services.h
===================================================================
--- uspace/lib/c/include/ipc/services.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/ipc/services.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -49,6 +49,4 @@
 	SERVICE_CLIPBOARD  = FOURCC('c', 'l', 'i', 'p'),
 	SERVICE_NETWORKING = FOURCC('n', 'e', 't', ' '),
-	SERVICE_LO         = FOURCC('l', 'o', ' ', ' '),
-	SERVICE_NE2000     = FOURCC('n', 'e', '2', 'k'),
 	SERVICE_ETHERNET   = FOURCC('e', 't', 'h', ' '),
 	SERVICE_NILDUMMY   = FOURCC('n', 'i', 'l', 'd'),
Index: uspace/lib/c/include/ipc/vfs.h
===================================================================
--- uspace/lib/c/include/ipc/vfs.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/ipc/vfs.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -42,4 +42,5 @@
 #define FS_NAME_MAXLEN  20
 #define MAX_PATH_LEN    (64 * 1024)
+#define MAX_MNTOPTS_LEN 256
 #define PLB_SIZE        (2 * MAX_PATH_LEN)
 
@@ -56,4 +57,5 @@
 	/** Unique identifier of the fs. */
 	char name[FS_NAME_MAXLEN + 1];
+	unsigned int instance;
 	bool concurrent_read_write;
 	bool write_retains_size;
@@ -79,4 +81,5 @@
 	VFS_IN_DUP,
 	VFS_IN_WAIT_HANDLE,
+	VFS_IN_MTAB_GET,
 } vfs_in_request_t;
 
Index: uspace/lib/c/include/net/device.h
===================================================================
--- uspace/lib/c/include/net/device.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/net/device.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Radim Vansa
  * All rights reserved.
  *
@@ -39,44 +40,134 @@
 
 #include <adt/int_map.h>
+#include <net/eth_phys.h>
+#include <bool.h>
+
+/** Ethernet address length. */
+#define ETH_ADDR  6
+
+/** MAC printing format */
+#define PRIMAC  "%02x:%02x:%02x:%02x:%02x:%02x"
+
+/** MAC arguments */
+#define ARGSMAC(__a) \
+	(__a)[0], (__a)[1], (__a)[2], (__a)[3], (__a)[4], (__a)[5]
+
+/* Compare MAC address with specific value */
+#define MAC_EQUALS_VALUE(__a, __a0, __a1, __a2, __a3, __a4, __a5) \
+	((__a)[0] == (__a0) && (__a)[1] == (__a1) && (__a)[2] == (__a2) \
+	&& (__a)[3] == (__a3) && (__a)[4] == (__a4) && (__a)[5] == (__a5))
+
+#define MAC_IS_ZERO(__x) \
+	MAC_EQUALS_VALUE(__x, 0, 0, 0, 0, 0, 0)
 
 /** Device identifier to generic type map declaration. */
-#define DEVICE_MAP_DECLARE	INT_MAP_DECLARE
+#define DEVICE_MAP_DECLARE  INT_MAP_DECLARE
 
 /** Device identifier to generic type map implementation. */
-#define DEVICE_MAP_IMPLEMENT	INT_MAP_IMPLEMENT
+#define DEVICE_MAP_IMPLEMENT  INT_MAP_IMPLEMENT
+
+/** Max length of any hw nic address (currently only eth) */
+#define NIC_MAX_ADDRESS_LENGTH  16
 
 /** Invalid device identifier. */
-#define DEVICE_INVALID_ID	(-1)
+#define NIC_DEVICE_INVALID_ID  (-1)
+
+#define NIC_VENDOR_MAX_LENGTH         64
+#define NIC_MODEL_MAX_LENGTH          64
+#define NIC_PART_NUMBER_MAX_LENGTH    64
+#define NIC_SERIAL_NUMBER_MAX_LENGTH  64
+
+/**
+ * The bitmap uses single bit for each of the 2^12 = 4096 possible VLAN tags.
+ * This means its size is 4096/8 = 512 bytes.
+ */
+#define NIC_VLAN_BITMAP_SIZE  512
+
+#define NIC_DEVICE_PRINT_FMT  "%x"
 
 /** Device identifier type. */
-typedef int device_id_t;
-
-/** Device state type. */
-typedef enum device_state device_state_t;
-
-/** Type definition of the device usage statistics.
- * @see device_stats
- */
-typedef struct device_stats device_stats_t;
+typedef int nic_device_id_t;
+
+/**
+ * Structure covering the MAC address.
+ */
+typedef struct nic_address {
+	uint8_t address[ETH_ADDR];
+} nic_address_t;
 
 /** Device state. */
-enum device_state {
-	/** Device not present or not initialized. */
-	NETIF_NULL = 0,
-	/** Device present and stopped. */
-	NETIF_STOPPED,
-	/** Device present and active. */
-	NETIF_ACTIVE,
-	/** Device present but unable to transmit. */
-	NETIF_CARRIER_LOST
-};
+typedef enum nic_device_state {
+	/**
+	 * Device present and stopped. Moving device to this state means to discard
+	 * all settings and WOL virtues, rebooting the NIC to state as if the
+	 * computer just booted (or the NIC was just inserted in case of removable
+	 * NIC).
+	 */
+	NIC_STATE_STOPPED,
+	/**
+	 * If the NIC is in this state no packets (frames) are transmitted nor
+	 * received. However, the settings are not restarted. You can use this state
+	 * to temporarily disable transmition/reception or atomically (with respect
+	 * to incoming/outcoming packets) change frames acceptance etc.
+	 */
+	NIC_STATE_DOWN,
+	/** Device is normally operating. */
+	NIC_STATE_ACTIVE,
+	/** Just a constant to limit the state numbers */
+	NIC_STATE_MAX,
+} nic_device_state_t;
+
+/**
+ * Channel operating mode used on the medium.
+ */
+typedef enum {
+	NIC_CM_UNKNOWN,
+	NIC_CM_FULL_DUPLEX,
+	NIC_CM_HALF_DUPLEX,
+	NIC_CM_SIMPLEX
+} nic_channel_mode_t;
+
+/**
+ * Role for the device (used e.g. for 1000Gb ethernet)
+ */
+typedef enum {
+	NIC_ROLE_UNKNOWN,
+	NIC_ROLE_AUTO,
+	NIC_ROLE_MASTER,
+	NIC_ROLE_SLAVE
+} nic_role_t;
+
+/**
+ * Current state of the cable in the device
+ */
+typedef enum {
+	NIC_CS_UNKNOWN,
+	NIC_CS_PLUGGED,
+	NIC_CS_UNPLUGGED
+} nic_cable_state_t;
+
+/**
+ * Result of the requested operation
+ */
+typedef enum {
+	/** Successfully disabled */
+	NIC_RESULT_DISABLED,
+	/** Successfully enabled */
+	NIC_RESULT_ENABLED,
+	/** Not supported at all */
+	NIC_RESULT_NOT_SUPPORTED,
+	/** Temporarily not available */
+	NIC_RESULT_NOT_AVAILABLE,
+	/** Result extensions */
+	NIC_RESULT_FIRST_EXTENSION
+} nic_result_t;
 
 /** Device usage statistics. */
-struct device_stats {
-	/** Total packets received. */
+typedef struct nic_device_stats {
+	/** Total packets received (accepted). */
 	unsigned long receive_packets;
 	/** Total packets transmitted. */
 	unsigned long send_packets;
-	/** Total bytes received. */
+	/** Total bytes received (accepted). */
 	unsigned long receive_bytes;
 	/** Total bytes transmitted. */
@@ -86,12 +177,20 @@
 	/** Packet transmition problems counter. */
 	unsigned long send_errors;
-	/** No space in buffers counter. */
+	/** Number of frames dropped due to insufficient space in RX buffers */
 	unsigned long receive_dropped;
-	/** No space available counter. */
+	/** Number of frames dropped due to insufficient space in TX buffers */
 	unsigned long send_dropped;
-	/** Total multicast packets received. */
-	unsigned long multicast;
+	/** Total multicast packets received (accepted). */
+	unsigned long receive_multicast;
+	/** Total broadcast packets received (accepted). */
+	unsigned long receive_broadcast;
 	/** The number of collisions due to congestion on the medium. */
 	unsigned long collisions;
+	/** Unicast packets received but not accepted (filtered) */
+	unsigned long receive_filtered_unicast;
+	/** Multicast packets received but not accepted (filtered) */
+	unsigned long receive_filtered_multicast;
+	/** Broadcast packets received but not accepted (filtered) */
+	unsigned long receive_filtered_broadcast;
 
 	/* detailed receive_errors */
@@ -129,5 +228,250 @@
 	/** Total compressed packet transmitted. */
 	unsigned long send_compressed;
-};
+} nic_device_stats_t;
+
+/** Errors corresponding to those in the nic_device_stats_t */
+typedef enum {
+	NIC_SEC_BUFFER_FULL,
+	NIC_SEC_ABORTED,
+	NIC_SEC_CARRIER_LOST,
+	NIC_SEC_FIFO_OVERRUN,
+	NIC_SEC_HEARTBEAT,
+	NIC_SEC_WINDOW_ERROR,
+	/* Error encountered during TX but with other type of error */
+	NIC_SEC_OTHER
+} nic_send_error_cause_t;
+
+/** Errors corresponding to those in the nic_device_stats_t */
+typedef enum {
+	NIC_REC_BUFFER_FULL,
+	NIC_REC_LENGTH,
+	NIC_REC_BUFFER_OVERFLOW,
+	NIC_REC_CRC,
+	NIC_REC_FRAME_ALIGNMENT,
+	NIC_REC_FIFO_OVERRUN,
+	NIC_REC_MISSED,
+	/* Error encountered during RX but with other type of error */
+	NIC_REC_OTHER
+} nic_receive_error_cause_t;
+
+/**
+ * Information about the NIC that never changes - name, vendor, model,
+ * capabilites and so on.
+ */
+typedef struct nic_device_info {
+	/* Device identification */
+	char vendor_name[NIC_VENDOR_MAX_LENGTH];
+	char model_name[NIC_MODEL_MAX_LENGTH];
+	char part_number[NIC_PART_NUMBER_MAX_LENGTH];
+	char serial_number[NIC_SERIAL_NUMBER_MAX_LENGTH];
+	uint16_t vendor_id;
+	uint16_t device_id;
+	uint16_t subsystem_vendor_id;
+	uint16_t subsystem_id;
+	/* Device capabilities */
+	uint16_t ethernet_support[ETH_PHYS_LAYERS];
+
+	/** The mask of all modes which the device can advertise
+	 *
+	 *  see ETH_AUTONEG_ macros in net/eth_phys.h of libc
+	 */
+	uint32_t autoneg_support;
+} nic_device_info_t;
+
+/**
+ * Type of the ethernet frame
+ */
+typedef enum nic_frame_type {
+	NIC_FRAME_UNICAST,
+	NIC_FRAME_MULTICAST,
+	NIC_FRAME_BROADCAST
+} nic_frame_type_t;
+
+/**
+ * Specifies which unicast frames is the NIC receiving.
+ */
+typedef enum nic_unicast_mode {
+	NIC_UNICAST_UNKNOWN,
+	/** No unicast frames are received */
+	NIC_UNICAST_BLOCKED,
+	/** Only the frames with this NIC's MAC as destination are received */
+	NIC_UNICAST_DEFAULT,
+	/**
+	 * Both frames with this NIC's MAC and those specified in the list are
+	 * received
+	 */
+	NIC_UNICAST_LIST,
+	/** All unicast frames are received */
+	NIC_UNICAST_PROMISC
+} nic_unicast_mode_t;
+
+typedef enum nic_multicast_mode {
+	NIC_MULTICAST_UNKNOWN,
+	/** No multicast frames are received */
+	NIC_MULTICAST_BLOCKED,
+	/** Frames with multicast addresses specified in this list are received */
+	NIC_MULTICAST_LIST,
+	/** All multicast frames are received */
+	NIC_MULTICAST_PROMISC
+} nic_multicast_mode_t;
+
+typedef enum nic_broadcast_mode {
+	NIC_BROADCAST_UNKNOWN,
+	/** Broadcast frames are dropped */
+	NIC_BROADCAST_BLOCKED,
+	/** Broadcast frames are received */
+	NIC_BROADCAST_ACCEPTED
+} nic_broadcast_mode_t;
+
+/**
+ * Structure covering the bitmap with VLAN tags.
+ */
+typedef struct nic_vlan_mask {
+	uint8_t bitmap[NIC_VLAN_BITMAP_SIZE];
+} nic_vlan_mask_t;
+
+/* WOL virtue identifier */
+typedef unsigned int nic_wv_id_t;
+
+/**
+ * Structure passed as argument for virtue NIC_WV_MAGIC_PACKET.
+ */
+typedef struct nic_wv_magic_packet_data {
+	uint8_t password[6];
+} nic_wv_magic_packet_data_t;
+
+/**
+ * Structure passed as argument for virtue NIC_WV_DIRECTED_IPV4
+ */
+typedef struct nic_wv_ipv4_data {
+	uint8_t address[4];
+} nic_wv_ipv4_data_t;
+
+/**
+ * Structure passed as argument for virtue NIC_WV_DIRECTED_IPV6
+ */
+typedef struct nic_wv_ipv6_data {
+	uint8_t address[16];
+} nic_wv_ipv6_data_t;
+
+/**
+ * WOL virtue types defining the interpretation of data passed to the virtue.
+ * Those tagged with S can have only single virtue active at one moment, those
+ * tagged with M can have multiple ones.
+ */
+typedef enum nic_wv_type {
+	/**
+	 * Used for deletion of the virtue - in this case the mask, data and length
+	 * arguments are ignored.
+	 */
+	NIC_WV_NONE,
+	/** S
+	 * Enabled <=> wakeup upon link change
+	 */
+	NIC_WV_LINK_CHANGE,
+	/** S
+	 * If this virtue is set up, wakeup can be issued by a magic packet frame.
+	 * If the data argument is not NULL, it must contain
+	 * nic_wv_magic_packet_data structure with the SecureOn password.
+	 */
+	NIC_WV_MAGIC_PACKET,
+	/** M
+	 * If the virtue is set up, wakeup can be issued by a frame targeted to
+	 * device with MAC address specified in data. The data must contain
+	 * nic_address_t structure.
+	 */
+	NIC_WV_DESTINATION,
+	/** S
+	 * Enabled <=> wakeup upon receiving broadcast frame
+	 */
+	NIC_WV_BROADCAST,
+	/** S
+	 * Enabled <=> wakeup upon receiving ARP Request
+	 */
+	NIC_WV_ARP_REQUEST,
+	/** M
+	 * If enabled, the wakeup is issued upon receiving frame with an IPv4 packet
+	 * with IPv4 address specified in data. The data must contain
+	 * nic_wv_ipv4_data structure.
+	 */
+	NIC_WV_DIRECTED_IPV4,
+	/** M
+	 * If enabled, the wakeup is issued upon receiving frame with an IPv4 packet
+	 * with IPv6 address specified in data. The data must contain
+	 * nic_wv_ipv6_data structure.
+	 */
+	NIC_WV_DIRECTED_IPV6,
+	/** M
+	 * First length/2 bytes in the argument are interpreted as mask, second
+	 * length/2 bytes are interpreted as content.
+	 * If enabled, the wakeup is issued upon receiving frame where the bytes
+	 * with non-zero value in the mask equal to those in the content.
+	 */
+	NIC_WV_FULL_MATCH,
+	/**
+	 * Dummy value, do not use.
+	 */
+	NIC_WV_MAX
+} nic_wv_type_t;
+
+/**
+ * Specifies the interrupt/polling mode used by the driver and NIC
+ */
+typedef enum nic_poll_mode {
+	/**
+	 * NIC issues interrupts upon events.
+	 */
+	NIC_POLL_IMMEDIATE,
+	/**
+	 * Some uspace app calls nic_poll_now(...) in order to check the NIC state
+	 * - no interrupts are received from the NIC.
+	 */
+	NIC_POLL_ON_DEMAND,
+	/**
+	 * The driver itself issues a poll request in a periodic manner. It is
+	 * allowed to use hardware timer if the NIC supports it.
+	 */
+	NIC_POLL_PERIODIC,
+	/**
+	 * The driver itself issued a poll request in a periodic manner. The driver
+	 * must create software timer, internal hardware timer of NIC must not be
+	 * used even if the NIC supports it.
+	 */
+	NIC_POLL_SOFTWARE_PERIODIC
+} nic_poll_mode_t;
+
+/**
+ * Says if this virtue type is a multi-virtue (there can be multiple virtues of
+ * this type at once).
+ *
+ * @param type
+ *
+ * @return true or false
+ */
+static inline int nic_wv_is_multi(nic_wv_type_t type) {
+	switch (type) {
+	case NIC_WV_FULL_MATCH:
+	case NIC_WV_DESTINATION:
+	case NIC_WV_DIRECTED_IPV4:
+	case NIC_WV_DIRECTED_IPV6:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static inline const char *nic_device_state_to_string(nic_device_state_t state)
+{
+	switch (state) {
+	case NIC_STATE_STOPPED:
+		return "stopped";
+	case NIC_STATE_DOWN:
+		return "down";
+	case NIC_STATE_ACTIVE:
+		return "active";
+	default:
+		return "undefined";
+	}
+}
 
 #endif
Index: uspace/lib/c/include/net/eth_phys.h
===================================================================
--- uspace/lib/c/include/net/eth_phys.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/c/include/net/eth_phys.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 LIBC_NET_ETH_PHYS_H_
+#define LIBC_NET_ETH_PHYS_H_
+
+#include <sys/types.h>
+
+/*****************************************************/
+/* Definitions of possible supported physical layers */
+/*****************************************************/
+
+/* Ethernet physical layers */
+#define ETH_OLD          0
+#define ETH_10M          1
+#define ETH_100M         2
+#define ETH_1000M        3
+#define ETH_10G          4
+#define ETH_40G_100G     5
+/* 6, 7 reserved for future use */
+#define ETH_PHYS_LAYERS  8
+
+/* < 10Mbs ethernets */
+#define ETH_EXPERIMENTAL     0x0001
+#define ETH_1BASE5           0x0002
+/* 10Mbs ethernets */
+#define ETH_10BASE5          0x0001
+#define ETH_10BASE2          0x0002
+#define ETH_10BROAD36        0x0004
+#define ETH_STARLAN_10       0x0008
+#define ETH_LATTISNET        0x0010
+#define ETH_10BASE_T         0x0020
+#define ETH_FOIRL            0x0040
+#define ETH_10BASE_FL        0x0080
+#define ETH_10BASE_FB        0x0100
+#define ETH_10BASE_FP        0x0200
+/* 100Mbs (fast) ethernets */
+#define ETH_100BASE_TX       0x0001
+#define ETH_100BASE_T4       0x0002
+#define ETH_100BASE_T2       0x0004
+#define ETH_100BASE_FX       0x0008
+#define ETH_100BASE_SX       0x0010
+#define ETH_100BASE_BX10     0x0020
+#define ETH_100BASE_LX10     0x0040
+#define ETH_100BASE_VG       0x0080
+/* 1000Mbs (gigabit) ethernets */
+#define ETH_1000BASE_T       0x0001
+#define ETH_1000BASE_TX      0x0002
+#define ETH_1000BASE_SX      0x0004
+#define ETH_1000BASE_LX      0x0008
+#define ETH_1000BASE_LH      0x0010
+#define ETH_1000BASE_CX      0x0020
+#define ETH_1000BASE_BX10    0x0040
+#define ETH_1000BASE_LX10    0x0080
+#define ETH_1000BASE_PX10_D  0x0100
+#define ETH_1000BASE_PX10_U  0x0200
+#define ETH_1000BASE_PX20_D  0x0400
+#define ETH_1000BASE_PX20_U  0x0800
+#define ETH_1000BASE_ZX      0x1000
+#define ETH_1000BASE_KX      0x2000
+/* 10Gbs ethernets */
+#define ETH_10GBASE_SR       0x0001
+#define ETH_10GBASE_LX4      0x0002
+#define ETH_10GBASE_LR       0x0004
+#define ETH_10GBASE_ER       0x0008
+#define ETH_10GBASE_SW       0x0010
+#define ETH_10GBASE_LW       0x0020
+#define ETH_10GBASE_EW       0x0040
+#define ETH_10GBASE_CX4      0x0080
+#define ETH_10GBASE_T        0x0100
+#define ETH_10GBASE_LRM      0x0200
+#define ETH_10GBASE_KX4      0x0400
+#define ETH_10GBASE_KR       0x0800
+/* 40Gbs and 100Gbs ethernets */
+#define ETH_40GBASE_SR4      0x0001
+#define ETH_40GBASE_LR4      0x0002
+#define ETH_40GBASE_CR4      0x0004
+#define ETH_40GBASE_KR4      0x0008
+#define ETH_100GBASE_SR10    0x0010
+#define ETH_100GBASE_LR4     0x0020
+#define ETH_100GBASE_ER4     0x0040
+#define ETH_100GBASE_CR10    0x0080
+
+/******************************************/
+/* Auto-negotiation advertisement options */
+/******************************************/
+
+#define ETH_AUTONEG_10BASE_T_HALF    UINT32_C(0x00000001)
+#define ETH_AUTONEG_10BASE_T_FULL    UINT32_C(0x00000002)
+#define ETH_AUTONEG_100BASE_TX_HALF  UINT32_C(0x00000004)
+#define ETH_AUTONEG_100BASE_T4_HALF  UINT32_C(0x00000008)
+#define ETH_AUTONEG_100BASE_T2_HALF  UINT32_C(0x00000010)
+#define ETH_AUTONEG_100BASE_TX_FULL  UINT32_C(0x00000020)
+#define ETH_AUTONEG_100BASE_T2_FULL  UINT32_C(0x00000040)
+#define ETH_AUTONEG_1000BASE_T_HALF  UINT32_C(0x00000080)
+#define ETH_AUTONEG_1000BASE_T_FULL  UINT32_C(0x00000100)
+
+/** Symetric pause packet (802.3x standard) */
+#define ETH_AUTONEG_PAUSE_SYMETRIC   UINT32_C(0x10000000)
+/** Asymetric pause packet (802.3z standard, gigabit ethernet) */
+#define ETH_AUTONEG_PAUSE_ASYMETRIC  UINT32_C(0x20000000)
+
+#define ETH_AUTONEG_MODE_MASK      UINT32_C(0x0FFFFFFF)
+#define ETH_AUTONEG_FEATURES_MASK  UINT32_C(~(ETH_AUTONEG_MODE_MASK))
+
+#define ETH_AUTONEG_MODES  9
+
+struct eth_autoneg_map {
+	uint32_t value;
+	const char *name;
+};
+
+extern const char *ethernet_names[8][17];
+extern const struct eth_autoneg_map ethernet_autoneg_mapping[ETH_AUTONEG_MODES];
+
+#endif
Index: uspace/lib/c/include/net/packet.h
===================================================================
--- uspace/lib/c/include/net/packet.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/net/packet.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -38,8 +38,10 @@
 #define LIBC_PACKET_H_
 
+#include <sys/types.h>
+
 /** Packet identifier type.
  * Value zero is used as an invalid identifier.
  */
-typedef int packet_id_t;
+typedef sysarg_t packet_id_t;
 
 /** Type definition of the packet.
@@ -51,5 +53,5 @@
  * @see packet_dimension
  */
-typedef struct packet_dimension	packet_dimension_t;
+typedef struct packet_dimension packet_dimension_t;
 
 /** Packet dimension. */
@@ -71,4 +73,5 @@
 extern packet_t *pm_find(packet_id_t);
 extern int pm_add(packet_t *);
+extern void pm_remove(packet_t *);
 extern int pm_init(void);
 extern void pm_destroy(void);
Index: uspace/lib/c/include/net/packet_header.h
===================================================================
--- uspace/lib/c/include/net/packet_header.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/net/packet_header.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -61,4 +61,7 @@
 #define PACKET_MAGIC_VALUE	0x11227788
 
+/** Maximum total length of the packet */
+#define PACKET_MAX_LENGTH  65536
+
 /** Packet header. */
 struct packet {
@@ -85,4 +88,10 @@
 	 */
 	size_t length;
+
+	/** Offload info provided by the NIC */
+	uint32_t offload_info;
+
+	/** Mask which bits in offload info are valid */
+	uint32_t offload_mask;
 
 	/** Stored source and destination addresses length. */
Index: uspace/lib/c/include/str.h
===================================================================
--- uspace/lib/c/include/str.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/str.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -91,4 +91,7 @@
 extern char *str_rchr(const char *str, wchar_t ch);
 
+extern void str_rtrim(char *str, wchar_t ch);
+extern void str_ltrim(char *str, wchar_t ch);
+
 extern bool wstr_linsert(wchar_t *str, wchar_t ch, size_t pos, size_t max_pos);
 extern bool wstr_remove(wchar_t *str, size_t pos);
Index: uspace/lib/c/include/vfs/vfs.h
===================================================================
--- uspace/lib/c/include/vfs/vfs.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/c/include/vfs/vfs.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -39,6 +39,8 @@
 #include <ipc/vfs.h>
 #include <ipc/loc.h>
+#include <adt/list.h>
 #include <stdio.h>
 #include <async.h>
+#include "vfs_mtab.h"
 
 enum vfs_change_state_type {
@@ -49,5 +51,5 @@
 
 extern int mount(const char *, const char *, const char *, const char *,
-    unsigned int);
+    unsigned int, unsigned int);
 extern int unmount(const char *);
 
@@ -55,4 +57,5 @@
 
 extern int fd_wait(void);
+extern int get_mtab_list(list_t *mtab_list);
 
 extern async_exch_t *vfs_exchange_begin(void);
Index: uspace/lib/c/include/vfs/vfs_mtab.h
===================================================================
--- uspace/lib/c/include/vfs/vfs_mtab.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/c/include/vfs/vfs_mtab.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Maurizio Lombardi
+ * 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_VFS_MTAB_H_
+#define LIBC_VFS_MTAB_H_
+
+#include <sys/types.h>
+#include <ipc/vfs.h>
+#include <adt/list.h>
+
+typedef struct mtab_ent {
+	link_t link;
+	char mp[MAX_PATH_LEN];
+	char opts[MAX_MNTOPTS_LEN];
+	char fs_name[FS_NAME_MAXLEN];
+	unsigned int instance;
+	service_id_t service_id;
+} mtab_ent_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/drv/Makefile
===================================================================
--- uspace/lib/drv/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/drv/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -39,4 +39,5 @@
 	generic/remote_hw_res.c \
 	generic/remote_char_dev.c \
+	generic/remote_nic.c \
 	generic/remote_usb.c \
 	generic/remote_pci.c \
Index: uspace/lib/drv/generic/dev_iface.c
===================================================================
--- uspace/lib/drv/generic/dev_iface.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/drv/generic/dev_iface.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -41,4 +41,5 @@
 #include "remote_hw_res.h"
 #include "remote_char_dev.h"
+#include "remote_nic.h"
 #include "remote_usb.h"
 #include "remote_usbhc.h"
@@ -50,4 +51,5 @@
 		&remote_hw_res_iface,
 		&remote_char_dev_iface,
+		&remote_nic_iface,
 		&remote_pci_iface,
 		&remote_usb_iface,
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/drv/generic/driver.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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) {
@@ -301,4 +301,14 @@
 	
 	async_answer_0(iid, res);
+}
+
+static void driver_dev_added(ipc_callid_t iid, ipc_call_t *icall)
+{
+	fibril_mutex_lock(&devices_mutex);
+	ddf_dev_t *dev = driver_get_device(IPC_GET_ARG1(*icall));
+	fibril_mutex_unlock(&devices_mutex);
+	
+	if (dev != NULL && driver->driver_ops->device_added != NULL)
+		driver->driver_ops->device_added(dev);
 }
 
@@ -450,4 +460,8 @@
 		case DRIVER_DEV_ADD:
 			driver_dev_add(callid, &call);
+			break;
+		case DRIVER_DEV_ADDED:
+			async_answer_0(callid, EOK);
+			driver_dev_added(callid, &call);
 			break;
 		case DRIVER_DEV_REMOVE:
@@ -956,5 +970,5 @@
 	
 	match_id->id = str_dup(match_id_str);
-	match_id->score = 90;
+	match_id->score = match_score;
 	
 	add_match_id(&fun->match_ids, match_id);
Index: uspace/lib/drv/generic/remote_nic.c
===================================================================
--- uspace/lib/drv/generic/remote_nic.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/drv/generic/remote_nic.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,1253 @@
+/*
+ * 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.
+ */
+
+/** @addtogroup libdrv
+ * @{
+ */
+/**
+ * @file
+ * @brief Driver-side RPC skeletons for DDF NIC interface
+ */
+
+#include <assert.h>
+#include <async.h>
+#include <errno.h>
+#include <ipc/services.h>
+#include <adt/measured_strings.h>
+#include <sys/time.h>
+#include "ops/nic.h"
+
+static void remote_nic_send_message(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->send_message);
+	
+	packet_id_t packet_id = (packet_id_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->send_message(dev, packet_id);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_connect_to_nil(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->connect_to_nil);
+	
+	services_t nil_service = (services_t) IPC_GET_ARG2(*call);
+	nic_device_id_t device_id = (nic_device_id_t) IPC_GET_ARG3(*call);
+	
+	int rc = nic_iface->connect_to_nil(dev, nil_service, device_id);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_get_state(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->get_state);
+	
+	nic_device_state_t state = NIC_STATE_MAX;
+	
+	int rc = nic_iface->get_state(dev, &state);
+	async_answer_1(callid, rc, state);
+}
+
+static void remote_nic_set_state(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->set_state);
+	
+	nic_device_state_t state = (nic_device_state_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->set_state(dev, state);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_get_address(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->get_address);
+	
+	nic_address_t address;
+	bzero(&address, sizeof(nic_address_t));
+	
+	int rc = nic_iface->get_address(dev, &address);
+	if (rc == EOK) {
+		size_t max_len;
+		ipc_callid_t data_callid;
+		
+		/* All errors will be translated into EPARTY anyway */
+		if (!async_data_read_receive(&data_callid, &max_len)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (max_len != sizeof(nic_address_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		async_data_read_finalize(data_callid, &address,
+		    sizeof(nic_address_t));
+	}
+	
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_set_address(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	size_t length;
+	ipc_callid_t data_callid;
+	if (!async_data_write_receive(&data_callid, &length)) {
+		async_answer_0(data_callid, EINVAL);
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+	
+	if (length > sizeof(nic_address_t)) {
+		async_answer_0(data_callid, ELIMIT);
+		async_answer_0(callid, ELIMIT);
+		return;
+	}
+	
+	nic_address_t address;
+	if (async_data_write_finalize(data_callid, &address, length) != EOK) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+	
+	if (nic_iface->set_address != NULL) {
+		int rc = nic_iface->set_address(dev, &address);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+}
+
+static void remote_nic_get_stats(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->get_stats == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_device_stats_t stats;
+	bzero(&stats, sizeof(nic_device_stats_t));
+	
+	int rc = nic_iface->get_stats(dev, &stats);
+	if (rc == EOK) {
+		ipc_callid_t data_callid;
+		size_t max_len;
+		if (!async_data_read_receive(&data_callid, &max_len)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (max_len < sizeof(nic_device_stats_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		async_data_read_finalize(data_callid, &stats,
+		    sizeof(nic_device_stats_t));
+	}
+	
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_get_device_info(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->get_device_info == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_device_info_t info;
+	bzero(&info, sizeof(nic_device_info_t));
+	
+	int rc = nic_iface->get_device_info(dev, &info);
+	if (rc == EOK) {
+		ipc_callid_t data_callid;
+		size_t max_len;
+		if (!async_data_read_receive(&data_callid, &max_len)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (max_len < sizeof (nic_device_info_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		async_data_read_finalize(data_callid, &info,
+		    sizeof(nic_device_info_t));
+	}
+	
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_get_cable_state(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->get_cable_state == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_cable_state_t cs = NIC_CS_UNKNOWN;
+	
+	int rc = nic_iface->get_cable_state(dev, &cs);
+	async_answer_1(callid, rc, (sysarg_t) cs);
+}
+
+static void remote_nic_get_operation_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->get_operation_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int speed = 0;
+	nic_channel_mode_t duplex = NIC_CM_UNKNOWN;
+	nic_role_t role = NIC_ROLE_UNKNOWN;
+	
+	int rc = nic_iface->get_operation_mode(dev, &speed, &duplex, &role);
+	async_answer_3(callid, rc, (sysarg_t) speed, (sysarg_t) duplex,
+	    (sysarg_t) role);
+}
+
+static void remote_nic_set_operation_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->set_operation_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int speed = (int) IPC_GET_ARG2(*call);
+	nic_channel_mode_t duplex = (nic_channel_mode_t) IPC_GET_ARG3(*call);
+	nic_role_t role = (nic_role_t) IPC_GET_ARG4(*call);
+	
+	int rc = nic_iface->set_operation_mode(dev, speed, duplex, role);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_autoneg_enable(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->autoneg_enable == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t advertisement = (uint32_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->autoneg_enable(dev, advertisement);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_autoneg_disable(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->autoneg_disable == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int rc = nic_iface->autoneg_disable(dev);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_autoneg_probe(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->autoneg_probe == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t our_adv = 0;
+	uint32_t their_adv = 0;
+	nic_result_t result = NIC_RESULT_NOT_AVAILABLE;
+	nic_result_t their_result = NIC_RESULT_NOT_AVAILABLE;
+	
+	int rc = nic_iface->autoneg_probe(dev, &our_adv, &their_adv, &result,
+	    &their_result);
+	async_answer_4(callid, rc, our_adv, their_adv, (sysarg_t) result,
+	    (sysarg_t) their_result);
+}
+
+static void remote_nic_autoneg_restart(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->autoneg_restart == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int rc = nic_iface->autoneg_restart(dev);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_get_pause(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->get_pause == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_result_t we_send;
+	nic_result_t we_receive;
+	uint16_t pause;
+	
+	int rc = nic_iface->get_pause(dev, &we_send, &we_receive, &pause);
+	async_answer_3(callid, rc, we_send, we_receive, pause);
+}
+
+static void remote_nic_set_pause(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->set_pause == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int allow_send = (int) IPC_GET_ARG2(*call);
+	int allow_receive = (int) IPC_GET_ARG3(*call);
+	uint16_t pause = (uint16_t) IPC_GET_ARG4(*call);
+	
+	int rc = nic_iface->set_pause(dev, allow_send, allow_receive,
+	    pause);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_unicast_get_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->unicast_get_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	size_t max_count = IPC_GET_ARG2(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (max_count != 0) {
+		address_list = malloc(max_count * sizeof (nic_address_t));
+		if (!address_list) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(address_list, max_count * sizeof(nic_address_t));
+	nic_unicast_mode_t mode = NIC_UNICAST_DEFAULT;
+	size_t address_count = 0;
+	
+	int rc = nic_iface->unicast_get_mode(dev, &mode, max_count, address_list,
+	    &address_count);
+	
+	if ((rc != EOK) || (max_count == 0) || (address_count == 0)) {
+		free(address_list);
+		async_answer_2(callid, rc, mode, address_count);
+		return;
+	}
+	
+	ipc_callid_t data_callid;
+	size_t max_len;
+	if (!async_data_read_receive(&data_callid, &max_len)) {
+		async_answer_0(data_callid, EINVAL);
+		async_answer_2(callid, rc, mode, address_count);
+		free(address_list);
+		return;
+	}
+	
+	if (max_len > address_count * sizeof(nic_address_t))
+		max_len = address_count * sizeof(nic_address_t);
+	
+	if (max_len > max_count * sizeof(nic_address_t))
+		max_len = max_count * sizeof(nic_address_t);
+	
+	async_data_read_finalize(data_callid, address_list, max_len);
+	async_answer_0(data_callid, EINVAL);
+	
+	free(address_list);
+	async_answer_2(callid, rc, mode, address_count);
+}
+
+static void remote_nic_unicast_set_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	size_t length;
+	nic_unicast_mode_t mode = IPC_GET_ARG2(*call);
+	size_t address_count = IPC_GET_ARG3(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (address_count) {
+		ipc_callid_t data_callid;
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (length != address_count * sizeof(nic_address_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		address_list = malloc(length);
+		if (address_list == NULL) {
+			async_answer_0(data_callid, ENOMEM);
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+		
+		if (async_data_write_finalize(data_callid, address_list,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			free(address_list);
+			return;
+		}
+	}
+	
+	if (nic_iface->unicast_set_mode != NULL) {
+		int rc = nic_iface->unicast_set_mode(dev, mode, address_list,
+		    address_count);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+	
+	free(address_list);
+}
+
+static void remote_nic_multicast_get_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->multicast_get_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	size_t max_count = IPC_GET_ARG2(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (max_count != 0) {
+		address_list = malloc(max_count * sizeof(nic_address_t));
+		if (!address_list) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(address_list, max_count * sizeof(nic_address_t));
+	nic_multicast_mode_t mode = NIC_MULTICAST_BLOCKED;
+	size_t address_count = 0;
+	
+	int rc = nic_iface->multicast_get_mode(dev, &mode, max_count, address_list,
+	    &address_count);
+	
+	
+	if ((rc != EOK) || (max_count == 0) || (address_count == 0)) {
+		free(address_list);
+		async_answer_2(callid, rc, mode, address_count);
+		return;
+	}
+	
+	ipc_callid_t data_callid;
+	size_t max_len;
+	if (!async_data_read_receive(&data_callid, &max_len)) {
+		async_answer_0(data_callid, EINVAL);
+		async_answer_2(callid, rc, mode, address_count);
+		free(address_list);
+		return;
+	}
+	
+	if (max_len > address_count * sizeof(nic_address_t))
+		max_len = address_count * sizeof(nic_address_t);
+	
+	if (max_len > max_count * sizeof(nic_address_t))
+		max_len = max_count * sizeof(nic_address_t);
+	
+	async_data_read_finalize(data_callid, address_list, max_len);
+	
+	free(address_list);
+	async_answer_2(callid, rc, mode, address_count);
+}
+
+static void remote_nic_multicast_set_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	nic_multicast_mode_t mode = IPC_GET_ARG2(*call);
+	size_t address_count = IPC_GET_ARG3(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (address_count) {
+		ipc_callid_t data_callid;
+		size_t length;
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (length != address_count * sizeof (nic_address_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		address_list = malloc(length);
+		if (address_list == NULL) {
+			async_answer_0(data_callid, ENOMEM);
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+		
+		if (async_data_write_finalize(data_callid, address_list,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			free(address_list);
+			return;
+		}
+	}
+	
+	if (nic_iface->multicast_set_mode != NULL) {
+		int rc = nic_iface->multicast_set_mode(dev, mode, address_list,
+		    address_count);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+	
+	free(address_list);
+}
+
+static void remote_nic_broadcast_get_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->broadcast_get_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_broadcast_mode_t mode = NIC_BROADCAST_ACCEPTED;
+	
+	int rc = nic_iface->broadcast_get_mode(dev, &mode);
+	async_answer_1(callid, rc, mode);
+}
+
+static void remote_nic_broadcast_set_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->broadcast_set_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_broadcast_mode_t mode = IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->broadcast_set_mode(dev, mode);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_defective_get_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->defective_get_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t mode = 0;
+	
+	int rc = nic_iface->defective_get_mode(dev, &mode);
+	async_answer_1(callid, rc, mode);
+}
+
+static void remote_nic_defective_set_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->defective_set_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t mode = IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->defective_set_mode(dev, mode);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_blocked_sources_get(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->blocked_sources_get == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	size_t max_count = IPC_GET_ARG2(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (max_count != 0) {
+		address_list = malloc(max_count * sizeof(nic_address_t));
+		if (!address_list) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(address_list, max_count * sizeof(nic_address_t));
+	size_t address_count = 0;
+	
+	int rc = nic_iface->blocked_sources_get(dev, max_count, address_list,
+	    &address_count);
+	
+	if ((rc != EOK) || (max_count == 0) || (address_count == 0)) {
+		async_answer_1(callid, rc, address_count);
+		free(address_list);
+		return;
+	}
+	
+	ipc_callid_t data_callid;
+	size_t max_len;
+	if (!async_data_read_receive(&data_callid, &max_len)) {
+		async_answer_0(data_callid, EINVAL);
+		async_answer_1(callid, rc, address_count);
+		free(address_list);
+		return;
+	}
+	
+	if (max_len > address_count * sizeof(nic_address_t))
+		max_len = address_count * sizeof(nic_address_t);
+	
+	if (max_len > max_count * sizeof(nic_address_t))
+		max_len = max_count * sizeof(nic_address_t);
+	
+	async_data_read_finalize(data_callid, address_list, max_len);
+	async_answer_0(data_callid, EINVAL);
+	
+	free(address_list);
+	async_answer_1(callid, rc, address_count);
+}
+
+static void remote_nic_blocked_sources_set(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	size_t length;
+	size_t address_count = IPC_GET_ARG2(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (address_count) {
+		ipc_callid_t data_callid;
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (length != address_count * sizeof(nic_address_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		address_list = malloc(length);
+		if (address_list == NULL) {
+			async_answer_0(data_callid, ENOMEM);
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+		
+		if (async_data_write_finalize(data_callid, address_list,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			free(address_list);
+			return;
+		}
+	}
+	
+	if (nic_iface->blocked_sources_set != NULL) {
+		int rc = nic_iface->blocked_sources_set(dev, address_list,
+		    address_count);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+	
+	free(address_list);
+}
+
+static void remote_nic_vlan_get_mask(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->vlan_get_mask == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_vlan_mask_t vlan_mask;
+	bzero(&vlan_mask, sizeof(nic_vlan_mask_t));
+	
+	int rc = nic_iface->vlan_get_mask(dev, &vlan_mask);
+	if (rc == EOK) {
+		ipc_callid_t data_callid;
+		size_t max_len;
+		if (!async_data_read_receive(&data_callid, &max_len)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (max_len != sizeof(nic_vlan_mask_t)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		async_data_read_finalize(data_callid, &vlan_mask, max_len);
+	}
+	
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_vlan_set_mask(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	nic_vlan_mask_t vlan_mask;
+	nic_vlan_mask_t *vlan_mask_pointer = NULL;
+	bool vlan_mask_set = (bool) IPC_GET_ARG2(*call);
+	
+	if (vlan_mask_set) {
+		ipc_callid_t data_callid;
+		size_t length;
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (length != sizeof(nic_vlan_mask_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		if (async_data_write_finalize(data_callid, &vlan_mask,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		vlan_mask_pointer = &vlan_mask;
+	}
+	
+	if (nic_iface->vlan_set_mask != NULL) {
+		int rc = nic_iface->vlan_set_mask(dev, vlan_mask_pointer);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+}
+
+static void remote_nic_vlan_set_tag(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	if (nic_iface->vlan_set_tag == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint16_t tag = (uint16_t) IPC_GET_ARG2(*call);
+	int add = (int) IPC_GET_ARG3(*call);
+	int strip = (int) IPC_GET_ARG4(*call);
+	
+	int rc = nic_iface->vlan_set_tag(dev, tag, add, strip);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_wol_virtue_add(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	int send_data = (int) IPC_GET_ARG3(*call);
+	ipc_callid_t data_callid;
+	
+	if (nic_iface->wol_virtue_add == NULL) {
+		if (send_data) {
+			async_data_write_receive(&data_callid, NULL);
+			async_answer_0(data_callid, ENOTSUP);
+		}
+		
+		async_answer_0(callid, ENOTSUP);
+	}
+	
+	size_t length = 0;
+	void *data = NULL;
+	
+	if (send_data) {
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		data = malloc(length);
+		if (data == NULL) {
+			async_answer_0(data_callid, ENOMEM);
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+		
+		if (async_data_write_finalize(data_callid, data,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			free(data);
+			return;
+		}
+	}
+	
+	nic_wv_id_t id = 0;
+	nic_wv_type_t type = (nic_wv_type_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->wol_virtue_add(dev, type, data, length, &id);
+	async_answer_1(callid, rc, (sysarg_t) id);
+	free(data);
+}
+
+static void remote_nic_wol_virtue_remove(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	if (nic_iface->wol_virtue_remove == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_wv_id_t id = (nic_wv_id_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->wol_virtue_remove(dev, id);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_wol_virtue_probe(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	if (nic_iface->wol_virtue_probe == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_wv_id_t id = (nic_wv_id_t) IPC_GET_ARG2(*call);
+	size_t max_length = IPC_GET_ARG3(*call);
+	nic_wv_type_t type = NIC_WV_NONE;
+	size_t length = 0;
+	ipc_callid_t data_callid;
+	void *data = NULL;
+	
+	if (max_length != 0) {
+		data = malloc(max_length);
+		if (data == NULL) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(data, max_length);
+	
+	int rc = nic_iface->wol_virtue_probe(dev, id, &type, max_length,
+	    data, &length);
+	
+	if ((max_length != 0) && (length != 0)) {
+		size_t req_length;
+		if (!async_data_read_receive(&data_callid, &req_length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			free(data);
+			return;
+		}
+		
+		if (req_length > length)
+			req_length = length;
+		
+		if (req_length > max_length)
+			req_length = max_length;
+		
+		async_data_read_finalize(data_callid, data, req_length);
+	}
+	
+	async_answer_2(callid, rc, (sysarg_t) type, (sysarg_t) length);
+	free(data);
+}
+
+static void remote_nic_wol_virtue_list(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->wol_virtue_list == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_wv_type_t type = (nic_wv_type_t) IPC_GET_ARG2(*call);
+	size_t max_count = IPC_GET_ARG3(*call);
+	size_t count = 0;
+	nic_wv_id_t *id_list = NULL;
+	ipc_callid_t data_callid;
+	
+	if (max_count != 0) {
+		id_list = malloc(max_count * sizeof(nic_wv_id_t));
+		if (id_list == NULL) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(id_list, max_count * sizeof (nic_wv_id_t));
+	
+	int rc = nic_iface->wol_virtue_list(dev, type, max_count, id_list,
+	    &count);
+	
+	if ((max_count != 0) && (count != 0)) {
+		size_t req_length;
+		if (!async_data_read_receive(&data_callid, &req_length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			free(id_list);
+			return;
+		}
+		
+		if (req_length > count * sizeof(nic_wv_id_t))
+			req_length = count * sizeof(nic_wv_id_t);
+		
+		if (req_length > max_count * sizeof(nic_wv_id_t))
+			req_length = max_count * sizeof(nic_wv_id_t);
+		
+		rc = async_data_read_finalize(data_callid, id_list, req_length);
+	}
+	
+	async_answer_1(callid, rc, (sysarg_t) count);
+	free(id_list);
+}
+
+static void remote_nic_wol_virtue_get_caps(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->wol_virtue_get_caps == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int count = -1;
+	nic_wv_type_t type = (nic_wv_type_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->wol_virtue_get_caps(dev, type, &count);
+	async_answer_1(callid, rc, (sysarg_t) count);
+}
+
+static void remote_nic_wol_load_info(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->wol_load_info == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	size_t max_length = (size_t) IPC_GET_ARG2(*call);
+	size_t frame_length = 0;
+	nic_wv_type_t type = NIC_WV_NONE;
+	uint8_t *data = NULL;
+	
+	if (max_length != 0) {
+		data = malloc(max_length);
+		if (data == NULL) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(data, max_length);
+	
+	int rc = nic_iface->wol_load_info(dev, &type, max_length, data,
+	    &frame_length);
+	if (rc == EOK) {
+		ipc_callid_t data_callid;
+		size_t req_length;
+		if (!async_data_read_receive(&data_callid, &req_length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			free(data);
+			return;
+		}
+		
+		req_length = req_length > max_length ? max_length : req_length;
+		req_length = req_length > frame_length ? frame_length : req_length;
+		async_data_read_finalize(data_callid, data, req_length);
+	}
+	
+	async_answer_2(callid, rc, (sysarg_t) type, (sysarg_t) frame_length);
+	free(data);
+}
+
+static void remote_nic_offload_probe(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->offload_probe == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t supported = 0;
+	uint32_t active = 0;
+	
+	int rc = nic_iface->offload_probe(dev, &supported, &active);
+	async_answer_2(callid, rc, supported, active);
+}
+
+static void remote_nic_offload_set(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->offload_set == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t mask = (uint32_t) IPC_GET_ARG2(*call);
+	uint32_t active = (uint32_t) IPC_GET_ARG3(*call);
+	
+	int rc = nic_iface->offload_set(dev, mask, active);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_poll_get_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->poll_get_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_poll_mode_t mode = NIC_POLL_IMMEDIATE;
+	int request_data = IPC_GET_ARG2(*call);
+	struct timeval period = {
+		.tv_sec = 0,
+		.tv_usec = 0
+	};
+	
+	int rc = nic_iface->poll_get_mode(dev, &mode, &period);
+	if ((rc == EOK) && (request_data)) {
+		size_t max_len;
+		ipc_callid_t data_callid;
+		
+		if (!async_data_read_receive(&data_callid, &max_len)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (max_len != sizeof(struct timeval)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		async_data_read_finalize(data_callid, &period,
+		    sizeof(struct timeval));
+	}
+	
+	async_answer_1(callid, rc, (sysarg_t) mode);
+}
+
+static void remote_nic_poll_set_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	nic_poll_mode_t mode = IPC_GET_ARG2(*call);
+	int has_period = IPC_GET_ARG3(*call);
+	struct timeval period_buf;
+	struct timeval *period = NULL;
+	size_t length;
+	
+	if (has_period) {
+		ipc_callid_t data_callid;
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (length != sizeof(struct timeval)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		period = &period_buf;
+		if (async_data_write_finalize(data_callid, period,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+	}
+	
+	if (nic_iface->poll_set_mode != NULL) {
+		int rc = nic_iface->poll_set_mode(dev, mode, period);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+}
+
+static void remote_nic_poll_now(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->poll_now == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int rc = nic_iface->poll_now(dev);
+	async_answer_0(callid, rc);
+}
+
+/** Remote NIC interface operations.
+ *
+ */
+static remote_iface_func_ptr_t remote_nic_iface_ops[] = {
+	&remote_nic_send_message,
+	&remote_nic_connect_to_nil,
+	&remote_nic_get_state,
+	&remote_nic_set_state,
+	&remote_nic_get_address,
+	&remote_nic_set_address,
+	&remote_nic_get_stats,
+	&remote_nic_get_device_info,
+	&remote_nic_get_cable_state,
+	&remote_nic_get_operation_mode,
+	&remote_nic_set_operation_mode,
+	&remote_nic_autoneg_enable,
+	&remote_nic_autoneg_disable,
+	&remote_nic_autoneg_probe,
+	&remote_nic_autoneg_restart,
+	&remote_nic_get_pause,
+	&remote_nic_set_pause,
+	&remote_nic_unicast_get_mode,
+	&remote_nic_unicast_set_mode,
+	&remote_nic_multicast_get_mode,
+	&remote_nic_multicast_set_mode,
+	&remote_nic_broadcast_get_mode,
+	&remote_nic_broadcast_set_mode,
+	&remote_nic_defective_get_mode,
+	&remote_nic_defective_set_mode,
+	&remote_nic_blocked_sources_get,
+	&remote_nic_blocked_sources_set,
+	&remote_nic_vlan_get_mask,
+	&remote_nic_vlan_set_mask,
+	&remote_nic_vlan_set_tag,
+	&remote_nic_wol_virtue_add,
+	&remote_nic_wol_virtue_remove,
+	&remote_nic_wol_virtue_probe,
+	&remote_nic_wol_virtue_list,
+	&remote_nic_wol_virtue_get_caps,
+	&remote_nic_wol_load_info,
+	&remote_nic_offload_probe,
+	&remote_nic_offload_set,
+	&remote_nic_poll_get_mode,
+	&remote_nic_poll_set_mode,
+	&remote_nic_poll_now
+};
+
+/** Remote NIC interface structure.
+ *
+ * Interface for processing request from remote
+ * clients addressed to the NIC interface.
+ *
+ */
+remote_iface_t remote_nic_iface = {
+	.method_count = sizeof(remote_nic_iface_ops) /
+	    sizeof(remote_iface_func_ptr_t),
+	.methods = remote_nic_iface_ops
+};
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/generic/remote_pci.c
===================================================================
--- uspace/lib/drv/generic/remote_pci.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/drv/generic/remote_pci.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/drv/generic/remote_usb.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/drv/generic/remote_usbhc.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/drv/include/ddf/driver.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -136,5 +136,5 @@
 typedef struct driver_ops {
 	/** Callback method for passing a new device to the device driver */
-	int (*add_device)(ddf_dev_t *);
+	int (*dev_add)(ddf_dev_t *);
 	/** Ask driver to remove a device */
 	int (*dev_remove)(ddf_dev_t *);
@@ -145,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 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/drv/include/ops/nic.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+/** @addtogroup libdrv
+ * @{
+ */
+/** @file
+ * @brief DDF NIC interface definition
+ */
+
+#ifndef LIBDRV_OPS_NIC_H_
+#define LIBDRV_OPS_NIC_H_
+
+#include <net/packet.h>
+#include <ipc/services.h>
+#include <net/device.h>
+#include <sys/time.h>
+
+#include "../ddf/driver.h"
+
+typedef struct nic_iface {
+	/** Mandatory methods */
+	int (*send_message)(ddf_fun_t *, packet_id_t);
+	int (*connect_to_nil)(ddf_fun_t *, services_t, nic_device_id_t);
+	int (*get_state)(ddf_fun_t *, nic_device_state_t *);
+	int (*set_state)(ddf_fun_t *, nic_device_state_t);
+	int (*get_address)(ddf_fun_t *, nic_address_t *);
+	
+	/** Optional methods */
+	int (*set_address)(ddf_fun_t *, const nic_address_t *);
+	int (*get_stats)(ddf_fun_t *, nic_device_stats_t *);
+	int (*get_device_info)(ddf_fun_t *, nic_device_info_t *);
+	int (*get_cable_state)(ddf_fun_t *, nic_cable_state_t *);
+	
+	int (*get_operation_mode)(ddf_fun_t *, int *, nic_channel_mode_t *,
+	    nic_role_t *);
+	int (*set_operation_mode)(ddf_fun_t *, int, nic_channel_mode_t,
+	    nic_role_t);
+	int (*autoneg_enable)(ddf_fun_t *, uint32_t);
+	int (*autoneg_disable)(ddf_fun_t *);
+	int (*autoneg_probe)(ddf_fun_t *, uint32_t *, uint32_t *,
+	    nic_result_t *, nic_result_t *);
+	int (*autoneg_restart)(ddf_fun_t *);
+	int (*get_pause)(ddf_fun_t *, nic_result_t *, nic_result_t *,
+		uint16_t *);
+	int (*set_pause)(ddf_fun_t *, int, int, uint16_t);
+	
+	int (*unicast_get_mode)(ddf_fun_t *, nic_unicast_mode_t *, size_t,
+	    nic_address_t *, size_t *);
+	int (*unicast_set_mode)(ddf_fun_t *, nic_unicast_mode_t,
+	    const nic_address_t *, size_t);
+	int (*multicast_get_mode)(ddf_fun_t *, nic_multicast_mode_t *, size_t,
+	    nic_address_t *, size_t *);
+	int (*multicast_set_mode)(ddf_fun_t *, nic_multicast_mode_t,
+	    const nic_address_t *, size_t);
+	int (*broadcast_get_mode)(ddf_fun_t *, nic_broadcast_mode_t *);
+	int (*broadcast_set_mode)(ddf_fun_t *, nic_broadcast_mode_t);
+	int (*defective_get_mode)(ddf_fun_t *, uint32_t *);
+	int (*defective_set_mode)(ddf_fun_t *, uint32_t);
+	int (*blocked_sources_get)(ddf_fun_t *, size_t, nic_address_t *,
+	    size_t *);
+	int (*blocked_sources_set)(ddf_fun_t *, const nic_address_t *, size_t);
+	
+	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 (*wol_virtue_add)(ddf_fun_t *, nic_wv_type_t, const void *,
+	    size_t, nic_wv_id_t *);
+	int (*wol_virtue_remove)(ddf_fun_t *, nic_wv_id_t);
+	int (*wol_virtue_probe)(ddf_fun_t *, nic_wv_id_t, nic_wv_type_t *,
+	    size_t, void *, size_t *);
+	int (*wol_virtue_list)(ddf_fun_t *, nic_wv_type_t, size_t,
+	    nic_wv_id_t *, size_t *);
+	int (*wol_virtue_get_caps)(ddf_fun_t *, nic_wv_type_t, int *);
+	int (*wol_load_info)(ddf_fun_t *, nic_wv_type_t *, size_t,
+	    uint8_t *, size_t *);
+	
+	int (*offload_probe)(ddf_fun_t *, uint32_t *, uint32_t *);
+	int (*offload_set)(ddf_fun_t *, uint32_t, uint32_t);
+	
+	int (*poll_get_mode)(ddf_fun_t *, nic_poll_mode_t *,
+	    struct timeval *);
+	int (*poll_set_mode)(ddf_fun_t *, nic_poll_mode_t,
+	    const struct timeval *);
+	int (*poll_now)(ddf_fun_t *);
+} nic_iface_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/remote_nic.h
===================================================================
--- uspace/lib/drv/include/remote_nic.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/drv/include/remote_nic.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+/** @addtogroup libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_NIC_H_
+#define LIBDRV_REMOTE_NIC_H_
+
+extern remote_iface_t remote_nic_iface;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/usb_iface.h
===================================================================
--- uspace/lib/drv/include/usb_iface.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/drv/include/usb_iface.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/drv/include/usbhc_iface.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/ext2/libext2_filesystem.c
===================================================================
--- uspace/lib/ext2/libext2_filesystem.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/ext2/libext2_filesystem.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -259,4 +259,10 @@
 	    bg_ref->block_group);
 	
+	rc = ext2_filesystem_put_block_group_ref(bg_ref);
+	if (rc != EOK) {
+		free(newref);
+		return rc;
+	}
+
 	inode_size = ext2_superblock_get_inode_size(fs->superblock);
 	block_size = ext2_superblock_get_block_size(fs->superblock);
Index: uspace/lib/fs/libfs.c
===================================================================
--- uspace/lib/fs/libfs.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/fs/libfs.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -877,4 +877,82 @@
 }
 
+static FIBRIL_MUTEX_INITIALIZE(instances_mutex);
+static LIST_INITIALIZE(instances_list);
+
+typedef struct {
+	service_id_t service_id;
+	link_t link;
+	void *data;
+} fs_instance_t;
+
+int fs_instance_create(service_id_t service_id, void *data)
+{
+	fs_instance_t *inst = malloc(sizeof(fs_instance_t));
+	if (!inst)
+		return ENOMEM;
+
+	link_initialize(&inst->link);
+	inst->service_id = service_id;
+	inst->data = data;
+
+	fibril_mutex_lock(&instances_mutex);
+	list_foreach(instances_list, link) {
+		fs_instance_t *cur = list_get_instance(link, fs_instance_t,
+		    link);
+
+		if (cur->service_id == service_id) {
+			fibril_mutex_unlock(&instances_mutex);
+			free(inst);
+			return EEXIST;
+		}
+
+		/* keep the list sorted */
+		if (cur->service_id < service_id) {
+			list_insert_before(&inst->link, &cur->link);
+			fibril_mutex_unlock(&instances_mutex);
+			return EOK;
+		}
+	}
+	list_append(&inst->link, &instances_list);
+	fibril_mutex_unlock(&instances_mutex);
+
+	return EOK;
+}
+
+int fs_instance_get(service_id_t service_id, void **idp)
+{
+	fibril_mutex_lock(&instances_mutex);
+	list_foreach(instances_list, link) {
+		fs_instance_t *inst = list_get_instance(link, fs_instance_t,
+		    link);
+
+		if (inst->service_id == service_id) {
+			*idp = inst->data;
+			fibril_mutex_unlock(&instances_mutex);
+			return EOK;
+		}
+	}
+	fibril_mutex_unlock(&instances_mutex);
+	return ENOENT;
+}
+
+int fs_instance_destroy(service_id_t service_id)
+{
+	fibril_mutex_lock(&instances_mutex);
+	list_foreach(instances_list, link) {
+		fs_instance_t *inst = list_get_instance(link, fs_instance_t,
+		    link);
+
+		if (inst->service_id == service_id) {
+			list_remove(&inst->link);
+			fibril_mutex_unlock(&instances_mutex);
+			free(inst);
+			return EOK;
+		}
+	}
+	fibril_mutex_unlock(&instances_mutex);
+	return ENOENT;
+}
+
 /** @}
  */
Index: uspace/lib/fs/libfs.h
===================================================================
--- uspace/lib/fs/libfs.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/fs/libfs.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -105,4 +105,8 @@
 extern void fs_node_initialize(fs_node_t *);
 
+extern int fs_instance_create(service_id_t, void *);
+extern int fs_instance_get(service_id_t, void **);
+extern int fs_instance_destroy(service_id_t);
+
 #endif
 
Index: uspace/lib/minix/minix.h
===================================================================
--- uspace/lib/minix/minix.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/minix/minix.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/Makefile
===================================================================
--- uspace/lib/net/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -40,6 +40,4 @@
 	generic/protocol_map.c \
 	adt/module_map.c \
-	netif/netif_remote.c \
-	netif/netif_skel.c \
 	nil/nil_remote.c \
 	nil/nil_skel.c \
Index: uspace/lib/net/generic/generic.c
===================================================================
--- uspace/lib/net/generic/generic.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/generic/generic.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -54,5 +54,5 @@
  */
 int generic_device_state_msg_remote(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, sysarg_t state, services_t target)
+    nic_device_id_t device_id, sysarg_t state, services_t target)
 {
 	async_exch_t *exch = async_exchange_begin(sess);
@@ -68,5 +68,4 @@
  * @param[in] message   Service specific message.
  * @param[in] device_id Device identifier.
- * @param[in] arg2      Second argument of the message.
  * @param[in] service   Device module service.
  *
@@ -77,9 +76,9 @@
  */
 int generic_device_req_remote(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, sysarg_t arg2, services_t service)
-{
-	async_exch_t *exch = async_exchange_begin(sess);
-	int rc = async_req_3_0(exch, message, (sysarg_t) device_id,
-	    arg2, (sysarg_t) service);
+    nic_device_id_t device_id, services_t service)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_0(exch, message, (sysarg_t) device_id, 0,
+	    (sysarg_t) service);
 	async_exchange_end(exch);
 	
@@ -103,27 +102,30 @@
  */
 int generic_get_addr_req(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, measured_string_t **address, uint8_t **data)
-{
-	if ((!address) || (!data))
-		return EBADMEM;
+    nic_device_id_t device_id, uint8_t *address, size_t max_len)
+{
+	aid_t aid;
+	ipc_call_t result;
+	
+	assert(address != NULL);
 	
 	/* Request the address */
 	async_exch_t *exch = async_exchange_begin(sess);
-	aid_t message_id = async_send_1(exch, message, (sysarg_t) device_id,
-	    NULL);
-	int rc = measured_strings_return(exch, address, data, 1);
-	async_exchange_end(exch);
-	
-	sysarg_t result;
-	async_wait_for(message_id, &result);
-	
-	/* If not successful */
-	if ((rc == EOK) && (result != EOK)) {
-		/* Clear the data */
-		free(*address);
-		free(*data);
-	}
-	
-	return (int) result;
+	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);
+	
+	if (rc != EOK) {
+		async_wait_for(aid, &ipcrc);
+		return rc;
+	}
+	
+	async_wait_for(aid, &ipcrc);
+	if (ipcrc == EOK) {
+		return IPC_GET_ARG1(result);
+	} else {
+		return (int) ipcrc;
+	}
 }
 
@@ -142,5 +144,5 @@
  */
 int generic_packet_size_req_remote(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, packet_dimension_t *packet_dimension)
+    nic_device_id_t device_id, packet_dimension_t *packet_dimension)
 {
 	if (!packet_dimension)
@@ -179,5 +181,5 @@
  */
 int generic_received_msg_remote(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, packet_id_t packet_id, services_t target,
+    nic_device_id_t device_id, packet_id_t packet_id, services_t target,
     services_t error)
 {
@@ -210,5 +212,5 @@
  */
 int generic_send_msg_remote(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, packet_id_t packet_id, services_t sender,
+    nic_device_id_t device_id, packet_id_t packet_id, services_t sender,
     services_t error)
 {
@@ -251,5 +253,5 @@
  */
 int generic_translate_req(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, services_t service,
+    nic_device_id_t device_id, services_t service,
     measured_string_t *configuration, size_t count,
     measured_string_t **translation, uint8_t **data)
Index: uspace/lib/net/generic/net_checksum.c
===================================================================
--- uspace/lib/net/generic/net_checksum.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/generic/net_checksum.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -40,8 +40,11 @@
 
 /** Big-endian encoding CRC divider. */
-#define CRC_DIVIDER_BE	0x04c11db7
+#define CRC_DIVIDER_BE  0x04c11db7
 
 /** Little-endian encoding CRC divider. */
-#define CRC_DIVIDER_LE	0xedb88320
+#define CRC_DIVIDER_LE  0xedb88320
+
+/** Polynomial used in multicast address hashing */
+#define CRC_MCAST_POLYNOMIAL  0x04c11db6
 
 /** Compacts the computed checksum to the 16 bit number adding the carries.
@@ -203,5 +206,5 @@
 }
 
-/** Computes the ip header checksum.
+/** Compute the IP header checksum.
  *
  * To compute the checksum of a new packet, the checksum header field must be
@@ -221,4 +224,39 @@
 }
 
+/** Compute the standard hash from MAC
+ *
+ * Hashing MAC into 64 possible values and using the value as index to
+ * 64bit number.
+ *
+ * The code is copied from qemu-0.13's implementation of ne2000 and rt8139
+ * drivers, but according to documentation there it originates in FreeBSD.
+ *
+ * @param[in] addr The 6-byte MAC address to be hashed
+ *
+ * @return 64-bit number with only single bit set to 1
+ *
+ */
+uint64_t multicast_hash(const uint8_t addr[6])
+{
+	uint32_t crc;
+    int carry, i, j;
+    uint8_t b;
+
+    crc = 0xffffffff;
+    for (i = 0; i < 6; i++) {
+        b = addr[i];
+        for (j = 0; j < 8; j++) {
+            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+            crc <<= 1;
+            b >>= 1;
+            if (carry)
+                crc = ((crc ^ CRC_MCAST_POLYNOMIAL) | carry);
+        }
+    }
+	
+    uint64_t one64 = 1;
+    return one64 << (crc >> 26);
+}
+
 /** @}
  */
Index: uspace/lib/net/generic/net_remote.c
===================================================================
--- uspace/lib/net/generic/net_remote.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/generic/net_remote.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -38,7 +38,7 @@
 #include <ipc/services.h>
 #include <ipc/net_net.h>
-
 #include <malloc.h>
-
+#include <async.h>
+#include <devman.h>
 #include <generic.h>
 #include <net/modules.h>
@@ -98,5 +98,5 @@
     size_t count, uint8_t **data)
 {
-	return generic_translate_req(sess, NET_NET_GET_DEVICE_CONF, 0, 0,
+	return generic_translate_req(sess, NET_NET_GET_CONF, 0, 0,
 	    *configuration, count, configuration, data);
 }
@@ -124,5 +124,5 @@
  *
  */
-int net_get_device_conf_req(async_sess_t *sess, device_id_t device_id,
+int net_get_device_conf_req(async_sess_t *sess, nic_device_id_t device_id,
     measured_string_t **configuration, size_t count, uint8_t **data)
 {
@@ -131,4 +131,49 @@
 }
 
+int net_get_devices_req(async_sess_t *sess, measured_string_t **devices,
+    size_t *count, uint8_t **data)
+{
+	if ((!devices) || (!count))
+		return EBADMEM;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	int rc = async_req_0_1(exch, NET_NET_GET_DEVICES_COUNT, count);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	if (*count == 0) {
+		async_exchange_end(exch);
+		*data = NULL;
+		return EOK;
+	}
+	
+	aid_t message_id = async_send_0(exch, NET_NET_GET_DEVICES, NULL);
+	rc = measured_strings_return(exch, devices, data, *count);
+	
+	async_exchange_end(exch);
+	
+	sysarg_t result;
+	async_wait_for(message_id, &result);
+	
+	if ((rc == EOK) && (result != EOK)) {
+		free(*devices);
+		free(*data);
+	}
+	
+	return (int) result;
+}
+
+int net_driver_ready(async_sess_t *sess, devman_handle_t handle)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_1_0(exch, NET_NET_DRIVER_READY, handle);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
 /** @}
  */
Index: uspace/lib/net/generic/packet_remote.c
===================================================================
--- uspace/lib/net/generic/packet_remote.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/generic/packet_remote.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -115,5 +115,5 @@
 	
 	*packet = pm_find(packet_id);
-	if (!*packet) {
+	if (*packet == NULL) {
 		async_exch_t *exch = async_exchange_begin(sess);
 		sysarg_t size;
@@ -130,5 +130,5 @@
 	}
 	
-	if ((*packet)->next) {
+	if ((*packet != NULL) && ((*packet)->next)) {
 		packet_t *next;
 		return packet_translate_remote(sess, &next, (*packet)->next);
Index: uspace/lib/net/generic/protocol_map.c
===================================================================
--- uspace/lib/net/generic/protocol_map.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/generic/protocol_map.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -50,5 +50,5 @@
 	switch (nil) {
 	case SERVICE_ETHERNET:
-	case SERVICE_NE2000:
+	case SERVICE_NILDUMMY:
 		switch (il) {
 		case SERVICE_IP:
@@ -76,5 +76,5 @@
 	switch (nil) {
 	case SERVICE_ETHERNET:
-	case SERVICE_NE2000:
+	case SERVICE_NILDUMMY:
 		switch (protocol) {
 		case ETH_P_IP:
@@ -139,5 +139,4 @@
 	switch (nil) {
 	case SERVICE_ETHERNET:
-	case SERVICE_NE2000:
 		return HW_ETHER;
 	default:
Index: uspace/lib/net/il/arp_remote.c
===================================================================
--- uspace/lib/net/il/arp_remote.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/il/arp_remote.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -84,5 +84,5 @@
  *
  */
-int arp_clear_address_req(async_sess_t *sess, device_id_t device_id,
+int arp_clear_address_req(async_sess_t *sess, nic_device_id_t device_id,
     services_t protocol, measured_string_t *address)
 {
@@ -108,5 +108,5 @@
  *
  */
-int arp_clear_device_req(async_sess_t *sess, device_id_t device_id)
+int arp_clear_device_req(async_sess_t *sess, nic_device_id_t device_id)
 {
 	async_exch_t *exch = async_exchange_begin(sess);
@@ -143,5 +143,5 @@
  *
  */
-int arp_device_req(async_sess_t *sess, device_id_t device_id,
+int arp_device_req(async_sess_t *sess, nic_device_id_t device_id,
     services_t protocol, services_t netif, measured_string_t *address)
 {
@@ -177,5 +177,5 @@
  *
  */
-int arp_translate_req(async_sess_t *sess, device_id_t device_id,
+int arp_translate_req(async_sess_t *sess, nic_device_id_t device_id,
     services_t protocol, measured_string_t *address,
     measured_string_t **translation, uint8_t **data)
Index: uspace/lib/net/il/il_remote.c
===================================================================
--- uspace/lib/net/il/il_remote.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/il/il_remote.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -55,6 +55,6 @@
  *
  */
-int il_device_state_msg(async_sess_t *sess, device_id_t device_id,
-    device_state_t state, services_t target)
+int il_device_state_msg(async_sess_t *sess, nic_device_id_t device_id,
+    nic_device_state_t state, services_t target)
 {
 	return generic_device_state_msg_remote(sess, NET_IL_DEVICE_STATE,
@@ -73,6 +73,6 @@
  *
  */
-int il_received_msg(async_sess_t *sess, device_id_t device_id, packet_t *packet,
-    services_t target)
+int il_received_msg(async_sess_t *sess, nic_device_id_t device_id,
+    packet_t *packet, services_t target)
 {
 	return generic_received_msg_remote(sess, NET_IL_RECEIVED, device_id,
@@ -91,5 +91,5 @@
  *
  */
-int il_mtu_changed_msg(async_sess_t *sess, device_id_t device_id, size_t mtu,
+int il_mtu_changed_msg(async_sess_t *sess, nic_device_id_t device_id, size_t mtu,
     services_t target)
 {
@@ -98,4 +98,26 @@
 }
 
+/** Notify IL layer modules about address change (implemented by ARP)
+ *
+ */
+int il_addr_changed_msg(async_sess_t *sess, nic_device_id_t device_id,
+    size_t addr_len, const uint8_t *address)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	aid_t message_id = async_send_1(exch, NET_IL_ADDR_CHANGED,
+			(sysarg_t) device_id, NULL);
+	int rc = async_data_write_start(exch, address, addr_len);
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+    async_wait_for(message_id, &res);
+    if (rc != EOK)
+		return rc;
+	
+    return (int) res;
+}
+
 /** @}
  */
Index: uspace/lib/net/il/ip_remote.c
===================================================================
--- uspace/lib/net/il/ip_remote.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/il/ip_remote.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -62,5 +62,5 @@
  *
  */
-int ip_add_route_req_remote(async_sess_t *sess, device_id_t device_id,
+int ip_add_route_req_remote(async_sess_t *sess, nic_device_id_t device_id,
     in_addr_t address, in_addr_t netmask, in_addr_t gateway)
 {
@@ -123,8 +123,8 @@
  *
  */
-int ip_device_req_remote(async_sess_t *sess, device_id_t device_id,
+int ip_device_req(async_sess_t *sess, nic_device_id_t device_id,
     services_t service)
 {
-	return generic_device_req_remote(sess, NET_IP_DEVICE, device_id, 0,
+	return generic_device_req_remote(sess, NET_IP_DEVICE, device_id,
 	    service);
 }
@@ -144,5 +144,5 @@
 int ip_get_route_req_remote(async_sess_t *sess, ip_protocol_t protocol,
     const struct sockaddr *destination, socklen_t addrlen,
-    device_id_t *device_id, void **header, size_t *headerlen)
+    nic_device_id_t *device_id, void **header, size_t *headerlen)
 {
 	if ((!destination) || (addrlen == 0))
@@ -196,5 +196,5 @@
  *
  */
-int ip_packet_size_req_remote(async_sess_t *sess, device_id_t device_id,
+int ip_packet_size_req_remote(async_sess_t *sess, nic_device_id_t device_id,
     packet_dimension_t *packet_dimension)
 {
@@ -216,5 +216,5 @@
  *
  */
-int ip_received_error_msg_remote(async_sess_t *sess, device_id_t device_id,
+int ip_received_error_msg_remote(async_sess_t *sess, nic_device_id_t device_id,
     packet_t *packet, services_t target, services_t error)
 {
@@ -240,5 +240,5 @@
  *
  */
-int ip_send_msg_remote(async_sess_t *sess, device_id_t device_id,
+int ip_send_msg_remote(async_sess_t *sess, nic_device_id_t device_id,
     packet_t *packet, services_t sender, services_t error)
 {
@@ -256,5 +256,5 @@
  *
  */
-int ip_set_gateway_req_remote(async_sess_t *sess, device_id_t device_id,
+int ip_set_gateway_req_remote(async_sess_t *sess, nic_device_id_t device_id,
     in_addr_t gateway)
 {
Index: uspace/lib/net/include/arp_interface.h
===================================================================
--- uspace/lib/net/include/arp_interface.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/include/arp_interface.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -46,10 +46,10 @@
 /*@{*/
 
-extern int arp_device_req(async_sess_t *, device_id_t, services_t, services_t,
+extern int arp_device_req(async_sess_t *, nic_device_id_t, services_t, services_t,
     measured_string_t *);
-extern int arp_translate_req(async_sess_t *, device_id_t, services_t,
+extern int arp_translate_req(async_sess_t *, nic_device_id_t, services_t,
     measured_string_t *, measured_string_t **, uint8_t **);
-extern int arp_clear_device_req(async_sess_t *, device_id_t);
-extern int arp_clear_address_req(async_sess_t *, device_id_t, services_t,
+extern int arp_clear_device_req(async_sess_t *, nic_device_id_t);
+extern int arp_clear_address_req(async_sess_t *, nic_device_id_t, services_t,
     measured_string_t *);
 extern int arp_clean_cache_req(async_sess_t *);
Index: uspace/lib/net/include/generic.h
===================================================================
--- uspace/lib/net/include/generic.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/include/generic.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -45,16 +45,16 @@
 
 extern int generic_device_state_msg_remote(async_sess_t *, sysarg_t,
-    device_id_t, sysarg_t, services_t);
-extern int generic_device_req_remote(async_sess_t *, sysarg_t, device_id_t,
-    sysarg_t, services_t);
-extern int generic_get_addr_req(async_sess_t *, sysarg_t, device_id_t,
-    measured_string_t **, uint8_t **);
-extern int generic_packet_size_req_remote(async_sess_t *, sysarg_t, device_id_t,
-    packet_dimension_t *);
-extern int generic_received_msg_remote(async_sess_t *, sysarg_t, device_id_t,
+    nic_device_id_t, sysarg_t, services_t);
+extern int generic_device_req_remote(async_sess_t *, sysarg_t, nic_device_id_t,
+    services_t);
+extern int generic_get_addr_req(async_sess_t *, sysarg_t, nic_device_id_t,
+    uint8_t *address, size_t max_length);
+extern int generic_packet_size_req_remote(async_sess_t *, sysarg_t,
+    nic_device_id_t, packet_dimension_t *);
+extern int generic_received_msg_remote(async_sess_t *, sysarg_t,
+    nic_device_id_t, packet_id_t, services_t, services_t);
+extern int generic_send_msg_remote(async_sess_t *, sysarg_t, nic_device_id_t,
     packet_id_t, services_t, services_t);
-extern int generic_send_msg_remote(async_sess_t *, sysarg_t, device_id_t,
-    packet_id_t, services_t, services_t);
-extern int generic_translate_req(async_sess_t *, sysarg_t, device_id_t,
+extern int generic_translate_req(async_sess_t *, sysarg_t, nic_device_id_t,
     services_t, measured_string_t *, size_t, measured_string_t **, uint8_t **);
 
Index: uspace/lib/net/include/il_remote.h
===================================================================
--- uspace/lib/net/include/il_remote.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/include/il_remote.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -50,8 +50,12 @@
 /*@{*/
 
-extern int il_device_state_msg(async_sess_t *, device_id_t, device_state_t,
+extern int il_device_state_msg(async_sess_t *, nic_device_id_t,
+    nic_device_state_t, services_t);
+extern int il_received_msg(async_sess_t *, nic_device_id_t, packet_t *,
     services_t);
-extern int il_received_msg(async_sess_t *, device_id_t, packet_t *, services_t);
-extern int il_mtu_changed_msg(async_sess_t *, device_id_t, size_t, services_t);
+extern int il_mtu_changed_msg(async_sess_t *, nic_device_id_t, size_t,
+    services_t);
+extern int il_addr_changed_msg(async_sess_t *, nic_device_id_t, size_t,
+    const uint8_t *);
 
 /*@}*/
Index: uspace/lib/net/include/ip_interface.h
===================================================================
--- uspace/lib/net/include/ip_interface.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/include/ip_interface.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -46,5 +46,4 @@
 #define ip_set_gateway_req     ip_set_gateway_req_remote
 #define ip_packet_size_req     ip_packet_size_req_remote
-#define ip_device_req          ip_device_req_remote
 #define ip_add_route_req       ip_add_route_req_remote
 #define ip_send_msg            ip_send_msg_remote
@@ -69,5 +68,5 @@
  *
  */
-typedef int (*tl_received_msg_t)(device_id_t device_id, packet_t *packet,
+typedef int (*tl_received_msg_t)(nic_device_id_t device_id, packet_t *packet,
     services_t receiver, services_t error);
 
Index: uspace/lib/net/include/ip_remote.h
===================================================================
--- uspace/lib/net/include/ip_remote.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/include/ip_remote.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -43,16 +43,16 @@
 #include <async.h>
 
-extern int ip_set_gateway_req_remote(async_sess_t *, device_id_t, in_addr_t);
-extern int ip_packet_size_req_remote(async_sess_t *, device_id_t,
+extern int ip_set_gateway_req_remote(async_sess_t *, nic_device_id_t, in_addr_t);
+extern int ip_packet_size_req_remote(async_sess_t *, nic_device_id_t,
     packet_dimension_t *);
-extern int ip_received_error_msg_remote(async_sess_t *, device_id_t, packet_t *,
+extern int ip_received_error_msg_remote(async_sess_t *, nic_device_id_t, packet_t *,
     services_t, services_t);
-extern int ip_device_req_remote(async_sess_t *, device_id_t, services_t);
-extern int ip_add_route_req_remote(async_sess_t *, device_id_t, in_addr_t,
+extern int ip_device_req(async_sess_t *, nic_device_id_t, services_t);
+extern int ip_add_route_req_remote(async_sess_t *, nic_device_id_t, in_addr_t,
     in_addr_t, in_addr_t);
-extern int ip_send_msg_remote(async_sess_t *, device_id_t, packet_t *,
+extern int ip_send_msg_remote(async_sess_t *, nic_device_id_t, packet_t *,
     services_t, services_t);
 extern int ip_get_route_req_remote(async_sess_t *, ip_protocol_t,
-    const struct sockaddr *, socklen_t, device_id_t *, void **, size_t *);
+    const struct sockaddr *, socklen_t, nic_device_id_t *, void **, size_t *);
 
 #endif
Index: uspace/lib/net/include/net_checksum.h
===================================================================
--- uspace/lib/net/include/net_checksum.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/include/net_checksum.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -30,5 +30,4 @@
  * @{
  */
-
 /** @file
  * General CRC and checksum computation.
@@ -42,14 +41,22 @@
 
 /** IP checksum value for computed zero checksum.
+ *
  * Zero is returned as 0xFFFF (not flipped)
+ *
  */
-#define IP_CHECKSUM_ZERO	0xffffU
+#define IP_CHECKSUM_ZERO  0xffffU
 
-#ifdef ARCH_IS_BIG_ENDIAN
+#ifdef __BE__
+
 #define compute_crc32(seed, data, length) \
 	compute_crc32_be(seed, (uint8_t *) data, length)
-#else
+
+#endif
+
+#ifdef __LE__
+
 #define compute_crc32(seed, data, length) \
 	compute_crc32_le(seed, (uint8_t *) data, length)
+
 #endif
 
@@ -60,4 +67,5 @@
 extern uint16_t flip_checksum(uint16_t);
 extern uint16_t ip_checksum(uint8_t *, size_t);
+extern uint64_t multicast_hash(const uint8_t addr[6]);
 
 #endif
Index: uspace/lib/net/include/net_interface.h
===================================================================
--- uspace/lib/net/include/net_interface.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/include/net_interface.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -35,8 +35,8 @@
 
 #include <ipc/services.h>
-
 #include <net/device.h>
 #include <adt/measured_strings.h>
 #include <async.h>
+#include <devman.h>
 
 /** @name Networking module interface
@@ -45,9 +45,12 @@
 /*@{*/
 
-extern int net_get_device_conf_req(async_sess_t *, device_id_t,
+extern int net_get_device_conf_req(async_sess_t *, nic_device_id_t,
     measured_string_t **, size_t, uint8_t **);
 extern int net_get_conf_req(async_sess_t *, measured_string_t **, size_t,
     uint8_t **);
 extern void net_free_settings(measured_string_t *, uint8_t *);
+extern int net_get_devices_req(async_sess_t *, measured_string_t **, size_t *,
+    uint8_t **);
+extern int net_driver_ready(async_sess_t *, devman_handle_t);
 extern async_sess_t *net_connect_module(void);
 
Index: uspace/lib/net/include/netif_remote.h
===================================================================
--- uspace/lib/net/include/netif_remote.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,55 +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 libnet
- * @{
- */
-
-#ifndef LIBNET_NETIF_REMOTE_H_
-#define LIBNET_NETIF_REMOTE_H_
-
-#include <ipc/services.h>
-#include <adt/measured_strings.h>
-#include <net/device.h>
-#include <net/packet.h>
-#include <async.h>
-
-extern int netif_get_addr_req(async_sess_t *, device_id_t, measured_string_t **,
-    uint8_t **);
-extern int netif_probe_req(async_sess_t *, device_id_t, int, void *);
-extern int netif_send_msg(async_sess_t *, device_id_t, packet_t *, services_t);
-extern int netif_start_req(async_sess_t *, device_id_t);
-extern int netif_stop_req(async_sess_t *, device_id_t);
-extern int netif_stats_req(async_sess_t *, device_id_t, device_stats_t *);
-extern async_sess_t *netif_bind_service(services_t, device_id_t, services_t,
-    async_client_conn_t);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/net/include/netif_skel.h
===================================================================
--- uspace/lib/net/include/netif_skel.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,212 +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 libnet
- * @{
- */
-
-/** @file
- * Network interface module skeleton.
- * The skeleton has to be part of each network interface module.
- */
-
-#ifndef NET_NETIF_SKEL_H_
-#define NET_NETIF_SKEL_H_
-
-#include <fibril_synch.h>
-#include <ipc/services.h>
-#include <adt/measured_strings.h>
-#include <net/device.h>
-#include <net/packet.h>
-#include <async.h>
-
-/** Network interface device specific data. */
-typedef struct {
-	device_id_t device_id;   /**< Device identifier. */
-	device_state_t state;    /**< Actual device state. */
-	void *specific;          /**< Driver specific data. */
-} netif_device_t;
-
-/** Device map.
- *
- * Maps device identifiers to the network interface device specific data.
- * @see device.h
- *
- */
-DEVICE_MAP_DECLARE(netif_device_map, netif_device_t);
-
-/** Network interface module skeleton global data. */
-typedef struct {
-	async_sess_t *sess;             /**< Networking module session. */
-	async_sess_t *nil_sess;         /**< Network interface layer session. */
-	netif_device_map_t device_map;  /**< Device map. */
-	fibril_rwlock_t lock;           /**< Safety lock. */
-} netif_globals_t;
-
-extern netif_globals_t netif_globals;
-
-/** Initialize the specific module.
- *
- * This function has to be implemented in user code.
- *
- */
-extern int netif_initialize(void);
-
-/** Probe the existence of the device.
- *
- * This has to be implemented in user code.
- *
- * @param[in] device_id Device identifier.
- * @param[in] irq       Device interrupt number.
- * @param[in] io        Device input/output address.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_probe_message(device_id_t device_id, int irq, void *io);
-
-/** Send the packet queue.
- *
- * This has to be implemented in user code.
- *
- * @param[in] device_id Device identifier.
- * @param[in] packet    Packet queue.
- * @param[in] sender    Sending module service.
- *
- * @return EOK on success.
- * @return EFORWARD if the device is not active (in the
- *         NETIF_ACTIVE state).
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_send_message(device_id_t device_id, packet_t *packet,
-    services_t sender);
-
-/** Start the device.
- *
- * This has to be implemented in user code.
- *
- * @param[in] device Device structure.
- *
- * @return New network interface state (non-negative values).
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_start_message(netif_device_t *device);
-
-/** Stop the device.
- *
- * This has to be implemented in user code.
- *
- * @param[in] device Device structure.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_stop_message(netif_device_t *device);
-
-/** Return the device local hardware address.
- *
- * This has to be implemented in user code.
- *
- * @param[in] device_id Device identifier.
- * @param[out] address  Device local hardware address.
- *
- * @return EOK on success.
- * @return EBADMEM if the address parameter is NULL.
- * @return ENOENT if there no such device.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_get_addr_message(device_id_t device_id,
-    measured_string_t *address);
-
-/** Process the netif driver specific message.
- *
- * This function is called for uncommon messages received by the netif
- * skeleton. This has to be implemented in user code.
- *
- * @param[in]  callid Message identifier.
- * @param[in]  call   Message.
- * @param[out] answer Answer.
- * @param[out] count  Number of answer arguments.
- *
- * @return EOK on success.
- * @return ENOTSUP if the message is not known.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_specific_message(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *count);
-
-/** Return the device usage statistics.
- *
- * This has to be implemented in user code.
- *
- * @param[in]  device_id Device identifier.
- * @param[out] stats     Device usage statistics.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_get_device_stats(device_id_t device_id,
-    device_stats_t *stats);
-
-extern int find_device(device_id_t, netif_device_t **);
-extern void null_device_stats(device_stats_t *);
-extern void netif_pq_release(packet_id_t);
-extern packet_t *netif_packet_get_1(size_t);
-
-extern int netif_module_start(void);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/net/include/nil_remote.h
===================================================================
--- uspace/lib/net/include/nil_remote.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/include/nil_remote.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -34,7 +34,7 @@
 #define __NET_NIL_REMOTE_H__
 
-#include <ipc/services.h>
 #include <net/device.h>
 #include <net/packet.h>
+#include <devman.h>
 #include <generic.h>
 #include <async.h>
@@ -58,11 +58,10 @@
 	    packet_get_id(packet), sender, 0)
 
-#define nil_device_req(sess, device_id, mtu, netif_service) \
-	generic_device_req_remote(sess, NET_NIL_DEVICE, device_id, mtu, \
-	    netif_service)
-
-extern int nil_device_state_msg(async_sess_t *, device_id_t, sysarg_t);
-extern int nil_received_msg(async_sess_t *, device_id_t, packet_t *,
-    services_t);
+extern int nil_device_req(async_sess_t *, nic_device_id_t, devman_handle_t,
+    size_t);
+extern int nil_device_state_msg(async_sess_t *, nic_device_id_t, sysarg_t);
+extern int nil_received_msg(async_sess_t *, nic_device_id_t, packet_id_t);
+extern int nil_addr_changed_msg(async_sess_t *, nic_device_id_t,
+    const nic_address_t *);
 
 #endif
Index: uspace/lib/net/include/nil_skel.h
===================================================================
--- uspace/lib/net/include/nil_skel.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/include/nil_skel.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -70,5 +70,5 @@
  *
  */
-extern int nil_device_state_msg_local(device_id_t device_id, sysarg_t state);
+extern int nil_device_state_msg_local(nic_device_id_t device_id, sysarg_t state);
 
 /** Pass the packet queue to the network interface layer.
@@ -81,5 +81,4 @@
  * @param[in] device_id Source device identifier.
  * @param[in] packet    Received packet or the received packet queue.
- * @param[in] target    Target service. Ignored parameter.
  *
  * @return EOK on success.
@@ -88,6 +87,5 @@
  *
  */
-extern int nil_received_msg_local(device_id_t device_id, packet_t *packet,
-    services_t target);
+extern int nil_received_msg_local(nic_device_id_t device_id, packet_t *packet);
 
 /** Message processing function.
Index: uspace/lib/net/include/tl_common.h
===================================================================
--- uspace/lib/net/include/tl_common.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/include/tl_common.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -52,7 +52,7 @@
 
 extern int tl_get_ip_packet_dimension(async_sess_t *, packet_dimensions_t *,
-    device_id_t, packet_dimension_t **);
+    nic_device_id_t, packet_dimension_t **);
 extern int tl_get_address_port(const struct sockaddr *, int, uint16_t *);
-extern int tl_update_ip_packet_dimension(packet_dimensions_t *, device_id_t,
+extern int tl_update_ip_packet_dimension(packet_dimensions_t *, nic_device_id_t,
     size_t);
 extern int tl_set_address_port(struct sockaddr *, int, uint16_t);
Index: uspace/lib/net/include/tl_remote.h
===================================================================
--- uspace/lib/net/include/tl_remote.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/include/tl_remote.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -51,6 +51,6 @@
 /*@{*/
 
-extern int tl_received_msg(async_sess_t *, device_id_t, packet_t *, services_t,
-    services_t);
+extern int tl_received_msg(async_sess_t *, nic_device_id_t, packet_t *,
+    services_t, services_t);
 
 /*@}*/
Index: uspace/lib/net/netif/netif_remote.c
===================================================================
--- uspace/lib/net/netif/netif_remote.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,199 +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 libnet
- * @{
- */
-
-/** @file
- * Network interface module interface implementation for remote modules.
- */
-
-#include <netif_remote.h>
-#include <packet_client.h>
-#include <generic.h>
-#include <ipc/services.h>
-#include <ipc/netif.h>
-#include <net/modules.h>
-#include <adt/measured_strings.h>
-#include <net/packet.h>
-#include <net/device.h>
-
-/** Return the device local hardware address.
- *
- * @param[in]  sess      Network interface session.
- * @param[in]  device_id Device identifier.
- * @param[out] address   Device local hardware address.
- * @param[out] data      Address data.
- *
- * @return EOK on success.
- * @return EBADMEM if the address parameter is NULL.
- * @return ENOENT if there no such device.
- * @return Other error codes as defined for the
- *         netif_get_addr_message() function.
- *
- */
-int netif_get_addr_req(async_sess_t *sess, device_id_t device_id,
-    measured_string_t **address, uint8_t **data)
-{
-	return generic_get_addr_req(sess, NET_NETIF_GET_ADDR, device_id,
-	    address, data);
-}
-
-/** Probe the existence of the device.
- *
- * @param[in] sess      Network interface session.
- * @param[in] device_id Device identifier.
- * @param[in] irq       Device interrupt number.
- * @param[in] io        Device input/output address.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the
- *         netif_probe_message().
- *
- */
-int netif_probe_req(async_sess_t *sess, device_id_t device_id, int irq, void *io)
-{
-	async_exch_t *exch = async_exchange_begin(sess);
-	int rc = async_req_3_0(exch, NET_NETIF_PROBE, device_id, (sysarg_t) irq,
-	    (sysarg_t) io);
-	async_exchange_end(exch);
-	
-	return rc;
-}
-
-/** Send the packet queue.
- *
- * @param[in] sess      Network interface session.
- * @param[in] device_id Device identifier.
- * @param[in] packet    Packet queue.
- * @param[in] sender    Sending module service.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the generic_send_msg()
- *         function.
- *
- */
-int netif_send_msg(async_sess_t *sess, device_id_t device_id, packet_t *packet,
-    services_t sender)
-{
-	return generic_send_msg_remote(sess, NET_NETIF_SEND, device_id,
-	    packet_get_id(packet), sender, 0);
-}
-
-/** Start the device.
- *
- * @param[in] sess      Network interface session.
- * @param[in] device_id Device identifier.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the
- *         netif_start_message() function.
- *
- */
-int netif_start_req(async_sess_t *sess, device_id_t device_id)
-{
-	async_exch_t *exch = async_exchange_begin(sess);
-	int rc = async_req_1_0(exch, NET_NETIF_START, device_id);
-	async_exchange_end(exch);
-	
-	return rc;
-}
-
-/** Stop the device.
- *
- * @param[in] sess      Network interface session.
- * @param[in] device_id Device identifier.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the
- *         netif_stop_message() function.
- *
- */
-int netif_stop_req(async_sess_t *sess, device_id_t device_id)
-{
-	async_exch_t *exch = async_exchange_begin(sess);
-	int rc = async_req_1_0(exch, NET_NETIF_STOP, device_id);
-	async_exchange_end(exch);
-	
-	return rc;
-}
-
-/** Return the device usage statistics.
- *
- * @param[in]  sess      Network interface session.
- * @param[in]  device_id Device identifier.
- * @param[out] stats     Device usage statistics.
- *
- * @return EOK on success.
- *
- */
-int netif_stats_req(async_sess_t *sess, device_id_t device_id,
-    device_stats_t *stats)
-{
-	if (!stats)
-		return EBADMEM;
-	
-	async_exch_t *exch = async_exchange_begin(sess);
-	aid_t message_id = async_send_1(exch, NET_NETIF_STATS,
-	    (sysarg_t) device_id, NULL);
-	async_data_read_start(exch, stats, sizeof(*stats));
-	async_exchange_end(exch);
-	
-	sysarg_t result;
-	async_wait_for(message_id, &result);
-	
-	return (int) result;
-}
-
-/** Create bidirectional connection with the network interface module
- *
- * Create bidirectional connection with the network interface module and
- * register the message receiver.
- *
- * @param[in] service   Network interface module service.
- * @param[in] device_id Device identifier.
- * @param[in] me        Requesting module service.
- * @param[in] receiver  Message receiver.
- *
- * @return Session to the needed service.
- * @return NULL on failure.
- *
- */
-async_sess_t *netif_bind_service(services_t service, device_id_t device_id,
-    services_t me, async_client_conn_t receiver)
-{
-	return bind_service(service, device_id, me, 0, receiver);
-}
-
-/** @}
- */
Index: uspace/lib/net/netif/netif_skel.c
===================================================================
--- uspace/lib/net/netif/netif_skel.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,422 +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 libnet
- * @{
- */
-
-/** @file
- * Network interface module skeleton implementation.
- * @see netif_skel.h
- */
-
-#include <async.h>
-#include <mem.h>
-#include <fibril_synch.h>
-#include <stdio.h>
-#include <ipc/services.h>
-#include <ipc/netif.h>
-#include <errno.h>
-
-#include <generic.h>
-#include <net/modules.h>
-#include <net/packet.h>
-#include <packet_client.h>
-#include <packet_remote.h>
-#include <adt/measured_strings.h>
-#include <net/device.h>
-#include <netif_skel.h>
-#include <nil_remote.h>
-
-DEVICE_MAP_IMPLEMENT(netif_device_map, netif_device_t);
-
-/** Network interface global data. */
-netif_globals_t netif_globals;
-
-/** Probe the existence of the device.
- *
- * @param[in] device_id   Device identifier.
- * @param[in] irq         Device interrupt number.
- * @param[in] io          Device input/output address.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the
- *         netif_probe_message().
- *
- */
-static int netif_probe_req_local(device_id_t device_id, int irq, void *io)
-{
-	fibril_rwlock_write_lock(&netif_globals.lock);
-	int result = netif_probe_message(device_id, irq, io);
-	fibril_rwlock_write_unlock(&netif_globals.lock);
-	
-	return result;
-}
-
-/** Send the packet queue.
- *
- * @param[in] device_id   Device identifier.
- * @param[in] packet      Packet queue.
- * @param[in] sender      Sending module service.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the generic_send_msg()
- *         function.
- *
- */
-static int netif_send_msg_local(device_id_t device_id, packet_t *packet,
-    services_t sender)
-{
-	fibril_rwlock_write_lock(&netif_globals.lock);
-	int result = netif_send_message(device_id, packet, sender);
-	fibril_rwlock_write_unlock(&netif_globals.lock);
-	
-	return result;
-}
-
-/** Start the device.
- *
- * @param[in] device_id   Device identifier.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the
- *         netif_start_message() function.
- *
- */
-static int netif_start_req_local(device_id_t device_id)
-{
-	fibril_rwlock_write_lock(&netif_globals.lock);
-	
-	netif_device_t *device;
-	int rc = find_device(device_id, &device);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return rc;
-	}
-	
-	int result = netif_start_message(device);
-	if (result > NETIF_NULL) {
-		nil_device_state_msg(netif_globals.nil_sess, device_id, result);
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return EOK;
-	}
-	
-	fibril_rwlock_write_unlock(&netif_globals.lock);
-	
-	return result;
-}
-
-/** Stop the device.
- *
- * @param[in] device_id   Device identifier.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the
- *         netif_stop_message() function.
- *
- */
-static int netif_stop_req_local(device_id_t device_id)
-{
-	fibril_rwlock_write_lock(&netif_globals.lock);
-	
-	netif_device_t *device;
-	int rc = find_device(device_id, &device);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return rc;
-	}
-	
-	int result = netif_stop_message(device);
-	if (result > NETIF_NULL) {
-		nil_device_state_msg(netif_globals.nil_sess, device_id, result);
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return EOK;
-	}
-	
-	fibril_rwlock_write_unlock(&netif_globals.lock);
-	
-	return result;
-}
-
-/** Find the device specific data.
- *
- * @param[in]  device_id Device identifier.
- * @param[out] device    Device specific data.
- *
- * @return EOK on success.
- * @return ENOENT if device is not found.
- * @return EPERM if the device is not initialized.
- *
- */
-int find_device(device_id_t device_id, netif_device_t **device)
-{
-	if (!device)
-		return EBADMEM;
-	
-	*device = netif_device_map_find(&netif_globals.device_map, device_id);
-	if (*device == NULL)
-		return ENOENT;
-	
-	if ((*device)->state == NETIF_NULL)
-		return EPERM;
-	
-	return EOK;
-}
-
-/** Clear the usage statistics.
- *
- * @param[in] stats The usage statistics.
- *
- */
-void null_device_stats(device_stats_t *stats)
-{
-	bzero(stats, sizeof(device_stats_t));
-}
-
-/** Release the given packet.
- *
- * Prepared for future optimization.
- *
- * @param[in] packet_id The packet identifier.
- *
- */
-void netif_pq_release(packet_id_t packet_id)
-{
-	pq_release_remote(netif_globals.sess, packet_id);
-}
-
-/** Allocate new packet to handle the given content size.
- *
- * @param[in] content Minimum content size.
- *
- * @return The allocated packet.
- * @return NULL on error.
- *
- */
-packet_t *netif_packet_get_1(size_t content)
-{
-	return packet_get_1_remote(netif_globals.sess, content);
-}
-
-/** Register the device notification receiver,
- *
- * Register a network interface layer module as the device
- * notification receiver.
- *
- * @param[in] sess      Session to the network interface layer module.
- *
- * @return EOK on success.
- * @return ELIMIT if there is another module registered.
- *
- */
-static int register_message(async_sess_t *sess)
-{
-	fibril_rwlock_write_lock(&netif_globals.lock);
-	if (netif_globals.nil_sess != NULL) {
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return ELIMIT;
-	}
-	
-	netif_globals.nil_sess = sess;
-	
-	fibril_rwlock_write_unlock(&netif_globals.lock);
-	return EOK;
-}
-
-/** Process the netif module messages.
- *
- * @param[in]  callid Mmessage identifier.
- * @param[in]  call   Message.
- * @param[out] answer Answer.
- * @param[out] count  Number of arguments of the answer.
- *
- * @return EOK on success.
- * @return ENOTSUP if the message is unknown.
- * @return Other error codes as defined for each specific module
- *         message function.
- *
- * @see IS_NET_NETIF_MESSAGE()
- *
- */
-static int netif_module_message(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *count)
-{
-	size_t length;
-	device_stats_t stats;
-	packet_t *packet;
-	measured_string_t address;
-	int rc;
-	
-	*count = 0;
-	
-	if (!IPC_GET_IMETHOD(*call))
-		return EOK;
-	
-	async_sess_t *callback =
-	    async_callback_receive_start(EXCHANGE_SERIALIZE, call);
-	if (callback)
-		return register_message(callback);
-	
-	switch (IPC_GET_IMETHOD(*call)) {
-	case NET_NETIF_PROBE:
-		return netif_probe_req_local(IPC_GET_DEVICE(*call),
-		    NETIF_GET_IRQ(*call), NETIF_GET_IO(*call));
-	
-	case NET_NETIF_SEND:
-		rc = packet_translate_remote(netif_globals.sess, &packet,
-		    IPC_GET_PACKET(*call));
-		if (rc != EOK)
-			return rc;
-		
-		return netif_send_msg_local(IPC_GET_DEVICE(*call), packet,
-		    IPC_GET_SENDER(*call));
-	
-	case NET_NETIF_START:
-		return netif_start_req_local(IPC_GET_DEVICE(*call));
-	
-	case NET_NETIF_STATS:
-		fibril_rwlock_read_lock(&netif_globals.lock);
-		
-		rc = async_data_read_receive(&callid, &length);
-		if (rc != EOK) {
-			fibril_rwlock_read_unlock(&netif_globals.lock);
-			return rc;
-		}
-		
-		if (length < sizeof(device_stats_t)) {
-			fibril_rwlock_read_unlock(&netif_globals.lock);
-			return EOVERFLOW;
-		}
-		
-		rc = netif_get_device_stats(IPC_GET_DEVICE(*call), &stats);
-		if (rc == EOK) {
-			rc = async_data_read_finalize(callid, &stats,
-			    sizeof(device_stats_t));
-		}
-		
-		fibril_rwlock_read_unlock(&netif_globals.lock);
-		return rc;
-	
-	case NET_NETIF_STOP:
-		return netif_stop_req_local(IPC_GET_DEVICE(*call));
-	
-	case NET_NETIF_GET_ADDR:
-		fibril_rwlock_read_lock(&netif_globals.lock);
-		
-		rc = netif_get_addr_message(IPC_GET_DEVICE(*call), &address);
-		if (rc == EOK)
-			rc = measured_strings_reply(&address, 1);
-		
-		fibril_rwlock_read_unlock(&netif_globals.lock);
-		return rc;
-	}
-	
-	return netif_specific_message(callid, call, answer, count);
-}
-
-/** Default fibril for new module connections.
- *
- * @param[in] iid   Initial message identifier.
- * @param[in] icall Initial message call structure.
- *
- */
-static void netif_client_connection(ipc_callid_t iid, ipc_call_t *icall,
-    void *arg)
-{
-	/*
-	 * Accept the connection by answering
-	 * the initial IPC_M_CONNECT_ME_TO call.
-	 */
-	async_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_call_t answer;
-		size_t count;
-		
-		/* Clear the answer structure */
-		refresh_answer(&answer, &count);
-		
-		/* Fetch the next message */
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		/* Process the message */
-		int res = netif_module_message(callid, &call, &answer, &count);
-		
-		/* End if said to either by the message or the processing result */
-		if ((!IPC_GET_IMETHOD(call)) || (res == EHANGUP))
-			return;
-		
-		/* Answer the message */
-		answer_call(callid, res, &answer, count);
-	}
-}
-
-/** Start the network interface module.
- *
- * Initialize the client connection serving function, initialize the module,
- * registers the module service and start the async manager, processing IPC
- * messages in an infinite loop.
- *
- * @return EOK on success.
- * @return Other error codes as defined for each specific module
- *         message function.
- *
- */
-int netif_module_start(void)
-{
-	async_set_client_connection(netif_client_connection);
-	
-	netif_globals.sess = connect_to_service(SERVICE_NETWORKING);
-	netif_globals.nil_sess = NULL;
-	netif_device_map_initialize(&netif_globals.device_map);
-	
-	int rc = pm_init();
-	if (rc != EOK)
-		return rc;
-	
-	fibril_rwlock_initialize(&netif_globals.lock);
-	
-	rc = netif_initialize();
-	if (rc != EOK) {
-		pm_destroy();
-		return rc;
-	}
-	
-	async_manager();
-	
-	pm_destroy();
-	return EOK;
-}
-
-/** @}
- */
Index: uspace/lib/net/nil/nil_remote.c
===================================================================
--- uspace/lib/net/nil/nil_remote.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/nil/nil_remote.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -54,5 +54,5 @@
  *
  */
-int nil_device_state_msg(async_sess_t *sess, device_id_t device_id,
+int nil_device_state_msg(async_sess_t *sess, nic_device_id_t device_id,
     sysarg_t state)
 {
@@ -76,9 +76,44 @@
  *
  */
-int nil_received_msg(async_sess_t *sess, device_id_t device_id,
-    packet_t *packet, services_t target)
+int nil_received_msg(async_sess_t *sess, nic_device_id_t device_id,
+    packet_id_t packet_id)
 {
 	return generic_received_msg_remote(sess, NET_NIL_RECEIVED,
-	    device_id, packet_get_id(packet), target, 0);
+	    device_id, packet_id, 0, 0);
+}
+
+/** Notify upper layers that device address has changed
+ *
+ */
+int nil_addr_changed_msg(async_sess_t *sess, nic_device_id_t device_id,
+    const nic_address_t *address)
+{
+	assert(sess);
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	aid_t message_id = async_send_1(exch, NET_NIL_ADDR_CHANGED,
+	    (sysarg_t) device_id, NULL);
+	int rc = async_data_write_start(exch, address, sizeof (nic_address_t));
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+    async_wait_for(message_id, &res);
+	
+    if (rc != EOK)
+		return rc;
+	
+    return (int) res;
+}
+
+int nil_device_req(async_sess_t *sess, nic_device_id_t device_id,
+    devman_handle_t handle, size_t mtu)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_0(exch, NET_NIL_DEVICE, (sysarg_t) device_id,
+	    (sysarg_t) handle, (sysarg_t) mtu);
+	async_exchange_end(exch);
+	return rc;
 }
 
Index: uspace/lib/net/tl/icmp_client.c
===================================================================
--- uspace/lib/net/tl/icmp_client.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/tl/icmp_client.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -39,12 +39,6 @@
 #include <icmp_header.h>
 #include <packet_client.h>
-
-#ifdef CONFIG_DEBUG
-#include <stdio.h>
-#endif
-
 #include <errno.h>
 #include <sys/types.h>
-
 #include <net/icmp_codes.h>
 #include <net/packet.h>
@@ -60,6 +54,5 @@
  * @return		Zero if the packet contains no data.
  */
-int
-icmp_client_process_packet(packet_t *packet, icmp_type_t *type,
+int icmp_client_process_packet(packet_t *packet, icmp_type_t *type,
     icmp_code_t *code, icmp_param_t *pointer, icmp_param_t *mtu)
 {
@@ -81,9 +74,4 @@
 		*mtu = header->un.frag.mtu;
 
-	/* Remove debug dump */
-#ifdef CONFIG_DEBUG
-	printf("ICMP error %d (%d) in packet %d\n", header->type, header->code,
-	    packet_get_id(packet));
-#endif
 	return sizeof(icmp_header_t);
 }
Index: uspace/lib/net/tl/tl_common.c
===================================================================
--- uspace/lib/net/tl/tl_common.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/tl/tl_common.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -119,5 +119,5 @@
  */
 int tl_get_ip_packet_dimension(async_sess_t *sess,
-    packet_dimensions_t *packet_dimensions, device_id_t device_id,
+    packet_dimensions_t *packet_dimensions, nic_device_id_t device_id,
     packet_dimension_t **packet_dimension)
 {
@@ -158,7 +158,6 @@
  * @return		ENOENT if the packet dimension is not cached.
  */
-int
-tl_update_ip_packet_dimension(packet_dimensions_t *packet_dimensions,
-    device_id_t device_id, size_t content)
+int tl_update_ip_packet_dimension(packet_dimensions_t *packet_dimensions,
+    nic_device_id_t device_id, size_t content)
 {
 	packet_dimension_t *packet_dimension;
@@ -170,7 +169,7 @@
 	packet_dimension->content = content;
 
-	if (device_id != DEVICE_INVALID_ID) {
+	if (device_id != NIC_DEVICE_INVALID_ID) {
 		packet_dimension = packet_dimensions_find(packet_dimensions,
-		    DEVICE_INVALID_ID);
+		    NIC_DEVICE_INVALID_ID);
 
 		if (packet_dimension) {
@@ -179,5 +178,5 @@
 			else
 				packet_dimensions_exclude(packet_dimensions,
-				    DEVICE_INVALID_ID, free);
+				    NIC_DEVICE_INVALID_ID, free);
 		}
 	}
Index: uspace/lib/net/tl/tl_remote.c
===================================================================
--- uspace/lib/net/tl/tl_remote.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/tl/tl_remote.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -56,5 +56,5 @@
  *
  */
-int tl_received_msg(async_sess_t *sess, device_id_t device_id, packet_t *packet,
+int tl_received_msg(async_sess_t *sess, nic_device_id_t device_id, packet_t *packet,
     services_t target, services_t error)
 {
Index: uspace/lib/net/tl/tl_skel.c
===================================================================
--- uspace/lib/net/tl/tl_skel.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/net/tl/tl_skel.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -123,4 +123,5 @@
 		goto out;
 	
+	task_retval(0);
 	async_manager();
 	
Index: uspace/lib/nic/Makefile
===================================================================
--- uspace/lib/nic/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,41 @@
+#
+# 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 = ../..
+LIBRARY = libnic
+LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBNET_PREFIX)/libnet.a
+EXTRA_CFLAGS += -DLIBNIC_INTERNAL -Iinclude -I$(LIBDRV_PREFIX)/include -I$(LIBNET_PREFIX)/include
+
+SOURCES = \
+	src/nic_driver.c \
+	src/nic_addr_db.c \
+	src/nic_rx_control.c \
+	src/nic_wol_virtues.c \
+	src/nic_impl.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/nic/include/nic.h
===================================================================
--- uspace/lib/nic/include/nic.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/include/nic.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,283 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Public header exposing NICF to drivers
+ */
+
+#ifndef __NIC_H__
+#define __NIC_H__
+
+#include <adt/list.h>
+#include <ddf/driver.h>
+#include <device/hw_res_parsed.h>
+#include <net/packet.h>
+#include <ops/nic.h>
+
+struct nic;
+typedef struct nic nic_t;
+
+/**
+ * Single WOL virtue descriptor.
+ */
+typedef struct nic_wol_virtue {
+	link_t item;
+	nic_wv_id_t id;
+	nic_wv_type_t type;
+	const void *data;
+	size_t length;
+	struct nic_wol_virtue *next;
+} nic_wol_virtue_t;
+
+/**
+ * Simple structure for sending the allocated frames (packets) in a list.
+ */
+typedef struct {
+	link_t link;
+	packet_t *packet;
+} nic_frame_t;
+
+typedef list_t nic_frame_list_t;
+
+/**
+ * Handler for writing packet data to the NIC device.
+ * The function is responsible for releasing the packet.
+ * It does not return anything, if some error is detected the function just
+ * silently fails (logging on debug level is suggested).
+ *
+ * @param nic_data
+ * @param packet	Pointer to the packet to be sent
+ */
+typedef void (*write_packet_handler)(nic_t *, packet_t *);
+/**
+ * The handler for transitions between driver states.
+ * If the handler returns negative error code, the transition between
+ * states is canceled (the state is not changed).
+ *
+ * @param nic_data	NICF main structure
+ *
+ * @return EOK	If everything is all right.
+ * @return negative error code on error.
+ */
+typedef int (*state_change_handler)(nic_t *);
+/**
+ * Handler for unicast filtering mode change.
+ *
+ * @param nic_data		NICF main structure
+ * @param new_mode		The mode that should be set up
+ * @param address_list	Addresses as argument to the mode
+ * @param address_count	Number of addresses in the list
+ *
+ * @return EOK		If the mode is set up
+ * @return ENOTSUP	If this mode is not supported
+ */
+typedef int (*unicast_mode_change_handler)(nic_t *,
+	nic_unicast_mode_t, const nic_address_t *, size_t);
+/**
+ * Handler for multicast filtering mode change.
+ *
+ * @param nic_data		NICF main structure
+ * @param new_mode		The mode that should be set up
+ * @param address_list	Addresses as argument to the mode
+ * @param address_count	Number of addresses in the list
+ *
+ * @return EOK		If the mode is set up
+ * @return ENOTSUP	If this mode is not supported
+ */
+typedef int (*multicast_mode_change_handler)(nic_t *,
+	nic_multicast_mode_t, const nic_address_t *, size_t);
+/**
+ * Handler for broadcast filtering mode change.
+ *
+ * @param nic_data	NICF main structure
+ * @param new_mode	The mode that should be set up
+ *
+ * @return EOK		If the mode is set up
+ * @return ENOTSUP	If this mode is not supported
+ */
+typedef int (*broadcast_mode_change_handler)(nic_t *, nic_broadcast_mode_t);
+/**
+ * Handler for blocked sources list change.
+ *
+ * @param nic_data		NICF main structure
+ * @param address_list	Addresses as argument to the mode
+ * @param address_count	Number of addresses in the list
+ */
+typedef void (*blocked_sources_change_handler)(nic_t *,
+	const nic_address_t *, size_t);
+/**
+ * Handler for VLAN filtering mask change.
+ * @param nic_data		NICF main structure
+ * @param vlan_mask		The new mask | NULL for disabling vlan filter
+ */
+typedef void (*vlan_mask_change_handler)(nic_t *, const nic_vlan_mask_t *);
+/**
+ * Handler called when a WOL virtue is added.
+ * If the maximum of accepted WOL virtues changes due to adding this virtue
+ * you should update the vector wol_virtues.caps_max.
+ * The driver is allowed to store pointer to the virtue data until
+ * on_wol_virtue_remove on these data is called (although probably this is
+ * not a good practice).
+ *
+ * @param nic_data	NICF main structure
+ * @param virtue	Structure with virtue description
+ *
+ * @return EOK		If the filter can be used. Software emulation of the
+ * 					filter is activated unless the emulate is set to 0.
+ * @return ENOTSUP	If this filter cannot work on this NIC (e.g. the NIC
+ * 					cannot run in promiscuous node or the limit of WOL
+ * 					packets' specifications was reached).
+ * @return ELIMIT	If this filter must implemented in HW but currently the
+ * 					limit of these HW filters was reached.
+ */
+typedef int (*wol_virtue_add_handler)(nic_t *, const nic_wol_virtue_t *);
+/**
+ * Handler called when a WOL virtue is removed.
+ * If the maximum of accepted WOL virtues changes due to removing this
+ * virtue you should update the vector wol_virtues.caps_max.
+ *
+ * @param nic_data	NICF main structure
+ * @param virtue		Structure with virtue description
+ */
+typedef void (*wol_virtue_remove_handler)(nic_t *, const nic_wol_virtue_t *);
+/**
+ * Handler for poll mode change.
+ *
+ * @param nic_data	NICF main structure
+ * @param mode		Mode to be set up
+ * @param period	New period of polling (with NIC_POLL_PERIODIC)
+ *
+ * @return EOK		If the mode was fully setup
+ * @return ENOTSUP	If NICF should do the periodic polling
+ * @return EINVAL	If this mode cannot be set up under no circumstances
+ */
+typedef int (*poll_mode_change_handler)(nic_t *,
+	nic_poll_mode_t, const struct timeval *);
+/**
+ * Event handler called when the NIC should poll its buffers for a new frame
+ * (in NIC_POLL_PERIODIC or NIC_POLL_ON_DEMAND) modes.
+ *
+ * @param nic_data	NICF main structure
+ */
+typedef void (*poll_request_handler)(nic_t *);
+
+/* nic_t allocation and deallocation */
+extern nic_t *nic_create_and_bind(ddf_dev_t *);
+extern void nic_unbind_and_destroy(ddf_dev_t *);
+
+/* Functions called in the main function */
+extern int nic_driver_init(const char *);
+extern void nic_driver_implement(driver_ops_t *, ddf_dev_ops_t *,
+	nic_iface_t *);
+
+/* Functions called in add_device */
+extern int nic_connect_to_services(nic_t *);
+extern int nic_register_as_ddf_fun(nic_t *, ddf_dev_ops_t *);
+extern int nic_get_resources(nic_t *, hw_res_list_parsed_t *);
+extern void nic_set_specific(nic_t *, void *);
+extern void nic_set_write_packet_handler(nic_t *, write_packet_handler);
+extern void nic_set_state_change_handlers(nic_t *,
+	state_change_handler, state_change_handler, state_change_handler);
+extern void nic_set_filtering_change_handlers(nic_t *,
+	unicast_mode_change_handler, multicast_mode_change_handler,
+	broadcast_mode_change_handler, blocked_sources_change_handler,
+	vlan_mask_change_handler);
+extern void nic_set_wol_virtue_change_handlers(nic_t *,
+	wol_virtue_add_handler, wol_virtue_remove_handler);
+extern void nic_set_poll_handlers(nic_t *,
+	poll_mode_change_handler, poll_request_handler);
+
+/* Functions called in device_added */
+extern int nic_ready(nic_t *);
+
+/* General driver functions */
+extern ddf_dev_t *nic_get_ddf_dev(nic_t *);
+extern ddf_fun_t *nic_get_ddf_fun(nic_t *);
+extern nic_t *nic_get_from_ddf_dev(ddf_dev_t *);
+extern nic_t *nic_get_from_ddf_fun(ddf_fun_t *);
+extern void *nic_get_specific(nic_t *);
+extern nic_device_state_t nic_query_state(nic_t *);
+extern void nic_set_tx_busy(nic_t *, int);
+extern int nic_report_address(nic_t *, const nic_address_t *);
+extern int nic_report_poll_mode(nic_t *, nic_poll_mode_t, struct timeval *);
+extern void nic_query_address(nic_t *, nic_address_t *);
+extern void nic_received_packet(nic_t *, packet_t *);
+extern void nic_received_noneth_packet(nic_t *, packet_t *);
+extern void nic_received_frame(nic_t *, nic_frame_t *);
+extern void nic_received_frame_list(nic_t *, nic_frame_list_t *);
+extern void nic_disable_interrupt(nic_t *, int);
+extern void nic_enable_interrupt(nic_t *, int);
+extern nic_poll_mode_t nic_query_poll_mode(nic_t *, struct timeval *);
+
+/* Statistics updates */
+extern void nic_report_send_ok(nic_t *, size_t, size_t);
+extern void nic_report_send_error(nic_t *, nic_send_error_cause_t, unsigned);
+extern void nic_report_receive_error(nic_t *, nic_receive_error_cause_t,
+    unsigned);
+extern void nic_report_collisions(nic_t *, unsigned);
+
+/* Packet / frame / frame list allocation and deallocation */
+extern packet_t *nic_alloc_packet(nic_t *, size_t);
+extern void nic_release_packet(nic_t *, packet_t *);
+extern nic_frame_t *nic_alloc_frame(nic_t *, size_t);
+extern nic_frame_list_t *nic_alloc_frame_list(void);
+extern void nic_frame_list_append(nic_frame_list_t *, nic_frame_t *);
+extern void nic_release_frame(nic_t *, nic_frame_t *);
+
+/* RXC query and report functions */
+extern void nic_report_hw_filtering(nic_t *, int, int, int);
+extern void nic_query_unicast(const nic_t *,
+	nic_unicast_mode_t *, size_t, nic_address_t *, size_t *);
+extern void nic_query_multicast(const nic_t *,
+	nic_multicast_mode_t *, size_t, nic_address_t *, size_t *);
+extern void nic_query_broadcast(const nic_t *, nic_broadcast_mode_t *);
+extern void nic_query_blocked_sources(const nic_t *,
+	size_t, nic_address_t *, size_t *);
+extern int nic_query_vlan_mask(const nic_t *, nic_vlan_mask_t *);
+extern int nic_query_wol_max_caps(const nic_t *, nic_wv_type_t);
+extern void nic_set_wol_max_caps(nic_t *, nic_wv_type_t, int);
+extern uint64_t nic_mcast_hash(const nic_address_t *, size_t);
+extern uint64_t nic_query_mcast_hash(nic_t *);
+
+/* Software period functions */
+extern void nic_sw_period_start(nic_t *);
+extern void nic_sw_period_stop(nic_t *);
+
+/* Packet DMA lock */
+extern void * nic_dma_lock_packet(packet_t * packet);
+extern void nic_dma_unlock_packet(packet_t * packet);
+
+#endif // __NIC_H__
+
+/** @}
+ */
Index: uspace/lib/nic/include/nic_addr_db.h
===================================================================
--- uspace/lib/nic/include/nic_addr_db.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/include/nic_addr_db.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Generic hash-set based database of addresses
+ */
+
+#ifndef __NIC_ADDR_DB_H__
+#define __NIC_ADDR_DB_H__
+
+#ifndef LIBNIC_INTERNAL
+#error "This is internal libnic header, please don't include it"
+#endif
+
+#include <adt/hash_set.h>
+
+/**
+ * Initial size of DB's hash set
+ */
+#define NIC_ADDR_DB_INIT_SIZE 	8
+/**
+ * Maximal length of addresses in the DB (in bytes).
+ */
+#define NIC_ADDR_MAX_LENGTH		16
+
+/**
+ * Fibril-safe database of addresses implemented using hash set.
+ */
+typedef struct nic_addr_db {
+	hash_set_t set;
+	size_t addr_len;
+} nic_addr_db_t;
+
+/**
+ * Helper structure for keeping the address in the hash set.
+ */
+typedef struct nic_addr_entry {
+	link_t item;
+	size_t addr_len;
+	uint8_t addr[NIC_ADDR_MAX_LENGTH];
+} nic_addr_entry_t;
+
+extern int nic_addr_db_init(nic_addr_db_t *db, size_t addr_len);
+extern void nic_addr_db_clear(nic_addr_db_t *db);
+extern void nic_addr_db_destroy(nic_addr_db_t *db);
+extern size_t nic_addr_db_count(const nic_addr_db_t *db);
+extern int nic_addr_db_insert(nic_addr_db_t *db, const uint8_t *addr);
+extern int nic_addr_db_remove(nic_addr_db_t *db, const uint8_t *addr);
+extern void nic_addr_db_remove_selected(nic_addr_db_t *db,
+	int (*func)(const uint8_t *, void *), void *arg);
+extern int nic_addr_db_contains(const nic_addr_db_t *db, const uint8_t *addr);
+extern void nic_addr_db_foreach(const nic_addr_db_t *db,
+	void (*func)(const uint8_t *, void *), void *arg);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/include/nic_driver.h
===================================================================
--- uspace/lib/nic/include/nic_driver.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/include/nic_driver.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Internal NICF structures
+ */
+
+#ifndef __NIC_DRIVER_H__
+#define __NIC_DRIVER_H__
+
+#ifndef LIBNIC_INTERNAL
+#error "This is internal libnic's header, please do not include it"
+#endif
+
+#include <fibril_synch.h>
+#include <net/device.h>
+#include <async.h>
+
+#include "nic.h"
+#include "nic_rx_control.h"
+#include "nic_wol_virtues.h"
+
+#define DEVICE_CATEGORY_NIC "nic"
+
+struct sw_poll_info {
+	fid_t fibril;
+	volatile int run;
+	volatile int running;
+};
+
+struct nic {
+	/**
+	 * Device from device manager's point of view.
+	 * The value must be set within the add_device handler
+	 * (in nic_create_and_bind) and must not be changed.
+	 */
+	ddf_dev_t *dev;
+	/**
+	 * Device's NIC function.
+	 * The value must be set within the add_device handler
+	 * (in nic_driver_register_as_ddf_function) and must not be changed.
+	 */
+	ddf_fun_t *fun;
+	/** Identifier for higher network stack layers */
+	nic_device_id_t device_id;
+	/** Current state of the device */
+	nic_device_state_t state;
+	/** Transmiter is busy - messages are dropped */
+	int tx_busy;
+	/** Device's MAC address */
+	nic_address_t mac;
+	/** Device's default MAC address (assigned the first time, used in STOP) */
+	nic_address_t default_mac;
+	/** Session to SERVICE_NETWORKING */
+	async_sess_t *net_session;
+	/** Session to SERVICE_ETHERNET or SERVICE_NILDUMMY */
+	async_sess_t *nil_session;
+	/** Phone to APIC or i8259 */
+	async_sess_t *irc_session;
+	/** Current polling mode of the NIC */
+	nic_poll_mode_t poll_mode;
+	/** Polling period (applicable when poll_mode == NIC_POLL_PERIODIC) */
+	struct timeval poll_period;
+	/** Current polling mode of the NIC */
+	nic_poll_mode_t default_poll_mode;
+	/** Polling period (applicable when default_poll_mode == NIC_POLL_PERIODIC) */
+	struct timeval default_poll_period;
+	/** Software period fibrill information */
+	struct sw_poll_info sw_poll_info;
+	/**
+	 * Lock on everything but statistics, rx control and wol virtues. This lock
+	 * cannot be used if filters_lock or stats_lock is already held - you must
+	 * acquire main_lock first (otherwise deadlock could happen).
+	 */
+	fibril_rwlock_t main_lock;
+	/** Device statistics */
+	nic_device_stats_t stats;
+	/**
+	 * Lock for statistics. You must not hold any other lock from nic_t except
+	 * the main_lock at the same moment. If both this lock and main_lock should
+	 * be locked, the main_lock must be locked as the first.
+	 */
+	fibril_rwlock_t stats_lock;
+	/** Receive control configuration */
+	nic_rxc_t rx_control;
+	/**
+	 * Lock for receive control. You must not hold any other lock from nic_t
+	 * except the main_lock at the same moment. If both this lock and main_lock
+	 * should be locked, the main_lock must be locked as the first.
+	 */
+	fibril_rwlock_t rxc_lock;
+	/** WOL virtues configuration */
+	nic_wol_virtues_t wol_virtues;
+	/**
+	 * Lock for WOL virtues. You must not hold any other lock from nic_t
+	 * except the main_lock at the same moment. If both this lock and main_lock
+	 * should be locked, the main_lock must be locked as the first.
+	 */
+	fibril_rwlock_t wv_lock;
+	/**
+	 * Function really sending the data. This MUST be filled in if the 
+	 * nic_send_message_impl function is used for sending messages (filled 
+	 * as send_message member of the nic_iface_t structure).
+	 * Called with the main_lock locked for reading.
+	 */
+	write_packet_handler write_packet;
+	/**
+	 * Event handler called when device goes to the ACTIVE state.
+	 * The implementation is optional.
+	 * Called with the main_lock locked for writing.
+	 */
+	state_change_handler on_activating;
+	/**
+	 * Event handler called when device goes to the DOWN state.
+	 * The implementation is optional.
+	 * Called with the main_lock locked for writing.
+	 */
+	state_change_handler on_going_down;
+	/**
+	 * Event handler called when device goes to the STOPPED state.
+	 * The implementation is optional.
+	 * Called with the main_lock locked for writing.
+	 */
+	state_change_handler on_stopping;
+	/**
+	 * Event handler called when the unicast receive mode is changed.
+	 * The implementation is optional. Called with rxc_lock locked for writing.
+	 */
+	unicast_mode_change_handler on_unicast_mode_change;
+	/**
+	 * Event handler called when the multicast receive mode is changed.
+	 * The implementation is optional. Called with rxc_lock locked for writing.
+	 */
+	multicast_mode_change_handler on_multicast_mode_change;
+	/**
+	 * Event handler called when the broadcast receive mode is changed.
+	 * The implementation is optional. Called with rxc_lock locked for writing.
+	 */
+	broadcast_mode_change_handler on_broadcast_mode_change;
+	/**
+	 * Event handler called when the blocked sources set is changed.
+	 * The implementation is optional. Called with rxc_lock locked for writing.
+	 */
+	blocked_sources_change_handler on_blocked_sources_change;
+	/**
+	 * Event handler called when the VLAN mask is changed.
+	 * The implementation is optional. Called with rxc_lock locked for writing.
+	 */
+	vlan_mask_change_handler on_vlan_mask_change;
+	/**
+	 * Event handler called when a new WOL virtue is added.
+	 * The implementation is optional.
+	 * Called with filters_lock locked for writing.
+	 */
+	wol_virtue_add_handler on_wol_virtue_add;
+	/**
+	 * Event handler called when a WOL virtue is removed.
+	 * The implementation is optional.
+	 * Called with filters_lock locked for writing.
+	 */
+	wol_virtue_remove_handler on_wol_virtue_remove;
+	/**
+	 * Event handler called when the polling mode is changed.
+	 * The implementation is optional.
+	 * Called with main_lock locked for writing.
+	 */
+	poll_mode_change_handler on_poll_mode_change;
+	/**
+	 * Event handler called when the NIC should poll its buffers for a new frame
+	 * (in NIC_POLL_PERIODIC or NIC_POLL_ON_DEMAND) modes.
+	 * Called with the main_lock locked for reading.
+	 * The implementation is optional.
+	 */
+	poll_request_handler on_poll_request;
+	/** Data specific for particular driver */
+	void *specific;
+};
+
+/**
+ * Structure keeping global data
+ */
+typedef struct nic_globals {
+	list_t frame_list_cache;
+	size_t frame_list_cache_size;
+	list_t frame_cache;
+	size_t frame_cache_size;
+	fibril_mutex_t lock;
+} nic_globals_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/include/nic_impl.h
===================================================================
--- uspace/lib/nic/include/nic_impl.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/include/nic_impl.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Prototypes of default DDF NIC interface methods implementations
+ */
+
+#ifndef NIC_IMPL_H__
+#define NIC_IMPL_H__
+
+#include <assert.h>
+#include <net/device.h>
+#include <ddf/driver.h>
+#include <nil_remote.h>
+
+/* Inclusion of this file is not prohibited, because drivers could want to
+ * inject some adaptation layer between the DDF call and NICF implementation */
+
+extern int nic_get_address_impl(ddf_fun_t *dev_fun, nic_address_t *address);
+extern int nic_send_message_impl(ddf_fun_t *dev_fun, packet_id_t packet_id);
+extern int nic_connect_to_nil_impl(ddf_fun_t *dev_fun, services_t nil_service,
+	int device_id);
+extern int nic_get_state_impl(ddf_fun_t *dev_fun, nic_device_state_t *state);
+extern int nic_set_state_impl(ddf_fun_t *dev_fun, nic_device_state_t state);
+extern int nic_get_stats_impl(ddf_fun_t *dev_fun, nic_device_stats_t *stats);
+extern int nic_unicast_get_mode_impl(ddf_fun_t *dev_fun,
+	nic_unicast_mode_t *, size_t, nic_address_t *, size_t *);
+extern int nic_unicast_set_mode_impl(ddf_fun_t *dev_fun,
+	nic_unicast_mode_t, const nic_address_t *, size_t);
+extern int nic_multicast_get_mode_impl(ddf_fun_t *dev_fun,
+	nic_multicast_mode_t *, size_t, nic_address_t *, size_t *);
+extern int nic_multicast_set_mode_impl(ddf_fun_t *dev_fun,
+	nic_multicast_mode_t, const nic_address_t *, size_t);
+extern int nic_broadcast_get_mode_impl(ddf_fun_t *, nic_broadcast_mode_t *);
+extern int nic_broadcast_set_mode_impl(ddf_fun_t *, nic_broadcast_mode_t);
+extern int nic_blocked_sources_get_impl(ddf_fun_t *,
+	size_t, nic_address_t *, size_t *);
+extern int nic_blocked_sources_set_impl(ddf_fun_t *, const nic_address_t *, size_t);
+extern int nic_vlan_get_mask_impl(ddf_fun_t *, nic_vlan_mask_t *);
+extern int nic_vlan_set_mask_impl(ddf_fun_t *, const nic_vlan_mask_t *);
+extern int nic_wol_virtue_add_impl(ddf_fun_t *dev_fun, nic_wv_type_t type,
+	const void *data, size_t length, nic_wv_id_t *new_id);
+extern int nic_wol_virtue_remove_impl(ddf_fun_t *dev_fun, nic_wv_id_t id);
+extern int nic_wol_virtue_probe_impl(ddf_fun_t *dev_fun, nic_wv_id_t id,
+	nic_wv_type_t *type, size_t max_length, void *data, size_t *length);
+extern int nic_wol_virtue_list_impl(ddf_fun_t *dev_fun, nic_wv_type_t type,
+	size_t max_count, nic_wv_id_t *id_list, size_t *id_count);
+extern int nic_wol_virtue_get_caps_impl(ddf_fun_t *, nic_wv_type_t, int *);
+extern int nic_poll_get_mode_impl(ddf_fun_t *,
+	nic_poll_mode_t *, struct timeval *);
+extern int nic_poll_set_mode_impl(ddf_fun_t *,
+	nic_poll_mode_t, const struct timeval *);
+extern int nic_poll_now_impl(ddf_fun_t *);
+
+extern void nic_default_handler_impl(ddf_fun_t *dev_fun,
+	ipc_callid_t callid, ipc_call_t *call);
+extern int nic_open_impl(ddf_fun_t *fun);
+extern void nic_close_impl(ddf_fun_t *fun);
+
+extern void nic_device_added_impl(ddf_dev_t *dev);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/include/nic_rx_control.h
===================================================================
--- uspace/lib/nic/include/nic_rx_control.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/include/nic_rx_control.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Incoming packets (frames) filtering control structures
+ */
+
+#ifndef __NIC_FILTERS_H__
+#define __NIC_FILTERS_H__
+
+#ifndef LIBNIC_INTERNAL
+#error "This is internal libnic's header, please do not include it"
+#endif
+
+#include <adt/hash_table.h>
+#include <fibril_synch.h>
+#include <net/device.h>
+#include <net/packet_header.h>
+
+#include "nic_addr_db.h"
+
+/**
+ * General structure describing receive control.
+ * The structure is not synchronized inside, the nic_driver should provide
+ * a synchronized facade.
+ */
+typedef struct nic_rxc {
+	/**
+	 * Allowed unicast destination MAC addresses
+	 */
+	nic_addr_db_t unicast_addrs;
+	/**
+	 * Allowed unicast destination MAC addresses
+	 */
+	nic_addr_db_t multicast_addrs;
+	/**
+	 * Single flag if any source is blocked
+	 */
+	int block_sources;
+	/**
+	 * Blocked source MAC addresses
+	 */
+	nic_addr_db_t blocked_sources;
+	/**
+	 * Selected mode for unicast frames
+	 */
+	nic_unicast_mode_t unicast_mode;
+	/**
+	 * Selected mode for multicast frames
+	 */
+	nic_multicast_mode_t multicast_mode;
+	/**
+	 * Selected mode for broadcast frames
+	 */
+	nic_broadcast_mode_t broadcast_mode;
+	/**
+	 * Mask for VLAN tags. This vector must be at least 512 bytes long.
+	 */
+	nic_vlan_mask_t *vlan_mask;
+	/**
+	 * If true, the NIC is receiving only unicast frames which we really want to
+	 * receive (the filtering is perfect).
+	 */
+	int unicast_exact;
+	/**
+	 * If true, the NIC is receiving only multicast frames which we really want
+	 * to receive (the filtering is perfect).
+	 */
+	int multicast_exact;
+	/**
+	 * If true, the NIC is receiving only frames with VLAN tags which we really
+	 * want to receive (the filtering is perfect).
+	 */
+	int vlan_exact;
+} nic_rxc_t;
+
+#define VLAN_TPID_UPPER 0x81
+#define VLAN_TPID_LOWER 0x00
+
+typedef struct vlan_header {
+	uint8_t tpid_upper;
+	uint8_t tpid_lower;
+	uint8_t vid_upper;
+	uint8_t vid_lower;
+} __attribute__ ((packed)) vlan_header_t;
+
+extern int nic_rxc_init(nic_rxc_t *rxc);
+extern int nic_rxc_clear(nic_rxc_t *rxc);
+extern int nic_rxc_set_addr(nic_rxc_t *rxc,
+	const nic_address_t *prev_addr, const nic_address_t *curr_addr);
+extern int nic_rxc_check(const nic_rxc_t *rxc,
+	const packet_t *packet, nic_frame_type_t *frame_type);
+extern void nic_rxc_hw_filtering(nic_rxc_t *rxc,
+	int unicast_exact, int multicast_exact, int vlan_exact);
+extern uint64_t nic_rxc_mcast_hash(const nic_address_t *list, size_t count);
+extern uint64_t nic_rxc_multicast_get_hash(const nic_rxc_t *rxc);
+extern void nic_rxc_unicast_get_mode(const nic_rxc_t *, nic_unicast_mode_t *,
+	size_t max_count, nic_address_t *address_list, size_t *address_count);
+extern int nic_rxc_unicast_set_mode(nic_rxc_t *rxc, nic_unicast_mode_t mode,
+	const nic_address_t *address_list, size_t address_count);
+extern void nic_rxc_multicast_get_mode(const nic_rxc_t *,
+	nic_multicast_mode_t *, size_t, nic_address_t *, size_t *);
+extern int nic_rxc_multicast_set_mode(nic_rxc_t *, nic_multicast_mode_t mode,
+	const nic_address_t *address_list, size_t address_count);
+extern void nic_rxc_broadcast_get_mode(const nic_rxc_t *,
+	nic_broadcast_mode_t *mode);
+extern int nic_rxc_broadcast_set_mode(nic_rxc_t *,
+	nic_broadcast_mode_t mode);
+extern void nic_rxc_blocked_sources_get(const nic_rxc_t *,
+	size_t max_count, nic_address_t *address_list, size_t *address_count);
+extern int nic_rxc_blocked_sources_set(nic_rxc_t *,
+	const nic_address_t *address_list, size_t address_count);
+extern int nic_rxc_vlan_get_mask(const nic_rxc_t *rxc, nic_vlan_mask_t *mask);
+extern int nic_rxc_vlan_set_mask(nic_rxc_t *rxc, const nic_vlan_mask_t *mask);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/include/nic_wol_virtues.h
===================================================================
--- uspace/lib/nic/include/nic_wol_virtues.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/include/nic_wol_virtues.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Wake-on-LAN support
+ */
+
+#ifndef __NIC_WOL_VIRTUES_H__
+#define __NIC_WOL_VIRTUES_H__
+
+#ifndef LIBNIC_INTERNAL
+#error "This is internal libnic's header, please do not include it"
+#endif
+
+#include <net/device.h>
+#include <adt/hash_table.h>
+#include "nic.h"
+
+typedef struct nic_wol_virtues {
+	/**
+	 * Operations for table
+	 */
+	hash_table_operations_t table_operations;
+	/**
+	 * WOL virtues hashed by their ID's.
+	 */
+	hash_table_t table;
+	/**
+	 * WOL virtues in lists by their type
+	 */
+	nic_wol_virtue_t *lists[NIC_WV_MAX];
+	/**
+	 * Number of virtues in the wv_types list
+	 */
+	size_t lists_sizes[NIC_WV_MAX];
+	/**
+	 * Counter for the ID's
+	 */
+	nic_wv_id_t next_id;
+	/**
+	 * Maximum capabilities
+	 */
+	int caps_max[NIC_WV_MAX];
+} nic_wol_virtues_t;
+
+extern int nic_wol_virtues_init(nic_wol_virtues_t *);
+extern void nic_wol_virtues_clear(nic_wol_virtues_t *);
+extern int nic_wol_virtues_verify(nic_wv_type_t, const void *, size_t);
+extern int nic_wol_virtues_list(const nic_wol_virtues_t *, nic_wv_type_t type,
+	size_t max_count, nic_wv_id_t *id_list, size_t *id_count);
+extern int nic_wol_virtues_add(nic_wol_virtues_t *, nic_wol_virtue_t *);
+extern nic_wol_virtue_t *nic_wol_virtues_remove(nic_wol_virtues_t *,
+	nic_wv_id_t);
+extern const nic_wol_virtue_t *nic_wol_virtues_find(const nic_wol_virtues_t *,
+	nic_wv_id_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/src/nic_addr_db.c
===================================================================
--- uspace/lib/nic/src/nic_addr_db.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/src/nic_addr_db.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,277 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Generic hash-set based database of addresses
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include <bool.h>
+#include <errno.h>
+#include <mem.h>
+
+#include "nic_addr_db.h"
+
+/**
+ * Hash set helper function
+ */
+static int nic_addr_equals(const link_t *item1, const link_t *item2)
+{
+	assert(item1 && item2);
+	size_t addr_len = ((const nic_addr_entry_t *) item1)->addr_len;
+
+	assert(addr_len	== ((const nic_addr_entry_t *) item2)->addr_len);
+
+	size_t i;
+	for (i = 0; i < addr_len; ++i) {
+		if (((nic_addr_entry_t *) item1)->addr[i] !=
+			((nic_addr_entry_t *) item2)->addr[i])
+			return false;
+	}
+	return true;
+}
+
+/**
+ * Hash set helper function
+ */
+static unsigned long nic_addr_hash(const link_t *item)
+{
+	assert(item);
+	const nic_addr_entry_t *entry = (const nic_addr_entry_t *) item;
+	unsigned long hash = 0;
+
+	size_t i;
+	for (i = 0; i < entry->addr_len; ++i) {
+		hash = (hash << 8) ^ (hash >> 24) ^ entry->addr[i];
+	}
+	return hash;
+}
+
+/**
+ * Helper wrapper
+ */
+static void nic_addr_destroy(link_t *item, void *unused)
+{
+	free(item);
+}
+
+/**
+ * Initialize the database
+ *
+ * @param[in,out]	db			Uninitialized storage
+ * @param[in]		addr_len	Size of addresses in the db
+ *
+ * @return EOK		If successfully initialized
+ * @return EINVAL	If the address length is too big
+ * @return ENOMEM	If there was not enough memory to initialize the storage
+ */
+int nic_addr_db_init(nic_addr_db_t *db, size_t addr_len)
+{
+	assert(db);
+	if (addr_len > NIC_ADDR_MAX_LENGTH) {
+		return EINVAL;
+	}
+	if (!hash_set_init(&db->set, nic_addr_hash, nic_addr_equals,
+		NIC_ADDR_DB_INIT_SIZE)) {
+		return ENOMEM;
+	}
+	db->addr_len = addr_len;
+	return EOK;
+}
+
+/**
+ * Remove all records from the DB
+ *
+ * @param db
+ */
+void nic_addr_db_clear(nic_addr_db_t *db)
+{
+	assert(db);
+	hash_set_clear(&db->set, nic_addr_destroy, NULL);
+}
+
+/**
+ * Free the memory used by db, including all records...
+ *
+ * @param	db
+ */
+void nic_addr_db_destroy(nic_addr_db_t *db)
+{
+	assert(db);
+	hash_set_apply(&db->set, nic_addr_destroy, NULL);
+	hash_set_destroy(&db->set);
+}
+
+/**
+ * Get number of addresses in the db
+ *
+ * @param	db
+ *
+ * @return Number of adresses
+ */
+size_t nic_addr_db_count(const nic_addr_db_t *db)
+{
+	assert(db);
+	return hash_set_count(&db->set);
+}
+
+/**
+ * Insert an address to the db
+ *
+ * @param	db
+ * @param	addr 	Inserted address. Length is implicitly concluded from the
+ * 					db's address length.
+ *
+ * @return EOK		If the address was inserted
+ * @return ENOMEM	If there was not enough memory
+ * @return EEXIST	If this adress already is in the db
+ */
+int nic_addr_db_insert(nic_addr_db_t *db, const uint8_t *addr)
+{
+	assert(db && addr);
+	nic_addr_entry_t *entry = malloc(sizeof (nic_addr_entry_t));
+	if (entry == NULL) {
+		return ENOMEM;
+	}
+	entry->addr_len = db->addr_len;
+	memcpy(entry->addr, addr, db->addr_len);
+
+	return hash_set_insert(&db->set, &entry->item) ? EOK : EEXIST;
+}
+
+/**
+ * Remove the address from the db
+ *
+ * @param	db
+ * @param	addr	Removed address.
+ *
+ * @return EOK		If the address was removed
+ * @return ENOENT	If there is no address
+ */
+int nic_addr_db_remove(nic_addr_db_t *db, const uint8_t *addr)
+{
+	assert(db && addr);
+	nic_addr_entry_t entry;
+	entry.addr_len = db->addr_len;
+	memcpy(entry.addr, addr, db->addr_len);
+
+	link_t *removed = hash_set_remove(&db->set, &entry.item);
+	free(removed);
+	return removed != NULL ? EOK : ENOENT;
+}
+
+/**
+ * Test if the address is contained in the db
+ *
+ * @param	db
+ * @param	addr	Tested addresss
+ *
+ * @return true if the address is in the db, false otherwise
+ */
+int nic_addr_db_contains(const nic_addr_db_t *db, const uint8_t *addr)
+{
+	assert(db && addr);
+	nic_addr_entry_t entry;
+	entry.addr_len = db->addr_len;
+	memcpy(entry.addr, addr, db->addr_len);
+
+	return hash_set_contains(&db->set, &entry.item);
+}
+
+/**
+ * Helper structure for nic_addr_db_foreach
+ */
+typedef struct {
+	void (*func)(const uint8_t *, void *);
+	void *arg;
+} nic_addr_db_fe_arg_t;
+
+/**
+ * Helper function for nic_addr_db_foreach
+ */
+static void nic_addr_db_fe_helper(link_t *item, void *arg) {
+	nic_addr_db_fe_arg_t *hs = (nic_addr_db_fe_arg_t *) arg;
+	hs->func(((nic_addr_entry_t *) item)->addr, hs->arg);
+}
+
+/**
+ * Executes a user-defined function on all addresses in the DB. The function
+ * must not change the addresses.
+ *
+ * @param	db
+ * @param	func	User-defined function
+ * @param	arg		Custom argument passed to the function
+ */
+void nic_addr_db_foreach(const nic_addr_db_t *db,
+	void (*func)(const uint8_t *, void *), void *arg)
+{
+	nic_addr_db_fe_arg_t hs = { .func = func, .arg = arg };
+	hash_set_apply((hash_set_t *) &db->set, nic_addr_db_fe_helper, &hs);
+}
+
+/**
+ * Helper structure for nic_addr_db_remove_selected
+ */
+typedef struct {
+	int (*func)(const uint8_t *, void *);
+	void *arg;
+} nic_addr_db_rs_arg_t;
+
+/**
+ * Helper function for nic_addr_db_foreach
+ */
+static int nic_addr_db_rs_helper(link_t *item, void *arg) {
+	nic_addr_db_rs_arg_t *hs = (nic_addr_db_rs_arg_t *) arg;
+	int retval = hs->func(((nic_addr_entry_t *) item)->addr, hs->arg);
+	if (retval) {
+		free(item);
+	}
+	return retval;
+}
+
+/**
+ * Removes all addresses for which the function returns non-zero.
+ *
+ * @param	db
+ * @param	func	User-defined function
+ * @param	arg		Custom argument passed to the function
+ */
+void nic_addr_db_remove_selected(nic_addr_db_t *db,
+	int (*func)(const uint8_t *, void *), void *arg)
+{
+	nic_addr_db_rs_arg_t hs = { .func = func, .arg = arg };
+	hash_set_remove_selected(&db->set, nic_addr_db_rs_helper, &hs);
+}
+
+/** @}
+ */
Index: uspace/lib/nic/src/nic_driver.c
===================================================================
--- uspace/lib/nic/src/nic_driver.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/src/nic_driver.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,1368 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Internal implementation of general NIC operations
+ */
+
+#include <assert.h>
+#include <fibril_synch.h>
+#include <ns.h>
+#include <stdio.h>
+#include <str_error.h>
+#include <ipc/services.h>
+#include <ipc/ns.h>
+#include <ipc/irc.h>
+#include <sysinfo.h>
+
+#include <devman.h>
+#include <ddf/interrupt.h>
+#include <net_interface.h>
+#include <ops/nic.h>
+#include <packet_client.h>
+#include <packet_remote.h>
+#include <net/packet_header.h>
+#include <errno.h>
+
+#include "nic_driver.h"
+#include "nic_impl.h"
+
+#define NIC_GLOBALS_MAX_CACHE_SIZE 16
+
+nic_globals_t nic_globals;
+
+/**
+ * Initializes libraries required for NIC framework - logger, packet manager
+ *
+ * @param name	Name of the device/driver (used in logging)
+ */
+int nic_driver_init(const char *name)
+{
+	list_initialize(&nic_globals.frame_list_cache);
+	nic_globals.frame_list_cache_size = 0;
+	list_initialize(&nic_globals.frame_cache);
+	nic_globals.frame_cache_size = 0;
+	fibril_mutex_initialize(&nic_globals.lock);
+	
+	char buffer[256];
+	snprintf(buffer, 256, "drv/" DEVICE_CATEGORY_NIC "/%s", name);
+	
+	/* Initialize packet manager */
+	return pm_init();
+}
+
+/**
+ * Fill in the default implementations for device options and NIC interface.
+ *
+ * @param driver_ops
+ * @param dev_ops
+ * @param iface
+ */
+void nic_driver_implement(driver_ops_t *driver_ops, ddf_dev_ops_t *dev_ops,
+    nic_iface_t *iface)
+{
+	if (driver_ops) {
+		if (!driver_ops->device_added)
+			driver_ops->device_added = nic_device_added_impl;
+	}
+
+	if (dev_ops) {
+		if (!dev_ops->open)
+			dev_ops->open = nic_open_impl;
+		if (!dev_ops->close)
+			dev_ops->close = nic_close_impl;
+		if (!dev_ops->interfaces[NIC_DEV_IFACE])
+			dev_ops->interfaces[NIC_DEV_IFACE] = iface;
+		if (!dev_ops->default_handler)
+			dev_ops->default_handler = nic_default_handler_impl;
+	}
+
+	if (iface) {
+		if (!iface->get_state)
+			iface->get_state = nic_get_state_impl;
+		if (!iface->set_state)
+			iface->set_state = nic_set_state_impl;
+		if (!iface->send_message)
+			iface->send_message = nic_send_message_impl;
+		if (!iface->connect_to_nil)
+			iface->connect_to_nil = nic_connect_to_nil_impl;
+		if (!iface->get_address)
+			iface->get_address = nic_get_address_impl;
+		if (!iface->get_stats)
+			iface->get_stats = nic_get_stats_impl;
+		if (!iface->unicast_get_mode)
+			iface->unicast_get_mode = nic_unicast_get_mode_impl;
+		if (!iface->unicast_set_mode)
+			iface->unicast_set_mode = nic_unicast_set_mode_impl;
+		if (!iface->multicast_get_mode)
+			iface->multicast_get_mode = nic_multicast_get_mode_impl;
+		if (!iface->multicast_set_mode)
+			iface->multicast_set_mode = nic_multicast_set_mode_impl;
+		if (!iface->broadcast_get_mode)
+			iface->broadcast_get_mode = nic_broadcast_get_mode_impl;
+		if (!iface->broadcast_set_mode)
+			iface->broadcast_set_mode = nic_broadcast_set_mode_impl;
+		if (!iface->blocked_sources_get)
+			iface->blocked_sources_get = nic_blocked_sources_get_impl;
+		if (!iface->blocked_sources_set)
+			iface->blocked_sources_set = nic_blocked_sources_set_impl;
+		if (!iface->vlan_get_mask)
+			iface->vlan_get_mask = nic_vlan_get_mask_impl;
+		if (!iface->vlan_set_mask)
+			iface->vlan_set_mask = nic_vlan_set_mask_impl;
+		if (!iface->wol_virtue_add)
+			iface->wol_virtue_add = nic_wol_virtue_add_impl;
+		if (!iface->wol_virtue_remove)
+			iface->wol_virtue_remove = nic_wol_virtue_remove_impl;
+		if (!iface->wol_virtue_probe)
+			iface->wol_virtue_probe = nic_wol_virtue_probe_impl;
+		if (!iface->wol_virtue_list)
+			iface->wol_virtue_list = nic_wol_virtue_list_impl;
+		if (!iface->wol_virtue_get_caps)
+			iface->wol_virtue_get_caps = nic_wol_virtue_get_caps_impl;
+		if (!iface->poll_get_mode)
+			iface->poll_get_mode = nic_poll_get_mode_impl;
+		if (!iface->poll_set_mode)
+			iface->poll_set_mode = nic_poll_set_mode_impl;
+		if (!iface->poll_now)
+			iface->poll_now = nic_poll_now_impl;
+	}
+}
+
+/**
+ * Setup write packet handler. This MUST be called in the add_device handler
+ * if the nic_send_message_impl function is used for sending messages (filled
+ * as send_message member of the nic_iface_t structure). The function must not
+ * be called anywhere else.
+ *
+ * @param nic_data
+ * @param wpfunc		Function handling the write_packet request
+ */
+void nic_set_write_packet_handler(nic_t *nic_data, write_packet_handler wpfunc)
+{
+	nic_data->write_packet = wpfunc;
+}
+
+/**
+ * Setup event handlers for transitions between driver states.
+ * This function can be called only in the add_device handler.
+ *
+ * @param on_activating	Called when device is going to the ACTIVE state.
+ * @param on_going_down Called when device is going to the DOWN state.
+ * @param on_stopping	Called when device is going to the STOP state.
+ */
+void nic_set_state_change_handlers(nic_t *nic_data,
+	state_change_handler on_activating, state_change_handler on_going_down,
+	state_change_handler on_stopping)
+{
+	nic_data->on_activating = on_activating;
+	nic_data->on_going_down = on_going_down;
+	nic_data->on_stopping = on_stopping;
+}
+
+/**
+ * Setup event handlers for changing the filtering modes.
+ * This function can be called only in the add_device handler.
+ *
+ * @param nic_data
+ * @param on_unicast_mode_change
+ * @param on_multicast_mode_change
+ * @param on_broadcast_mode_change
+ * @param on_blocked_sources_change
+ * @param on_vlan_mask_change
+ */
+void nic_set_filtering_change_handlers(nic_t *nic_data,
+	unicast_mode_change_handler on_unicast_mode_change,
+	multicast_mode_change_handler on_multicast_mode_change,
+	broadcast_mode_change_handler on_broadcast_mode_change,
+	blocked_sources_change_handler on_blocked_sources_change,
+	vlan_mask_change_handler on_vlan_mask_change)
+{
+	nic_data->on_unicast_mode_change = on_unicast_mode_change;
+	nic_data->on_multicast_mode_change = on_multicast_mode_change;
+	nic_data->on_broadcast_mode_change = on_broadcast_mode_change;
+	nic_data->on_blocked_sources_change = on_blocked_sources_change;
+	nic_data->on_vlan_mask_change = on_vlan_mask_change;
+}
+
+/**
+ * Setup filters for WOL virtues add and removal.
+ * This function can be called only in the add_device handler. Both handlers
+ * must be set or none of them.
+ *
+ * @param on_wv_add		Called when a virtue is added
+ * @param on_wv_remove	Called when a virtue is removed
+ */
+void nic_set_wol_virtue_change_handlers(nic_t *nic_data,
+	wol_virtue_add_handler on_wv_add, wol_virtue_remove_handler on_wv_remove)
+{
+	assert(on_wv_add != NULL && on_wv_remove != NULL);
+	nic_data->on_wol_virtue_add = on_wv_add;
+	nic_data->on_wol_virtue_remove = on_wv_remove;
+}
+
+/**
+ * Setup poll handlers.
+ * This function can be called only in the add_device handler.
+ *
+ * @param on_poll_mode_change	Called when the mode is about to be changed
+ * @param on_poll_request		Called when poll request is triggered
+ */
+void nic_set_poll_handlers(nic_t *nic_data,
+	poll_mode_change_handler on_poll_mode_change, poll_request_handler on_poll_req)
+{
+	nic_data->on_poll_mode_change = on_poll_mode_change;
+	nic_data->on_poll_request = on_poll_req;
+}
+
+/**
+ * Connect to the parent's driver and get HW resources list in parsed format.
+ * Note: this function should be called only from add_device handler, therefore
+ * we don't need to use locks.
+ *
+ * @param		nic_data
+ * @param[out]	resources	Parsed lists of resources.
+ *
+ * @return EOK or negative error code
+ */
+int nic_get_resources(nic_t *nic_data, hw_res_list_parsed_t *resources)
+{
+	ddf_dev_t *dev = nic_data->dev;
+	
+	/* Connect to the parent's driver. */
+	dev->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
+		dev->handle, IPC_FLAG_BLOCKING);
+	if (dev->parent_sess == NULL)
+		return EPARTY;
+	
+	return hw_res_get_list_parsed(nic_data->dev->parent_sess, resources, 0);
+}
+
+/**
+ * Just a wrapper over the packet_get_1_remote function
+ */
+packet_t *nic_alloc_packet(nic_t *nic_data, size_t data_size)
+{
+	return packet_get_1_remote(nic_data->net_session, data_size);
+}
+
+
+/**
+ * Just a wrapper over the pq_release_remote function
+ */
+void nic_release_packet(nic_t *nic_data, packet_t *packet)
+{
+	pq_release_remote(nic_data->net_session, packet_get_id(packet));
+}
+
+/** Allocate frame and packet
+ *
+ *  @param nic_data 	The NIC driver data
+ *  @param packet_size	Size of packet
+ *  @param offload_size	Size of packet offload
+ *  @return pointer to allocated frame if success, NULL otherwise
+ */
+nic_frame_t *nic_alloc_frame(nic_t *nic_data, size_t packet_size)
+{
+	nic_frame_t *frame;
+	fibril_mutex_lock(&nic_globals.lock);
+	if (nic_globals.frame_cache_size > 0) {
+		link_t *first = list_first(&nic_globals.frame_cache);
+		list_remove(first);
+		nic_globals.frame_cache_size--;
+		frame = list_get_instance(first, nic_frame_t, link);
+		fibril_mutex_unlock(&nic_globals.lock);
+	} else {
+		fibril_mutex_unlock(&nic_globals.lock);
+		frame = malloc(sizeof(nic_frame_t));
+		if (!frame)
+			return NULL;
+		
+		link_initialize(&frame->link);
+	}
+
+	packet_t *packet = nic_alloc_packet(nic_data, packet_size);
+	if (!packet) {
+		free(frame);
+		return NULL;
+	}
+
+	frame->packet = packet;
+	return frame;
+}
+
+/** Release frame
+ *
+ * @param nic_data	The driver data
+ * @param frame		The frame to release
+ */
+void nic_release_frame(nic_t *nic_data, nic_frame_t *frame)
+{
+	if (!frame)
+		return;
+	if (frame->packet != NULL) {
+		nic_release_packet(nic_data, frame->packet);
+	}
+	fibril_mutex_lock(&nic_globals.lock);
+	if (nic_globals.frame_cache_size >= NIC_GLOBALS_MAX_CACHE_SIZE) {
+		fibril_mutex_unlock(&nic_globals.lock);
+		free(frame);
+	} else {
+		list_prepend(&frame->link, &nic_globals.frame_cache);
+		nic_globals.frame_cache_size++;
+		fibril_mutex_unlock(&nic_globals.lock);
+	}
+}
+
+/**
+ * Allocate a new frame list
+ *
+ * @return New frame list or NULL on error.
+ */
+nic_frame_list_t *nic_alloc_frame_list(void)
+{
+	nic_frame_list_t *frames;
+	fibril_mutex_lock(&nic_globals.lock);
+	
+	if (nic_globals.frame_list_cache_size > 0) {
+		frames =
+		    list_get_instance(list_first(&nic_globals.frame_list_cache),
+		    nic_frame_list_t, head);
+		list_remove(&frames->head);
+		list_initialize(frames);
+		nic_globals.frame_list_cache_size--;
+		fibril_mutex_unlock(&nic_globals.lock);
+	} else {
+		fibril_mutex_unlock(&nic_globals.lock);
+		
+		frames = malloc(sizeof (nic_frame_list_t));
+		if (frames != NULL)
+			list_initialize(frames);
+	}
+	
+	return frames;
+}
+
+static void nic_driver_release_frame_list(nic_frame_list_t *frames)
+{
+	if (!frames)
+		return;
+	fibril_mutex_lock(&nic_globals.lock);
+	if (nic_globals.frame_list_cache_size >= NIC_GLOBALS_MAX_CACHE_SIZE) {
+		fibril_mutex_unlock(&nic_globals.lock);
+		free(frames);
+	} else {
+		list_prepend(&frames->head, &nic_globals.frame_list_cache);
+		nic_globals.frame_list_cache_size++;
+		fibril_mutex_unlock(&nic_globals.lock);
+	}
+}
+
+/**
+ * Append a frame to the frame list
+ *
+ * @param frames	Frame list
+ * @param frame		Appended frame
+ */
+void nic_frame_list_append(nic_frame_list_t *frames,
+	nic_frame_t *frame)
+{
+	assert(frame != NULL && frames != NULL);
+	list_append(&frame->link, frames);
+}
+
+
+/**
+ * Enable interrupts for this driver.
+ *
+ * @param nic_data
+ * @param irq			The IRQ number for this device
+ */
+void nic_enable_interrupt(nic_t *nic_data, int irq)
+{
+	async_exch_t *exch = async_exchange_begin(nic_data->irc_session);
+	async_msg_1(exch, IRC_ENABLE_INTERRUPT, irq);
+	async_exchange_end(exch);
+}
+
+/**
+ * Disable interrupts for this driver.
+ *
+ * @param nic_data
+ * @param irq			The IRQ number for this device
+ */
+void nic_disable_interrupt(nic_t *nic_data, int irq)
+{
+	async_exch_t *exch = async_exchange_begin(nic_data->irc_session);
+	async_msg_1(exch, IRC_CLEAR_INTERRUPT, irq);
+	async_exchange_end(exch);
+}
+
+/** Get the polling mode information from the device 
+ *
+ *	The main lock should be locked, otherwise the inconsistency between
+ *	mode and period can occure.
+ *
+ *  @param nic_data The controller data
+ *  @param period [out] The the period. Valid only if mode == NIC_POLL_PERIODIC
+ *  @return Current polling mode of the controller
+ */
+nic_poll_mode_t nic_query_poll_mode(nic_t *nic_data, struct timeval *period)
+{
+	if (period)
+		*period = nic_data->poll_period;
+	return nic_data->poll_mode;
+};
+
+/**
+ * Connect to the NET and IRQ services. This function should be called only from
+ * the add_device handler, thus no locking is required.
+ *
+ * @param nic_data
+ *
+ * @return EOK		If connection was successful.
+ * @return EINVAL	If the IRC service cannot be determined.
+ * @return EREFUSED	If NET or IRC service cannot be connected.
+ */
+int nic_connect_to_services(nic_t *nic_data)
+{
+	/* NET service */
+	nic_data->net_session = service_connect_blocking(EXCHANGE_SERIALIZE,
+		SERVICE_NETWORKING, 0, 0);
+	if (nic_data->net_session == NULL)
+		return errno;
+	
+	/* IRC service */
+	sysarg_t apic;
+	sysarg_t i8259;
+	services_t irc_service = -1;
+	if (((sysinfo_get_value("apic", &apic) == EOK) && (apic)) ||
+	    ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259)))
+		irc_service = SERVICE_IRC;
+	else
+		return EINVAL;
+	
+	nic_data->irc_session = service_connect_blocking(EXCHANGE_SERIALIZE,
+		irc_service, 0, 0);
+	if (nic_data->irc_session == NULL)
+		return errno;
+	
+	return EOK;
+}
+
+/** Notify the NET service that the device is ready
+ *
+ * @param nic NICF structure
+ *
+ * @return EOK on success
+ *
+ */
+int nic_ready(nic_t *nic)
+{
+	fibril_rwlock_read_lock(&nic->main_lock);
+	
+	async_sess_t *session = nic->net_session;
+	devman_handle_t handle = nic->dev->handle;
+	
+	fibril_rwlock_read_unlock(&nic->main_lock);
+	
+	if (session == NULL)
+		return EINVAL;
+	
+	return net_driver_ready(session, handle);
+}
+
+/** Inform the NICF about poll mode
+ *
+ *  @param nic_data The controller data
+ *  @param mode
+ *  @param period [out] The the period. Valid only if mode == NIC_POLL_PERIODIC
+ *  @return EOK
+ *  @return EINVAL
+ */
+int nic_report_poll_mode(nic_t *nic_data, nic_poll_mode_t mode,
+	struct timeval *period)
+{
+	int rc = EOK;
+	fibril_rwlock_write_lock(&nic_data->main_lock);
+	nic_data->poll_mode = mode;
+	nic_data->default_poll_mode = mode;
+	if (mode == NIC_POLL_PERIODIC) {
+		if (period) {
+			memcpy(&nic_data->default_poll_period, period, sizeof (struct timeval));
+			memcpy(&nic_data->poll_period, period, sizeof (struct timeval));
+		} else {
+			rc = EINVAL;
+		}
+	}
+	fibril_rwlock_write_unlock(&nic_data->main_lock);
+	return rc;
+}
+
+/** Inform the NICF about device's MAC adress.
+ *
+ * @return EOK On success
+ *
+ */
+int nic_report_address(nic_t *nic_data, const nic_address_t *address)
+{
+	assert(nic_data);
+	
+	if (address->address[0] & 1)
+		return EINVAL;
+	
+	fibril_rwlock_write_lock(&nic_data->main_lock);
+	
+	/* Notify NIL layer (and uppper) if bound - not in add_device */
+	if (nic_data->nil_session != NULL) {
+		int rc = nil_addr_changed_msg(nic_data->nil_session,
+		    nic_data->device_id, address);
+		if (rc != EOK) {
+			fibril_rwlock_write_unlock(&nic_data->main_lock);
+			return rc;
+		}
+	}
+	
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	
+	/*
+	 * The initial address (all zeroes) shouldn't be
+	 * there and we will ignore that error -- in next
+	 * calls this should not happen.
+	 */
+	int rc = nic_rxc_set_addr(&nic_data->rx_control,
+	    &nic_data->mac, address);
+	
+	/* For the first time also record the default MAC */
+	if (MAC_IS_ZERO(nic_data->default_mac.address)) {
+		assert(MAC_IS_ZERO(nic_data->mac.address));
+		memcpy(&nic_data->default_mac, address, sizeof(nic_address_t));
+	}
+	
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	
+	if ((rc != EOK) && (rc != ENOENT)) {
+		fibril_rwlock_write_unlock(&nic_data->main_lock);
+		return rc;
+	}
+	
+	memcpy(&nic_data->mac, address, sizeof(nic_address_t));
+	
+	fibril_rwlock_write_unlock(&nic_data->main_lock);
+	
+	return EOK;
+}
+
+/**
+ * Used to obtain devices MAC address.
+ *
+ * The main lock should be locked, otherwise the inconsistent address
+ * can be returend.
+ *
+ * @param nic_data The controller data
+ * @param address The output for address.
+ */
+void nic_query_address(nic_t *nic_data, nic_address_t *addr) {
+	if (!addr)
+		return;
+	if (!nic_data)
+		memset(addr, 0, sizeof(nic_address_t));
+
+	memcpy(addr, &nic_data->mac, sizeof(nic_address_t));
+};
+
+/**
+ * The busy flag can be set to 1 only in the write_packet handler, to 0 it can
+ * be set anywhere.
+ *
+ * @param nic_data
+ * @param busy
+ */
+void nic_set_tx_busy(nic_t *nic_data, int busy)
+{
+	/*
+	 * When the function is called in write_packet handler the main lock is
+	 * locked so no race can happen.
+	 * Otherwise, when it is unexpectedly set to 0 (even with main lock held
+	 * by other fibril) it cannot crash anything.
+	 */
+	nic_data->tx_busy = busy;
+}
+
+/**
+ * Provided for correct naming conventions.
+ * The packet is checked by filters and then sent up to the NIL layer or
+ * discarded, the frame is released.
+ *
+ * @param nic_data
+ * @param frame		The frame containing received packet
+ */
+void nic_received_frame(nic_t *nic_data, nic_frame_t *frame)
+{
+	nic_received_packet(nic_data, frame->packet);
+	frame->packet = NULL;
+	nic_release_frame(nic_data, frame);
+}
+
+/**
+ * This is the function that the driver should call when it receives a packet.
+ * The packet is checked by filters and then sent up to the NIL layer or
+ * discarded.
+ *
+ * @param nic_data
+ * @param packet		The received packet
+ */
+void nic_received_packet(nic_t *nic_data, packet_t *packet)
+{
+	/* Note: this function must not lock main lock, because loopback driver
+	 * 		 calls it inside write_packet handler (with locked main lock) */
+	packet_id_t pid = packet_get_id(packet);
+	
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	nic_frame_type_t frame_type;
+	int check = nic_rxc_check(&nic_data->rx_control, packet, &frame_type);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	/* Update statistics */
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	/* Both sending message up and releasing packet are atomic IPC calls */
+	if (nic_data->state == NIC_STATE_ACTIVE && check) {
+		nic_data->stats.receive_packets++;
+		nic_data->stats.receive_bytes += packet_get_data_length(packet);
+		switch (frame_type) {
+		case NIC_FRAME_MULTICAST:
+			nic_data->stats.receive_multicast++;
+			break;
+		case NIC_FRAME_BROADCAST:
+			nic_data->stats.receive_broadcast++;
+			break;
+		default:
+			break;
+		}
+		fibril_rwlock_write_unlock(&nic_data->stats_lock);
+		nil_received_msg(nic_data->nil_session, nic_data->device_id, pid);
+	} else {
+		switch (frame_type) {
+		case NIC_FRAME_UNICAST:
+			nic_data->stats.receive_filtered_unicast++;
+			break;
+		case NIC_FRAME_MULTICAST:
+			nic_data->stats.receive_filtered_multicast++;
+			break;
+		case NIC_FRAME_BROADCAST:
+			nic_data->stats.receive_filtered_broadcast++;
+			break;
+		}
+		fibril_rwlock_write_unlock(&nic_data->stats_lock);
+		nic_release_packet(nic_data, packet);
+	}
+}
+
+/**
+ * This function is to be used only in the loopback driver. It's workaround
+ * for the situation when the packet does not contain ethernet address.
+ * The filtering is therefore not applied here.
+ *
+ * @param nic_data
+ * @param packet
+ */
+void nic_received_noneth_packet(nic_t *nic_data, packet_t *packet)
+{
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	nic_data->stats.receive_packets++;
+	nic_data->stats.receive_bytes += packet_get_data_length(packet);
+	fibril_rwlock_write_unlock(&nic_data->stats_lock);
+	
+	nil_received_msg(nic_data->nil_session, nic_data->device_id,
+	    packet_get_id(packet));
+}
+
+/**
+ * Some NICs can receive multiple packets during single interrupt. These can
+ * send them in whole list of frames (actually nic_frame_t structures), then
+ * the list is deallocated and each packet is passed to the
+ * nic_received_packet function.
+ *
+ * @param nic_data
+ * @param frames		List of received frames
+ */
+void nic_received_frame_list(nic_t *nic_data, nic_frame_list_t *frames)
+{
+	if (frames == NULL)
+		return;
+	while (!list_empty(frames)) {
+		nic_frame_t *frame =
+			list_get_instance(list_first(frames), nic_frame_t, link);
+
+		list_remove(&frame->link);
+		nic_received_packet(nic_data, frame->packet);
+		frame->packet = NULL;
+		nic_release_frame(nic_data, frame);
+	}
+	nic_driver_release_frame_list(frames);
+}
+
+/** Allocate and initialize the driver data.
+ *
+ * @return Allocated structure or NULL.
+ *
+ */
+static nic_t *nic_create(void)
+{
+	nic_t *nic_data = malloc(sizeof(nic_t));
+	if (nic_data == NULL)
+		return NULL;
+	
+	/* Force zero to all uninitialized fields (e.g. added in future) */
+	bzero(nic_data, sizeof(nic_t));
+	if (nic_rxc_init(&nic_data->rx_control) != EOK) {
+		free(nic_data);
+		return NULL;
+	}
+	
+	if (nic_wol_virtues_init(&nic_data->wol_virtues) != EOK) {
+		free(nic_data);
+		return NULL;
+	}
+	
+	nic_data->dev = NULL;
+	nic_data->fun = NULL;
+	nic_data->device_id = NIC_DEVICE_INVALID_ID;
+	nic_data->state = NIC_STATE_STOPPED;
+	nic_data->net_session = NULL;
+	nic_data->nil_session = NULL;
+	nic_data->irc_session = NULL;
+	nic_data->poll_mode = NIC_POLL_IMMEDIATE;
+	nic_data->default_poll_mode = NIC_POLL_IMMEDIATE;
+	nic_data->write_packet = NULL;
+	nic_data->on_activating = NULL;
+	nic_data->on_going_down = NULL;
+	nic_data->on_stopping = NULL;
+	nic_data->specific = NULL;
+	
+	fibril_rwlock_initialize(&nic_data->main_lock);
+	fibril_rwlock_initialize(&nic_data->stats_lock);
+	fibril_rwlock_initialize(&nic_data->rxc_lock);
+	fibril_rwlock_initialize(&nic_data->wv_lock);
+	
+	bzero(&nic_data->mac, sizeof(nic_address_t));
+	bzero(&nic_data->default_mac, sizeof(nic_address_t));
+	bzero(&nic_data->stats, sizeof(nic_device_stats_t));
+	
+	return nic_data;
+}
+
+/** Create NIC structure for the device and bind it to dev_fun_t
+ *
+ * The pointer to the created and initialized NIC structure will
+ * be stored in device->nic_data.
+ *
+ * @param device The NIC device structure
+ *
+ * @return Pointer to created nic_t structure or NULL
+ *
+ */
+nic_t *nic_create_and_bind(ddf_dev_t *device)
+{
+	assert(device);
+	assert(!device->driver_data);
+	
+	nic_t *nic_data = nic_create();
+	if (!nic_data)
+		return NULL;
+	
+	nic_data->dev = device;
+	device->driver_data = nic_data;
+	
+	return nic_data;
+}
+
+/**
+ * Hangs up the phones in the structure, deallocates specific data and then
+ * the structure itself.
+ *
+ * @param data
+ */
+static void nic_destroy(nic_t *nic_data) {
+	if (nic_data->net_session != NULL) {
+		async_hangup(nic_data->net_session);
+	}
+
+	if (nic_data->nil_session != NULL) {
+		async_hangup(nic_data->nil_session);
+	}
+
+	free(nic_data->specific);
+	free(nic_data);
+}
+
+/**
+ * Unbind and destroy nic_t stored in ddf_dev_t.nic_data.
+ * The ddf_dev_t.nic_data will be set to NULL, specific driver data will be
+ * destroyed.
+ *
+ * @param device The NIC device structure
+ */
+void nic_unbind_and_destroy(ddf_dev_t *device){
+	if (!device)
+		return;
+	if (!device->driver_data)
+		return;
+
+	nic_destroy((nic_t *) device->driver_data);
+	device->driver_data = NULL;
+	return;
+}
+
+/**
+ * Creates an exposed DDF function for the device, named "port0".
+ * Device options are set as this function's options. The function is bound
+ * (see ddf_fun_bind) and then registered to the DEVICE_CATEGORY_NIC class.
+ * Note: this function should be called only from add_device handler, therefore
+ * we don't need to use locks.
+ *
+ * @param nic_data	The NIC structure
+ * @param ops		Device options for the DDF function.
+ */
+int nic_register_as_ddf_fun(nic_t *nic_data, ddf_dev_ops_t *ops)
+{
+	int rc;
+	assert(nic_data);
+
+	nic_data->fun = ddf_fun_create(nic_data->dev, fun_exposed, "port0");
+	if (nic_data->fun == NULL)
+		return ENOMEM;
+	
+	nic_data->fun->ops = ops;
+	nic_data->fun->driver_data = nic_data;
+
+	rc = ddf_fun_bind(nic_data->fun);
+	if (rc != EOK) {
+		ddf_fun_destroy(nic_data->fun);
+		return rc;
+	}
+
+	rc = ddf_fun_add_to_category(nic_data->fun, DEVICE_CATEGORY_NIC);
+	if (rc != EOK) {
+		ddf_fun_destroy(nic_data->fun);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/**
+ * Set information about current HW filtering.
+ *  1 ...	Only those frames we want to receive are passed through HW
+ *  0 ...	The HW filtering is imperfect
+ * -1 ...	Don't change the setting
+ * Can be called only from the on_*_change handler.
+ *
+ * @param	nic_data
+ * @param	unicast_exact	Unicast frames
+ * @param	mcast_exact		Multicast frames
+ * @param	vlan_exact		VLAN tags
+ */
+void nic_report_hw_filtering(nic_t *nic_data,
+	int unicast_exact, int multicast_exact, int vlan_exact)
+{
+	nic_rxc_hw_filtering(&nic_data->rx_control,
+		unicast_exact, multicast_exact, vlan_exact);
+}
+
+/**
+ * Computes hash for the address list based on standard multicast address
+ * hashing.
+ *
+ * @param address_list
+ * @param count
+ *
+ * @return Multicast hash
+ *
+ * @see multicast_hash
+ */
+uint64_t nic_mcast_hash(const nic_address_t *list, size_t count)
+{
+	return nic_rxc_mcast_hash(list, count);
+}
+
+/**
+ * Computes hash for multicast addresses currently set up in the RX multicast
+ * filtering. For promiscuous mode returns all ones, for blocking all zeroes.
+ * Can be called only from the state change handlers (on_activating,
+ * on_going_down and on_stopping).
+ *
+ * @param nic_data
+ *
+ * @return Multicast hash
+ *
+ * @see multicast_hash
+ */
+uint64_t nic_query_mcast_hash(nic_t *nic_data)
+{
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	uint64_t hash = nic_rxc_multicast_get_hash(&nic_data->rx_control);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return hash;
+}
+
+/**
+ * Queries the current mode of unicast frames receiving.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param nic_data
+ * @param mode			The new unicast mode
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of addresses in the list
+ */
+void nic_query_unicast(const nic_t *nic_data,
+	nic_unicast_mode_t *mode,
+	size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	assert(mode != NULL);
+	nic_rxc_unicast_get_mode(&nic_data->rx_control, mode,
+		max_count, address_list, address_count);
+}
+
+/**
+ * Queries the current mode of multicast frames receiving.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param nic_data
+ * @param mode			The current multicast mode
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of addresses in the list
+ */
+void nic_query_multicast(const nic_t *nic_data,
+	nic_multicast_mode_t *mode,
+	size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	assert(mode != NULL);
+	nic_rxc_multicast_get_mode(&nic_data->rx_control, mode,
+		max_count, address_list, address_count);
+}
+
+/**
+ * Queries the current mode of broadcast frames receiving.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param nic_data
+ * @param mode			The new broadcast mode
+ */
+void nic_query_broadcast(const nic_t *nic_data,
+	nic_broadcast_mode_t *mode)
+{
+	assert(mode != NULL);
+	nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode);
+}
+
+/**
+ * Queries the current blocked source addresses.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param nic_data
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of addresses in the list
+ */
+void nic_query_blocked_sources(const nic_t *nic_data,
+	size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	nic_rxc_blocked_sources_get(&nic_data->rx_control,
+		max_count, address_list, address_count);
+}
+
+/**
+ * Query mask used for filtering according to the VLAN tags.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param nic_data
+ * @param mask		Must be 512 bytes long
+ *
+ * @return EOK
+ * @return ENOENT
+ */
+int nic_query_vlan_mask(const nic_t *nic_data, nic_vlan_mask_t *mask)
+{
+	assert(mask);
+	return nic_rxc_vlan_get_mask(&nic_data->rx_control, mask);
+}
+
+/**
+ * Query maximum number of WOL virtues of specified type allowed on the device.
+ * Can be called only from add_device and on_wol_virtue_* handlers.
+ *
+ * @param nic_data
+ * @param type		The type of the WOL virtues
+ *
+ * @return	Maximal number of allowed virtues of this type. -1 means this type
+ * 			is not supported at all.
+ */
+int nic_query_wol_max_caps(const nic_t *nic_data, nic_wv_type_t type)
+{
+	return nic_data->wol_virtues.caps_max[type];
+}
+
+/**
+ * Sets maximum number of WOL virtues of specified type allowed on the device.
+ * Can be called only from add_device and on_wol_virtue_* handlers.
+ *
+ * @param nic_data
+ * @param type		The type of the WOL virtues
+ * @param count		Maximal number of allowed virtues of this type. -1 means
+ * 					this type is not supported at all.
+ */
+void nic_set_wol_max_caps(nic_t *nic_data, nic_wv_type_t type, int count)
+{
+	nic_data->wol_virtues.caps_max[type] = count;
+}
+
+/**
+ * @param nic_data
+ * @return The driver-specific structure for this NIC.
+ */
+void *nic_get_specific(nic_t *nic_data)
+{
+	return nic_data->specific;
+}
+
+/**
+ * @param nic_data
+ * @param specific The driver-specific structure for this NIC.
+ */
+void nic_set_specific(nic_t *nic_data, void *specific)
+{
+	nic_data->specific = specific;
+}
+
+/**
+ * You can call the function only from one of the state change handlers.
+ * @param	nic_data
+ * @return	Current state of the NIC, prior to the actually executed change
+ */
+nic_device_state_t nic_query_state(nic_t *nic_data)
+{
+	return nic_data->state;
+}
+
+/**
+ * @param nic_data
+ * @return DDF device associated with this NIC.
+ */
+ddf_dev_t *nic_get_ddf_dev(nic_t *nic_data)
+{
+	return nic_data->dev;
+}
+
+/**
+ * @param nic_data
+ * @return DDF function associated with this NIC.
+ */
+ddf_fun_t *nic_get_ddf_fun(nic_t *nic_data)
+{
+	return nic_data->fun;
+}
+
+/** 
+ * @param dev DDF device associated with NIC
+ * @return The associated NIC structure
+ */
+nic_t *nic_get_from_ddf_dev(ddf_dev_t *dev)
+{
+	return (nic_t *) dev->driver_data;
+};
+
+/** 
+ * @param dev DDF function associated with NIC
+ * @return The associated NIC structure
+ */
+nic_t *nic_get_from_ddf_fun(ddf_fun_t *fun)
+{
+	return (nic_t *) fun->driver_data;
+};
+
+/**
+ * Raises the send_packets and send_bytes in device statistics.
+ *
+ * @param nic_data
+ * @param packets	Number of received packets
+ * @param bytes		Number of received bytes
+ */
+void nic_report_send_ok(nic_t *nic_data, size_t packets, size_t bytes)
+{
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	nic_data->stats.send_packets += packets;
+	nic_data->stats.send_bytes += bytes;
+	fibril_rwlock_write_unlock(&nic_data->stats_lock);
+}
+
+/**
+ * Raises total error counter (send_errors) and the concrete send error counter
+ * determined by the cause argument.
+ *
+ * @param nic_data
+ * @param cause		The concrete error cause.
+ */
+void nic_report_send_error(nic_t *nic_data, nic_send_error_cause_t cause, 
+    unsigned count)
+{
+	if (count == 0)
+		return;
+	
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	nic_data->stats.send_errors += count;
+	switch (cause) {
+	case NIC_SEC_BUFFER_FULL:
+		nic_data->stats.send_dropped += count;
+		break;
+	case NIC_SEC_ABORTED:
+		nic_data->stats.send_aborted_errors += count;
+		break;
+	case NIC_SEC_CARRIER_LOST:
+		nic_data->stats.send_carrier_errors += count;
+		break;
+	case NIC_SEC_FIFO_OVERRUN:
+		nic_data->stats.send_fifo_errors += count;
+		break;
+	case NIC_SEC_HEARTBEAT:
+		nic_data->stats.send_heartbeat_errors += count;
+		break;
+	case NIC_SEC_WINDOW_ERROR:
+		nic_data->stats.send_window_errors += count;
+		break;
+	case NIC_SEC_OTHER:
+		break;
+	}
+	fibril_rwlock_write_unlock(&nic_data->stats_lock);
+}
+
+/**
+ * Raises total error counter (receive_errors) and the concrete receive error
+ * counter determined by the cause argument.
+ *
+ * @param nic_data
+ * @param cause		The concrete error cause
+ */
+void nic_report_receive_error(nic_t *nic_data,
+	nic_receive_error_cause_t cause, unsigned count)
+{
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	nic_data->stats.receive_errors += count;
+	switch (cause) {
+	case NIC_REC_BUFFER_FULL:
+		nic_data->stats.receive_dropped += count;
+		break;
+	case NIC_REC_LENGTH:
+		nic_data->stats.receive_length_errors += count;
+		break;
+	case NIC_REC_BUFFER_OVERFLOW:
+		nic_data->stats.receive_dropped += count;
+		break;
+	case NIC_REC_CRC:
+		nic_data->stats.receive_crc_errors += count;
+		break;
+	case NIC_REC_FRAME_ALIGNMENT:
+		nic_data->stats.receive_frame_errors += count;
+		break;
+	case NIC_REC_FIFO_OVERRUN:
+		nic_data->stats.receive_fifo_errors += count;
+		break;
+	case NIC_REC_MISSED:
+		nic_data->stats.receive_missed_errors += count;
+		break;
+	case NIC_REC_OTHER:
+		break;
+	}
+	fibril_rwlock_write_unlock(&nic_data->stats_lock);
+}
+
+/**
+ * Raises the collisions counter in device statistics.
+ */
+void nic_report_collisions(nic_t *nic_data, unsigned count)
+{
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	nic_data->stats.collisions += count;
+	fibril_rwlock_write_unlock(&nic_data->stats_lock);
+}
+
+/** Just wrapper for checking nonzero time interval 
+ *
+ *  @oaram t The interval to check
+ *  @returns Zero if the t is nonzero interval
+ *  @returns Nonzero if t is zero interval
+ */
+static int timeval_nonpositive(struct timeval t) {
+	return (t.tv_sec <= 0) && (t.tv_usec <= 0);
+}
+
+/** Main function of software period fibrill
+ *
+ *  Just calls poll() in the nic->poll_period period
+ *
+ *  @param  data The NIC structure pointer
+ *
+ *  @return 0, never reached
+ */
+static int period_fibril_fun(void *data)
+{
+	nic_t *nic = data;
+	struct sw_poll_info *info = &nic->sw_poll_info;
+	while (true) {
+		fibril_rwlock_read_lock(&nic->main_lock);
+		int run = info->run;
+		int running = info->running;
+		struct timeval remaining = nic->poll_period;
+		fibril_rwlock_read_unlock(&nic->main_lock);
+
+		if (!running) {
+			remaining.tv_sec = 5;
+			remaining.tv_usec = 0;
+		}
+
+		/* Wait the period (keep attention to overflows) */
+		while (!timeval_nonpositive(remaining)) {
+			suseconds_t wait = 0;
+			if (remaining.tv_sec > 0) {
+				time_t wait_sec = remaining.tv_sec;
+				/* wait maximaly 5 seconds to get reasonable reaction time
+				 * when period is reset
+				 */
+				if (wait_sec > 5)
+					wait_sec = 5;
+
+				wait = (suseconds_t) wait_sec * 1000000;
+
+				remaining.tv_sec -= wait_sec;
+			} else {
+				wait = remaining.tv_usec;
+
+				if (wait > 5 * 1000000) {
+					wait = 5 * 1000000;
+				}
+
+				remaining.tv_usec -= wait;
+			}
+			async_usleep(wait);
+			
+			/* Check if the period was not reset */
+			if (info->run != run)
+				break;
+		}
+		
+		/* Provide polling if the period finished */
+		fibril_rwlock_read_lock(&nic->main_lock);
+		if (info->running && info->run == run) {
+			nic->on_poll_request(nic);
+		}
+		fibril_rwlock_read_unlock(&nic->main_lock);
+	}
+	return 0;
+}
+
+/** Starts software periodic polling
+ *
+ *  Reset to new period if the original period was running
+ *
+ *  @param nic_data Nic data structure
+ */
+void nic_sw_period_start(nic_t *nic_data)
+{
+	/* Create the fibril if it is not crated */
+	if (nic_data->sw_poll_info.fibril == 0) {
+		nic_data->sw_poll_info.fibril = fibril_create(period_fibril_fun, 
+		    nic_data);
+		nic_data->sw_poll_info.running = 0;
+		nic_data->sw_poll_info.run = 0;
+
+		/* Start fibril */
+		fibril_add_ready(nic_data->sw_poll_info.fibril);
+	}
+
+	/* Inform fibril about running with new period */
+	nic_data->sw_poll_info.run = (nic_data->sw_poll_info.run + 1) % 100;
+	nic_data->sw_poll_info.running = 1;
+}
+
+/** Stops software periodic polling
+ *
+ *  @param nic_data Nic data structure
+ */
+void nic_sw_period_stop(nic_t *nic_data)
+{
+	nic_data->sw_poll_info.running = 0;
+}
+
+// FIXME: Later
+#if 0
+
+/** Lock packet for DMA usage
+ *
+ * @param packet
+ * @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;
+}
+
+/** Unlock packet after DMA usage
+ *
+ * @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
+
+/** @}
+ */
Index: uspace/lib/nic/src/nic_impl.c
===================================================================
--- uspace/lib/nic/src/nic_impl.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/src/nic_impl.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,878 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Default DDF NIC interface methods implementations
+ */
+
+#include <str_error.h>
+#include <ipc/services.h>
+#include <ns.h>
+#include <packet_client.h>
+#include <packet_remote.h>
+#include "nic_driver.h"
+#include "nic_impl.h"
+
+/**
+ * Default implementation of the set_state method. Trivial.
+ *
+ * @param		fun
+ * @param[out]	state
+ *
+ * @return EOK always.
+ */
+int nic_get_state_impl(ddf_fun_t *fun, nic_device_state_t *state)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->main_lock);
+	*state = nic_data->state;
+	fibril_rwlock_read_unlock(&nic_data->main_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of the set_state method. Changes the internal
+ * driver's state, calls the appropriate callback and notifies the NIL service
+ * about this change.
+ *
+ * @param	fun
+ * @param	state	The new device's state
+ *
+ * @return EOK		If the state was changed
+ * @return EINVAL	If the state cannot be changed
+ */
+int nic_set_state_impl(ddf_fun_t *fun, nic_device_state_t state)
+{
+	if (state >= NIC_STATE_MAX) {
+		return EINVAL;
+	}
+
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+
+	fibril_rwlock_write_lock(&nic_data->main_lock);
+	if (nic_data->state == state) {
+		/* No change, nothing to do */
+		fibril_rwlock_write_unlock(&nic_data->main_lock);
+		return EOK;
+	}
+	if (state == NIC_STATE_ACTIVE) {
+		if (nic_data->nil_session == NULL || nic_data->net_session == NULL
+		    || nic_data->device_id < 0) {
+			fibril_rwlock_write_unlock(&nic_data->main_lock);
+			return EINVAL;
+		}
+	}
+
+	state_change_handler event_handler = NULL;
+	switch (state) {
+	case NIC_STATE_STOPPED:
+		event_handler = nic_data->on_stopping;
+		break;
+	case NIC_STATE_DOWN:
+		event_handler = nic_data->on_going_down;
+		break;
+	case NIC_STATE_ACTIVE:
+		event_handler = nic_data->on_activating;
+		break;
+	default:
+		break;
+	}
+	if (event_handler != NULL) {
+		int rc = event_handler(nic_data);
+		if (rc != EOK) {
+			fibril_rwlock_write_unlock(&nic_data->main_lock);
+			return EINVAL;
+		}
+	}
+
+	if (state == NIC_STATE_STOPPED) {
+		/* Notify upper layers that we are reseting the MAC */
+		int rc = nil_addr_changed_msg(nic_data->nil_session,
+			nic_data->device_id, &nic_data->default_mac);
+		nic_data->poll_mode = nic_data->default_poll_mode;
+		memcpy(&nic_data->poll_period, &nic_data->default_poll_period,
+			sizeof (struct timeval));
+		if (rc != EOK) {
+			/* We have already ran the on stopped handler, even if we
+			 * terminated the state change we would end up in undefined state.
+			 * Therefore we just log the problem. */
+		}
+
+		fibril_rwlock_write_lock(&nic_data->stats_lock);
+		bzero(&nic_data->stats, sizeof (nic_device_stats_t));
+		fibril_rwlock_write_unlock(&nic_data->stats_lock);
+
+		fibril_rwlock_write_lock(&nic_data->rxc_lock);
+		nic_rxc_clear(&nic_data->rx_control);
+		/* Reinsert device's default MAC */
+		nic_rxc_set_addr(&nic_data->rx_control, NULL,
+			&nic_data->default_mac);
+		fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+		memcpy(&nic_data->mac, &nic_data->default_mac, sizeof (nic_address_t));
+
+		fibril_rwlock_write_lock(&nic_data->wv_lock);
+		nic_wol_virtues_clear(&nic_data->wol_virtues);
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+
+		/* Ensure stopping period of NIC_POLL_SOFTWARE_PERIODIC */
+		nic_sw_period_stop(nic_data);
+	}
+
+	nic_data->state = state;
+
+	nil_device_state_msg(nic_data->nil_session, nic_data->device_id, state);
+
+	fibril_rwlock_write_unlock(&nic_data->main_lock);
+
+	return EOK;
+}
+
+/**
+ * Default implementation of the send_message method.
+ * Send messages to the network.
+ *
+ * @param	fun
+ * @param	packet_id	ID of the first packet in a queue of sent packets
+ *
+ * @return EOK		If the message was sent
+ * @return EBUSY	If the device is not in state when the packet can be set.
+ * @return EINVAL	If the packet ID is invalid
+ */
+int nic_send_message_impl(ddf_fun_t *fun, packet_id_t packet_id)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	packet_t *packet, *next;
+
+	fibril_rwlock_read_lock(&nic_data->main_lock);
+	if (nic_data->state != NIC_STATE_ACTIVE || nic_data->tx_busy) {
+		fibril_rwlock_read_unlock(&nic_data->main_lock);
+		pq_release_remote(nic_data->net_session, packet_id);
+		return EBUSY;
+	}
+
+	int rc = packet_translate_remote(nic_data->net_session, &packet, packet_id);
+
+	if (rc != EOK) {
+		fibril_rwlock_read_unlock(&nic_data->main_lock);
+		return EINVAL;
+	}
+
+	/*
+	 * Process the packet queue. Each sent packet must be detached from the
+	 * queue and destroyed. This is why the cycle differs from loopback's
+	 * cycle, where the packets are immediately used in upper layers and
+	 * therefore they must not be destroyed (released).
+	 */
+	assert(nic_data->write_packet != NULL);
+	do {
+		next = pq_detach(packet);
+		nic_data->write_packet(nic_data, packet);
+		packet = next;
+	} while (packet);
+	fibril_rwlock_read_unlock(&nic_data->main_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of the connect_to_nil method.
+ * Connects the driver to the NIL service.
+ *
+ * @param	fun
+ * @param	nil_service	ID of the server implementing the NIL service
+ * @param	device_id	ID of the device as used in higher layers
+ *
+ * @return EOK		If the services were bound
+ * @return 			Negative error code from service_connect_blocking
+ */
+int nic_connect_to_nil_impl(ddf_fun_t *fun, services_t nil_service,
+    nic_device_id_t device_id)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_write_lock(&nic_data->main_lock);
+	
+	nic_data->device_id = device_id;
+	
+	nic_data->nil_session = service_connect_blocking(EXCHANGE_SERIALIZE,
+	    nil_service, 0, 0);
+	if (nic_data->nil_session != NULL) {
+		fibril_rwlock_write_unlock(&nic_data->main_lock);
+		return EOK;
+	}
+	
+	fibril_rwlock_write_unlock(&nic_data->main_lock);
+	return EHANGUP;
+}
+
+/**
+ * Default implementation of the get_address method.
+ * Retrieves the NIC's physical address.
+ *
+ * @param	fun
+ * @param	address	Pointer to the structure where the address will be stored.
+ *
+ * @return EOK		If the services were bound
+ * @return ELIMIT	If the buffer is too short
+ */
+int nic_get_address_impl(ddf_fun_t *fun, nic_address_t *address)
+{
+	assert(address);
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->main_lock);
+	memcpy(address, &nic_data->mac, sizeof (nic_address_t));
+	fibril_rwlock_read_unlock(&nic_data->main_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of the get_stats method. Copies the statistics from
+ * the drivers data to supplied buffer.
+ *
+ * @param		fun
+ * @param[out]	stats	The buffer for statistics
+ *
+ * @return EOK (cannot fail)
+ */
+int nic_get_stats_impl(ddf_fun_t *fun, nic_device_stats_t *stats)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	assert (stats != NULL);
+	fibril_rwlock_read_lock(&nic_data->stats_lock);
+	memcpy(stats, &nic_data->stats, sizeof (nic_device_stats_t));
+	fibril_rwlock_read_unlock(&nic_data->stats_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of unicast_get_mode method.
+ *
+ * @param		fun
+ * @param[out]	mode		Current operation mode
+ * @param[in]	max_count	Max number of addresses that can be written into the
+ * 							buffer (addr_list).
+ * @param[out]	addr_list	Buffer for addresses
+ * @param[out]	addr_count	Number of addresses written into the list
+ *
+ * @return EOK
+ */
+int nic_unicast_get_mode_impl(ddf_fun_t *fun, nic_unicast_mode_t *mode,
+	size_t max_count, nic_address_t *addr_list, size_t *addr_count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	nic_rxc_unicast_get_mode(&nic_data->rx_control, mode, max_count,
+		addr_list, addr_count);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of unicast_set_mode method.
+ *
+ * @param		fun
+ * @param[in]	mode		New operation mode
+ * @param[in]	addr_list	List of unicast addresses
+ * @param[in]	addr_count	Number of addresses in the list
+ *
+ * @return EOK
+ * @return EINVAL
+ * @return ENOTSUP
+ * @return ENOMEM
+ */
+int nic_unicast_set_mode_impl(ddf_fun_t *fun,
+	nic_unicast_mode_t mode, const nic_address_t *addr_list, size_t addr_count)
+{
+	assert((addr_count == 0 && addr_list == NULL)
+		|| (addr_count != 0 && addr_list != NULL));
+	size_t i;
+	for (i = 0; i < addr_count; ++i) {
+		if (addr_list[i].address[0] & 1)
+			return EINVAL;
+	}
+
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	int rc = ENOTSUP;
+	if (nic_data->on_unicast_mode_change) {
+		rc = nic_data->on_unicast_mode_change(nic_data,
+			mode, addr_list, addr_count);
+	}
+	if (rc == EOK) {
+		rc = nic_rxc_unicast_set_mode(&nic_data->rx_control, mode,
+			addr_list, addr_count);
+		/* After changing the mode the addr db gets cleared, therefore we have
+		 * to reinsert also the physical address of NIC.
+		 */
+		nic_rxc_set_addr(&nic_data->rx_control, NULL, &nic_data->mac);
+	}
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+
+/**
+ * Default implementation of multicast_get_mode method.
+ *
+ * @param		fun
+ * @param[out]	mode		Current operation mode
+ * @param[in]	max_count	Max number of addresses that can be written into the
+ * 							buffer (addr_list).
+ * @param[out]	addr_list	Buffer for addresses
+ * @param[out]	addr_count	Number of addresses written into the list
+ *
+ * @return EOK
+ */
+int nic_multicast_get_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t *mode,
+	size_t max_count, nic_address_t *addr_list, size_t *addr_count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	nic_rxc_multicast_get_mode(&nic_data->rx_control, mode, max_count,
+		addr_list, addr_count);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of multicast_set_mode method.
+ *
+ * @param		fun
+ * @param[in]	mode		New operation mode
+ * @param[in]	addr_list	List of multicast addresses
+ * @param[in]	addr_count	Number of addresses in the list
+ *
+ * @return EOK
+ * @return EINVAL
+ * @return ENOTSUP
+ * @return ENOMEM
+ */
+int nic_multicast_set_mode_impl(ddf_fun_t *fun,	nic_multicast_mode_t mode,
+	const nic_address_t *addr_list, size_t addr_count)
+{
+	assert((addr_count == 0 && addr_list == NULL)
+		|| (addr_count != 0 && addr_list != NULL));
+	size_t i;
+	for (i = 0; i < addr_count; ++i) {
+		if (!(addr_list[i].address[0] & 1))
+			return EINVAL;
+	}
+
+	nic_t *nic_data = (nic_t *) fun->dev->driver_data;
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	int rc = ENOTSUP;
+	if (nic_data->on_multicast_mode_change) {
+		rc = nic_data->on_multicast_mode_change(nic_data, mode, addr_list, addr_count);
+	}
+	if (rc == EOK) {
+		rc = nic_rxc_multicast_set_mode(&nic_data->rx_control, mode,
+			addr_list, addr_count);
+	}
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of broadcast_get_mode method.
+ *
+ * @param		fun
+ * @param[out]	mode		Current operation mode
+ *
+ * @return EOK
+ */
+int nic_broadcast_get_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t *mode)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of broadcast_set_mode method.
+ *
+ * @param		fun
+ * @param[in]	mode		New operation mode
+ *
+ * @return EOK
+ * @return EINVAL
+ * @return ENOTSUP
+ * @return ENOMEM
+ */
+int nic_broadcast_set_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t mode)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	int rc = ENOTSUP;
+	if (nic_data->on_broadcast_mode_change) {
+		rc = nic_data->on_broadcast_mode_change(nic_data, mode);
+	}
+	if (rc == EOK) {
+		rc = nic_rxc_broadcast_set_mode(&nic_data->rx_control, mode);
+	}
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of blocked_sources_get method.
+ *
+ * @param		fun
+ * @param[in]	max_count	Max number of addresses that can be written into the
+ * 							buffer (addr_list).
+ * @param[out]	addr_list	Buffer for addresses
+ * @param[out]	addr_count	Number of addresses written into the list
+ *
+ * @return EOK
+ */
+int nic_blocked_sources_get_impl(ddf_fun_t *fun,
+	size_t max_count, nic_address_t *addr_list, size_t *addr_count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	nic_rxc_blocked_sources_get(&nic_data->rx_control,
+		max_count, addr_list, addr_count);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of blocked_sources_set method.
+ *
+ * @param		fun
+ * @param[in]	addr_list	List of blocked addresses
+ * @param[in]	addr_count	Number of addresses in the list
+ *
+ * @return EOK
+ * @return EINVAL
+ * @return ENOTSUP
+ * @return ENOMEM
+ */
+int nic_blocked_sources_set_impl(ddf_fun_t *fun,
+	const nic_address_t *addr_list, size_t addr_count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	if (nic_data->on_blocked_sources_change) {
+		nic_data->on_blocked_sources_change(nic_data, addr_list, addr_count);
+	}
+	int rc = nic_rxc_blocked_sources_set(&nic_data->rx_control,
+		addr_list, addr_count);
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of vlan_get_mask method.
+ *
+ * @param		fun
+ * @param[out]	mask	Current VLAN mask
+ *
+ * @return EOK
+ * @return ENOENT	If the mask is not set
+ */
+int nic_vlan_get_mask_impl(ddf_fun_t *fun, nic_vlan_mask_t *mask)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	int rc = nic_rxc_vlan_get_mask(&nic_data->rx_control, mask);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of vlan_set_mask method.
+ *
+ * @param		fun
+ * @param[in]	mask	The new VLAN mask
+ *
+ * @return EOK
+ * @return ENOMEM
+ */
+int nic_vlan_set_mask_impl(ddf_fun_t *fun, const nic_vlan_mask_t *mask)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	int rc = nic_rxc_vlan_set_mask(&nic_data->rx_control, mask);
+	if (rc == EOK && nic_data->on_vlan_mask_change) {
+		nic_data->on_vlan_mask_change(nic_data, mask);
+	}
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of the wol_virtue_add method.
+ * Create a new WOL virtue.
+ *
+ * @param[in]	fun
+ * @param[in]	type		Type of the virtue
+ * @param[in]	data		Data required for this virtue (depends on type)
+ * @param[in]	length		Length of the data
+ * @param[out]	filter		Identifier of the new virtue
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return EINVAL	If virtue type is not supported or the data are invalid
+ * @return ELIMIT	If the driver does not allow to create more virtues
+ * @return ENOMEM	If there was not enough memory to complete the operation
+ */
+int nic_wol_virtue_add_impl(ddf_fun_t *fun, nic_wv_type_t type,
+	const void *data, size_t length, nic_wv_id_t *new_id)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	if (nic_data->on_wol_virtue_add == NULL
+		|| nic_data->on_wol_virtue_remove == NULL) {
+		return ENOTSUP;
+	}
+	if (type == NIC_WV_NONE || type >= NIC_WV_MAX) {
+		return EINVAL;
+	}
+	if (nic_wol_virtues_verify(type, data, length) != EOK) {
+		return EINVAL;
+	}
+	nic_wol_virtue_t *virtue = malloc(sizeof (nic_wol_virtue_t));
+	if (virtue == NULL) {
+		return ENOMEM;
+	}
+	bzero(virtue, sizeof (nic_wol_virtue_t));
+	if (length != 0) {
+		virtue->data = malloc(length);
+		if (virtue->data == NULL) {
+			free(virtue);
+			return ENOMEM;
+		}
+		memcpy((void *) virtue->data, data, length);
+	}
+	virtue->type = type;
+	virtue->length = length;
+
+	fibril_rwlock_write_lock(&nic_data->wv_lock);
+	/* Check if we haven't reached the maximum */
+	if (nic_data->wol_virtues.caps_max[type] < 0) {
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+		return EINVAL;
+	}
+	if ((int) nic_data->wol_virtues.lists_sizes[type] >=
+		nic_data->wol_virtues.caps_max[type]) {
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+		return ELIMIT;
+	}
+	/* Call the user-defined add callback */
+	int rc = nic_data->on_wol_virtue_add(nic_data, virtue);
+	if (rc != EOK) {
+		free(virtue->data);
+		free(virtue);
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+		return rc;
+	}
+	rc = nic_wol_virtues_add(&nic_data->wol_virtues, virtue);
+	if (rc != EOK) {
+		/* If the adding fails, call user-defined remove callback */
+		nic_data->on_wol_virtue_remove(nic_data, virtue);
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+		free(virtue->data);
+		free(virtue);
+		return rc;
+	} else {
+		*new_id = virtue->id;
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+	}
+	return EOK;
+}
+
+/**
+ * Default implementation of the wol_virtue_remove method.
+ * Destroys the WOL virtue.
+ *
+ * @param[in] fun
+ * @param[in] id	WOL virtue identification
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return ENOTSUP	If the function is not supported by the driver or device
+ * @return ENOENT	If the virtue identifier is not valid.
+ */
+int nic_wol_virtue_remove_impl(ddf_fun_t *fun, nic_wv_id_t id)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	if (nic_data->on_wol_virtue_add == NULL
+		|| nic_data->on_wol_virtue_remove == NULL) {
+		return ENOTSUP;
+	}
+	fibril_rwlock_write_lock(&nic_data->wv_lock);
+	nic_wol_virtue_t *virtue =
+		nic_wol_virtues_remove(&nic_data->wol_virtues, id);
+	if (virtue == NULL) {
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+		return ENOENT;
+	}
+	/* The event handler is called after the filter was removed */
+	nic_data->on_wol_virtue_remove(nic_data, virtue);
+	fibril_rwlock_write_unlock(&nic_data->wv_lock);
+	free(virtue->data);
+	free(virtue);
+	return EOK;
+}
+
+/**
+ * Default implementation of the wol_virtue_probe method.
+ * Queries the type and data of the virtue.
+ *
+ * @param[in]	fun
+ * @param[in]	id		Virtue identifier
+ * @param[out]	type		Type of the virtue. Can be NULL.
+ * @param[out]	data		Data used when the virtue was created. Can be NULL.
+ * @param[out]	length		Length of the data. Can be NULL.
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return ENOENT	If the virtue identifier is not valid.
+ * @return ENOMEM	If there was not enough memory to complete the operation
+ */
+int nic_wol_virtue_probe_impl(ddf_fun_t *fun, nic_wv_id_t id,
+	nic_wv_type_t *type, size_t max_length, void *data, size_t *length)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->wv_lock);
+	const nic_wol_virtue_t *virtue =
+			nic_wol_virtues_find(&nic_data->wol_virtues, id);
+	if (virtue == NULL) {
+		*type = NIC_WV_NONE;
+		*length = 0;
+		fibril_rwlock_read_unlock(&nic_data->wv_lock);
+		return ENOENT;
+	} else {
+		*type = virtue->type;
+		if (max_length > virtue->length) {
+			max_length = virtue->length;
+		}
+		memcpy(data, virtue->data, max_length);
+		*length = virtue->length;
+		fibril_rwlock_read_unlock(&nic_data->wv_lock);
+		return EOK;
+	}
+}
+
+/**
+ * Default implementation of the wol_virtue_list method.
+ * List filters of the specified type. If NIC_WV_NONE is the type, it lists all
+ * filters.
+ *
+ * @param[in]	fun
+ * @param[in]	type	Type of the virtues
+ * @param[out]	virtues	Vector of virtue ID's.
+ * @param[out]	count	Length of the data. Can be NULL.
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return ENOENT	If the filter identification is not valid.
+ * @return ENOMEM	If there was not enough memory to complete the operation
+ */
+int nic_wol_virtue_list_impl(ddf_fun_t *fun, nic_wv_type_t type,
+	size_t max_count, nic_wv_id_t *id_list, size_t *id_count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->wv_lock);
+	int rc = nic_wol_virtues_list(&nic_data->wol_virtues, type,
+		max_count, id_list, id_count);
+	fibril_rwlock_read_unlock(&nic_data->wv_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of the wol_virtue_get_caps method.
+ * Queries for the current capabilities for some type of filter.
+ *
+ * @param[in]	fun
+ * @param[in]	type	Type of the virtues
+ * @param[out]	count	Number of virtues of this type that can be currently set
+ *
+ * @return EOK		If the operation was successfully completed
+  */
+int nic_wol_virtue_get_caps_impl(ddf_fun_t *fun, nic_wv_type_t type, int *count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->wv_lock);
+	*count = nic_data->wol_virtues.caps_max[type]
+	    - (int) nic_data->wol_virtues.lists_sizes[type];
+	fibril_rwlock_read_unlock(&nic_data->wv_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of the poll_get_mode method.
+ * Queries the current interrupt/poll mode of the NIC
+ *
+ * @param[in]	fun
+ * @param[out]	mode		Current poll mode
+ * @param[out]	period		Period used in periodic polling. Can be NULL.
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return ENOTSUP	This function is not supported.
+ * @return EPARTY	Error in communication protocol
+ */
+int nic_poll_get_mode_impl(ddf_fun_t *fun,
+	nic_poll_mode_t *mode, struct timeval *period)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->main_lock);
+	*mode = nic_data->poll_mode;
+	memcpy(period, &nic_data->poll_period, sizeof (struct timeval));
+	fibril_rwlock_read_unlock(&nic_data->main_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of the poll_set_mode_impl method.
+ * Sets the interrupt/poll mode of the NIC.
+ *
+ * @param[in]	fun
+ * @param[in]	mode		The new poll mode
+ * @param[in]	period		Period used in periodic polling. Can be NULL.
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return ENOTSUP	This operation is not supported.
+ * @return EPARTY	Error in communication protocol
+ */
+int nic_poll_set_mode_impl(ddf_fun_t *fun,
+	nic_poll_mode_t mode, const struct timeval *period)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	/* If the driver does not implement the poll mode change handler it cannot
+	 * switch off interrupts and this is not supported. */
+	if (nic_data->on_poll_mode_change == NULL)
+		return ENOTSUP;
+
+	if ((mode == NIC_POLL_ON_DEMAND) && nic_data->on_poll_request == NULL)
+		return ENOTSUP;
+
+	if (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) {
+		if (period == NULL)
+			return EINVAL;
+		if (period->tv_sec == 0 && period->tv_usec == 0)
+			return EINVAL;
+		if (period->tv_sec < 0 || period->tv_usec < 0)
+			return EINVAL;
+	}
+	fibril_rwlock_write_lock(&nic_data->main_lock);
+	int rc = nic_data->on_poll_mode_change(nic_data, mode, period);
+	assert(rc == EOK || rc == ENOTSUP || rc == EINVAL);
+	if (rc == ENOTSUP && (nic_data->on_poll_request != NULL) && 
+	    (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) ) {
+
+		rc = nic_data->on_poll_mode_change(nic_data, NIC_POLL_ON_DEMAND, NULL);
+		assert(rc == EOK || rc == ENOTSUP);
+		if (rc == EOK) 
+			nic_sw_period_start(nic_data);
+	}
+	if (rc == EOK) {
+		nic_data->poll_mode = mode;
+		if (period)
+			nic_data->poll_period = *period;
+	}
+	fibril_rwlock_write_unlock(&nic_data->main_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of the poll_now method.
+ * Wrapper for the actual poll implementation.
+ *
+ * @param[in]	fun
+ *
+ * @return EOK		If the NIC was polled
+ * @return ENOTSUP	If the function is not supported
+ * @return EINVAL	If the NIC is not in state where it allows on demand polling
+ */
+int nic_poll_now_impl(ddf_fun_t *fun) {
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->main_lock);
+	if (nic_data->poll_mode != NIC_POLL_ON_DEMAND) {
+		fibril_rwlock_read_unlock(&nic_data->main_lock);
+		return EINVAL;
+	}
+	if (nic_data->on_poll_request != NULL) {
+		nic_data->on_poll_request(nic_data);
+		fibril_rwlock_read_unlock(&nic_data->main_lock);
+		return EOK;
+	} else {
+		fibril_rwlock_read_unlock(&nic_data->main_lock);
+		return ENOTSUP;
+	}
+}
+
+/** Default implementation of the device_added method
+ *
+ * Just calls nic_ready.
+ *
+ * @param dev
+ *
+ */
+void nic_device_added_impl(ddf_dev_t *dev)
+{
+	nic_ready((nic_t *) dev->driver_data);
+}
+
+/**
+ * Default handler for unknown methods (outside of the NIC interface).
+ * Logs a warning message and returns ENOTSUP to the caller.
+ *
+ * @param fun		The DDF function where the method should be called.
+ * @param callid	IPC call identifier
+ * @param call		IPC call data
+ */
+void nic_default_handler_impl(ddf_fun_t *fun, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	async_answer_0(callid, ENOTSUP);
+}
+
+/**
+ * Default (empty) OPEN function implementation.
+ *
+ * @param fun	The DDF function
+ *
+ * @return EOK always.
+ */
+int nic_open_impl(ddf_fun_t *fun)
+{
+	return EOK;
+}
+
+/**
+ * Default (empty) OPEN function implementation.
+ *
+ * @param fun	The DDF function
+ */
+void nic_close_impl(ddf_fun_t *fun)
+{
+}
+
+/** @}
+ */
Index: uspace/lib/nic/src/nic_rx_control.c
===================================================================
--- uspace/lib/nic/src/nic_rx_control.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/src/nic_rx_control.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,539 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Incoming packets (frames) filtering functions
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <bool.h>
+#include <errno.h>
+#include <net/device.h>
+#include <net_checksum.h>
+#include <packet_client.h>
+#include "nic_rx_control.h"
+
+/**
+ * Initializes the receive control structure
+ *
+ * @param rxc
+ *
+ * @return EOK		On success
+ * @return ENOMEM	On not enough memory
+ * @return EINVAL	Internal error, should not happen
+ */
+int nic_rxc_init(nic_rxc_t *rxc)
+{
+	bzero(rxc, sizeof (nic_rxc_t));
+	int rc;
+	rc = nic_addr_db_init(&rxc->blocked_sources, ETH_ADDR);
+	if (rc != EOK) {
+		return rc;
+	}
+	rc = nic_addr_db_init(&rxc->unicast_addrs, ETH_ADDR);
+	if (rc != EOK) {
+		return rc;
+	}
+	rc = nic_addr_db_init(&rxc->multicast_addrs, ETH_ADDR);
+	if (rc != EOK) {
+		return rc;
+	}
+	rxc->block_sources = false;
+	rxc->unicast_mode = NIC_UNICAST_DEFAULT;
+	rxc->multicast_mode = NIC_MULTICAST_BLOCKED;
+	rxc->broadcast_mode = NIC_BROADCAST_ACCEPTED;
+
+	/* Default NIC behavior */
+	rxc->unicast_exact = true;
+	rxc->multicast_exact = false;
+	rxc->vlan_exact = true;
+	return EOK;
+}
+
+/** Reinitialize the structure.
+ *
+ * @param filters
+ */
+int nic_rxc_clear(nic_rxc_t *rxc)
+{
+	nic_addr_db_destroy(&rxc->unicast_addrs);
+	nic_addr_db_destroy(&rxc->multicast_addrs);
+	nic_addr_db_destroy(&rxc->blocked_sources);
+	return nic_rxc_init(rxc);
+}
+
+/** Set the NIC's address that should be used as the default address during
+ * the checks.
+ *
+ * @param rxc
+ * @param prev_addr Previously used default address. Can be NULL
+ *                  if this is the first call after filters' initialization.
+ * @param curr_addr The new default address.
+ *
+ * @return EOK On success
+ *
+ */
+int nic_rxc_set_addr(nic_rxc_t *rxc, const nic_address_t *prev_addr,
+    const nic_address_t *curr_addr)
+{
+	if (prev_addr != NULL) {
+		int rc = nic_addr_db_remove(&rxc->unicast_addrs,
+		    (const uint8_t *) &prev_addr->address);
+		if (rc != EOK)
+			return rc;
+	}
+	
+	return nic_addr_db_insert(&rxc->unicast_addrs,
+	    (const uint8_t *) &curr_addr->address);
+}
+
+/* Helper structure */
+typedef struct {
+	size_t max_count;
+	nic_address_t *address_list;
+	size_t address_count;
+} nic_rxc_add_addr_t;
+
+/** Helper function */
+static void nic_rxc_add_addr(const uint8_t *addr, void *arg)
+{
+	nic_rxc_add_addr_t *hs = (nic_rxc_add_addr_t *) arg;
+	if (hs->address_count < hs->max_count && hs->address_list != NULL) {
+		memcpy(&hs->address_list[hs->address_count].address, addr, ETH_ADDR);
+	}
+	hs->address_count++;
+}
+
+/**
+ * Queries the current mode of unicast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The new unicast mode
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of accepted addresses (can be > max_count)
+ */
+void nic_rxc_unicast_get_mode(const nic_rxc_t *rxc, nic_unicast_mode_t *mode,
+	size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	*mode = rxc->unicast_mode;
+	if (rxc->unicast_mode == NIC_UNICAST_LIST) {
+		nic_rxc_add_addr_t hs = {
+			.max_count = max_count,
+			.address_list = address_list,
+			.address_count = 0
+		};
+		nic_addr_db_foreach(&rxc->unicast_addrs, nic_rxc_add_addr, &hs);
+		if (address_count) {
+			*address_count = hs.address_count;
+		}
+	}
+}
+
+/**
+ * Sets the current mode of unicast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The current unicast mode
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of addresses in the list
+ *
+ * @return EOK		On success
+ * @return EINVAL	If any of the MAC addresses is not a unicast address.
+ * @return ENOMEM	If there was not enough memory
+ */
+int nic_rxc_unicast_set_mode(nic_rxc_t *rxc, nic_unicast_mode_t mode,
+	const nic_address_t *address_list, size_t address_count)
+{
+	if (mode == NIC_UNICAST_LIST && address_list == NULL) {
+		return EINVAL;
+	} else if (mode != NIC_UNICAST_LIST && address_list != NULL) {
+		return EINVAL;
+	}
+
+	if (rxc->unicast_mode == NIC_UNICAST_LIST) {
+		nic_addr_db_clear(&rxc->unicast_addrs);
+	}
+	rxc->unicast_mode = mode;
+	size_t i;
+	for (i = 0; i < address_count; ++i) {
+		int rc = nic_addr_db_insert(&rxc->unicast_addrs,
+			(const uint8_t *) &address_list[i].address);
+		if (rc == ENOMEM) {
+			return ENOMEM;
+		}
+	}
+	return EOK;
+}
+
+/**
+ * Queries the current mode of multicast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The current multicast mode
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of accepted addresses (can be > max_count)
+ */
+void nic_rxc_multicast_get_mode(const nic_rxc_t *rxc,
+	nic_multicast_mode_t *mode, size_t max_count, nic_address_t *address_list,
+	size_t *address_count)
+{
+	*mode = rxc->multicast_mode;
+	if (rxc->multicast_mode == NIC_MULTICAST_LIST) {
+		nic_rxc_add_addr_t hs = {
+			.max_count = max_count,
+			.address_list = address_list,
+			.address_count = 0
+		};
+		nic_addr_db_foreach(&rxc->multicast_addrs, nic_rxc_add_addr, &hs);
+		if (address_count) {
+			*address_count = hs.address_count;
+		}
+	}
+}
+
+/**
+ * Sets the current mode of multicast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The new multicast mode
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of addresses in the list
+ *
+ * @return EOK		On success
+ * @return EINVAL	If any of the MAC addresses is not a multicast address.
+ * @return ENOMEM	If there was not enough memory
+ */
+int nic_rxc_multicast_set_mode(nic_rxc_t *rxc, nic_multicast_mode_t mode,
+	const nic_address_t *address_list, size_t address_count)
+{
+	if (mode == NIC_MULTICAST_LIST && address_list == NULL)
+		return EINVAL;
+	else if (mode != NIC_MULTICAST_LIST && address_list != NULL)
+		return EINVAL;
+	
+	if (rxc->multicast_mode == NIC_MULTICAST_LIST)
+		nic_addr_db_clear(&rxc->multicast_addrs);
+	
+	rxc->multicast_mode = mode;
+	size_t i;
+	for (i = 0; i < address_count; ++i) {
+		int rc = nic_addr_db_insert(&rxc->multicast_addrs,
+			(const uint8_t *)&address_list[i].address);
+		if (rc == ENOMEM) {
+			return ENOMEM;
+		}
+	}
+	return EOK;
+}
+
+/**
+ * Queries the current mode of broadcast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The new broadcast mode
+ */
+void nic_rxc_broadcast_get_mode(const nic_rxc_t *rxc, nic_broadcast_mode_t *mode)
+{
+	*mode = rxc->broadcast_mode;
+}
+
+/**
+ * Sets the current mode of broadcast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The new broadcast mode
+ *
+ * @return EOK		On success
+ */
+int nic_rxc_broadcast_set_mode(nic_rxc_t *rxc, nic_broadcast_mode_t mode)
+{
+	rxc->broadcast_mode = mode;
+	return EOK;
+}
+
+/**
+ * Queries the current blocked source addresses.
+ *
+ * @param rxc
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of blocked addresses (can be > max_count)
+ */
+void nic_rxc_blocked_sources_get(const nic_rxc_t *rxc,
+	size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	nic_rxc_add_addr_t hs = {
+		.max_count = max_count,
+		.address_list = address_list,
+		.address_count = 0
+	};
+	nic_addr_db_foreach(&rxc->blocked_sources, nic_rxc_add_addr, &hs);
+	if (address_count) {
+		*address_count = hs.address_count;
+	}
+}
+
+/**
+ * Clears the currently blocked addresses and sets the addresses contained in
+ * the list as the set of blocked source addresses (no frame with this source
+ * address will be received). Duplicated addresses are ignored.
+ *
+ * @param rxc
+ * @param address_list	List of the blocked addresses. Can be NULL.
+ * @param address_count Number of addresses in the list
+ *
+ * @return EOK		On success
+ * @return ENOMEM	If there was not enough memory
+ */
+int nic_rxc_blocked_sources_set(nic_rxc_t *rxc,
+	const nic_address_t *address_list, size_t address_count)
+{
+	assert((address_count == 0 && address_list == NULL)
+		|| (address_count != 0 && address_list != NULL));
+
+	nic_addr_db_clear(&rxc->blocked_sources);
+	rxc->block_sources = (address_count != 0);
+	size_t i;
+	for (i = 0; i < address_count; ++i) {
+		int rc = nic_addr_db_insert(&rxc->blocked_sources,
+			(const uint8_t *) &address_list[i].address);
+		if (rc == ENOMEM) {
+			return ENOMEM;
+		}
+	}
+	return EOK;
+}
+
+/**
+ * Query mask used for filtering according to the VLAN tags.
+ *
+ * @param rxc
+ * @param mask		Must be 512 bytes long
+ *
+ * @return EOK
+ * @return ENOENT
+ */
+int nic_rxc_vlan_get_mask(const nic_rxc_t *rxc, nic_vlan_mask_t *mask)
+{
+	if (rxc->vlan_mask == NULL) {
+		return ENOENT;
+	}
+	memcpy(mask, rxc->vlan_mask, sizeof (nic_vlan_mask_t));
+	return EOK;
+}
+
+/**
+ * Set mask for filtering according to the VLAN tags.
+ *
+ * @param rxc
+ * @param mask		Must be 512 bytes long
+ *
+ * @return EOK
+ * @return ENOMEM
+ */
+int nic_rxc_vlan_set_mask(nic_rxc_t *rxc, const nic_vlan_mask_t *mask)
+{
+	if (mask == NULL) {
+		if (rxc->vlan_mask) {
+			free(rxc->vlan_mask);
+		}
+		rxc->vlan_mask = NULL;
+		return EOK;
+	}
+	if (!rxc->vlan_mask) {
+		rxc->vlan_mask = malloc(sizeof (nic_vlan_mask_t));
+		if (rxc->vlan_mask == NULL) {
+			return ENOMEM;
+		}
+	}
+	memcpy(rxc->vlan_mask, mask, sizeof (nic_vlan_mask_t));
+	return EOK;
+}
+
+
+/**
+ * Check if the frame passes through the receive control.
+ *
+ * @param rxc
+ * @param packet	The probed frame
+ *
+ * @return True if the frame passes, false if it does not
+ */
+int nic_rxc_check(const nic_rxc_t *rxc, const packet_t *packet,
+	nic_frame_type_t *frame_type)
+{
+	assert(frame_type != NULL);
+	uint8_t *dest_addr = (uint8_t *) packet + packet->data_start;
+	uint8_t *src_addr = dest_addr + ETH_ADDR;
+
+	if (dest_addr[0] & 1) {
+		/* Multicast or broadcast */
+		if (*(uint32_t *) dest_addr == 0xFFFFFFFF &&
+		    *(uint16_t *) (dest_addr + 4) == 0xFFFF) {
+			/* It is broadcast */
+			*frame_type = NIC_FRAME_BROADCAST;
+			if (rxc->broadcast_mode == NIC_BROADCAST_BLOCKED)
+				return false;
+		} else {
+			*frame_type = NIC_FRAME_MULTICAST;
+			/* In promiscuous mode the multicast_exact should be set to true */
+			if (!rxc->multicast_exact) {
+				if (rxc->multicast_mode == NIC_MULTICAST_BLOCKED)
+					return false;
+				else {
+					if (!nic_addr_db_contains(&rxc->multicast_addrs,
+					    dest_addr))
+						return false;
+				}
+			}
+		}
+	} else {
+		/* Unicast */
+		*frame_type = NIC_FRAME_UNICAST;
+		/* In promiscuous mode the unicast_exact should be set to true */
+		if (!rxc->unicast_exact) {
+			if (rxc->unicast_mode == NIC_UNICAST_BLOCKED)
+				return false;
+			else {
+				if (!nic_addr_db_contains(&rxc->unicast_addrs,
+				    dest_addr))
+					return false;
+			}
+		}
+	}
+	/* Blocked source addresses */
+	if (rxc->block_sources) {
+		if (nic_addr_db_contains(&rxc->blocked_sources, src_addr))
+			return false;
+	}
+	/* VLAN filtering */
+	if (!rxc->vlan_exact && rxc->vlan_mask != NULL) {
+		vlan_header_t *vlan_header = (vlan_header_t *)
+			((uint8_t *) packet + packet->data_start + 2 * ETH_ADDR);
+		if (vlan_header->tpid_upper == VLAN_TPID_UPPER &&
+			vlan_header->tpid_lower == VLAN_TPID_LOWER) {
+			int index = ((int) (vlan_header->vid_upper & 0xF) << 5) |
+			    (vlan_header->vid_lower >> 3);
+			if (!(rxc->vlan_mask->bitmap[index] &
+			    (1 << (vlan_header->vid_lower & 0x7))))
+				return false;
+		}
+	}
+	
+	return true;
+}
+
+/**
+ * Set information about current HW filtering.
+ *  1 ...	Only those frames we want to receive are passed through HW
+ *  0 ...	The HW filtering is imperfect
+ * -1 ...	Don't change the setting
+ * This function should be called only from the mode change event handler.
+ *
+ * @param	rxc
+ * @param	unicast_exact	Unicast frames
+ * @param	mcast_exact		Multicast frames
+ * @param	vlan_exact		VLAN tags
+ */
+void nic_rxc_hw_filtering(nic_rxc_t *rxc,
+	int unicast_exact, int multicast_exact, int vlan_exact)
+{
+	if (unicast_exact >= 0)
+		rxc->unicast_exact = unicast_exact;
+	if (multicast_exact >= 0)
+		rxc->multicast_exact = multicast_exact;
+	if (vlan_exact >= 0)
+		rxc->vlan_exact = vlan_exact;
+}
+
+/**
+ * Computes hash for the address list based on standard multicast address
+ * hashing.
+ *
+ * @param address_list
+ * @param count
+ *
+ * @return Multicast hash
+ *
+ * @see multicast_hash
+ */
+uint64_t nic_rxc_mcast_hash(const nic_address_t *address_list, size_t count)
+{
+	size_t i;
+	uint64_t hash = 0;
+	for (i = 0; i < count; ++i) {
+		hash |= multicast_hash(address_list[i].address);
+	}
+	return hash;
+}
+
+static void nic_rxc_hash_addr(const uint8_t *address, void *arg)
+{
+	*((uint64_t *) arg) |= multicast_hash(address);
+}
+
+/**
+ * Computes hash for multicast addresses currently set up in the RX multicast
+ * filtering. For promiscuous mode returns all ones, for blocking all zeroes.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param rxc
+ *
+ * @return Multicast hash
+ *
+ * @see multicast_hash
+ */
+uint64_t nic_rxc_multicast_get_hash(const nic_rxc_t *rxc)
+{
+	switch (rxc->multicast_mode) {
+	case NIC_MULTICAST_UNKNOWN:
+	case NIC_MULTICAST_BLOCKED:
+		return 0;
+	case NIC_MULTICAST_LIST:
+		break;
+	case NIC_MULTICAST_PROMISC:
+		return ~ (uint64_t) 0;
+	}
+	uint64_t hash;
+	nic_addr_db_foreach(&rxc->multicast_addrs, nic_rxc_hash_addr, &hash);
+	return hash;
+}
+
+/** @}
+ */
Index: uspace/lib/nic/src/nic_wol_virtues.c
===================================================================
--- uspace/lib/nic/src/nic_wol_virtues.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/lib/nic/src/nic_wol_virtues.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,296 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Wake-on-LAN support
+ */
+
+#include "nic_wol_virtues.h"
+#include <assert.h>
+
+#define NIC_WV_HASH_COUNT 32
+
+/**
+ * Hash table helper function
+ */
+static int nic_wv_compare(unsigned long key[], hash_count_t keys,
+	link_t *item)
+{
+	nic_wol_virtue_t *virtue = (nic_wol_virtue_t *) item;
+	return (virtue->id == (nic_wv_id_t) key[0]);
+}
+
+/**
+ * Hash table helper function
+ */
+static void nic_wv_rc(link_t *item)
+{
+}
+
+/**
+ * Hash table helper function
+ */
+static hash_index_t nic_wv_hash(unsigned long keys[])
+{
+	return keys[0] % NIC_WV_HASH_COUNT;
+}
+
+/**
+ * Initializes the WOL virtues structure
+ *
+ * @param wvs
+ *
+ * @return EOK		On success
+ * @return ENOMEM	On not enough memory
+ */
+int nic_wol_virtues_init(nic_wol_virtues_t *wvs)
+{
+	bzero(wvs, sizeof (nic_wol_virtues_t));
+	wvs->table_operations.compare = nic_wv_compare;
+	wvs->table_operations.hash = nic_wv_hash;
+	wvs->table_operations.remove_callback = nic_wv_rc;
+	if (!hash_table_create(&wvs->table, NIC_WV_HASH_COUNT, 1,
+		&wvs->table_operations)) {
+		return ENOMEM;
+	}
+	size_t i;
+	for (i = 0; i < NIC_WV_MAX; ++i) {
+		wvs->caps_max[i] = -1;
+	}
+	wvs->next_id = 0;
+	return EOK;
+}
+
+/**
+ * Reinitializes the structure, destroying all virtues. The next_id is not
+ * changed (some apps could still hold the filter IDs).
+ *
+ * @param wvs
+ */
+void nic_wol_virtues_clear(nic_wol_virtues_t *wvs)
+{
+	hash_table_clear(&wvs->table);
+	nic_wv_type_t type;
+	for (type = NIC_WV_NONE; type < NIC_WV_MAX; ++type) {
+		nic_wol_virtue_t *virtue = wvs->lists[type];
+		while (virtue != NULL) {
+			nic_wol_virtue_t *next = virtue->next;
+			free(virtue->data);
+			free(virtue);
+			virtue = next;
+		}
+		wvs->lists_sizes[type] = 0;
+	}
+}
+
+/**
+ * Verifies that the arguments for the WOL virtues are correct.
+ *
+ * @param type		Type of the virtue
+ * @param data		Data argument for the virtue
+ * @param length	Length of the data
+ *
+ * @return EOK		The arguments are correct
+ * @return EINVAL	The arguments are incorrect
+ * @return ENOTSUP	This type is unknown
+ */
+int nic_wol_virtues_verify(nic_wv_type_t type, const void *data, size_t length)
+{
+	switch (type) {
+	case NIC_WV_ARP_REQUEST:
+	case NIC_WV_BROADCAST:
+	case NIC_WV_LINK_CHANGE:
+		return EOK;
+	case NIC_WV_DESTINATION:
+		return length == sizeof (nic_address_t) ? EOK : EINVAL;
+	case NIC_WV_DIRECTED_IPV4:
+		return length == sizeof (nic_wv_ipv4_data_t) ? EOK : EINVAL;
+	case NIC_WV_DIRECTED_IPV6:
+		return length == sizeof (nic_wv_ipv6_data_t) ? EOK : EINVAL;
+	case NIC_WV_FULL_MATCH:
+		return length % 2 == 0 ? EOK : EINVAL;
+	case NIC_WV_MAGIC_PACKET:
+		return data == NULL || length == sizeof (nic_wv_magic_packet_data_t) ?
+			EOK : EINVAL;
+	default:
+		return ENOTSUP;
+	}
+}
+
+/**
+ * Adds the virtue to the list of known virtues, activating it.
+ *
+ * @param wvs
+ * @param virtue	The virtue structure
+ *
+ * @return EOK		On success
+ * @return ENOTSUP	If the virtue type is not supported
+ * @return EINVAL	If the virtue type is a single-filter and there's already
+ * 					a virtue of this type defined, or there is something wrong
+ * 					with the data
+ * @return ENOMEM	Not enough memory to activate the virtue
+ */
+int nic_wol_virtues_add(nic_wol_virtues_t *wvs, nic_wol_virtue_t *virtue)
+{
+	if (!nic_wv_is_multi(virtue->type) &&
+		wvs->lists[virtue->type] != NULL) {
+		return EINVAL;
+	}
+	do {
+		virtue->id = wvs->next_id++;
+	} while (NULL !=
+		hash_table_find(&wvs->table, (unsigned long *) &virtue->id));
+	hash_table_insert(&wvs->table,
+		(unsigned long *) &virtue->id, &virtue->item);
+	virtue->next = wvs->lists[virtue->type];
+	wvs->lists[virtue->type] = virtue;
+	wvs->lists_sizes[virtue->type]++;
+	return EOK;
+}
+
+/**
+ * Removes the virtue from the list of virtues, but NOT deallocating the
+ * nic_wol_virtue structure.
+ *
+ * @param wvs
+ * @param id	Identifier of the removed virtue
+ *
+ * @return Removed virtue structure or NULL if not found.
+ */
+nic_wol_virtue_t *nic_wol_virtues_remove(nic_wol_virtues_t *wvs, nic_wv_id_t id)
+{
+	nic_wol_virtue_t *virtue = (nic_wol_virtue_t *)
+		hash_table_find(&wvs->table, (unsigned long *) &id);
+	if (virtue == NULL) {
+		return NULL;
+	}
+
+	/* Remove from filter_table */
+	hash_table_remove(&wvs->table, (unsigned long *) &id, 1);
+
+	/* Remove from filter_types */
+	assert(wvs->lists[virtue->type] != NULL);
+	if (wvs->lists[virtue->type] == virtue) {
+		wvs->lists[virtue->type] = virtue->next;
+	} else {
+		nic_wol_virtue_t *wv = wvs->lists[virtue->type];
+		while (wv->next != virtue) {
+			wv = wv->next;
+			assert(wv != NULL);
+		}
+		wv->next = virtue->next;
+	}
+	wvs->lists_sizes[virtue->type]--;
+
+	virtue->next = NULL;
+	return virtue;
+}
+
+
+/**
+ * Searches the filters table for a filter with specified ID
+ *
+ * @param wvs
+ * @param id	Identifier of the searched virtue
+ *
+ * @return Requested filter or NULL if not found.
+ */
+const nic_wol_virtue_t *nic_wol_virtues_find(const nic_wol_virtues_t *wvs,
+	nic_wv_id_t id)
+{
+	/*
+	 * The hash_table_find cannot be const, because it would require the
+	 * returned link to be const as well. But in this case, when we're returning
+	 * constant virtue the retyping is correct.
+	 */
+	link_t *virtue = hash_table_find(
+		&((nic_wol_virtues_t *) wvs)->table, (unsigned long *) &id);
+	return (const nic_wol_virtue_t *) virtue;
+}
+
+/**
+ * Fill identifiers of current wol virtues of the specified type into the list.
+ * If the type is set to NIC_WV_NONE, all virtues are used.
+ *
+ * @param		wvs
+ * @param[in]	type		Type of the virtues or NIC_WV_NONE
+ * @param[out]	id_list		The new vector of filter IDs. Can be NULL.
+ * @param[out]	count		Number of IDs in the filter_list. Can be NULL.
+ *
+ * @return EOK		If it completes successfully
+ * @return EINVAL	If the filter type is invalid
+ */
+int nic_wol_virtues_list(const nic_wol_virtues_t *wvs, nic_wv_type_t type,
+	size_t max_count, nic_wv_id_t *id_list, size_t *id_count)
+{
+	size_t count = 0;
+	if (type == NIC_WV_NONE) {
+		size_t i;
+		for (i = NIC_WV_NONE; i < NIC_WV_MAX; ++i) {
+			if (id_list != NULL) {
+				nic_wol_virtue_t *virtue = wvs->lists[i];
+				while (virtue != NULL) {
+					if (count < max_count) {
+						id_list[count] = virtue->id;
+					}
+					++count;
+					virtue = virtue->next;
+				}
+			} else {
+				count += wvs->lists_sizes[i];
+			}
+		}
+	} else if (type >= NIC_WV_MAX) {
+		return EINVAL;
+	} else {
+		if (id_list != NULL) {
+			nic_wol_virtue_t *virtue = wvs->lists[type];
+			while (virtue != NULL) {
+				if (count < max_count) {
+					id_list[count] = virtue->id;
+				}
+				++count;
+				virtue = virtue->next;
+			}
+		} else {
+			count = wvs->lists_sizes[type];
+		}
+	}
+	if (id_count != NULL) {
+		*id_count = count;
+	}
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/lib/packet/Makefile
===================================================================
--- uspace/lib/packet/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,37 +1,0 @@
-#
-# Copyright (c) 2005 Martin Decky
-# Copyright (c) 2007 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.
-#
-
-USPACE_PREFIX = ../..
-EXTRA_CFLAGS = -Iinclude
-LIBRARY = libpacket
-
-SOURCES = \
-	generic/packet_server.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/packet/generic/packet_server.c
===================================================================
--- uspace/lib/packet/generic/packet_server.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,374 +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 libpacket
- *  @{
- */
-
-/** @file
- * Packet server implementation.
- */
-
-#include <packet_server.h>
-#include <align.h>
-#include <assert.h>
-#include <async.h>
-#include <errno.h>
-#include <fibril_synch.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <ipc/packet.h>
-#include <ipc/net.h>
-#include <net/packet.h>
-#include <net/packet_header.h>
-
-#define FREE_QUEUES_COUNT	7
-
-/** The default address length reserved for new packets. */
-#define DEFAULT_ADDR_LEN	32
-
-/** The default prefix reserved for new packets. */
-#define DEFAULT_PREFIX		64
-
-/** The default suffix reserved for new packets. */
-#define DEFAULT_SUFFIX		64
-
-/** Packet server global data. */
-static struct {
-	/** Safety lock. */
-	fibril_mutex_t lock;
-	/** Free packet queues. */
-	packet_t *free[FREE_QUEUES_COUNT];
-	
-	/**
-	 * Packet length upper bounds of the free packet queues. The maximal
-	 * lengths of packets in each queue in the ascending order. The last
-	 * queue is not limited.
-	 */
-	size_t sizes[FREE_QUEUES_COUNT];
-	
-	/** Total packets allocated. */
-	unsigned int count;
-} ps_globals = {
-	.lock = FIBRIL_MUTEX_INITIALIZER(ps_globals.lock),
-	.free = {
-		NULL,
-		NULL,
-		NULL,
-		NULL,
-		NULL,
-		NULL,
-		NULL
-	},
-	.sizes = {
-		PAGE_SIZE,
-		PAGE_SIZE * 2,
-		PAGE_SIZE * 4,
-		PAGE_SIZE * 8,
-		PAGE_SIZE * 16,
-		PAGE_SIZE * 32,
-		PAGE_SIZE * 64
-	},
-	.count = 0
-};
-
-/** Clears and initializes the packet according to the given dimensions.
- *
- * @param[in] packet	The packet to be initialized.
- * @param[in] addr_len	The source and destination addresses maximal length in
- *			bytes.
- * @param[in] max_prefix The maximal prefix length in bytes.
- * @param[in] max_content The maximal content length in bytes.
- * @param[in] max_suffix The maximal suffix length in bytes.
- */
-static void
-packet_init(packet_t *packet, size_t addr_len, size_t max_prefix,
-    size_t max_content, size_t max_suffix)
-{
-	/* Clear the packet content */
-	bzero(((void *) packet) + sizeof(packet_t),
-	    packet->length - sizeof(packet_t));
-	
-	/* Clear the packet header */
-	packet->order = 0;
-	packet->metric = 0;
-	packet->previous = 0;
-	packet->next = 0;
-	packet->addr_len = 0;
-	packet->src_addr = sizeof(packet_t);
-	packet->dest_addr = packet->src_addr + addr_len;
-	packet->max_prefix = max_prefix;
-	packet->max_content = max_content;
-	packet->data_start = packet->dest_addr + addr_len + packet->max_prefix;
-	packet->data_end = packet->data_start;
-}
-
-/** Creates a new packet of dimensions at least as given.
- *
- * @param[in] length	The total length of the packet, including the header,
- *			the addresses and the data of the packet.
- * @param[in] addr_len	The source and destination addresses maximal length in
- *			bytes.
- * @param[in] max_prefix The maximal prefix length in bytes.
- * @param[in] max_content The maximal content length in bytes.
- * @param[in] max_suffix The maximal suffix length in bytes.
- * @return		The packet of dimensions at least as given.
- * @return		NULL if there is not enough memory left.
- */
-static packet_t *
-packet_create(size_t length, size_t addr_len, size_t max_prefix,
-    size_t max_content, size_t max_suffix)
-{
-	packet_t *packet;
-	int rc;
-
-	assert(fibril_mutex_is_locked(&ps_globals.lock));
-
-	/* Already locked */
-	packet = (packet_t *) mmap(NULL, length, PROTO_READ | PROTO_WRITE,
-	    MAP_SHARED | MAP_ANONYMOUS, 0, 0);
-	if (packet == MAP_FAILED)
-		return NULL;
-
-	ps_globals.count++;
-	packet->packet_id = ps_globals.count;
-	packet->length = length;
-	packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
-	packet->magic_value = PACKET_MAGIC_VALUE;
-	rc = pm_add(packet);
-	if (rc != EOK) {
-		munmap(packet, packet->length);
-		return NULL;
-	}
-	
-	return packet;
-}
-
-/** Return the packet of dimensions at least as given.
- *
- * Try to reuse free packets first.
- * Create a new packet aligned to the memory page size if none available.
- * Lock the global data during its processing.
- *
- * @param[in] addr_len	The source and destination addresses maximal length in
- *			bytes.
- * @param[in] max_prefix The maximal prefix length in bytes.
- * @param[in] max_content The maximal content length in bytes.
- * @param[in] max_suffix The maximal suffix length in bytes.
- * @return		The packet of dimensions at least as given.
- * @return		NULL if there is not enough memory left.
- */
-static packet_t *
-packet_get_local(size_t addr_len, size_t max_prefix, size_t max_content,
-    size_t max_suffix)
-{
-	size_t length = ALIGN_UP(sizeof(packet_t) + 2 * addr_len +
-	    max_prefix + max_content + max_suffix, PAGE_SIZE);
-	
-	fibril_mutex_lock(&ps_globals.lock);
-	
-	packet_t *packet;
-	unsigned int index;
-	
-	for (index = 0; index < FREE_QUEUES_COUNT; index++) {
-		if ((length > ps_globals.sizes[index]) &&
-		    (index < FREE_QUEUES_COUNT - 1))
-			continue;
-		
-		packet = ps_globals.free[index];
-		while (packet_is_valid(packet) && (packet->length < length))
-			packet = pm_find(packet->next);
-		
-		if (packet_is_valid(packet)) {
-			if (packet == ps_globals.free[index])
-				ps_globals.free[index] = pq_detach(packet);
-			else
-				pq_detach(packet);
-			
-			packet_init(packet, addr_len, max_prefix, max_content,
-			    max_suffix);
-			fibril_mutex_unlock(&ps_globals.lock);
-			
-			return packet;
-		}
-	}
-	
-	packet = packet_create(length, addr_len, max_prefix, max_content,
-	    max_suffix);
-	
-	fibril_mutex_unlock(&ps_globals.lock);
-	
-	return packet;
-}
-
-/** Release the packet and returns it to the appropriate free packet queue.
- *
- * @param[in] packet	The packet to be released.
- *
- */
-static void packet_release(packet_t *packet)
-{
-	int index;
-	int result;
-
-	assert(fibril_mutex_is_locked(&ps_globals.lock));
-
-	for (index = 0; (index < FREE_QUEUES_COUNT - 1) &&
-	    (packet->length > ps_globals.sizes[index]); index++) {
-		;
-	}
-	
-	result = pq_add(&ps_globals.free[index], packet, packet->length,
-	    packet->length);
-	assert(result == EOK);
-}
-
-/** Releases the packet queue.
- *
- * @param[in] packet_id	The first packet identifier.
- * @return		EOK on success.
- * @return		ENOENT if there is no such packet.
- */
-static int packet_release_wrapper(packet_id_t packet_id)
-{
-	packet_t *packet;
-
-	packet = pm_find(packet_id);
-	if (!packet_is_valid(packet))
-		return ENOENT;
-
-	fibril_mutex_lock(&ps_globals.lock);
-	pq_destroy(packet, packet_release);
-	fibril_mutex_unlock(&ps_globals.lock);
-
-	return EOK;
-}
-
-/** Shares the packet memory block.
- * @param[in] packet	The packet to be shared.
- * @return		EOK on success.
- * @return		EINVAL if the packet is not valid.
- * @return		EINVAL if the calling module does not accept the memory.
- * @return		ENOMEM if the desired and actual sizes differ.
- * @return		Other error codes as defined for the
- *			async_share_in_finalize() function.
- */
-static int packet_reply(packet_t *packet)
-{
-	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);
-		return ENOMEM;
-	}
-	
-	return async_share_in_finalize(callid, packet,
-	    PROTO_READ | PROTO_WRITE);
-}
-
-/** Processes the packet server 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		ENOMEM if there is not enough memory left.
- * @return		ENOENT if there is no such packet as in the packet
- *			message parameter.
- * @return		ENOTSUP if the message is not known.
- * @return		Other error codes as defined for the
- *			packet_release_wrapper() function.
- */
-int packet_server_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
-    size_t *answer_count)
-{
-	packet_t *packet;
-	
-	if (!IPC_GET_IMETHOD(*call))
-		return EOK;
-	
-	*answer_count = 0;
-	switch (IPC_GET_IMETHOD(*call)) {
-	case NET_PACKET_CREATE_1:
-		packet = packet_get_local(DEFAULT_ADDR_LEN, DEFAULT_PREFIX,
-		    IPC_GET_CONTENT(*call), DEFAULT_SUFFIX);
-		if (!packet)
-			return ENOMEM;
-		*answer_count = 2;
-		IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
-		IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
-		return EOK;
-	
-	case NET_PACKET_CREATE_4:
-		packet = packet_get_local(
-		    ((DEFAULT_ADDR_LEN < IPC_GET_ADDR_LEN(*call)) ?
-		    IPC_GET_ADDR_LEN(*call) : DEFAULT_ADDR_LEN),
-		    DEFAULT_PREFIX + IPC_GET_PREFIX(*call),
-		    IPC_GET_CONTENT(*call),
-		    DEFAULT_SUFFIX + IPC_GET_SUFFIX(*call));
-		if (!packet)
-			return ENOMEM;
-		*answer_count = 2;
-		IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
-		IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
-		return EOK;
-	
-	case NET_PACKET_GET:
-		packet = pm_find(IPC_GET_ID(*call));
-		if (!packet_is_valid(packet))
-			return ENOENT;
-		return packet_reply(packet);
-	
-	case NET_PACKET_GET_SIZE:
-		packet = pm_find(IPC_GET_ID(*call));
-		if (!packet_is_valid(packet))
-			return ENOENT;
-		IPC_SET_ARG1(*answer, (sysarg_t) packet->length);
-		*answer_count = 1;
-		return EOK;
-	
-	case NET_PACKET_RELEASE:
-		return packet_release_wrapper(IPC_GET_ID(*call));
-	}
-	
-	return ENOTSUP;
-}
-
-/** @}
- */
Index: uspace/lib/packet/include/packet_server.h
===================================================================
--- uspace/lib/packet/include/packet_server.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,55 +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 libpacket
- * @{
- */
-
-/** @file
- * Packet server.
- * The hosting module has to be compiled with both the packet.c and the
- * packet_server.c source files. To function correctly, initialization of the
- * packet map by the pm_init() function has to happen at the first place. Then
- * the packet messages have to be processed by the packet_server_message()
- * function. The packet map should be released by the pm_destroy() function
- * during the module termination.
- * @see IS_NET_PACKET_MESSAGE()
- */
-
-#ifndef LIBPACKET_PACKET_SERVER_H_
-#define LIBPACKET_PACKET_SERVER_H_
-
-#include <ipc/common.h>
-
-extern int packet_server_message(ipc_callid_t, ipc_call_t *, ipc_call_t *,
-    size_t *);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/usb/Makefile
===================================================================
--- uspace/lib/usb/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usb/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -31,4 +31,5 @@
 EXTRA_CFLAGS += \
 	-I$(LIBDRV_PREFIX)/include \
+	-I$(LIBUSBDEV_PREFIX)/include \
 	-Iinclude
 
Index: uspace/lib/usb/include/usb/classes/hub.h
===================================================================
--- uspace/lib/usb/include/usb/classes/hub.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usb/include/usb/classes/hub.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -72,5 +72,9 @@
 	uint8_t port_count;
 	/** Characteristics bitmask. */
-	uint16_t characteristics;
+	uint8_t characteristics;
+#define HUB_CHAR_POWER_PER_PORT_FLAG  (1 << 0)
+#define HUB_CHAR_NO_POWER_SWITCH_FLAG (1 << 1)
+	/* Unused part of characteristics field */
+	uint8_t characteristics_reserved;
 	/** Time from power-on to stabilization of current on the port. */
 	uint8_t power_good_time;
@@ -92,5 +96,5 @@
 
     /** Number of downstream ports that this hub supports */
-    uint8_t ports_count;
+    uint8_t port_count;
 
     /**
@@ -119,6 +123,4 @@
      */
     uint16_t hub_characteristics;
-#define HUB_CHAR_POWER_PER_PORT_FLAG  (1 << 0)
-#define HUB_CHAR_NO_POWER_SWITCH_FLAG (1 << 1)
 
     /**
@@ -214,11 +216,6 @@
  *	Maximum size of usb hub descriptor in bytes
  */
-extern size_t USB_HUB_MAX_DESCRIPTOR_SIZE;
-
-
-
-
-
-
+/* 7 (basic size) + 2*32 (port bitmasks) */
+#define USB_HUB_MAX_DESCRIPTOR_SIZE 71
 
 #endif
Index: uspace/lib/usb/include/usb/ddfiface.h
===================================================================
--- uspace/lib/usb/include/usb/ddfiface.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usb/include/usb/ddfiface.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usb/include/usb/hc.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -53,5 +53,5 @@
 
 int usb_hc_connection_initialize_from_device(usb_hc_connection_t *,
-    ddf_dev_t *);
+    const ddf_dev_t *);
 int usb_hc_connection_initialize(usb_hc_connection_t *, devman_handle_t);
 
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usb/src/class.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usb/src/ddfiface.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usb/src/hc.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -50,5 +50,5 @@
  */
 int usb_hc_connection_initialize_from_device(usb_hc_connection_t *connection,
-    ddf_dev_t *device)
+    const ddf_dev_t *device)
 {
 	assert(connection);
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usb/src/resolve.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/include/usb/dev/dp.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -54,10 +54,10 @@
 } 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. */
 typedef struct {
 	/** Used descriptor nesting. */
-	usb_dp_descriptor_nesting_t *nesting;
+	const usb_dp_descriptor_nesting_t *nesting;
 } usb_dp_parser_t;
 
@@ -65,5 +65,5 @@
 typedef struct {
 	/** Data to be parsed. */
-	uint8_t *data;
+	const uint8_t *data;
 	/** Size of input data in bytes. */
 	size_t size;
@@ -72,11 +72,13 @@
 } usb_dp_parser_data_t;
 
-uint8_t *usb_dp_get_nested_descriptor(usb_dp_parser_t *,
-    usb_dp_parser_data_t *, uint8_t *);
-uint8_t *usb_dp_get_sibling_descriptor(usb_dp_parser_t *,
-    usb_dp_parser_data_t *, uint8_t *, uint8_t *);
+typedef void (*walk_callback_t)(const uint8_t *, size_t, void *);
 
-void usb_dp_walk_simple(uint8_t *, size_t, usb_dp_descriptor_nesting_t *,
-    void (*)(uint8_t *, size_t, void *), void *);
+const uint8_t *usb_dp_get_nested_descriptor(const usb_dp_parser_t *,
+    const usb_dp_parser_data_t *, const uint8_t *);
+const uint8_t *usb_dp_get_sibling_descriptor(const usb_dp_parser_t *,
+    const usb_dp_parser_data_t *, const uint8_t *, const uint8_t *);
+
+void usb_dp_walk_simple(uint8_t *, size_t, const usb_dp_descriptor_nesting_t *,
+    walk_callback_t, void *);
 
 #endif
Index: uspace/lib/usbdev/include/usb/dev/driver.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/driver.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/include/usb/dev/driver.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -43,5 +43,5 @@
 	usb_standard_device_descriptor_t device;
 	/** Full configuration descriptor of current configuration. */
-	uint8_t *configuration;
+	const uint8_t *configuration;
 	size_t configuration_size;
 } usb_device_descriptors_t;
@@ -53,7 +53,7 @@
 typedef struct {
 	/** Interface descriptor. */
-	usb_standard_interface_descriptor_t *interface;
+	const usb_standard_interface_descriptor_t *interface;
 	/** Pointer to start of descriptor tree bound with this interface. */
-	uint8_t *nested_descriptors;
+	const uint8_t *nested_descriptors;
 	/** Size of data pointed by nested_descriptors in bytes. */
 	size_t nested_descriptors_size;
@@ -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. */
+	/** Generic DDF device backing this one. DO NOT TOUCH! */
 	ddf_dev_t *ddf_dev;
 	/** Custom driver data.
@@ -103,15 +104,14 @@
 	 */
 	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;
 
 /** USB driver ops. */
 typedef struct {
-	/** Callback when new device is about to be controlled by the driver. */
-	int (*add_device)(usb_device_t *);
+	/** Callback when a new device was added to the system. */
+	int (*device_add)(usb_device_t *);
+	/** Callback when a device is about to be removed from the system. */
+	int (*device_rem)(usb_device_t *);
+	/** Callback when a device was removed from the system. */
+	int (*device_gone)(usb_device_t *);
 } usb_driver_ops_t;
 
@@ -152,26 +152,32 @@
 \endcode
 	 */
-	usb_endpoint_description_t **endpoints;
+	const usb_endpoint_description_t **endpoints;
 	/** Driver ops. */
-	usb_driver_ops_t *ops;
+	const usb_driver_ops_t *ops;
 } usb_driver_t;
 
-int usb_driver_main(usb_driver_t *);
+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,
-    usb_endpoint_description_t **);
+    const usb_endpoint_description_t **);
 
 int usb_device_retrieve_descriptors(usb_pipe_t *, usb_device_descriptors_t *);
-int usb_device_create_pipes(ddf_dev_t *, usb_device_connection_t *,
-    usb_endpoint_description_t **, uint8_t *, size_t, int, int,
+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(ddf_dev_t *, usb_endpoint_mapping_t *, size_t);
-int usb_device_create(ddf_dev_t *, usb_endpoint_description_t **, usb_device_t **, const char **);
-void usb_device_destroy(usb_device_t *);
+int usb_device_destroy_pipes(const ddf_dev_t *, usb_endpoint_mapping_t *, size_t);
 
-size_t usb_interface_count_alternates(uint8_t *, size_t, uint8_t);
-int usb_alternate_interfaces_create(uint8_t *, size_t, int,
-    usb_alternate_interfaces_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_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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/include/usb/dev/hub.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -38,11 +38,11 @@
 #define LIBUSBDEV_HUB_H_
 
+#include <ddf/driver.h>
 #include <sys/types.h>
 #include <usb/hc.h>
 
 int usb_hc_new_device_wrapper(ddf_dev_t *, usb_hc_connection_t *, usb_speed_t,
-    int (*)(int, void *), int, void *,
-    usb_address_t *, devman_handle_t *,
-    ddf_dev_ops_t *, void *, ddf_fun_t **);
+    int (*)(void *), void *, usb_address_t *, ddf_dev_ops_t *, void *,
+    ddf_fun_t **);
 
 /** Info about device attached to host controller.
@@ -55,11 +55,12 @@
 	/** Device address. */
 	usb_address_t address;
-	/** Devman handle of the device. */
-	devman_handle_t handle;
-} usb_hc_attached_device_t;
+	/** DDF function (external) of the device. */
+	ddf_fun_t *fun;
+} 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_hc_attached_device_t *);
+    const usb_hub_attached_device_t *);
 int usb_hc_unregister_device(usb_hc_connection_t *, usb_address_t);
 
Index: uspace/lib/usbdev/include/usb/dev/pipes.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/pipes.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/include/usb/dev/pipes.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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;
@@ -159,9 +159,9 @@
     usb_device_connection_t *, usb_hc_connection_t *);
 int usb_device_connection_initialize_from_device(usb_device_connection_t *,
-    ddf_dev_t *);
+    const ddf_dev_t *);
 int usb_device_connection_initialize(usb_device_connection_t *,
     devman_handle_t, usb_address_t);
 
-int usb_device_get_assigned_interface(ddf_dev_t *);
+int usb_device_get_assigned_interface(const ddf_dev_t *);
 
 int usb_pipe_initialize(usb_pipe_t *, usb_device_connection_t *,
@@ -171,7 +171,5 @@
 int usb_pipe_probe_default_control(usb_pipe_t *);
 int usb_pipe_initialize_from_configuration(usb_endpoint_mapping_t *,
-    size_t, 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 *);
+    size_t, const uint8_t *, size_t, usb_device_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,10 +179,10 @@
 
 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 *, void *, size_t,
+int usb_pipe_control_read(usb_pipe_t *, const void *, size_t,
     void *, size_t, size_t *);
-int usb_pipe_control_write(usb_pipe_t *, void *, size_t,
-    void *, size_t);
+int usb_pipe_control_write(usb_pipe_t *, const void *, size_t,
+    const void *, size_t);
 
 #endif
Index: uspace/lib/usbdev/include/usb/dev/poll.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/poll.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/include/usb/dev/poll.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/include/usb/dev/recognise.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -50,6 +50,6 @@
 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,
-    ddf_dev_t *, devman_handle_t *, ddf_dev_ops_t *, void *, ddf_fun_t **);
+int usb_device_register_child_in_devman(usb_pipe_t *ctrl_pipe,
+    ddf_dev_t *, ddf_dev_ops_t *, void *, ddf_fun_t **);
 
 #endif
Index: uspace/lib/usbdev/include/usb/dev/request.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/request.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/include/usb/dev/request.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/src/altiface.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -48,5 +48,5 @@
  * @return Number of alternate interfaces for @p interface_no interface.
  */
-size_t usb_interface_count_alternates(uint8_t *config_descr,
+size_t usb_interface_count_alternates(const uint8_t *config_descr,
     size_t config_descr_size, uint8_t interface_no)
 {
@@ -54,8 +54,8 @@
 	assert(config_descr_size > 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,
@@ -65,13 +65,11 @@
 	size_t alternate_count = 0;
 
-	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,54 +80,46 @@
 }
 
-/** 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(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->alternatives = NULL;
+	alternates->alternative_count = 0;
+	alternates->current = 0;
+
+	/* No interfaces. */
 	if (interface_number < 0) {
-		alternates_ptr = NULL;
 		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;
 	}
 
-	alternates->alternatives = malloc(alternates->alternative_count
-	    * sizeof(usb_alternate_interface_descriptors_t));
+	alternates->alternatives = calloc(alternates->alternative_count,
+	    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,
@@ -137,44 +127,50 @@
 	};
 
-	usb_alternate_interface_descriptors_t *cur_alt_iface
+	usb_alternate_interface_descriptors_t *iterator
 	    = &alternates->alternatives[0];
 
-	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) {
-			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_deinit(usb_alternate_interfaces_t *alternate)
+{
+	if (!alternate)
+		return;
+	free(alternate->alternatives);
+}
 /**
  * @}
Index: uspace/lib/usbdev/src/devdrv.c
===================================================================
--- uspace/lib/usbdev/src/devdrv.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/src/devdrv.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -41,8 +41,12 @@
 #include <assert.h>
 
-static int generic_add_device(ddf_dev_t *);
+static int generic_device_add(ddf_dev_t *);
+static int generic_device_remove(ddf_dev_t *);
+static int generic_device_gone(ddf_dev_t *);
 
 static driver_ops_t generic_driver_ops = {
-	.add_device = generic_add_device
+	.dev_add = generic_device_add,
+	.dev_remove = generic_device_remove,
+	.dev_gone = generic_device_gone,
 };
 static driver_t generic_driver = {
@@ -50,5 +54,5 @@
 };
 
-static usb_driver_t *driver = NULL;
+static const usb_driver_t *driver = NULL;
 
 
@@ -60,5 +64,5 @@
  * @return Task exit status.
  */
-int usb_driver_main(usb_driver_t *drv)
+int usb_driver_main(const usb_driver_t *drv)
 {
 	assert(drv != NULL);
@@ -77,15 +81,9 @@
  * @return Number of pipes (excluding default control pipe).
  */
-static size_t count_other_pipes(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;
 }
@@ -97,7 +95,9 @@
  * @return Error code.
  */
-static int initialize_other_pipes(usb_endpoint_description_t **endpoints,
+static int initialize_other_pipes(const usb_endpoint_description_t **endpoints,
     usb_device_t *dev, int alternate_setting)
 {
+	assert(dev);
+
 	if (endpoints == NULL) {
 		dev->pipes = NULL;
@@ -111,6 +111,5 @@
 	int rc = usb_device_create_pipes(dev->ddf_dev, &dev->wire, endpoints,
 	    dev->descriptors.configuration, dev->descriptors.configuration_size,
-	    dev->interface_no, alternate_setting,
-	    &pipes, &pipes_count);
+	    dev->interface_no, alternate_setting, &pipes, &pipes_count);
 
 	if (rc != EOK) {
@@ -123,32 +122,76 @@
 	return EOK;
 }
-
-/** Callback when new device is supposed to be controlled by this driver.
- *
- * This callback is a wrapper for USB specific version of @c add_device.
+/*----------------------------------------------------------------------------*/
+/** Callback when a new device is supposed to be controlled by this driver.
+ *
+ * This callback is a wrapper for USB specific version of @c device_add.
  *
  * @param gen_dev Device structure as prepared by DDF.
  * @return Error code.
  */
-int generic_add_device(ddf_dev_t *gen_dev)
+int generic_device_add(ddf_dev_t *gen_dev)
 {
 	assert(driver);
 	assert(driver->ops);
-	assert(driver->ops->add_device);
-
-	int rc;
-
-	usb_device_t *dev = NULL;
+	assert(driver->ops->device_add);
+
+	usb_device_t *dev = ddf_dev_data_alloc(gen_dev, sizeof(usb_device_t));
+	if (dev == NULL) {
+		usb_log_error("USB device `%s' structure allocation failed.\n",
+		    gen_dev->name);
+		return ENOMEM;
+	}
 	const char *err_msg = NULL;
-	rc = usb_device_create(gen_dev, driver->endpoints, &dev, &err_msg);
-	if (rc != EOK) {
-		usb_log_error("USB device `%s' creation failed (%s): %s.\n",
+	int rc = usb_device_init(dev, gen_dev, driver->endpoints, &err_msg);
+	if (rc != EOK) {
+		usb_log_error("USB device `%s' init failed (%s): %s.\n",
 		    gen_dev->name, err_msg, str_error(rc));
 		return rc;
 	}
 
-	return driver->ops->add_device(dev);
-}
-
+	rc = driver->ops->device_add(dev);
+	if (rc != EOK)
+		usb_device_deinit(dev);
+	return rc;
+}
+/*----------------------------------------------------------------------------*/
+/** Callback when a device is supposed to be removed from the system.
+ *
+ * This callback is a wrapper for USB specific version of @c device_remove.
+ *
+ * @param gen_dev Device structure as prepared by DDF.
+ * @return Error code.
+ */
+int generic_device_remove(ddf_dev_t *gen_dev)
+{
+	assert(driver);
+	assert(driver->ops);
+	if (driver->ops->device_rem == NULL)
+		return ENOTSUP;
+	/* Just tell the driver to stop whatever it is doing, keep structures */
+	return driver->ops->device_rem(gen_dev->driver_data);
+}
+/*----------------------------------------------------------------------------*/
+/** Callback when a device was removed from the system.
+ *
+ * This callback is a wrapper for USB specific version of @c device_gone.
+ *
+ * @param gen_dev Device structure as prepared by DDF.
+ * @return Error code.
+ */
+int generic_device_gone(ddf_dev_t *gen_dev)
+{
+	assert(driver);
+	assert(driver->ops);
+	if (driver->ops->device_gone == NULL)
+		return ENOTSUP;
+	usb_device_t *usb_dev = gen_dev->driver_data;
+	const int ret = driver->ops->device_gone(usb_dev);
+	if (ret == EOK)
+		usb_device_deinit(usb_dev);
+
+	return ret;
+}
+/*----------------------------------------------------------------------------*/
 /** Destroy existing pipes of a USB device.
  *
@@ -193,5 +236,5 @@
  */
 int usb_device_select_interface(usb_device_t *dev, uint8_t alternate_setting,
-    usb_endpoint_description_t **endpoints)
+    const usb_endpoint_description_t **endpoints)
 {
 	if (dev->interface_no < 0) {
@@ -253,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;
 }
 
@@ -272,10 +326,10 @@
  *	(not NULL terminated).
  * @param[out] pipes_count_ptr Where to store number of pipes
- *	(set to if you wish to ignore the count).
- * @return Error code.
- */
-int usb_device_create_pipes(ddf_dev_t *dev, usb_device_connection_t *wire,
-    usb_endpoint_description_t **endpoints,
-    uint8_t *config_descr, size_t config_descr_size,
+ *	(set to NULL if you wish to ignore the count).
+ * @return Error code.
+ */
+int usb_device_create_pipes(const ddf_dev_t *dev, usb_device_connection_t *wire,
+    const usb_endpoint_description_t **endpoints,
+    const uint8_t *config_descr, size_t config_descr_size,
     int interface_no, int interface_setting,
     usb_endpoint_mapping_t **pipes_ptr, size_t *pipes_count_ptr)
@@ -291,6 +345,8 @@
 	int rc;
 
-	size_t pipe_count = count_other_pipes(endpoints);
+	const size_t pipe_count = count_other_pipes(endpoints);
 	if (pipe_count == 0) {
+		if (pipes_count_ptr)
+			*pipes_count_ptr = pipe_count;
 		*pipes_ptr = NULL;
 		return EOK;
@@ -298,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;
@@ -341,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) {
@@ -349,5 +395,7 @@
 	}
 
-	usb_hc_connection_close(&hc_conn);
+	if (usb_hc_connection_close(&hc_conn) != EOK)
+		usb_log_warning("%s: Failed to close connection.\n",
+		    __FUNCTION__);
 
 	*pipes_ptr = pipes;
@@ -367,9 +415,11 @@
 	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);
 		}
 	}
 
-	usb_hc_connection_close(&hc_conn);
+	if (usb_hc_connection_close(&hc_conn) != EOK)
+		usb_log_warning("usb_device_create_pipes(): "
+		    "Failed to close connection.\n");
 
 	/*
@@ -379,9 +429,4 @@
 	 */
 rollback_free_only:
-	for (i = 0; i < pipe_count; i++) {
-		if (pipes[i].pipe != NULL) {
-			free(pipes[i].pipe);
-		}
-	}
 	free(pipes);
 
@@ -395,14 +440,14 @@
  * @param[in] pipes_count Number of endpoints.
  */
-int usb_device_destroy_pipes(ddf_dev_t *dev,
+int usb_device_destroy_pipes(const ddf_dev_t *dev,
     usb_endpoint_mapping_t *pipes, size_t pipes_count)
 {
 	assert(dev != NULL);
-	assert(((pipes != NULL) && (pipes_count > 0))
-	    || ((pipes == NULL) && (pipes_count == 0)));
 
 	if (pipes_count == 0) {
+		assert(pipes == NULL);
 		return EOK;
 	}
+	assert(pipes != NULL);
 
 	int rc;
@@ -422,9 +467,13 @@
 	size_t i;
 	for (i = 0; i < pipes_count; i++) {
-		usb_pipe_unregister(pipes[i].pipe, &hc_conn);
-		free(pipes[i].pipe);
-	}
-
-	usb_hc_connection_close(&hc_conn);
+		usb_log_debug2("Unregistering pipe %zu (%spresent).\n",
+		    i, pipes[i].present ? "" : "not ");
+		if (pipes[i].present)
+			usb_pipe_unregister(&pipes[i].pipe, &hc_conn);
+	}
+
+	if (usb_hc_connection_close(&hc_conn) != EOK)
+		usb_log_warning("usb_device_destroy_pipes(): "
+		    "Failed to close connection.\n");
 
 	free(pipes);
@@ -433,78 +482,50 @@
 }
 
-/** 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;
-}
-
-
-/** Create new instance of USB device.
- *
+/** Initialize new instance of USB device.
+ *
+ * @param[in] usb_dev Pointer to the new device.
  * @param[in] ddf_dev Generic DDF device backing the USB one.
  * @param[in] endpoints NULL terminated array of endpoints (NULL for none).
- * @param[out] dev_ptr Where to store pointer to the new device.
  * @param[out] errstr_ptr Where to store description of context
  *	(in case error occurs).
  * @return Error code.
  */
-int usb_device_create(ddf_dev_t *ddf_dev,
-    usb_endpoint_description_t **endpoints,
-    usb_device_t **dev_ptr, const char **errstr_ptr)
-{
-	assert(dev_ptr != NULL);
+int usb_device_init(usb_device_t *usb_dev, ddf_dev_t *ddf_dev,
+    const usb_endpoint_description_t **endpoints, const char **errstr_ptr)
+{
+	assert(usb_dev != NULL);
 	assert(ddf_dev != NULL);
 
-	int rc;
-
-	usb_device_t *dev = malloc(sizeof(usb_device_t));
-	if (dev == NULL) {
-		*errstr_ptr = "structure allocation";
-		return ENOMEM;
-	}
-
-	// FIXME: proper deallocation in case of errors
-
-	dev->ddf_dev = ddf_dev;
-	dev->driver_data = NULL;
-	dev->descriptors.configuration = NULL;
-	dev->alternate_interfaces = NULL;
-
-	dev->pipes_count = 0;
-	dev->pipes = NULL;
+	*errstr_ptr = NULL;
+
+	usb_dev->ddf_dev = ddf_dev;
+	usb_dev->driver_data = NULL;
+	usb_dev->descriptors.configuration = NULL;
+	usb_dev->pipes_count = 0;
+	usb_dev->pipes = NULL;
 
 	/* Initialize backing wire and control pipe. */
-	rc = init_wire_and_ctrl_pipe(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;
 	}
 
 	/* Get our interface. */
-	dev->interface_no = usb_device_get_assigned_interface(dev->ddf_dev);
+	usb_dev->interface_no = usb_device_get_assigned_interface(ddf_dev);
 
 	/* Retrieve standard descriptors. */
-	rc = usb_device_retrieve_descriptors(&dev->ctrl_pipe,
-	    &dev->descriptors);
+	rc = usb_device_retrieve_descriptors(&usb_dev->ctrl_pipe,
+	    &usb_dev->descriptors);
 	if (rc != EOK) {
 		*errstr_ptr = "descriptor retrieval";
@@ -512,49 +533,52 @@
 	}
 
-	/* Create alternate interfaces. */
-	rc = usb_alternate_interfaces_create(dev->descriptors.configuration,
-	    dev->descriptors.configuration_size, dev->interface_no,
-	    &dev->alternate_interfaces);
-	if (rc != EOK) {
-		/* We will try to silently ignore this. */
-		dev->alternate_interfaces = NULL;
-	}
-
-	rc = initialize_other_pipes(endpoints, dev, 0);
-	if (rc != EOK) {
+	/* 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. */
+		usb_device_release_descriptors(&usb_dev->descriptors);
+		/* Alternate interfaces may be allocated */
+		usb_alternate_interfaces_deinit(&usb_dev->alternate_interfaces);
 		*errstr_ptr = "pipes initialization";
 		return rc;
 	}
 
-	*errstr_ptr = NULL;
-	*dev_ptr = dev;
-
 	return EOK;
 }
 
-/** Destroy instance of a USB device.
- *
- * @param dev Device to be destroyed.
- */
-void usb_device_destroy(usb_device_t *dev)
-{
-	if (dev == NULL) {
-		return;
-	}
-
-	/* Ignore errors and hope for the best. */
-	usb_device_destroy_pipes(dev->ddf_dev, dev->pipes, dev->pipes_count);
-	if (dev->descriptors.configuration != NULL) {
-		free(dev->descriptors.configuration);
-	}
-
-	if (dev->alternate_interfaces != NULL) {
-		if (dev->alternate_interfaces->alternatives != NULL) {
-			free(dev->alternate_interfaces->alternatives);
-		}
-		free(dev->alternate_interfaces);
-	}
-
-	free(dev);
+/** Clean instance of a USB device.
+ *
+ * @param dev Device to be de-initialized.
+ *
+ * Does not free/destroy supplied pointer.
+ */
+void usb_device_deinit(usb_device_t *dev)
+{
+	if (dev) {
+		/* Ignore errors and hope for the best. */
+		destroy_current_pipes(dev);
+
+		usb_alternate_interfaces_deinit(&dev->alternate_interfaces);
+		usb_device_release_descriptors(&dev->descriptors);
+		free(dev->driver_data);
+	}
+}
+
+void * usb_device_data_alloc(usb_device_t *usb_dev, size_t size)
+{
+	assert(usb_dev);
+	assert(usb_dev->driver_data == NULL);
+	return usb_dev->driver_data = calloc(1, size);
+
 }
 
Index: uspace/lib/usbdev/src/devpoll.c
===================================================================
--- uspace/lib/usbdev/src/devpoll.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/src/devpoll.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/src/dp.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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),
@@ -75,6 +75,6 @@
  * @return Whether @p ptr points inside <code>data->data</code> field.
  */
-static bool is_valid_descriptor_pointer(usb_dp_parser_data_t *data,
-    uint8_t *ptr)
+static bool is_valid_descriptor_pointer(const usb_dp_parser_data_t *data,
+    const uint8_t *ptr)
 {
 	if (ptr == NULL) {
@@ -100,11 +100,11 @@
  * @retval NULL Invalid input or no next descriptor.
  */
-static uint8_t *get_next_descriptor(usb_dp_parser_data_t *data,
-    uint8_t *current)
+static const uint8_t *get_next_descriptor(const usb_dp_parser_data_t *data,
+    const uint8_t *current)
 {
 	assert(is_valid_descriptor_pointer(data, current));
 
-	uint8_t current_length = *current;
-	uint8_t *next = current + current_length;
+	const uint8_t current_length = *current;
+	const uint8_t *next = current + current_length;
 
 	if (!is_valid_descriptor_pointer(data, next)) {
@@ -124,5 +124,5 @@
  * @retval -1 Invalid input.
  */
-static int get_descriptor_type(usb_dp_parser_data_t *data, uint8_t *start)
+static int get_descriptor_type(const usb_dp_parser_data_t *data, const uint8_t *start)
 {
 	if (start == NULL) {
@@ -145,8 +145,8 @@
  * @return Whether @p child could be child of @p parent.
  */
-static bool is_nested_descriptor_type(usb_dp_parser_t *parser,
+static bool is_nested_descriptor_type(const usb_dp_parser_t *parser,
     int child, int parent)
 {
-	usb_dp_descriptor_nesting_t *nesting = parser->nesting;
+	const usb_dp_descriptor_nesting_t *nesting = parser->nesting;
 	while ((nesting->child > 0) && (nesting->parent > 0)) {
 		if ((nesting->child == child) && (nesting->parent == parent)) {
@@ -166,6 +166,6 @@
  * @return Whether @p child could be child of @p parent.
  */
-static bool is_nested_descriptor(usb_dp_parser_t *parser,
-    usb_dp_parser_data_t *data, uint8_t *child, uint8_t *parent)
+static bool is_nested_descriptor(const usb_dp_parser_t *parser,
+    const usb_dp_parser_data_t *data, const uint8_t *child, const uint8_t *parent)
 {
 	return is_nested_descriptor_type(parser,
@@ -183,6 +183,6 @@
  * @retval NULL Invalid input.
  */
-uint8_t *usb_dp_get_nested_descriptor(usb_dp_parser_t *parser,
-    usb_dp_parser_data_t *data, uint8_t *parent)
+const uint8_t *usb_dp_get_nested_descriptor(const usb_dp_parser_t *parser,
+    const usb_dp_parser_data_t *data, const uint8_t *parent)
 {
 	if (!is_valid_descriptor_pointer(data, parent)) {
@@ -190,5 +190,5 @@
 	}
 
-	uint8_t *next = get_next_descriptor(data, parent);
+	const uint8_t *next = get_next_descriptor(data, parent);
 	if (next == NULL) {
 		return NULL;
@@ -211,12 +211,14 @@
  * @retval NULL Invalid input.
  */
-static uint8_t *skip_nested_descriptors(usb_dp_parser_t *parser,
-    usb_dp_parser_data_t *data, uint8_t *parent)
-{
-	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, parent);
+static const uint8_t *skip_nested_descriptors(const usb_dp_parser_t *parser,
+    const usb_dp_parser_data_t *data, const uint8_t *parent)
+{
+	const uint8_t *child =
+	    usb_dp_get_nested_descriptor(parser, data, parent);
 	if (child == NULL) {
 		return get_next_descriptor(data, parent);
 	}
-	uint8_t *next_child = skip_nested_descriptors(parser, data, child);
+	const uint8_t *next_child =
+	    skip_nested_descriptors(parser, data, child);
 	while (is_nested_descriptor(parser, data, next_child, parent)) {
 		next_child = skip_nested_descriptors(parser, data, next_child);
@@ -236,6 +238,7 @@
  * @retval NULL Invalid input.
  */
-uint8_t *usb_dp_get_sibling_descriptor(usb_dp_parser_t *parser,
-    usb_dp_parser_data_t *data, uint8_t *parent, uint8_t *sibling)
+const uint8_t *usb_dp_get_sibling_descriptor(
+    const usb_dp_parser_t *parser, const usb_dp_parser_data_t *data,
+    const uint8_t *parent, const uint8_t *sibling)
 {
 	if (!is_valid_descriptor_pointer(data, parent)
@@ -244,5 +247,6 @@
 	}
 
-	uint8_t *possible_sibling = skip_nested_descriptors(parser, data, sibling);
+	const uint8_t *possible_sibling =
+	    skip_nested_descriptors(parser, data, sibling);
 	if (possible_sibling == NULL) {
 		return NULL;
@@ -269,7 +273,7 @@
  * @param arg Custom (user) argument.
  */
-static void usb_dp_browse_simple_internal(usb_dp_parser_t *parser,
-    usb_dp_parser_data_t *data, uint8_t *root, size_t depth,
-    void (*callback)(uint8_t *, size_t, void *), void *arg)
+static void usb_dp_browse_simple_internal(const usb_dp_parser_t *parser,
+    const usb_dp_parser_data_t *data, const uint8_t *root, size_t depth,
+    void (*callback)(const uint8_t *, size_t, void *), void *arg)
 {
 	if (root == NULL) {
@@ -277,5 +281,5 @@
 	}
 	callback(root, depth, arg);
-	uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
+	const uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
 	do {
 		usb_dp_browse_simple_internal(parser, data, child, depth + 1,
@@ -301,6 +305,6 @@
  */
 void usb_dp_walk_simple(uint8_t *descriptors, size_t descriptors_size,
-    usb_dp_descriptor_nesting_t *descriptor_nesting,
-    void (*callback)(uint8_t *, size_t, void *), void *arg)
+    const usb_dp_descriptor_nesting_t *descriptor_nesting,
+    walk_callback_t callback, void *arg)
 {
 	if ((descriptors == NULL) || (descriptors_size == 0)
@@ -309,5 +313,5 @@
 	}
 
-	usb_dp_parser_data_t data = {
+	const usb_dp_parser_data_t data = {
 		.data = descriptors,
 		.size = descriptors_size,
@@ -315,5 +319,5 @@
 	};
 
-	usb_dp_parser_t parser = {
+	const usb_dp_parser_t parser = {
 		.nesting = descriptor_nesting
 	};
Index: uspace/lib/usbdev/src/hub.c
===================================================================
--- uspace/lib/usbdev/src/hub.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/src/hub.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -37,4 +37,5 @@
 #include <usb/dev/request.h>
 #include <usb/dev/recognise.h>
+#include <usb/debug.h>
 #include <usbhc_iface.h>
 #include <errno.h>
@@ -57,5 +58,6 @@
 		assert((conn)); \
 		if (!usb_hc_connection_is_opened((conn))) { \
-			return ENOENT; \
+			usb_log_error("Connection not open.\n"); \
+			return ENOTCONN; \
 		} \
 	} while (false)
@@ -64,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).
@@ -69,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;
 }
 
@@ -94,19 +94,19 @@
  * @return Error code.
  */
-int usb_hc_register_device(usb_hc_connection_t * connection,
-    const usb_hc_attached_device_t *attached_device)
+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,
-	    attached_device->address, attached_device->handle);
+	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;
 }
 
@@ -121,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;
 }
 
@@ -155,8 +184,6 @@
  * The @p enable_port function is expected to enable signaling on given
  * port.
- * The two arguments to it can have arbitrary meaning
- * (the @p port_no is only a suggestion)
- * and are not touched at all by this function
- * (they are passed as is to the @p enable_port function).
+ * The argument can have arbitrary meaning and it is not touched at all
+ * by this function (it is passed as is to the @p enable_port function).
  *
  * If the @p enable_port fails (i.e. does not return EOK), the device
@@ -171,18 +198,18 @@
  *
  * @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
  *	device is attached to.
- * @param[in] port_no Port number (passed through to @p enable_port).
  * @param[in] arg Any data argument to @p enable_port.
  * @param[out] assigned_address USB address of the device.
- * @param[out] assigned_handle Devman handle of the new 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.
@@ -192,16 +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 (*enable_port)(int port_no, void *arg), int port_no, void *arg,
-    usb_address_t *assigned_address, devman_handle_t *assigned_handle,
+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;
@@ -217,13 +243,13 @@
 		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) {
-		usb_hc_connection_close(&hc_conn);
-		return EADDRNOTAVAIL;
+		rc = EADDRNOTAVAIL;
+		goto close_connection;
 	}
 
@@ -243,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;
@@ -251,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;
 
@@ -270,14 +306,11 @@
 	 * 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.
-	 */
-	rc = enable_port(port_no, arg);
+	/* Endpoint is registered. We can enable the port and change address. */
+	rc = enable_port(arg);
 	if (rc != EOK) {
 		goto leave_release_default_address;
@@ -290,4 +323,5 @@
 	async_usleep(10000);
 
+	/* Get max_packet_size value. */
 	rc = usb_pipe_probe_default_control(&ctrl_pipe);
 	if (rc != EOK) {
@@ -296,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;
@@ -302,59 +336,43 @@
 	}
 
-	/*
-	 * 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);
+	/* 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(&ctrl_pipe,
+	    parent, dev_ops, new_dev_data, &child_fun);
 	if (rc != EOK) {
 		goto leave_release_free_address;
 	}
 
-	/*
-	 * It is time to register the device with devman.
-	 */
-	/* FIXME: create device_register that will get opened ctrl pipe. */
-	devman_handle_t child_handle;
-	rc = usb_device_register_child_in_devman(dev_addr, dev_conn.hc_handle,
-	    parent, &child_handle,
-	    dev_ops, new_dev_data, new_fun);
-	if (rc != EOK) {
-		rc = ESTALL;
-		goto leave_release_free_address;
-	}
-
-	/*
-	 * And now inform the host controller about the handle.
-	 */
-	usb_hc_attached_device_t new_device = {
+	const usb_hub_attached_device_t new_device = {
 		.address = dev_addr,
-		.handle = child_handle
+		.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;
 	}
-	
-	usb_hc_connection_close(&hc_conn);
-
-	/*
-	 * And we are done.
-	 */
+
 	if (assigned_address != NULL) {
 		*assigned_address = dev_addr;
 	}
-	if (assigned_handle != NULL) {
-		*assigned_handle = child_handle;
-	}
-
-	return EOK;
-
-
+
+	*new_fun = child_fun;
+
+	rc = EOK;
+	goto close_connection;
 
 	/*
@@ -363,10 +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);
-
-	usb_hc_connection_close(&hc_conn);
+	/* 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("%s: Failed to close hc connection.\n",
+		    __FUNCTION__);
 
 	return rc;
Index: uspace/lib/usbdev/src/pipepriv.c
===================================================================
--- uspace/lib/usbdev/src/pipepriv.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/src/pipepriv.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/src/pipes.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -52,23 +52,17 @@
  * @return USB address or error code.
  */
-static usb_address_t get_my_address(async_sess_t *sess, ddf_dev_t *dev)
-{
+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).
- */
-int usb_device_get_assigned_interface(ddf_dev_t *device)
-{
+ * @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;
 }
 
@@ -108,5 +100,5 @@
  */
 int usb_device_connection_initialize_from_device(
-    usb_device_connection_t *connection, ddf_dev_t *dev)
+    usb_device_connection_t *connection, const ddf_dev_t *dev)
 {
 	assert(connection);
Index: uspace/lib/usbdev/src/pipesinit.c
===================================================================
--- uspace/lib/usbdev/src/pipesinit.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/src/pipesinit.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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),
@@ -68,5 +68,5 @@
  * @return Whether the given descriptor is endpoint descriptor.
  */
-static inline bool is_endpoint_descriptor(uint8_t *descriptor)
+static inline bool is_endpoint_descriptor(const uint8_t *descriptor)
 {
 	return descriptor[1] == USB_DESCTYPE_ENDPOINT;
@@ -80,5 +80,5 @@
  */
 static bool endpoint_fits_description(const usb_endpoint_description_t *wanted,
-    usb_endpoint_description_t *found)
+    const usb_endpoint_description_t *found)
 {
 #define _SAME(fieldname) ((wanted->fieldname) == (found->fieldname))
@@ -120,5 +120,5 @@
 static usb_endpoint_mapping_t *find_endpoint_mapping(
     usb_endpoint_mapping_t *mapping, size_t mapping_count,
-    usb_endpoint_description_t *found_endpoint,
+    const usb_endpoint_description_t *found_endpoint,
     int interface_number, int interface_setting)
 {
@@ -160,5 +160,4 @@
     usb_device_connection_t *wire)
 {
-	usb_endpoint_description_t description;
 
 	/*
@@ -167,18 +166,19 @@
 
 	/* Actual endpoint number is in bits 0..3 */
-	usb_endpoint_t ep_no = endpoint->endpoint_address & 0x0F;
-
-	/* Endpoint direction is set by bit 7 */
-	description.direction = (endpoint->endpoint_address & 128)
-	    ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
-	/* Transfer type is in bits 0..2 and the enum values corresponds 1:1 */
-	description.transfer_type = endpoint->attributes & 3;
-
-	/*
-	 * Get interface characteristics.
-	 */
-	description.interface_class = interface->interface_class;
-	description.interface_subclass = interface->interface_subclass;
-	description.interface_protocol = interface->interface_protocol;
+	const usb_endpoint_t ep_no = endpoint->endpoint_address & 0x0F;
+
+	const usb_endpoint_description_t description = {
+		/* Endpoint direction is set by bit 7 */
+		.direction = (endpoint->endpoint_address & 128)
+		    ? USB_DIRECTION_IN : USB_DIRECTION_OUT,
+		/* Transfer type is in bits 0..2 and
+		 * the enum values corresponds 1:1 */
+		.transfer_type = endpoint->attributes & 3,
+
+		/* Get interface characteristics. */
+		.interface_class = interface->interface_class,
+		.interface_subclass = interface->interface_subclass,
+		.interface_protocol = interface->interface_protocol,
+	};
 
 	/*
@@ -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);
@@ -224,8 +221,8 @@
 static int process_interface(
     usb_endpoint_mapping_t *mapping, size_t mapping_count,
-    usb_dp_parser_t *parser, usb_dp_parser_data_t *parser_data,
-    uint8_t *interface_descriptor)
-{
-	uint8_t *descriptor = usb_dp_get_nested_descriptor(parser,
+    const usb_dp_parser_t *parser, const usb_dp_parser_data_t *parser_data,
+    const uint8_t *interface_descriptor)
+{
+	const uint8_t *descriptor = usb_dp_get_nested_descriptor(parser,
 	    parser_data, interface_descriptor);
 
@@ -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)
@@ -284,22 +281,19 @@
 int usb_pipe_initialize_from_configuration(
     usb_endpoint_mapping_t *mapping, size_t mapping_count,
-    uint8_t *configuration_descriptor, size_t configuration_descriptor_size,
+    const uint8_t *config_descriptor, size_t config_descriptor_size,
     usb_device_connection_t *connection)
 {
 	assert(connection);
 
-	if (configuration_descriptor == NULL) {
+	if (config_descriptor == NULL) {
 		return EBADMEM;
 	}
-	if (configuration_descriptor_size
+	if (config_descriptor_size
 	    < sizeof(usb_standard_configuration_descriptor_t)) {
 		return ERANGE;
 	}
 
-	/*
-	 * 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,13 +301,11 @@
 	}
 
-	/*
-	 * Prepare the descriptor parser.
-	 */
-	usb_dp_parser_t dp_parser = {
+	/* Prepare the descriptor parser. */
+	const usb_dp_parser_t dp_parser = {
 		.nesting = descriptor_nesting
 	};
-	usb_dp_parser_data_t dp_data = {
-		.data = configuration_descriptor,
-		.size = configuration_descriptor_size,
+	const usb_dp_parser_data_t dp_data = {
+		.data = config_descriptor,
+		.size = config_descriptor_size,
 		.arg = connection
 	};
@@ -322,6 +314,6 @@
 	 * Iterate through all interfaces.
 	 */
-	uint8_t *interface = usb_dp_get_nested_descriptor(&dp_parser,
-	    &dp_data, configuration_descriptor);
+	const uint8_t *interface = usb_dp_get_nested_descriptor(&dp_parser,
+	    &dp_data, config_descriptor);
 	if (interface == NULL) {
 		return ENOENT;
@@ -329,8 +321,7 @@
 	do {
 		(void) process_interface(mapping, mapping_count,
-		    &dp_parser, &dp_data,
-		    interface);
+		    &dp_parser, &dp_data, interface);
 		interface = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
-		    configuration_descriptor, interface);
+		    config_descriptor, interface);
 	} while (interface != NULL);
 
@@ -414,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);
@@ -424,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,
@@ -455,51 +442,22 @@
  * @return Error code.
  */
-int usb_pipe_register(usb_pipe_t *pipe,
-    unsigned int interval,
+int usb_pipe_register(usb_pipe_t *pipe, unsigned 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(pipe->wire);
 	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));
+	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);
-	
-#undef _PACK2
-#undef _PACK3
-	
-	return rc;
+	return ret;
 }
 
@@ -514,16 +472,18 @@
 {
 	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);
-	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_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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/src/pipesio.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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,116 +162,28 @@
  * @return Error code.
  */
-static int usb_pipe_control_read_no_check(usb_pipe_t *pipe,
-    void *setup_buffer, size_t setup_buffer_size,
+int usb_pipe_control_read(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);
+	assert(pipe);
+
+	if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
+		return EINVAL;
+	}
+
+	if ((data_buffer == NULL) || (data_buffer_size == 0)) {
+		return EINVAL;
+	}
+
+	if ((pipe->direction != USB_DIRECTION_BOTH)
+	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
+		return EBADF;
+	}
+
 	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,
-    void *setup_buffer, size_t setup_buffer_size,
-    void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
-{
-	assert(pipe);
-
-	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
-		return EINVAL;
-	}
-
-	if ((data_buffer == NULL) || (data_buffer_size == 0)) {
-		return EINVAL;
-	}
-
-	if ((pipe->direction != USB_DIRECTION_BOTH)
-	    || (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_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,103 +210,32 @@
  * @return Error code.
  */
-static int usb_pipe_control_write_no_check(usb_pipe_t *pipe,
-    void *setup_buffer, size_t setup_buffer_size,
-    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);
+int usb_pipe_control_write(usb_pipe_t *pipe,
+    const void *setup_buffer, size_t setup_buffer_size,
+    const void *data_buffer, size_t data_buffer_size)
+{
+	assert(pipe);
+
+	if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
+		return EINVAL;
+	}
+
+	if ((data_buffer == NULL) && (data_buffer_size > 0)) {
+		return EINVAL;
+	}
+
+	if ((data_buffer != NULL) && (data_buffer_size == 0)) {
+		return EINVAL;
+	}
+
+	if ((pipe->direction != USB_DIRECTION_BOTH)
+	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
+		return EBADF;
+	}
+
 	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,
-    void *setup_buffer, size_t setup_buffer_size,
-    void *data_buffer, size_t data_buffer_size)
-{
-	assert(pipe);
-
-	if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
-		return EINVAL;
-	}
-
-	if ((data_buffer == NULL) && (data_buffer_size > 0)) {
-		return EINVAL;
-	}
-
-	if ((data_buffer != NULL) && (data_buffer_size == 0)) {
-		return EINVAL;
-	}
-
-	if ((pipe->direction != USB_DIRECTION_BOTH)
-	    || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
-		return EBADF;
-	}
-
-	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);
+	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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/src/recognise.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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,9 +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[out] child_handle Handle of the child 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.
@@ -347,36 +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, devman_handle_t *child_handle,
-    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;
-	}
 
 	/*
@@ -384,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;
@@ -403,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;
@@ -414,23 +384,16 @@
 	}
 
-	if (child_handle != NULL) {
-		*child_handle = child->handle;
-	}
-
-	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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbdev/src/request.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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,
@@ -425,6 +390,5 @@
 
 	/* Everything is okay, copy the descriptor. */
-	memcpy(descriptor, &descriptor_tmp,
-	    sizeof(descriptor_tmp));
+	memcpy(descriptor, &descriptor_tmp, sizeof(descriptor_tmp));
 
 	return EOK;
@@ -470,6 +434,5 @@
 
 	/* Everything is okay, copy the descriptor. */
-	memcpy(descriptor, &descriptor_tmp,
-	    sizeof(descriptor_tmp));
+	memcpy(descriptor, &descriptor_tmp, sizeof(descriptor_tmp));
 
 	return EOK;
Index: uspace/lib/usbhid/include/usb/hid/hiddescriptor.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/hiddescriptor.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhid/include/usb/hid/hiddescriptor.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -42,12 +42,12 @@
 #include <usb/hid/hidtypes.h>
 
-int usb_hid_parse_report_descriptor(usb_hid_report_t *report, 
+int usb_hid_parse_report_descriptor(usb_hid_report_t *report,
 		const uint8_t *data, size_t size);
-
-void usb_hid_free_report(usb_hid_report_t *report);
 
 void usb_hid_descriptor_print(usb_hid_report_t *report);
 
 int usb_hid_report_init(usb_hid_report_t *report);
+
+void usb_hid_report_deinit(usb_hid_report_t *report);
 
 int usb_hid_report_append_fields(usb_hid_report_t *report,
@@ -78,6 +78,4 @@
 void usb_hid_report_reset_local_items(usb_hid_report_item_t *report_item);
 
-void usb_hid_free_report_list(list_t *list);
-
 usb_hid_report_item_t *usb_hid_report_item_clone(
 		const usb_hid_report_item_t *item);
Index: uspace/lib/usbhid/include/usb/hid/usages/consumer.h
===================================================================
--- uspace/lib/usbhid/include/usb/hid/usages/consumer.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhid/include/usb/hid/usages/consumer.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhid/src/consumer.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhid/src/hiddescriptor.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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;
 }
 
@@ -974,40 +974,4 @@
 /*---------------------------------------------------------------------------*/
 
-/**
- * Releases whole linked list of report items
- *
- * @param list List of report descriptor items (usb_hid_report_item_t)
- * @return void
- */
-void usb_hid_free_report_list(list_t *list)
-{
-	return; /* XXX What's this? */
-	
-/*	usb_hid_report_item_t *report_item;
-	link_t *next;
-	
-	if(list == NULL || list_empty(list)) {
-	    return;
-	}
-	
-	next = list->head.next;
-	while (next != &list->head) {
-		report_item = list_get_instance(next, usb_hid_report_item_t,
-		    rpath_items_link);
-
-		while(!list_empty(&report_item->usage_path->link)) {
-			usb_hid_report_remove_last_item(report_item->usage_path);
-		}
-
-		
-	    next = next->next;
-	    
-	    free(report_item);
-	}
-	
-	return;
-	*/
-}
-/*---------------------------------------------------------------------------*/
 
 /** Frees the HID report descriptor parser structure 
@@ -1016,5 +980,5 @@
  * @return void
  */
-void usb_hid_free_report(usb_hid_report_t *report)
+void usb_hid_report_deinit(usb_hid_report_t *report)
 {
 	if(report == NULL){
Index: uspace/lib/usbhid/src/hidparser.c
===================================================================
--- uspace/lib/usbhid/src/hidparser.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhid/src/hidparser.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -52,12 +52,9 @@
 	int32_t value);
 
-int usb_pow(int a, int b);
-
-/*---------------------------------------------------------------------------*/
-
-// TODO: tohle ma bejt asi jinde
-int usb_pow(int a, int b)
-{
-	switch(b) {
+/*---------------------------------------------------------------------------*/
+
+static int usb_pow(int a, int b)
+{
+	switch (b) {
 	case 0:
 		return 1;
@@ -67,5 +64,5 @@
 		break;
 	default:
-		return a * usb_pow(a, b-1);
+		return a * usb_pow(a, b - 1);
 		break;
 	}
@@ -81,17 +78,16 @@
  */
 size_t usb_hid_report_size(usb_hid_report_t *report, uint8_t report_id, 
-                           usb_hid_report_type_t type)
+    usb_hid_report_type_t type)
 {
 	usb_hid_report_description_t *report_des;
 
-	if(report == NULL) {
+	if (report == NULL) {
 		return 0;
 	}
 
-	report_des = usb_hid_report_find_description (report, report_id, type);
-	if(report_des == NULL){
+	report_des = usb_hid_report_find_description(report, report_id, type);
+	if (report_des == NULL) {
 		return 0;
-	}
-	else {
+	} else {
 		return report_des->item_length;
 	}
@@ -106,17 +102,16 @@
  */
 size_t usb_hid_report_byte_size(usb_hid_report_t *report, uint8_t report_id, 
-                           usb_hid_report_type_t type)
+    usb_hid_report_type_t type)
 {
 	usb_hid_report_description_t *report_des;
 
-	if(report == NULL) {
+	if (report == NULL) {
 		return 0;
 	}
 
-	report_des = usb_hid_report_find_description (report, report_id, type);
-	if(report_des == NULL){
+	report_des = usb_hid_report_find_description(report, report_id, type);
+	if (report_des == NULL) {
 		return 0;
-	}
-	else {
+	} else {
 		return ((report_des->bit_length + 7) / 8) ;
 	}
@@ -133,5 +128,5 @@
  */ 
 int usb_hid_parse_report(const usb_hid_report_t *report, const uint8_t *data, 
-	size_t size, uint8_t *report_id)
+    size_t size, uint8_t *report_id)
 {
 	usb_hid_report_field_t *item;
@@ -140,20 +135,18 @@
 	usb_hid_report_type_t type = USB_HID_REPORT_TYPE_INPUT;
 	
-	if(report == NULL) {
+	if (report == NULL) {
 		return EINVAL;
 	}
 
-	if(report->use_report_ids != 0) {
+	if (report->use_report_ids != 0) {
 		*report_id = data[0];
-	}	
-	else {
+	} else {
 		*report_id = 0;
 	}
 
-
 	report_des = usb_hid_report_find_description(report, *report_id, 
-		type);
-
-	if(report_des == NULL) {
+	    type);
+
+	if (report_des == NULL) {
 		return EINVAL;
 	}
@@ -162,35 +155,32 @@
 	list_foreach(report_des->report_items, list_item) {
 		item = list_get_instance(list_item, usb_hid_report_field_t, 
-				ritems_link);
-
-		if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) == 0) {
+		    ritems_link);
+
+		if (USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) == 0) {
 			
-			if(USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0){
-
-				// array
+			if (USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0) {
+				/* array */
 				item->value = 
 					usb_hid_translate_data(item, data);
 		
 				item->usage = USB_HID_EXTENDED_USAGE(
-				    item->usages[
-				    item->value - item->physical_minimum]);
+				    item->usages[item->value -
+				    item->physical_minimum]);
 
 				item->usage_page = 
 				    USB_HID_EXTENDED_USAGE_PAGE(
-				    item->usages[
-				    item->value - item->physical_minimum]);
-
-				usb_hid_report_set_last_item (
+				    item->usages[item->value -
+				    item->physical_minimum]);
+
+				usb_hid_report_set_last_item(
 				    item->collection_path, 
 				    USB_HID_TAG_CLASS_GLOBAL, 
 				    item->usage_page);
 
-				usb_hid_report_set_last_item (
+				usb_hid_report_set_last_item(
 				    item->collection_path, 
 				    USB_HID_TAG_CLASS_LOCAL, item->usage);
-				
-			}
-			else {
-				// variable item
+			} else {
+				/* variable item */
 				item->value = usb_hid_translate_data(item, 
 				    data);				
@@ -200,5 +190,4 @@
 	
 	return EOK;
-	
 }
 
@@ -217,14 +206,14 @@
 	int part_size;
 	
-	int32_t value=0;
-	int32_t mask=0;
-	const uint8_t *foo=0;
-
-	// now only shot tags are allowed
-	if(item->size > 32) {
+	int32_t value = 0;
+	int32_t mask = 0;
+	const uint8_t *foo = 0;
+
+	/* now only short tags are allowed */
+	if (item->size > 32) {
 		return 0;
 	}
 
-	if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
+	if ((item->physical_minimum == 0) && (item->physical_maximum == 0)) {
 		item->physical_minimum = item->logical_minimum;
 		item->physical_maximum = item->logical_maximum;			
@@ -232,57 +221,55 @@
 	
 
-	if(item->physical_maximum == item->physical_minimum){
+	if (item->physical_maximum == item->physical_minimum) {
 	    resolution = 1;
-	}
-	else {
+	} else {
 	    resolution = (item->logical_maximum - item->logical_minimum) / 
 		((item->physical_maximum - item->physical_minimum) * 
-		(usb_pow(10,(item->unit_exponent))));
+		(usb_pow(10, (item->unit_exponent))));
 	}
 
 	offset = item->offset;
 	// FIXME
-	if((size_t)(offset/8) != (size_t)((offset+item->size-1)/8)) {
+	if ((size_t) (offset / 8) != (size_t) ((offset+item->size - 1) / 8)) {
 		
 		part_size = 0;
 
-		size_t i=0;
-		for(i=(size_t)(offset/8); i<=(size_t)(offset+item->size-1)/8; i++){
-			if(i == (size_t)(offset/8)) {
-				// the higher one
+		size_t i = 0;
+		for (i = (size_t) (offset / 8);
+		    i <= (size_t) (offset + item->size - 1) / 8; i++) {
+			if (i == (size_t) (offset / 8)) {
+				/* the higher one */
 				part_size = 8 - (offset % 8);
 				foo = data + i;
-				mask =  ((1 << (item->size-part_size))-1);
+				mask =  ((1 << (item->size - part_size)) - 1);
 				value = (*foo & mask);
-			}
-			else if(i == ((offset+item->size-1)/8)){
-				// the lower one
+			} else if (i == ((offset + item->size - 1) / 8)) {
+				/* the lower one */
 				foo = data + i;
-				mask = ((1 << (item->size - part_size)) - 1) 
-					<< (8 - (item->size - part_size));
+				mask = ((1 << (item->size - part_size)) - 1) <<
+				    (8 - (item->size - part_size));
 
 				value = (((*foo & mask) >> (8 - 
-				    (item->size - part_size))) << part_size ) 
-				    + value;
-			}
-			else {
-				value = (*(data + 1) << (part_size + 8)) + value;
+				    (item->size - part_size))) << part_size) + 
+				    value;
+			} else {
+				value = (*(data + 1) << (part_size + 8)) +
+				    value;
 				part_size += 8;
 			}
 		}
-	}
-	else {		
-		foo = data+(offset/8);
-		mask =  ((1 << item->size)-1) << (8-((offset%8)+item->size));
-		value = (*foo & mask) >> (8-((offset%8)+item->size));
-	}
-
-	if((item->logical_minimum < 0) || (item->logical_maximum < 0)){
+	} else {		
+		foo = data + (offset / 8);
+		mask = ((1 << item->size) - 1) <<
+		    (8 - ((offset % 8) + item->size));
+		value = (*foo & mask) >> (8 - ((offset % 8) + item->size));
+	}
+
+	if ((item->logical_minimum < 0) || (item->logical_maximum < 0)) {
 		value = USB_HID_UINT32_TO_INT32(value, item->size);
 	}
 
-	return (int)(((value - item->logical_minimum) / resolution) + 
-		item->physical_minimum);
-	
+	return (int) (((value - item->logical_minimum) / resolution) + 
+	    item->physical_minimum);
 }
 
@@ -299,7 +286,7 @@
  */
 uint8_t *usb_hid_report_output(usb_hid_report_t *report, size_t *size, 
-	uint8_t report_id)
-{
-	if(report == NULL) {
+    uint8_t report_id)
+{
+	if (report == NULL) {
 		*size = 0;
 		return NULL;
@@ -310,18 +297,17 @@
 	list_foreach(report->reports, report_it) {
 		report_des = list_get_instance(report_it,
-			usb_hid_report_description_t, reports_link);
+		    usb_hid_report_description_t, reports_link);
 		
-		if((report_des->report_id == report_id) &&
-			(report_des->type == USB_HID_REPORT_TYPE_OUTPUT)){
+		if ((report_des->report_id == report_id) &&
+		    (report_des->type == USB_HID_REPORT_TYPE_OUTPUT)) {
 			break;
 		}
 	}
 
-	if(report_des == NULL){
+	if (report_des == NULL) {
 		*size = 0;
 		return NULL;
-	}
-	else {
-		*size = (report_des->bit_length + (8 - 1))/8;
+	} else {
+		*size = (report_des->bit_length + (8 - 1)) / 8;
 		uint8_t *ret = malloc((*size) * sizeof(uint8_t));
 		memset(ret, 0, (*size) * sizeof(uint8_t));
@@ -337,8 +323,7 @@
  */
 void usb_hid_report_output_free(uint8_t *output)
-
-{
-	if(output != NULL) {
-		free (output);
+{
+	if (output != NULL) {
+		free(output);
 	}
 }
@@ -354,24 +339,24 @@
  */
 int usb_hid_report_output_translate(usb_hid_report_t *report, 
-	uint8_t report_id, uint8_t *buffer, size_t size)
-{
-	int32_t value=0;
+    uint8_t report_id, uint8_t *buffer, size_t size)
+{
+	int32_t value = 0;
 	int offset;
 	int length;
 	int32_t tmp_value;
 	
-	if(report == NULL) {
+	if (report == NULL) {
 		return EINVAL;
 	}
 
-	if(report->use_report_ids != 0) {
+	if (report->use_report_ids != 0) {
 		buffer[0] = report_id;		
 	}
 
 	usb_hid_report_description_t *report_des;
-	report_des = usb_hid_report_find_description (report, report_id, 
-		USB_HID_REPORT_TYPE_OUTPUT);
-	
-	if(report_des == NULL){
+	report_des = usb_hid_report_find_description(report, report_id, 
+	    USB_HID_REPORT_TYPE_OUTPUT);
+	
+	if (report_des == NULL) {
 		return EINVAL;
 	}
@@ -384,5 +369,5 @@
 
 		value = usb_hid_translate_data_reverse(report_item, 
-			report_item->value);
+		    report_item->value);
 
 		offset = report_des->bit_length - report_item->offset - 1;
@@ -391,55 +376,53 @@
 		usb_log_debug("\ttranslated value: %x\n", value);
 
-		if((offset/8) == ((offset+length-1)/8)) {
-			// je to v jednom bytu
-			if(((size_t)(offset/8) >= size) || 
-				((size_t)(offset+length-1)/8) >= size) {
+		if ((offset / 8) == ((offset + length - 1) / 8)) {
+			if (((size_t) (offset / 8) >= size) || 
+			    ((size_t) (offset + length - 1) / 8) >= size) {
 				break; // TODO ErrorCode
 			}
-			size_t shift = 8 - offset%8 - length;
+			size_t shift = 8 - offset % 8 - length;
 			value = value << shift;							
-			value = value & (((1 << length)-1) << shift);
+			value = value & (((1 << length) - 1) << shift);
 				
 			uint8_t mask = 0;
 			mask = 0xff - (((1 << length) - 1) << shift);
-			buffer[offset/8] = (buffer[offset/8] & mask) | value;
-		}
-		else {
+			buffer[offset / 8] = (buffer[offset / 8] & mask) |
+			    value;
+		} else {
 			int i = 0;
 			uint8_t mask = 0;
-			for(i = (offset/8); i <= ((offset+length-1)/8); i++) {
-				if(i == (offset/8)) {
+			for (i = (offset / 8);
+			    i <= ((offset + length - 1) / 8); i++) {
+				if (i == (offset / 8)) {
 					tmp_value = value;
 					tmp_value = tmp_value & 
-						((1 << (8-(offset%8)))-1);
-
-					tmp_value = tmp_value << (offset%8);
-	
-					mask = ~(((1 << (8-(offset%8)))-1) << 
-							(offset%8));
+					    ((1 << (8 - (offset % 8))) - 1);
+
+					tmp_value = tmp_value << (offset % 8);
+	
+					mask = ~(((1 << (8 - (offset % 8))) - 1)
+					    << (offset % 8));
 
 					buffer[i] = (buffer[i] & mask) | 
-						tmp_value;
-				}
-				else if (i == ((offset + length -1)/8)) {
+					    tmp_value;
+				} else if (i == ((offset + length - 1) / 8)) {
 					
 					value = value >> (length - 
-						((offset + length) % 8));
+					    ((offset + length) % 8));
 
 					value = value & ((1 << (length - 
-						((offset + length) % 8))) - 1);
+					    ((offset + length) % 8))) - 1);
 				
 					mask = (1 << (length - 
-						((offset + length) % 8))) - 1;
+					    ((offset + length) % 8))) - 1;
 
 					buffer[i] = (buffer[i] & mask) | value;
-				}
-				else {
-					buffer[i] = value & (0xFF << i);
+				} else {
+					buffer[i] = value & (0xff << i);
 				}
 			}
 		}
 
-		// reset value
+		/* reset value */
 		report_item->value = 0;
 	}
@@ -456,39 +439,39 @@
  */
 uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, 
-	int value)
-{
-	int ret=0;
+    int value)
+{
+	int ret = 0;
 	int resolution;
 
-	if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags)) {
+	if (USB_HID_ITEM_FLAG_CONSTANT(item->item_flags)) {
 		ret = item->logical_minimum;
 	}
 
-	if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
+	if ((item->physical_minimum == 0) && (item->physical_maximum == 0)) {
 		item->physical_minimum = item->logical_minimum;
 		item->physical_maximum = item->logical_maximum;			
 	}
 	
-	// variable item
-	if(item->physical_maximum == item->physical_minimum){
+	/* variable item */
+	if (item->physical_maximum == item->physical_minimum) {
 	    resolution = 1;
-	}
-	else {
+	} else {
 	    resolution = (item->logical_maximum - item->logical_minimum) /
 		((item->physical_maximum - item->physical_minimum) *
-		(usb_pow(10,(item->unit_exponent))));
+		(usb_pow(10, (item->unit_exponent))));
 	}
 
 	ret = ((value - item->physical_minimum) * resolution) + 
-		item->logical_minimum;
-
-	usb_log_debug("\tvalue(%x), resolution(%x), phymin(%x) logmin(%x), \
-		ret(%x)\n", value, resolution, item->physical_minimum, 
-		item->logical_minimum, ret);
-	
-	if((item->logical_minimum < 0) || (item->logical_maximum < 0)){
+	    item->logical_minimum;
+
+	usb_log_debug("\tvalue(%x), resolution(%x), phymin(%x) logmin(%x), "
+	    "ret(%x)\n", value, resolution, item->physical_minimum, 
+	    item->logical_minimum, ret);
+	
+	if ((item->logical_minimum < 0) || (item->logical_maximum < 0)) {
 		return USB_HID_INT32_TO_UINT32(ret, item->size);
 	}
-	return (int32_t)0 + ret;
+
+	return (int32_t) 0 + ret;
 }
 
@@ -501,9 +484,9 @@
  */
 usb_hid_report_item_t *usb_hid_report_item_clone(
-	const usb_hid_report_item_t *item)
+    const usb_hid_report_item_t *item)
 {
 	usb_hid_report_item_t *new_report_item;
 	
-	if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
+	if (!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
 		return NULL;
 	}					
@@ -529,42 +512,37 @@
  */
 usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report, 
-	usb_hid_report_field_t *field, usb_hid_report_path_t *path, int flags, 
-	usb_hid_report_type_t type)
+    usb_hid_report_field_t *field, usb_hid_report_path_t *path, int flags, 
+    usb_hid_report_type_t type)
 {
 	usb_hid_report_description_t *report_des = 
-		usb_hid_report_find_description(report, path->report_id, type);
+	    usb_hid_report_find_description(report, path->report_id, type);
 
 	link_t *field_it;
 	
-	if(report_des == NULL){
+	if (report_des == NULL) {
 		return NULL;
 	}
 
-	if(field == NULL){
+	if (field == NULL) {
 		field_it = report_des->report_items.head.next;
-	}
-	else {
+	} else {
 		field_it = field->ritems_link.next;
 	}
 
-	while(field_it != &report_des->report_items.head) {
+	while (field_it != &report_des->report_items.head) {
 		field = list_get_instance(field_it, usb_hid_report_field_t, 
-			ritems_link);
-
-		if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
-			usb_hid_report_path_append_item (
-				field->collection_path, field->usage_page, 
-				field->usage);
-
-			if(usb_hid_report_compare_usage_path(
-				field->collection_path, path, flags) == EOK){
-
+		    ritems_link);
+
+		if (USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
+			usb_hid_report_path_append_item(field->collection_path,
+			    field->usage_page, field->usage);
+
+			if (usb_hid_report_compare_usage_path(
+			    field->collection_path, path, flags) == EOK) {
 				usb_hid_report_remove_last_item(
-					field->collection_path);
-
+				    field->collection_path);
 				return field;
 			}
-			usb_hid_report_remove_last_item (
-				field->collection_path);
+			usb_hid_report_remove_last_item(field->collection_path);
 		}
 		field_it = field_it->next;
@@ -586,8 +564,8 @@
  * @retval report_id otherwise
  */
-uint8_t usb_hid_get_next_report_id(usb_hid_report_t *report, 
-	uint8_t report_id, usb_hid_report_type_t type)
-{
-	if(report == NULL){
+uint8_t usb_hid_get_next_report_id(usb_hid_report_t *report, uint8_t report_id,
+    usb_hid_report_type_t type)
+{
+	if (report == NULL) {
 		return 0;
 	}
@@ -596,23 +574,21 @@
 	link_t *report_it;
 	
-	if(report_id > 0) {
+	if (report_id > 0) {
 		report_des = usb_hid_report_find_description(report, report_id, 
-			type);
-		if(report_des == NULL) {
+		    type);
+		if (report_des == NULL) {
 			return 0;
-		}
-		else {
+		} else {
 			report_it = report_des->reports_link.next;
 		}	
-	}
-	else {
+	} else {
 		report_it = report->reports.head.next;
 	}
 
-	while(report_it != &report->reports.head) {
+	while (report_it != &report->reports.head) {
 		report_des = list_get_instance(report_it, 
-			usb_hid_report_description_t, reports_link);
-
-		if(report_des->type == type){
+		    usb_hid_report_description_t, reports_link);
+
+		if (report_des->type == type) {
 			return report_des->report_id;
 		}
@@ -635,5 +611,5 @@
 void usb_hid_report_reset_local_items(usb_hid_report_item_t *report_item)
 {
-	if(report_item == NULL)	{
+	if (report_item == NULL) {
 		return;
 	}
@@ -651,7 +627,6 @@
 	report_item->string_minimum = 0;
 	report_item->string_maximum = 0;
-
-	return;
-}
+}
+
 /**
  * @}
Index: uspace/lib/usbhid/src/hidpath.c
===================================================================
--- uspace/lib/usbhid/src/hidpath.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhid/src/hidpath.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -76,7 +76,8 @@
                                     int32_t usage_page, int32_t usage)
 {	
-	usb_hid_report_usage_path_t *item;
-
-	if(!(item=malloc(sizeof(usb_hid_report_usage_path_t)))) {
+	usb_hid_report_usage_path_t *item
+		= malloc(sizeof(usb_hid_report_usage_path_t));
+
+	if (item == NULL) {
 		return ENOMEM;
 	}
@@ -384,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/hidreport.c
===================================================================
--- uspace/lib/usbhid/src/hidreport.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhid/src/hidreport.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -69,5 +69,5 @@
 	 * First nested descriptor of the configuration descriptor.
 	 */
-	uint8_t *d = 
+	const uint8_t *d = 
 	    usb_dp_get_nested_descriptor(&parser, &parser_data, 
 	    dev->descriptors.configuration);
@@ -92,5 +92,5 @@
 	 * First nested descriptor of the interface descriptor.
 	 */
-	uint8_t *iface_desc = d;
+	const uint8_t *iface_desc = d;
 	d = usb_dp_get_nested_descriptor(&parser, &parser_data, iface_desc);
 	
Index: uspace/lib/usbhid/src/hidreq.c
===================================================================
--- uspace/lib/usbhid/src/hidreq.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhid/src/hidreq.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/include/usb/host/endpoint.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/endpoint.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhost/include/usb/host/endpoint.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -36,51 +36,69 @@
 #define LIBUSBHOST_HOST_ENDPOINT_H
 
-#include <assert.h>
 #include <bool.h>
 #include <adt/list.h>
 #include <fibril_synch.h>
-
 #include <usb/usb.h>
 
+/** Host controller side endpoint structure. */
 typedef struct endpoint {
+	/** Part of linked list. */
+	link_t link;
+	/** USB address. */
 	usb_address_t address;
+	/** USB endpoint number. */
 	usb_endpoint_t endpoint;
+	/** Communication direction. */
 	usb_direction_t direction;
+	/** USB transfer type. */
 	usb_transfer_type_t transfer_type;
+	/** Communication speed. */
 	usb_speed_t speed;
+	/** Maximum size of data packets. */
 	size_t max_packet_size;
+	/** Necessary bandwidth. */
+	size_t bandwidth;
+	/** Value of the toggle bit. */
 	unsigned toggle:1;
+	/** True if there is a batch using this scheduled for this endpoint. */
+	volatile bool active;
+	/** Protects resources and active status changes. */
 	fibril_mutex_t guard;
+	/** Signals change of active status. */
 	fibril_condvar_t avail;
-	volatile bool active;
-	void (*destroy_hook)(struct endpoint *);
+	/** Optional device specific data. */
 	struct {
+		/** Device specific data. */
 		void *data;
+		/** Callback to get the value of toggle bit. */
 		int (*toggle_get)(void *);
+		/** Callback to set the value of toggle bit. */
 		void (*toggle_set)(void *, int);
 	} hc_data;
 } endpoint_t;
 
-endpoint_t * endpoint_get(usb_address_t address, usb_endpoint_t endpoint,
+endpoint_t * endpoint_create(usb_address_t address, usb_endpoint_t endpoint,
     usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed,
-    size_t max_packet_size);
-
+    size_t max_packet_size, size_t bw);
 void endpoint_destroy(endpoint_t *instance);
 
 void endpoint_set_hc_data(endpoint_t *instance,
-    void *data, void (*destroy_hook)(endpoint_t *),
-    int (*toggle_get)(void *), void (*toggle_set)(void *, int));
-
+    void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int));
 void endpoint_clear_hc_data(endpoint_t *instance);
 
 void endpoint_use(endpoint_t *instance);
-
 void endpoint_release(endpoint_t *instance);
 
 int endpoint_toggle_get(endpoint_t *instance);
-
 void endpoint_toggle_set(endpoint_t *instance, int toggle);
 
-void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target);
+/** list_get_instance wrapper.
+ * @param item Pointer to link member.
+ * @return Pointer to enpoint_t structure.
+ */
+static inline endpoint_t * endpoint_get_instance(link_t *item)
+{
+	return list_get_instance(item, endpoint_t, link);
+}
 #endif
 /**
Index: uspace/lib/usbhost/include/usb/host/hcd.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/hcd.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhost/include/usb/host/hcd.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -37,42 +37,65 @@
 
 #include <assert.h>
+#include <usbhc_iface.h>
+
 #include <usb/host/usb_device_manager.h>
 #include <usb/host/usb_endpoint_manager.h>
 #include <usb/host/usb_transfer_batch.h>
-#include <usbhc_iface.h>
 
 typedef struct hcd hcd_t;
 
+/** Generic host controller driver structure. */
 struct hcd {
+	/** Device manager storing handles and addresses. */
 	usb_device_manager_t dev_manager;
+	/** Endpoint manager. */
 	usb_endpoint_manager_t ep_manager;
+
+	/** Device specific driver data. */
 	void *private_data;
-
+	/** Transfer scheduling, implement in device driver. */
 	int (*schedule)(hcd_t *, usb_transfer_batch_t *);
+	/** Hook called upon registering new endpoint. */
 	int (*ep_add_hook)(hcd_t *, endpoint_t *);
+	/** Hook called upon removing of an endpoint. */
+	void (*ep_remove_hook)(hcd_t *, endpoint_t *);
 };
 /*----------------------------------------------------------------------------*/
-static inline int hcd_init(hcd_t *hcd, size_t bandwidth,
+/** Initialize hcd_t structure.
+ * 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, 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);
-	return usb_endpoint_manager_init(&hcd->ep_manager, bandwidth, bw_count);
+	usb_device_manager_init(&hcd->dev_manager, max_speed);
+	usb_endpoint_manager_init(&hcd->ep_manager, bandwidth, bw_count);
+	hcd->private_data = NULL;
+	hcd->schedule = NULL;
+	hcd->ep_add_hook = NULL;
+	hcd->ep_remove_hook = NULL;
 }
 /*----------------------------------------------------------------------------*/
-static inline void hcd_destroy(hcd_t *hcd)
-{
-	usb_endpoint_manager_destroy(&hcd->ep_manager);
-}
-/*----------------------------------------------------------------------------*/
-static inline void reset_ep_if_need(
-    hcd_t *hcd, usb_target_t target, const char* setup_data)
+/** Check registered endpoints and reset toggle bit if necessary.
+ * @param hcd hcd_t structure, non-null.
+ * @param target Control communication target.
+ * @param setup_data Setup packet of the control communication.
+ */
+static inline void reset_ep_if_need(hcd_t *hcd, usb_target_t target,
+    const char setup_data[8])
 {
 	assert(hcd);
-	usb_endpoint_manager_reset_if_need(
+	usb_endpoint_manager_reset_eps_if_need(
 	    &hcd->ep_manager, target, (const uint8_t *)setup_data);
 }
 /*----------------------------------------------------------------------------*/
-static inline hcd_t * fun_to_hcd(ddf_fun_t *fun)
+/** Data retrieve wrapper.
+ * @param fun ddf function, non-null.
+ * @return pointer cast to hcd_t*.
+ */
+static inline hcd_t * fun_to_hcd(const ddf_fun_t *fun)
 {
 	assert(fun);
Index: uspace/lib/usbhost/include/usb/host/usb_device_manager.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_device_manager.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhost/include/usb/host/usb_device_manager.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -49,39 +49,37 @@
 #define USB_ADDRESS_COUNT (USB11_ADDRESS_MAX + 1)
 
-/** Information about attached USB device. */
-struct usb_device_info {
-	usb_speed_t speed;
-	bool occupied;
-	devman_handle_t handle;
-};
-
 /** Host controller device manager.
- * You shall not access members directly but only using functions below.
+ * You shall not access members directly.
  */
 typedef struct {
-	struct usb_device_info devices[USB_ADDRESS_COUNT];
+	/** Information about attached USB devices. */
+	struct {
+		usb_speed_t speed;      /**< Device speed */
+		bool occupied;          /**< The address is in use. */
+		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 */
 	usb_address_t last_address;
 } 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);
 
-void 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);
 
-void usb_device_manager_release(usb_device_manager_t *instance,
+int usb_device_manager_release_address(usb_device_manager_t *instance,
     usb_address_t address);
 
-usb_address_t usb_device_manager_find(usb_device_manager_t *instance,
+usb_address_t usb_device_manager_find_address(usb_device_manager_t *instance,
     devman_handle_t handle);
 
-bool usb_device_manager_find_by_address(usb_device_manager_t *instance,
-    usb_address_t address, devman_handle_t *handle);
-
-usb_speed_t usb_device_manager_get_speed(usb_device_manager_t *instance,
-    usb_address_t address);
+int usb_device_manager_get_info_by_address(usb_device_manager_t *instance,
+    usb_address_t address, devman_handle_t *handle, usb_speed_t *speed);
 #endif
 /**
Index: uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -40,17 +40,26 @@
 #define LIBUSBHOST_HOST_USB_ENDPOINT_MANAGER_H
 
-#include <stdlib.h>
-#include <adt/hash_table.h>
+#include <adt/list.h>
 #include <fibril_synch.h>
 #include <usb/usb.h>
+
 #include <usb/host/endpoint.h>
 
-#define BANDWIDTH_TOTAL_USB11 12000000
+/** Bytes per second in FULL SPEED */
+#define BANDWIDTH_TOTAL_USB11 (12000000 / 8)
+/** 90% of total bandwidth is available for periodic transfers */
 #define BANDWIDTH_AVAILABLE_USB11 ((BANDWIDTH_TOTAL_USB11 / 10) * 9)
+/** 16 addresses per list */
+#define ENDPOINT_LIST_COUNT 8
 
+/** Endpoint management structure */
 typedef struct usb_endpoint_manager {
-	hash_table_t ep_table;
+	/** Store endpoint_t instances */
+	list_t endpoint_lists[ENDPOINT_LIST_COUNT];
+	/** Prevents races accessing lists */
 	fibril_mutex_t guard;
+	/** Size of the bandwidth pool */
 	size_t free_bw;
+	/** Use this function to count bw required by EP */
 	size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t);
 } usb_endpoint_manager_t;
@@ -63,40 +72,27 @@
     size_t (*bw_count)(usb_speed_t, usb_transfer_type_t, size_t, size_t));
 
-void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance);
+void usb_endpoint_manager_reset_eps_if_need(usb_endpoint_manager_t *instance,
+    usb_target_t target, const uint8_t data[8]);
 
-int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
-    endpoint_t *ep, size_t data_size);
-
-int usb_endpoint_manager_unregister_ep(usb_endpoint_manager_t *instance,
+int usb_endpoint_manager_register_ep(
+    usb_endpoint_manager_t *instance, endpoint_t *ep, size_t data_size);
+int usb_endpoint_manager_unregister_ep(
+    usb_endpoint_manager_t *instance, endpoint_t *ep);
+endpoint_t * usb_endpoint_manager_find_ep(usb_endpoint_manager_t *instance,
     usb_address_t address, usb_endpoint_t ep, usb_direction_t direction);
 
-endpoint_t * usb_endpoint_manager_get_ep(usb_endpoint_manager_t *instance,
-    usb_address_t address, usb_endpoint_t ep, usb_direction_t direction,
-    size_t *bw);
-
-void usb_endpoint_manager_reset_if_need(
-    usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data);
-
-/** Wrapper combining allocation and insertion */
-static inline int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
+int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
     usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
     usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size,
-    size_t data_size)
-{
-	endpoint_t *ep = endpoint_get(
-	    address, endpoint, direction, type, speed, max_packet_size);
-	if (!ep)
-		return ENOMEM;
+    size_t data_size, int (*callback)(endpoint_t *, void *), void *arg);
 
-	const int ret =
-	    usb_endpoint_manager_register_ep(instance, ep, data_size);
-	if (ret != EOK) {
-		endpoint_destroy(ep);
-	}
-	return ret;
-}
+int usb_endpoint_manager_remove_ep(usb_endpoint_manager_t *instance,
+    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/include/usb/host/usb_transfer_batch.h
===================================================================
--- uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -43,7 +43,6 @@
 #define USB_SETUP_PACKET_SIZE 8
 
-typedef struct usb_transfer_batch usb_transfer_batch_t;
 /** Structure stores additional data needed for communication with EP */
-struct usb_transfer_batch {
+typedef struct usb_transfer_batch {
 	/** Endpoint used for communication */
 	endpoint_t *ep;
@@ -77,5 +76,5 @@
 	/** Callback to properly remove driver data during destruction */
 	void (*private_data_dtor)(void *p_data);
-};
+} usb_transfer_batch_t;
 
 /** Printf formatting string for dumping usb_transfer_batch_t. */
@@ -93,5 +92,5 @@
 
 
-usb_transfer_batch_t * usb_transfer_batch_get(
+usb_transfer_batch_t * usb_transfer_batch_create(
     endpoint_t *ep,
     char *buffer,
@@ -105,36 +104,10 @@
     void (*private_data_dtor)(void *p_data)
 );
+void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance);
 
-void usb_transfer_batch_finish(usb_transfer_batch_t *instance,
+void usb_transfer_batch_finish(const usb_transfer_batch_t *instance,
     const void* data, size_t size);
-void usb_transfer_batch_call_in(usb_transfer_batch_t *instance);
-void usb_transfer_batch_call_out(usb_transfer_batch_t *instance);
-void usb_transfer_batch_dispose(usb_transfer_batch_t *instance);
-
-/** Helper function, calls callback and correctly destroys batch structure.
- *
- * @param[in] instance Batch structure to use.
- */
-static inline void usb_transfer_batch_call_in_and_dispose(
-    usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	usb_transfer_batch_call_in(instance);
-	usb_transfer_batch_dispose(instance);
-}
 /*----------------------------------------------------------------------------*/
-/** Helper function calls callback and correctly destroys batch structure.
- *
- * @param[in] instance Batch structure to use.
- */
-static inline void usb_transfer_batch_call_out_and_dispose(
-    usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	usb_transfer_batch_call_out(instance);
-	usb_transfer_batch_dispose(instance);
-}
-/*----------------------------------------------------------------------------*/
-/** Helper function, sets error value and finishes transfer.
+/** Override error value and finishes transfer.
  *
  * @param[in] instance Batch structure to use.
@@ -151,6 +124,6 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Helper function, determines batch direction absed on the present callbacks
- * @param[in] instance Batch structure to use.
+/** Determine batch direction based on the callbacks present
+ * @param[in] instance Batch structure to use, non-null.
  * @return USB_DIRECTION_IN, or USB_DIRECTION_OUT.
  */
Index: uspace/lib/usbhost/src/endpoint.c
===================================================================
--- uspace/lib/usbhost/src/endpoint.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhost/src/endpoint.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -26,6 +26,5 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
-/** @addtogroup drvusbuhcihc
+/** @addtogroup libusbhost
  * @{
  */
@@ -39,7 +38,17 @@
 #include <usb/host/endpoint.h>
 
-endpoint_t * endpoint_get(usb_address_t address, usb_endpoint_t endpoint,
+/** Allocate ad initialize endpoint_t structure.
+ * @param address USB address.
+ * @param endpoint USB endpoint number.
+ * @param direction Communication direction.
+ * @param type USB transfer type.
+ * @param speed Communication speed.
+ * @param max_packet_size Maximum size of data packets.
+ * @param bw Required bandwidth.
+ * @return Pointer to initialized endpoint_t structure, NULL on failure.
+ */
+endpoint_t * endpoint_create(usb_address_t address, usb_endpoint_t endpoint,
     usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed,
-    size_t max_packet_size)
+    size_t max_packet_size, size_t bw)
 {
 	endpoint_t *instance = malloc(sizeof(endpoint_t));
@@ -51,48 +60,63 @@
 		instance->speed = speed;
 		instance->max_packet_size = max_packet_size;
+		instance->bandwidth = bw;
 		instance->toggle = 0;
 		instance->active = false;
-		instance->destroy_hook = NULL;
 		instance->hc_data.data = NULL;
 		instance->hc_data.toggle_get = NULL;
 		instance->hc_data.toggle_set = NULL;
+		link_initialize(&instance->link);
 		fibril_mutex_initialize(&instance->guard);
 		fibril_condvar_initialize(&instance->avail);
-		endpoint_clear_hc_data(instance);
 	}
 	return instance;
 }
 /*----------------------------------------------------------------------------*/
+/** Properly dispose of endpoint_t structure.
+ * @param instance endpoint_t structure.
+ */
 void endpoint_destroy(endpoint_t *instance)
 {
 	assert(instance);
+	//TODO: Do something about waiting fibrils.
 	assert(!instance->active);
-	if (instance->hc_data.data) {
-		assert(instance->destroy_hook);
-		instance->destroy_hook(instance);
-	}
+	assert(instance->hc_data.data == NULL);
 	free(instance);
 }
 /*----------------------------------------------------------------------------*/
+/** Set device specific data and hooks.
+ * @param instance endpoint_t structure.
+ * @param data device specific data.
+ * @param toggle_get Hook to call when retrieving value of toggle bit.
+ * @param toggle_set Hook to call when setting the value of toggle bit.
+ */
 void endpoint_set_hc_data(endpoint_t *instance,
-    void *data, void (*destroy_hook)(endpoint_t *),
-    int (*toggle_get)(void *), void (*toggle_set)(void *, int))
+    void *data, int (*toggle_get)(void *), void (*toggle_set)(void *, int))
 {
 	assert(instance);
-	instance->destroy_hook = destroy_hook;
+	fibril_mutex_lock(&instance->guard);
 	instance->hc_data.data = data;
 	instance->hc_data.toggle_get = toggle_get;
 	instance->hc_data.toggle_set = toggle_set;
+	fibril_mutex_unlock(&instance->guard);
 }
 /*----------------------------------------------------------------------------*/
+/** Clear device specific data and hooks.
+ * @param instance endpoint_t structure.
+ * @note This function does not free memory pointed to by data pointer.
+ */
 void endpoint_clear_hc_data(endpoint_t *instance)
 {
 	assert(instance);
-	instance->destroy_hook = NULL;
+	fibril_mutex_lock(&instance->guard);
 	instance->hc_data.data = NULL;
 	instance->hc_data.toggle_get = NULL;
 	instance->hc_data.toggle_set = NULL;
+	fibril_mutex_unlock(&instance->guard);
 }
 /*----------------------------------------------------------------------------*/
+/** Mark the endpoint as active and block access for further fibrils.
+ * @param instance endpoint_t structure.
+ */
 void endpoint_use(endpoint_t *instance)
 {
@@ -105,4 +129,7 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Mark the endpoint as inactive and allow access for further fibrils.
+ * @param instance endpoint_t structure.
+ */
 void endpoint_release(endpoint_t *instance)
 {
@@ -114,28 +141,33 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Get the value of toggle bit.
+ * @param instance endpoint_t structure.
+ * @note Will use provided hook.
+ */
 int endpoint_toggle_get(endpoint_t *instance)
 {
 	assert(instance);
+	fibril_mutex_lock(&instance->guard);
 	if (instance->hc_data.toggle_get)
 		instance->toggle =
 		    instance->hc_data.toggle_get(instance->hc_data.data);
-	return (int)instance->toggle;
+	const int ret = instance->toggle;
+	fibril_mutex_unlock(&instance->guard);
+	return ret;
 }
 /*----------------------------------------------------------------------------*/
+/** Set the value of toggle bit.
+ * @param instance endpoint_t structure.
+ * @note Will use provided hook.
+ */
 void endpoint_toggle_set(endpoint_t *instance, int toggle)
 {
 	assert(instance);
 	assert(toggle == 0 || toggle == 1);
+	fibril_mutex_lock(&instance->guard);
+	instance->toggle = toggle;
 	if (instance->hc_data.toggle_set)
 		instance->hc_data.toggle_set(instance->hc_data.data, toggle);
-	instance->toggle = toggle;
-}
-/*----------------------------------------------------------------------------*/
-void endpoint_toggle_reset_filtered(endpoint_t *instance, usb_target_t target)
-{
-	assert(instance);
-	if (instance->address == target.address &&
-	    (instance->endpoint == target.endpoint || target.endpoint == 0))
-		endpoint_toggle_set(instance, 0);
+	fibril_mutex_unlock(&instance->guard);
 }
 /**
Index: uspace/lib/usbhost/src/iface.c
===================================================================
--- uspace/lib/usbhost/src/iface.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhost/src/iface.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -49,9 +49,6 @@
 	assert(hcd);
 
-	int ret;
-
-	size_t res_bw;
-	endpoint_t *ep = usb_endpoint_manager_get_ep(&hcd->ep_manager,
-	    target.address, target.endpoint, direction, &res_bw);
+	endpoint_t *ep = usb_endpoint_manager_find_ep(&hcd->ep_manager,
+	    target.address, target.endpoint, direction);
 	if (ep == NULL) {
 		usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
@@ -65,8 +62,9 @@
 	const size_t bw = bandwidth_count_usb11(
 	    ep->speed, ep->transfer_type, size, ep->max_packet_size);
-	if (res_bw < bw) {
+	/* Check if we have enough bandwidth reserved */
+	if (ep->bandwidth < bw) {
 		usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
 		    "but only %zu is reserved.\n",
-		    target.address, target.endpoint, name, bw, res_bw);
+		    ep->address, ep->endpoint, name, bw, ep->bandwidth);
 		return ENOSPC;
 	}
@@ -78,5 +76,5 @@
 	/* No private data and no private data dtor */
 	usb_transfer_batch_t *batch =
-	    usb_transfer_batch_get(ep, data, size, setup_data,
+	    usb_transfer_batch_create(ep, data, size, setup_data,
 	    in, out, arg, fun, NULL, NULL);
 	if (!batch) {
@@ -84,9 +82,39 @@
 	}
 
-	ret = hcd->schedule(hcd, batch);
+	const int ret = hcd->schedule(hcd, batch);
 	if (ret != EOK)
-		usb_transfer_batch_dispose(batch);
+		usb_transfer_batch_destroy(batch);
 
 	return ret;
+}
+/*----------------------------------------------------------------------------*/
+static int register_helper(endpoint_t *ep, void *arg)
+{
+	hcd_t *hcd = arg;
+	assert(ep);
+	assert(hcd);
+	if (hcd->ep_add_hook)
+		return hcd->ep_add_hook(hcd, ep);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+static void unregister_helper(endpoint_t *ep, void *arg)
+{
+	hcd_t *hcd = arg;
+	assert(ep);
+	assert(hcd);
+	if (hcd->ep_remove_hook)
+		hcd->ep_remove_hook(hcd, ep);
+}
+/*----------------------------------------------------------------------------*/
+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);
 }
 /*----------------------------------------------------------------------------*/
@@ -99,5 +127,5 @@
  */
 static int request_address(
-    ddf_fun_t *fun, usb_speed_t speed, usb_address_t *address)
+    ddf_fun_t *fun, usb_address_t *address, bool strict, usb_speed_t speed)
 {
 	assert(fun);
@@ -106,11 +134,8 @@
 	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;
+	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);
 }
 /*----------------------------------------------------------------------------*/
@@ -130,6 +155,6 @@
 
 	usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
-	usb_device_manager_bind(&hcd->dev_manager, address, handle);
-	return EOK;
+	return usb_device_manager_bind_address(
+	    &hcd->dev_manager, address, handle);
 }
 /*----------------------------------------------------------------------------*/
@@ -147,7 +172,6 @@
 	hcd_t *hcd = fun_to_hcd(fun);
 	assert(hcd);
-	const bool found =
-	    usb_device_manager_find_by_address(&hcd->dev_manager, address, handle);
-	return found ? EOK : ENOENT;
+	return usb_device_manager_get_info_by_address(
+	    &hcd->dev_manager, address, handle, NULL);
 }
 /*----------------------------------------------------------------------------*/
@@ -164,11 +188,12 @@
 	assert(hcd);
 	usb_log_debug("Address release %d.\n", address);
-	usb_device_manager_release(&hcd->dev_manager, 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)
@@ -178,8 +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. */
-	const usb_speed_t speed = (address == 0) ? ep_speed :
-	    usb_device_manager_get_speed(&hcd->dev_manager, 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",
@@ -188,23 +215,7 @@
 	    max_packet_size, interval);
 
-	endpoint_t *ep = endpoint_get(
-	    address, endpoint, direction, transfer_type, speed, max_packet_size);
-	if (!ep)
-		return ENOMEM;
-	int ret = EOK;
-
-	if (hcd->ep_add_hook) {
-		ret = hcd->ep_add_hook(hcd, ep);
-	}
-	if (ret != EOK) {
-		endpoint_destroy(ep);
-		return ret;
-	}
-
-	ret = usb_endpoint_manager_register_ep(&hcd->ep_manager, ep, size);
-	if (ret != EOK) {
-		endpoint_destroy(ep);
-	}
-	return ret;
+	return usb_endpoint_manager_add_ep(&hcd->ep_manager, address, endpoint,
+	    direction, transfer_type, speed, max_packet_size, size,
+	    register_helper, hcd);
 }
 /*----------------------------------------------------------------------------*/
@@ -218,6 +229,6 @@
 	usb_log_debug("Unregister endpoint %d:%d %s.\n",
 	    address, endpoint, usb_str_direction(direction));
-	return usb_endpoint_manager_unregister_ep(&hcd->ep_manager, address,
-	    endpoint, direction);
+	return usb_endpoint_manager_remove_ep(&hcd->ep_manager, address,
+	    endpoint, direction, unregister_helper, hcd);
 }
 /*----------------------------------------------------------------------------*/
@@ -241,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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhost/src/usb_device_manager.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -38,59 +38,91 @@
 #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)
-{
-	assert(instance);
-	unsigned i = 0;
-	for (; i < USB_ADDRESS_COUNT; ++i) {
+void usb_device_manager_init(
+    usb_device_manager_t *instance, usb_speed_t max_speed)
+{
+	assert(instance);
+	for (unsigned i = 0; i < USB_ADDRESS_COUNT; ++i) {
 		instance->devices[i].occupied = false;
 		instance->devices[i].handle = 0;
 		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;
-		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);
-
-	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;
 }
 /*----------------------------------------------------------------------------*/
@@ -100,17 +132,28 @@
  * @param[in] address Device address
  * @param[in] handle Devman handle of the device.
- */
-void usb_device_manager_bind(usb_device_manager_t *instance,
+ * @return Error code.
+ */
+int usb_device_manager_bind_address(usb_device_manager_t *instance,
     usb_address_t address, devman_handle_t handle)
 {
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-
-	assert(address > 0);
-	assert(address <= USB11_ADDRESS_MAX);
-	assert(instance->devices[address].occupied);
-
+	if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) {
+		return EINVAL;
+	}
+	assert(instance);
+
+	fibril_mutex_lock(&instance->guard);
+	/* Not reserved */
+	if (!instance->devices[address].occupied) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOENT;
+	}
+	/* Already bound */
+	if (instance->devices[address].handle != 0) {
+		fibril_mutex_unlock(&instance->guard);
+		return EEXISTS;
+	}
 	instance->devices[address].handle = handle;
 	fibril_mutex_unlock(&instance->guard);
+	return EOK;
 }
 /*----------------------------------------------------------------------------*/
@@ -119,17 +162,24 @@
  * @param[in] instance Device manager structure to use.
  * @param[in] address Device address
- */
-void usb_device_manager_release(
+ * @return Error code.
+ */
+int usb_device_manager_release_address(
     usb_device_manager_t *instance, usb_address_t address)
 {
-	assert(instance);
-	assert(address > 0);
-	assert(address <= USB11_ADDRESS_MAX);
-
-	fibril_mutex_lock(&instance->guard);
-	assert(instance->devices[address].occupied);
+	if ((address < 0) || (address >= USB_ADDRESS_COUNT)) {
+		return EINVAL;
+	}
+	assert(instance);
+
+	fibril_mutex_lock(&instance->guard);
+	if (!instance->devices[address].occupied) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOENT;
+	}
 
 	instance->devices[address].occupied = false;
-	fibril_mutex_unlock(&instance->guard);
+	instance->devices[address].handle = 0;
+	fibril_mutex_unlock(&instance->guard);
+	return EOK;
 }
 /*----------------------------------------------------------------------------*/
@@ -140,11 +190,11 @@
  * @return USB Address, or error code.
  */
-usb_address_t usb_device_manager_find(
+usb_address_t usb_device_manager_find_address(
     usb_device_manager_t *instance, devman_handle_t handle)
 {
 	assert(instance);
 	fibril_mutex_lock(&instance->guard);
-	usb_address_t address = 1;
-	while (address <= USB11_ADDRESS_MAX) {
+	for (usb_address_t address = 1; address <= USB11_ADDRESS_MAX; ++address)
+	{
 		if (instance->devices[address].handle == handle) {
 			assert(instance->devices[address].occupied);
@@ -152,30 +202,30 @@
 			return address;
 		}
-		++address;
 	}
 	fibril_mutex_unlock(&instance->guard);
 	return ENOENT;
 }
-
-/** Find devman handle assigned to USB address.
- * Intentionally refuse to find handle of default address.
+/*----------------------------------------------------------------------------*/
+/** Find devman handle and speed assigned to USB address.
+ * Intentionally refuse to work on default address.
  *
  * @param[in] instance Device manager structure to use.
  * @param[in] address Address the caller wants to find.
  * @param[out] handle Where to store found handle.
- * @return Whether such address is currently occupied.
- */
-bool usb_device_manager_find_by_address(usb_device_manager_t *instance,
-    usb_address_t address, devman_handle_t *handle)
-{
-	assert(instance);
-	fibril_mutex_lock(&instance->guard);
-	if ((address <= 0) || (address >= USB_ADDRESS_COUNT)) {
-		fibril_mutex_unlock(&instance->guard);
-		return false;
-	}
+ * @param[out] speed Assigned speed.
+ * @return Error code.
+ */
+int usb_device_manager_get_info_by_address(usb_device_manager_t *instance,
+    usb_address_t address, devman_handle_t *handle, usb_speed_t *speed)
+{
+	assert(instance);
+	if ((address < 0) || (address >= USB_ADDRESS_COUNT)) {
+		return EINVAL;
+	}
+
+	fibril_mutex_lock(&instance->guard);
 	if (!instance->devices[address].occupied) {
 		fibril_mutex_unlock(&instance->guard);
-		return false;
+		return ENOENT;
 	}
 
@@ -183,24 +233,10 @@
 		*handle = instance->devices[address].handle;
 	}
-
-	fibril_mutex_unlock(&instance->guard);
-	return true;
-}
-
-/*----------------------------------------------------------------------------*/
-/** Get speed associated with the address
- *
- * @param[in] instance Device manager structure to use.
- * @param[in] address Address of the device.
- * @return USB speed.
- */
-usb_speed_t usb_device_manager_get_speed(
-    usb_device_manager_t *instance, usb_address_t address)
-{
-	assert(instance);
-	assert(address >= 0);
-	assert(address <= USB11_ADDRESS_MAX);
-
-	return instance->devices[address].speed;
+	if (speed != NULL) {
+		*speed = instance->devices[address].speed;
+	}
+
+	fibril_mutex_unlock(&instance->guard);
+	return EOK;
 }
 /**
Index: uspace/lib/usbhost/src/usb_endpoint_manager.c
===================================================================
--- uspace/lib/usbhost/src/usb_endpoint_manager.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhost/src/usb_endpoint_manager.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -34,65 +34,68 @@
 #include <usb/host/usb_endpoint_manager.h>
 
-#define BUCKET_COUNT 7
-
-#define MAX_KEYS (3)
-typedef struct {
-	link_t link;
-	size_t bw;
-	endpoint_t *ep;
-} node_t;
-/*----------------------------------------------------------------------------*/
-static hash_index_t node_hash(unsigned long key[])
-{
-	/* USB endpoints use 4 bits, thus ((key[0] << 4) | key[1])
-	 * produces unique value for every address.endpoint pair */
-	return ((key[0] << 4) | key[1]) % BUCKET_COUNT;
-}
-/*----------------------------------------------------------------------------*/
-static int node_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	assert(item);
-	node_t *node = hash_table_get_instance(item, node_t, link);
-	assert(node);
-	assert(node->ep);
-	bool match = true;
-	switch (keys) {
-	case 3:
-		match = match &&
-		    ((key[2] == node->ep->direction)
-		    || (node->ep->direction == USB_DIRECTION_BOTH));
-	case 2:
-		match = match && (key[1] == (unsigned long)node->ep->endpoint);
-	case 1:
-		match = match && (key[0] == (unsigned long)node->ep->address);
-		break;
-	default:
-		match = false;
-	}
-	return match;
-}
-/*----------------------------------------------------------------------------*/
-static void node_remove(link_t *item)
-{
-	assert(item);
-	node_t *node = hash_table_get_instance(item, node_t, link);
-	endpoint_destroy(node->ep);
-	free(node);
-}
-/*----------------------------------------------------------------------------*/
-static void node_toggle_reset_filtered(link_t *item, void *arg)
-{
-	assert(item);
-	node_t *node = hash_table_get_instance(item, node_t, link);
-	usb_target_t *target = arg;
-	endpoint_toggle_reset_filtered(node->ep, *target);
-}
-/*----------------------------------------------------------------------------*/
-static hash_table_operations_t op = {
-	.hash = node_hash,
-	.compare = node_compare,
-	.remove_callback = node_remove,
-};
-/*----------------------------------------------------------------------------*/
+/** Endpoint compare helper function.
+ *
+ * USB_DIRECTION_BOTH matches both IN and OUT.
+ * @param ep Endpoint to compare, non-null.
+ * @param address Tested address.
+ * @param endpoint Tested endpoint number.
+ * @param direction Tested direction.
+ * @return True if ep can be used to communicate with given device,
+ * false otherwise.
+ */
+static inline bool ep_match(const endpoint_t *ep,
+    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	assert(ep);
+	return
+	    ((direction == ep->direction)
+	        || (ep->direction == USB_DIRECTION_BOTH)
+	        || (direction == USB_DIRECTION_BOTH))
+	    && (endpoint == ep->endpoint)
+	    && (address == ep->address);
+}
+/*----------------------------------------------------------------------------*/
+/** Get list that holds endpints for given address.
+ * @param instance usb_endpoint_manager structure, non-null.
+ * @param addr USB address, must be >= 0.
+ * @return Pointer to the appropriate list.
+ */
+static list_t * get_list(usb_endpoint_manager_t *instance, usb_address_t addr)
+{
+	assert(instance);
+	assert(addr >= 0);
+	return &instance->endpoint_lists[addr % ENDPOINT_LIST_COUNT];
+}
+/*----------------------------------------------------------------------------*/
+/** Internal search function, works on locked structure.
+ * @param instance usb_endpoint_manager structure, non-null.
+ * @param address USB address, must be valid.
+ * @param endpoint USB endpoint number.
+ * @param direction Communication direction.
+ * @return Pointer to endpoint_t structure representing given communication
+ * target, NULL if there is no such endpoint registered.
+ */
+static endpoint_t * find_locked(usb_endpoint_manager_t *instance,
+    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	assert(instance);
+	assert(fibril_mutex_is_locked(&instance->guard));
+	if (address < 0)
+		return NULL;
+	list_foreach(*get_list(instance, address), iterator) {
+		endpoint_t *ep = endpoint_get_instance(iterator);
+		if (ep_match(ep, address, endpoint, direction))
+			return ep;
+	}
+	return NULL;
+}
+/*----------------------------------------------------------------------------*/
+/** Calculate bandwidth that needs to be reserved for communication with EP.
+ * Calculation follows USB 1.1 specification.
+ * @param speed Device's speed.
+ * @param type Type of the transfer.
+ * @param size Number of byte to transfer.
+ * @param max_packet_size Maximum bytes in one packet.
+ */
 size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type,
     size_t size, size_t max_packet_size)
@@ -106,7 +109,6 @@
 	const unsigned packet_count =
 	    (size + max_packet_size - 1) / max_packet_size;
-	/* TODO: It may be that ISO and INT transfers use only one data packet
-	 * per transaction, but I did not find text in UB spec that confirms
-	 * this */
+	/* TODO: It may be that ISO and INT transfers use only one packet per
+	 * transaction, but I did not find text in USB spec to confirm this */
 	/* NOTE: All data packets will be considered to be max_packet_size */
 	switch (speed)
@@ -137,4 +139,13 @@
 }
 /*----------------------------------------------------------------------------*/
+/** Initialize to default state.
+ * You need to provide valid bw_count function if you plan to use
+ * add_endpoint/remove_endpoint pair.
+ *
+ * @param instance usb_endpoint_manager structure, non-null.
+ * @param available_bandwidth Size of the bandwidth pool.
+ * @param bw_count function to use to calculate endpoint bw requirements.
+ * @return Error code.
+ */
 int usb_endpoint_manager_init(usb_endpoint_manager_t *instance,
     size_t available_bandwidth,
@@ -145,113 +156,20 @@
 	instance->free_bw = available_bandwidth;
 	instance->bw_count = bw_count;
-	const bool ht =
-	    hash_table_create(&instance->ep_table, BUCKET_COUNT, MAX_KEYS, &op);
-	return ht ? EOK : ENOMEM;
-}
-/*----------------------------------------------------------------------------*/
-void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance)
-{
-	hash_table_destroy(&instance->ep_table);
-}
-/*----------------------------------------------------------------------------*/
-int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
-    endpoint_t *ep, size_t data_size)
-{
-	assert(instance);
-	assert(instance->bw_count);
-	assert(ep);
-	const size_t bw = instance->bw_count(ep->speed, ep->transfer_type,
-	    data_size, ep->max_packet_size);
-
-	fibril_mutex_lock(&instance->guard);
-
-	if (bw > instance->free_bw) {
-		fibril_mutex_unlock(&instance->guard);
-		return ENOSPC;
-	}
-
-	unsigned long key[MAX_KEYS] =
-	    {ep->address, ep->endpoint, ep->direction};
-
-	const link_t *item =
-	    hash_table_find(&instance->ep_table, key);
-	if (item != NULL) {
-		fibril_mutex_unlock(&instance->guard);
-		return EEXISTS;
-	}
-
-	node_t *node = malloc(sizeof(node_t));
-	if (node == NULL) {
-		fibril_mutex_unlock(&instance->guard);
-		return ENOMEM;
-	}
-
-	node->bw = bw;
-	node->ep = ep;
-	link_initialize(&node->link);
-
-	hash_table_insert(&instance->ep_table, key, &node->link);
-	instance->free_bw -= bw;
-	fibril_mutex_unlock(&instance->guard);
+	for (unsigned i = 0; i < ENDPOINT_LIST_COUNT; ++i) {
+		list_initialize(&instance->endpoint_lists[i]);
+	}
 	return EOK;
 }
 /*----------------------------------------------------------------------------*/
-int usb_endpoint_manager_unregister_ep(usb_endpoint_manager_t *instance,
-    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
-{
-	assert(instance);
-	unsigned long key[MAX_KEYS] = {address, endpoint, direction};
-
-	fibril_mutex_lock(&instance->guard);
-	link_t *item = hash_table_find(&instance->ep_table, key);
-	if (item == NULL) {
-		fibril_mutex_unlock(&instance->guard);
-		return EINVAL;
-	}
-
-	node_t *node = hash_table_get_instance(item, node_t, link);
-	if (node->ep->active) {
-		fibril_mutex_unlock(&instance->guard);
-		return EBUSY;
-	}
-
-	instance->free_bw += node->bw;
-	hash_table_remove(&instance->ep_table, key, MAX_KEYS);
-
-	fibril_mutex_unlock(&instance->guard);
-	return EOK;
-}
-/*----------------------------------------------------------------------------*/
-endpoint_t * usb_endpoint_manager_get_ep(usb_endpoint_manager_t *instance,
-    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
-    size_t *bw)
-{
-	assert(instance);
-	unsigned long key[MAX_KEYS] = {address, endpoint, direction};
-
-	fibril_mutex_lock(&instance->guard);
-	const link_t *item = hash_table_find(&instance->ep_table, key);
-	if (item == NULL) {
-		fibril_mutex_unlock(&instance->guard);
-		return NULL;
-	}
-	const node_t *node = hash_table_get_instance(item, node_t, link);
-	if (bw)
-		*bw = node->bw;
-
-	fibril_mutex_unlock(&instance->guard);
-	return node->ep;
-}
-/*----------------------------------------------------------------------------*/
 /** Check setup packet data for signs of toggle reset.
  *
- * @param[in] instance Device keeper structure to use.
+ * @param[in] instance usb_endpoint_manager structure, non-null.
  * @param[in] target Device to receive setup packet.
  * @param[in] data Setup packet data.
  *
- * Really ugly one.
- */
-void usb_endpoint_manager_reset_if_need(
-    usb_endpoint_manager_t *instance, usb_target_t target, const uint8_t *data)
+ * Really ugly one. Resets toggle bit on all endpoints that need it.
+ */
+void usb_endpoint_manager_reset_eps_if_need(usb_endpoint_manager_t *instance,
+    usb_target_t target, const uint8_t data[8])
 {
 	assert(instance);
@@ -267,10 +185,13 @@
 		/* Recipient is endpoint, value is zero (ENDPOINT_STALL) */
 		if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
+			fibril_mutex_lock(&instance->guard);
 			/* endpoint number is < 16, thus first byte is enough */
-			usb_target_t reset_target =
-			    { .address = target.address, data[4] };
-			fibril_mutex_lock(&instance->guard);
-			hash_table_apply(&instance->ep_table,
-			    node_toggle_reset_filtered, &reset_target);
+			list_foreach(*get_list(instance, target.address), it) {
+				endpoint_t *ep = endpoint_get_instance(it);
+				if ((ep->address == target.address)
+				    && (ep->endpoint = data[4])) {
+					endpoint_toggle_set(ep,0);
+				}
+			}
 			fibril_mutex_unlock(&instance->guard);
 		}
@@ -279,11 +200,15 @@
 	case 0x9: /* Set Configuration */
 	case 0x11: /* Set Interface */
-		/* Recipient must be device */
+		/* Recipient must be device, this resets all endpoints,
+		 * In fact there should be no endpoints but EP 0 registered
+		 * as different interfaces use different endpoints. */
 		if ((data[0] & 0xf) == 0) {
-			usb_target_t reset_target =
-			    { .address = target.address, 0 };
 			fibril_mutex_lock(&instance->guard);
-			hash_table_apply(&instance->ep_table,
-			    node_toggle_reset_filtered, &reset_target);
+			list_foreach(*get_list(instance, target.address), it) {
+				endpoint_t *ep = endpoint_get_instance(it);
+				if (ep->address == target.address) {
+					endpoint_toggle_set(ep,0);
+				}
+			}
 			fibril_mutex_unlock(&instance->guard);
 		}
@@ -291,2 +216,189 @@
 	}
 }
+/*----------------------------------------------------------------------------*/
+/** Register endpoint structure.
+ * Checks for duplicates.
+ * @param instance usb_endpoint_manager, non-null.
+ * @param ep endpoint_t to register.
+ * @param data_size Size of data to transfer.
+ * @return Error code.
+ */
+int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
+    endpoint_t *ep, size_t data_size)
+{
+	assert(instance);
+	if (ep == NULL || ep->address < 0)
+		return EINVAL;
+
+	fibril_mutex_lock(&instance->guard);
+	/* Check for available bandwidth */
+	if (ep->bandwidth > instance->free_bw) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOSPC;
+	}
+
+	/* Check for existence */
+	const endpoint_t *endpoint =
+	    find_locked(instance, ep->address, ep->endpoint, ep->direction);
+	if (endpoint != NULL) {
+		fibril_mutex_unlock(&instance->guard);
+		return EEXISTS;
+	}
+	list_append(&ep->link, get_list(instance, ep->address));
+
+	instance->free_bw -= ep->bandwidth;
+	fibril_mutex_unlock(&instance->guard);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Unregister endpoint structure.
+ * Checks for duplicates.
+ * @param instance usb_endpoint_manager, non-null.
+ * @param ep endpoint_t to unregister.
+ * @return Error code.
+ */
+int usb_endpoint_manager_unregister_ep(
+    usb_endpoint_manager_t *instance, endpoint_t *ep)
+{
+	assert(instance);
+	if (ep == NULL || ep->address < 0)
+		return EINVAL;
+
+	fibril_mutex_lock(&instance->guard);
+	if (!list_member(&ep->link, get_list(instance, ep->address))) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOENT;
+	}
+	list_remove(&ep->link);
+	instance->free_bw += ep->bandwidth;
+	fibril_mutex_unlock(&instance->guard);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Find endpoint_t representing the given communication route.
+ * @param instance usb_endpoint_manager, non-null.
+ * @param address
+ */
+endpoint_t * usb_endpoint_manager_find_ep(usb_endpoint_manager_t *instance,
+    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
+{
+	assert(instance);
+
+	fibril_mutex_lock(&instance->guard);
+	endpoint_t *ep = find_locked(instance, address, endpoint, direction);
+	fibril_mutex_unlock(&instance->guard);
+	return ep;
+}
+/*----------------------------------------------------------------------------*/
+/** Create and register new endpoint_t structure.
+ * @param instance usb_endpoint_manager structure, non-null.
+ * @param address USB address.
+ * @param endpoint USB endpoint number.
+ * @param direction Communication direction.
+ * @param type USB transfer type.
+ * @param speed USB Communication speed.
+ * @param max_packet_size Maximum size of data packets.
+ * @param data_size Expected communication size.
+ * @param callback function to call just after registering.
+ * @param arg Argument to pass to the callback function.
+ * @return Error code.
+ */
+int usb_endpoint_manager_add_ep(usb_endpoint_manager_t *instance,
+    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
+    usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size,
+    size_t data_size, int (*callback)(endpoint_t *, void *), void *arg)
+{
+	assert(instance);
+	if (instance->bw_count == NULL)
+		return ENOTSUP;
+	if (address < 0)
+		return EINVAL;
+
+	const size_t bw =
+	    instance->bw_count(speed, type, data_size, max_packet_size);
+
+	fibril_mutex_lock(&instance->guard);
+	/* Check for available bandwidth */
+	if (bw > instance->free_bw) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOSPC;
+	}
+
+	/* Check for existence */
+	endpoint_t *ep = find_locked(instance, address, endpoint, direction);
+	if (ep != NULL) {
+		fibril_mutex_unlock(&instance->guard);
+		return EEXISTS;
+	}
+
+	ep = endpoint_create(
+	    address, endpoint, direction, type, speed, max_packet_size, bw);
+	if (!ep) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOMEM;
+	}
+
+	if (callback) {
+		const int ret = callback(ep, arg);
+		if (ret != EOK) {
+			fibril_mutex_unlock(&instance->guard);
+			endpoint_destroy(ep);
+			return ret;
+		}
+	}
+	list_append(&ep->link, get_list(instance, ep->address));
+
+	instance->free_bw -= ep->bandwidth;
+	fibril_mutex_unlock(&instance->guard);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+/** Unregister and destroy endpoint_t structure representing given route.
+ * @param instance usb_endpoint_manager structure, non-null.
+ * @param address USB address.
+ * @param endpoint USB endpoint number.
+ * @param direction Communication direction.
+ * @param callback Function to call after unregister, before destruction.
+ * @arg Argument to pass to the callback function.
+ * @return Error code.
+ */
+int usb_endpoint_manager_remove_ep(usb_endpoint_manager_t *instance,
+    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
+    void (*callback)(endpoint_t *, void *), void *arg)
+{
+	assert(instance);
+	fibril_mutex_lock(&instance->guard);
+	endpoint_t *ep = find_locked(instance, address, endpoint, direction);
+	if (ep != NULL) {
+		list_remove(&ep->link);
+		instance->free_bw += ep->bandwidth;
+	}
+	fibril_mutex_unlock(&instance->guard);
+	if (ep == NULL)
+		return ENOENT;
+
+	if (callback) {
+		callback(ep, arg);
+	}
+	endpoint_destroy(ep);
+	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/lib/usbhost/src/usb_transfer_batch.c
===================================================================
--- uspace/lib/usbhost/src/usb_transfer_batch.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/lib/usbhost/src/usb_transfer_batch.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -37,8 +37,21 @@
 #include <usb/usb.h>
 #include <usb/debug.h>
+
 #include <usb/host/usb_transfer_batch.h>
 #include <usb/host/hcd.h>
 
-usb_transfer_batch_t * usb_transfer_batch_get(
+/** Allocate and initialize usb_transfer_batch structure.
+ * @param ep endpoint used by the transfer batch.
+ * @param buffer data to send/recieve.
+ * @param buffer_size Size of data buffer.
+ * @param setup_buffer Data to send in SETUP stage of control transfer.
+ * @param func_in callback on IN transfer completion.
+ * @param func_out callback on OUT transfer completion.
+ * @param arg Argument to pass to the callback function.
+ * @param private_data driver specific per batch data.
+ * @param private_data_dtor Function to properly destroy private_data.
+ * @return Pointer to valid usb_transfer_batch_t structure, NULL on failure.
+ */
+usb_transfer_batch_t * usb_transfer_batch_create(
     endpoint_t *ep,
     char *buffer,
@@ -53,4 +66,9 @@
     )
 {
+	if (func_in == NULL && func_out == NULL)
+		return NULL;
+	if (func_in != NULL && func_out != NULL)
+		return NULL;
+
 	usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
 	if (instance) {
@@ -78,78 +96,9 @@
 }
 /*----------------------------------------------------------------------------*/
-/** Mark batch as finished and run callback.
- *
- * @param[in] instance Batch structure to use.
- * @param[in] data Data to copy to the output buffer.
- * @param[in] size Size of @p data.
- */
-void usb_transfer_batch_finish(
-    usb_transfer_batch_t *instance, const void *data, size_t size)
-{
-	assert(instance);
-	assert(instance->ep);
-	/* we care about the data and there are some to copy */
-        if (instance->ep->direction != USB_DIRECTION_OUT
-	    && data) {
-		const size_t min_size =
-		    size < instance->buffer_size ? size : instance->buffer_size;
-                memcpy(instance->buffer, data, min_size);
-        }
-        if (instance->callback_out)
-                usb_transfer_batch_call_out(instance);
-        if (instance->callback_in)
-                usb_transfer_batch_call_in(instance);
-
-}
-/*----------------------------------------------------------------------------*/
-/** Prepare data, get error status and call callback in.
- *
- * @param[in] instance Batch structure to use.
- * Copies data from transport buffer, and calls callback with appropriate
- * parameters.
- */
-void usb_transfer_batch_call_in(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	assert(instance->callback_in);
-
-	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed (%zuB): %s.\n",
-	    instance, USB_TRANSFER_BATCH_ARGS(*instance),
-	    instance->transfered_size, str_error(instance->error));
-
-	instance->callback_in(instance->fun, instance->error,
-	    instance->transfered_size, instance->arg);
-}
-/*----------------------------------------------------------------------------*/
-/** Get error status and call callback out.
- *
- * @param[in] instance Batch structure to use.
- */
-void usb_transfer_batch_call_out(usb_transfer_batch_t *instance)
-{
-	assert(instance);
-	assert(instance->callback_out);
-
-	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed: %s.\n",
-	    instance, USB_TRANSFER_BATCH_ARGS(*instance),
-	    str_error(instance->error));
-
-	if (instance->ep->transfer_type == USB_TRANSFER_CONTROL
-	    && instance->error == EOK) {
-		const usb_target_t target =
-		    {{ instance->ep->address, instance->ep->endpoint }};
-		reset_ep_if_need(
-		    fun_to_hcd(instance->fun), target, instance->setup_buffer);
-	}
-
-	instance->callback_out(instance->fun,
-	    instance->error, instance->arg);
-}
-/*----------------------------------------------------------------------------*/
 /** Correctly dispose all used data structures.
  *
  * @param[in] instance Batch structure to use.
  */
-void usb_transfer_batch_dispose(usb_transfer_batch_t *instance)
+void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance)
 {
 	if (!instance)
@@ -166,4 +115,43 @@
 	free(instance);
 }
+/*----------------------------------------------------------------------------*/
+/** Prepare data and call the right callback.
+ *
+ * @param[in] instance Batch structure to use.
+ * @param[in] data Data to copy to the output buffer.
+ * @param[in] size Size of @p data.
+ */
+void usb_transfer_batch_finish(
+    const usb_transfer_batch_t *instance, const void *data, size_t size)
+{
+	assert(instance);
+	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.\n",
+	    instance, USB_TRANSFER_BATCH_ARGS(*instance));
+
+	/* NOTE: Only one of these pointers should be set. */
+        if (instance->callback_out) {
+		/* Check for commands that reset toggle bit */
+		if (instance->ep->transfer_type == USB_TRANSFER_CONTROL
+		    && instance->error == EOK) {
+			const usb_target_t target =
+			    {{ instance->ep->address, instance->ep->endpoint }};
+			reset_ep_if_need(fun_to_hcd(instance->fun), target,
+			    instance->setup_buffer);
+		}
+		instance->callback_out(instance->fun,
+		    instance->error, instance->arg);
+	}
+
+        if (instance->callback_in) {
+		/* We care about the data and there are some to copy */
+		if (data) {
+			const size_t min_size = size < instance->buffer_size
+			    ? size : instance->buffer_size;
+	                memcpy(instance->buffer, data, min_size);
+		}
+		instance->callback_in(instance->fun, instance->error,
+		    instance->transfered_size, instance->arg);
+	}
+}
 /**
  * @}
Index: uspace/srv/bd/rd/rd.c
===================================================================
--- uspace/srv/bd/rd/rd.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/bd/rd/rd.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/devman/devman.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -794,4 +794,7 @@
 	case EOK:
 		dev->state = DEVICE_USABLE;
+		exch = async_exchange_begin(drv->sess);
+		async_msg_1(exch, DRIVER_DEV_ADDED, dev->handle);
+		async_exchange_end(exch);
 		break;
 	case ENOENT:
@@ -1066,4 +1069,7 @@
 	
 	link = hash_table_find(&tree->devman_devices, &key);
+	if (link == NULL)
+		return NULL;
+	
 	return hash_table_get_instance(link, dev_node_t, devman_dev);
 }
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/devman/main.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -490,4 +490,6 @@
 	if (rc == EOK) {
 		loc_service_add_to_cat(fun->service_id, cat_id);
+		log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",
+		    fun->pathname, cat_name);
 	} else {
 		log_msg(LVL_ERROR, "Failed adding function `%s' to category "
@@ -495,11 +497,8 @@
 	}
 	
-	log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",
-	    fun->pathname, cat_name);
-
 	fibril_rwlock_read_unlock(&device_tree.rwlock);
 	fun_del_ref(fun);
-
-	async_answer_0(callid, EOK);
+	
+	async_answer_0(callid, rc);
 }
 
@@ -635,4 +634,7 @@
 				fibril_rwlock_read_unlock(&device_tree.rwlock);
 				dev_del_ref(dev);
+				if (gone_rc == EOK)
+					gone_rc = ENOTSUP;
+				async_answer_0(callid, gone_rc);
 				return;
 			}
Index: uspace/srv/fs/cdfs/cdfs.c
===================================================================
--- uspace/srv/fs/cdfs/cdfs.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/cdfs/cdfs.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -52,4 +52,5 @@
 	.concurrent_read_write = false,
 	.write_retains_size = false,
+	.instance = 0,
 };
 
@@ -58,4 +59,13 @@
 	printf("%s: HelenOS cdfs file system server\n", NAME);
 	
+	if (argc == 3) {
+		if (!str_cmp(argv[1], "--instance"))
+			cdfs_vfs_info.instance = strtol(argv[2], NULL, 10);
+		else {
+			printf(NAME " Unrecognized parameters");
+			return -1;
+		}
+	}
+
 	if (!cdfs_init()) {
 		printf("%s: failed to initialize cdfs\n", NAME);
Index: uspace/srv/fs/exfat/exfat.c
===================================================================
--- uspace/srv/fs/exfat/exfat.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/exfat/exfat.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -54,5 +54,6 @@
 	.name = NAME,
 	.concurrent_read_write = false,
-	.write_retains_size = false,	
+	.write_retains_size = false,
+	.instance = 0,
 };
 
@@ -60,4 +61,13 @@
 {
 	printf(NAME ": HelenOS exFAT file system server\n");
+
+	if (argc == 3) {
+		if (!str_cmp(argv[1], "--instance"))
+			exfat_vfs_info.instance = strtol(argv[2], NULL, 10);
+		else {
+			printf(NAME " Unrecognized parameters");
+			return -1;
+		}
+	}
 
 	int rc = exfat_idx_init();
Index: uspace/srv/fs/exfat/exfat_directory.c
===================================================================
--- uspace/srv/fs/exfat/exfat_directory.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/exfat/exfat_directory.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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,5 +110,5 @@
 
 	if (di->b && di->bnum != i) {
-		block_put(di->b);
+		rc = block_put(di->b);
 		di->b = NULL;
 	}
@@ -126,5 +128,5 @@
 		di->bnum = i;
 	}
-	return EOK;
+	return rc;
 }
 
@@ -285,6 +287,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);
@@ -312,6 +316,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;
@@ -424,5 +430,4 @@
 
 		di->b->dirty = true;
-		sname += chars;
 	}
 	
@@ -434,4 +439,6 @@
 	int rc, count;
 	exfat_dentry_t *de;
+
+	di->pos = pos;
 
 	rc = exfat_directory_get(di, &de);
Index: uspace/srv/fs/ext2fs/ext2fs.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/ext2fs/ext2fs.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -52,4 +52,5 @@
 vfs_info_t ext2fs_vfs_info = {
 	.name = NAME,
+	.instance = 0,
 };
 
@@ -57,4 +58,13 @@
 {
 	printf(NAME ": HelenOS EXT2 file system server\n");
+
+	if (argc == 3) {
+		if (!str_cmp(argv[1], "--instance"))
+			ext2fs_vfs_info.instance = strtol(argv[2], NULL, 10);
+		else {
+			printf(NAME " Unrecognized parameters");
+			return -1;
+		}
+	}
 	
 	async_sess_t *vfs_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
Index: uspace/srv/fs/fat/fat.c
===================================================================
--- uspace/srv/fs/fat/fat.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/fat/fat.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -54,5 +54,6 @@
 	.name = NAME,
 	.concurrent_read_write = false,
-	.write_retains_size = false,	
+	.write_retains_size = false,
+	.instance = 0,
 };
 
@@ -61,4 +62,13 @@
 	printf(NAME ": HelenOS FAT file system server\n");
 	
+	if (argc == 3) {
+		if (!str_cmp(argv[1], "--instance"))
+			fat_vfs_info.instance = strtol(argv[2], NULL, 10);
+		else {
+			printf(NAME " Unrecognized parameters");
+			return -1;
+		}
+	}
+
 	int rc = fat_idx_init();
 	if (rc != EOK)
Index: uspace/srv/fs/fat/fat.h
===================================================================
--- uspace/srv/fs/fat/fat.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/fat/fat.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -141,4 +141,18 @@
 } __attribute__ ((packed)) fat_bs_t;
 
+#define FAT32_FSINFO_SIG1	"RRaA"
+#define FAT32_FSINFO_SIG2	"rrAa"
+#define FAT32_FSINFO_SIG3	"\x00\x00\x55\xaa"
+
+typedef struct {
+	uint8_t	sig1[4];
+	uint8_t res1[480];
+	uint8_t sig2[4];
+	uint32_t free_clusters;
+	uint32_t last_allocated_cluster;
+	uint8_t res2[12];
+	uint8_t sig3[4];
+} __attribute__ ((packed)) fat32_fsinfo_t;
+
 typedef enum {
 	FAT_INVALID,
@@ -230,4 +244,8 @@
 } fat_node_t;
 
+typedef struct {
+	bool lfn_enabled;
+} fat_instance_t;
+
 extern vfs_out_ops_t fat_ops;
 extern libfs_ops_t fat_libfs_ops;
Index: uspace/srv/fs/fat/fat_directory.c
===================================================================
--- uspace/srv/fs/fat/fat_directory.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/fat/fat_directory.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -262,5 +262,10 @@
 {
 	int rc;
-	bool enable_lfn = true; /* TODO: make this a mount option */
+	void *data;
+	fat_instance_t *instance;
+
+	rc = fs_instance_get(di->nodep->idx->service_id, &data);
+	assert(rc == EOK);
+	instance = (fat_instance_t *) data;
 	
 	if (fat_valid_short_name(name)) {
@@ -277,5 +282,5 @@
 		rc = fat_directory_write_dentry(di, de);
 		return rc;
-	} else if (enable_lfn && fat_valid_name(name)) {
+	} else if (instance->lfn_enabled && fat_valid_name(name)) {
 		/* We should create long entries to store name */
 		int long_entry_count;
@@ -292,5 +297,5 @@
 		if (lfn_size % FAT_LFN_ENTRY_SIZE)
 			long_entry_count++;
-		rc = fat_directory_lookup_free(di, long_entry_count+1);
+		rc = fat_directory_lookup_free(di, long_entry_count + 1);
 		if (rc != EOK)
 			return rc;
@@ -328,5 +333,5 @@
 		FAT_LFN_ORDER(d) |= FAT_LFN_LAST;
 
-		rc = fat_directory_seek(di, start_pos+long_entry_count);
+		rc = fat_directory_seek(di, start_pos + long_entry_count);
 		return rc;
 	}
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -871,22 +871,37 @@
     aoff64_t *size, unsigned *linkcnt)
 {
-	enum cache_mode cmode;
+	enum cache_mode cmode = CACHE_MODE_WB;
 	fat_bs_t *bs;
-	int rc;
-
-	/* Check for option enabling write through. */
-	if (str_cmp(opts, "wtcache") == 0)
-		cmode = CACHE_MODE_WT;
-	else
-		cmode = CACHE_MODE_WB;
+	fat_instance_t *instance;
+	int rc;
+
+	instance = malloc(sizeof(fat_instance_t));
+	if (!instance)
+		return ENOMEM;
+	instance->lfn_enabled = true;
+
+	/* Parse mount options. */
+	char *mntopts = (char *) opts;
+	char *saveptr;
+	char *opt;
+	while ((opt = strtok_r(mntopts, " ,", &saveptr)) != NULL) {
+		if (str_cmp(opt, "wtcache") == 0)
+			cmode = CACHE_MODE_WT;
+		else if (str_cmp(opt, "nolfn") == 0)
+			instance->lfn_enabled = false;
+		mntopts = NULL;
+	}
 
 	/* initialize libblock */
 	rc = block_init(EXCHANGE_SERIALIZE, service_id, BS_SIZE);
-	if (rc != EOK)
-		return rc;
+	if (rc != EOK) {
+		free(instance);
+		return rc;
+	}
 
 	/* prepare the boot block */
 	rc = block_bb_read(service_id, BS_BLOCK);
 	if (rc != EOK) {
+		free(instance);
 		block_fini(service_id);
 		return rc;
@@ -897,4 +912,5 @@
 	
 	if (BPS(bs) != BS_SIZE) {
+		free(instance);
 		block_fini(service_id);
 		return ENOTSUP;
@@ -904,4 +920,5 @@
 	rc = block_cache_init(service_id, BPS(bs), 0 /* XXX */, cmode);
 	if (rc != EOK) {
+		free(instance);
 		block_fini(service_id);
 		return rc;
@@ -911,4 +928,5 @@
 	rc = fat_sanity_check(bs, service_id);
 	if (rc != EOK) {
+		free(instance);
 		(void) block_cache_fini(service_id);
 		block_fini(service_id);
@@ -918,4 +936,5 @@
 	rc = fat_idx_init_by_service_id(service_id);
 	if (rc != EOK) {
+		free(instance);
 		(void) block_cache_fini(service_id);
 		block_fini(service_id);
@@ -926,4 +945,5 @@
 	fs_node_t *rfn = (fs_node_t *)malloc(sizeof(fs_node_t));
 	if (!rfn) {
+		free(instance);
 		(void) block_cache_fini(service_id);
 		block_fini(service_id);
@@ -935,4 +955,5 @@
 	fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
 	if (!rootp) {
+		free(instance);
 		free(rfn);
 		(void) block_cache_fini(service_id);
@@ -945,4 +966,5 @@
 	fat_idx_t *ridxp = fat_idx_get_by_pos(service_id, FAT_CLST_ROOTPAR, 0);
 	if (!ridxp) {
+		free(instance);
 		free(rfn);
 		free(rootp);
@@ -964,4 +986,6 @@
 		rc = fat_clusters_get(&clusters, bs, service_id, rootp->firstc);
 		if (rc != EOK) {
+			fibril_mutex_unlock(&ridxp->lock);
+			free(instance);
 			free(rfn);
 			free(rootp);
@@ -975,4 +999,16 @@
 		rootp->size = RDE(bs) * sizeof(fat_dentry_t);
 
+	rc = fs_instance_create(service_id, instance);
+	if (rc != EOK) {
+		fibril_mutex_unlock(&ridxp->lock);
+		free(instance);
+		free(rfn);
+		free(rootp);
+		(void) block_cache_fini(service_id);
+		block_fini(service_id);
+		fat_idx_fini_by_service_id(service_id);
+		return rc;
+	}
+
 	rootp->idx = ridxp;
 	ridxp->nodep = rootp;
@@ -989,9 +1025,43 @@
 }
 
+static int fat_update_fat32_fsinfo(service_id_t service_id)
+{
+	fat_bs_t *bs;
+	fat32_fsinfo_t *info;
+	block_t *b;
+	int rc;
+
+	bs = block_bb_get(service_id);
+	assert(FAT_IS_FAT32(bs));
+
+	rc = block_get(&b, service_id, uint16_t_le2host(bs->fat32.fsinfo_sec),
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
+
+	info = (fat32_fsinfo_t *) b->data;
+
+	if (bcmp(info->sig1, FAT32_FSINFO_SIG1, sizeof(info->sig1)) ||
+	    bcmp(info->sig2, FAT32_FSINFO_SIG2, sizeof(info->sig2)) ||
+	    bcmp(info->sig3, FAT32_FSINFO_SIG3, sizeof(info->sig3))) {
+		(void) block_put(b);
+		return EINVAL;
+	}
+
+	/* For now, invalidate the counter. */
+	info->free_clusters = host2uint16_t_le(-1);
+
+	b->dirty = true;
+	return block_put(b);
+}
+
 static int fat_unmounted(service_id_t service_id)
 {
 	fs_node_t *fn;
 	fat_node_t *nodep;
-	int rc;
+	fat_bs_t *bs;
+	int rc;
+
+	bs = block_bb_get(service_id);
 
 	rc = fat_root_get(&fn, service_id);
@@ -1007,4 +1077,11 @@
 		(void) fat_node_put(fn);
 		return EBUSY;
+	}
+
+	if (FAT_IS_FAT32(bs)) {
+		/*
+		 * Attempt to update the FAT32 FS info.
+		 */
+		(void) fat_update_fat32_fsinfo(service_id);
 	}
 
@@ -1024,4 +1101,10 @@
 	(void) block_cache_fini(service_id);
 	block_fini(service_id);
+
+	void *data;
+	if (fs_instance_get(service_id, &data) == EOK) {
+		fs_instance_destroy(service_id);
+		free(data);
+	}
 
 	return EOK;
Index: uspace/srv/fs/locfs/locfs.c
===================================================================
--- uspace/srv/fs/locfs/locfs.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/locfs/locfs.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -55,4 +55,5 @@
 	.concurrent_read_write = false,
 	.write_retains_size = false,
+	.instance = 0,
 };
 
@@ -61,4 +62,14 @@
 	printf("%s: HelenOS Device Filesystem\n", NAME);
 	
+	if (argc == 3) {
+		if (!str_cmp(argv[1], "--instance"))
+			locfs_vfs_info.instance = strtol(argv[2], NULL, 10);
+		else {
+			printf(NAME " Unrecognized parameters");
+			return -1;
+		}
+	}
+
+
 	if (!locfs_init()) {
 		printf("%s: failed to initialize locfs\n", NAME);
Index: uspace/srv/fs/locfs/locfs_ops.c
===================================================================
--- uspace/srv/fs/locfs/locfs_ops.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/locfs/locfs_ops.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -593,4 +593,8 @@
 		sysarg_t rc;
 		async_wait_for(msg, &rc);
+
+		/* Do not propagate EHANGUP back to VFS. */
+		if ((int) rc == EHANGUP)
+			rc = ENOTSUP;
 		
 		*rbytes = IPC_GET_ARG1(answer);
@@ -655,4 +659,8 @@
 		sysarg_t rc;
 		async_wait_for(msg, &rc);
+
+		/* Do not propagate EHANGUP back to VFS. */
+		if ((int) rc == EHANGUP)
+			rc = ENOTSUP;
 		
 		*wbytes = IPC_GET_ARG1(answer);
Index: uspace/srv/fs/mfs/mfs.c
===================================================================
--- uspace/srv/fs/mfs/mfs.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/mfs/mfs.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -39,4 +39,6 @@
 
 #include <ipc/services.h>
+#include <stdlib.h>
+#include <str.h>
 #include <ns.h>
 #include <async.h>
@@ -52,4 +54,5 @@
 	.concurrent_read_write = false,
 	.write_retains_size = false,
+	.instance = 0,
 };
 
@@ -60,6 +63,16 @@
 	printf(NAME ": HelenOS Minix file system server\n");
 
+	if (argc == 3) {
+		if (!str_cmp(argv[1], "--instance"))
+			mfs_vfs_info.instance = strtol(argv[2], NULL, 10);
+		else {
+			printf(NAME " Unrecognized parameters");
+			rc = -1;
+			goto err;
+		}
+	}
+
 	async_sess_t *vfs_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
-				SERVICE_VFS, 0, 0);
+	    SERVICE_VFS, 0, 0);
 
 	if (!vfs_sess) {
Index: uspace/srv/fs/mfs/mfs.h
===================================================================
--- uspace/srv/fs/mfs/mfs.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/mfs/mfs.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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,29 +107,28 @@
 	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;
 };
 
 struct mfs_instance {
-	link_t link;
 	service_id_t service_id;
 	struct mfs_sb_info *sbi;
@@ -137,5 +136,5 @@
 };
 
-/*MinixFS node in core*/
+/* MinixFS node in core */
 struct mfs_node {
 	struct mfs_ino_info *ino_i;
@@ -146,5 +145,5 @@
 };
 
-/*mfs_ops.c*/
+/* mfs_ops.c */
 extern vfs_out_ops_t mfs_ops;
 extern libfs_ops_t mfs_libfs_ops;
@@ -153,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
@@ -164,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);
@@ -170,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
@@ -189,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);
@@ -202,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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/mfs/mfs_balloc.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -36,5 +36,5 @@
 static int
 find_free_bit_and_set(bitchunk_t *b, const int bsize,
-		      const bool native, unsigned start_bit);
+    const bool native, unsigned start_bit);
 
 static int
@@ -129,19 +129,19 @@
 		if (idx > sbi->nzones) {
 			printf(NAME ": Error! Trying to free beyond the" \
-			       "bitmap max size\n");
+			    "bitmap max size\n");
 			return -1;
 		}
 	} else {
-		/*bid == BMAP_INODE*/
+		/* bid == BMAP_INODE */
 		search = &sbi->isearch;
 		start_block = 2;
 		if (idx > sbi->ninodes) {
 			printf(NAME ": Error! Trying to free beyond the" \
-			       "bitmap max size\n");
+			    "bitmap max size\n");
 			return -1;
 		}
 	}
 
-	/*Compute the bitmap block*/
+	/* Compute the bitmap block */
 	uint32_t block = idx / (sbi->block_size * 8) + start_block;
 
@@ -150,5 +150,5 @@
 		goto out_err;
 
-	/*Compute the bit index in the block*/
+	/* Compute the bit index in the block */
 	idx %= (sbi->block_size * 8);
 	bitchunk_t *ptr = b->data;
@@ -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)
@@ -220,7 +220,7 @@
 
 		freebit = find_free_bit_and_set(b->data, sbi->block_size,
-						sbi->native, tmp);
+		    sbi->native, tmp);
 		if (freebit == -1) {
-			/*No free bit in this block*/
+			/* No free bit in this block */
 			r = block_put(b);
 			if (r != EOK)
@@ -229,8 +229,8 @@
 		}
 
-		/*Free bit found in this block, compute the real index*/
+		/* Free bit found in this block, compute the real index */
 		*idx = freebit + bits_per_block * i;
 		if (*idx > limit) {
-			/*Index is beyond the limit, it is invalid*/
+			/* Index is beyond the limit, it is invalid */
 			r = block_put(b);
 			if (r != EOK)
@@ -246,10 +246,10 @@
 
 	if (*search > 0) {
-		/*Repeat the search from the first bitmap block*/
+		/* Repeat the search from the first bitmap block */
 		*search = 0;
 		goto retry;
 	}
 
-	/*Free bit not found, return error*/
+	/* Free bit not found, return error */
 	return ENOSPC;
 
@@ -260,5 +260,5 @@
 static int
 find_free_bit_and_set(bitchunk_t *b, const int bsize,
-		      const bool native, unsigned start_bit)
+    const bool native, unsigned start_bit)
 {
 	int r = -1;
@@ -268,7 +268,8 @@
 
 	for (i = start_bit / chunk_bits;
-	     i < bsize / sizeof(bitchunk_t); ++i) {
+	    i < bsize / sizeof(bitchunk_t); ++i) {
+
 		if (!(~b[i])) {
-			/*No free bit in this chunk*/
+			/* No free bit in this chunk */
 			continue;
 		}
Index: uspace/srv/fs/mfs/mfs_dentry.c
===================================================================
--- uspace/srv/fs/mfs/mfs_dentry.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/mfs/mfs_dentry.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -44,5 +44,5 @@
 int
 mfs_read_dentry(struct mfs_node *mnode,
-		     struct mfs_dentry_info *d_info, unsigned index)
+    struct mfs_dentry_info *d_info, unsigned index)
 {
 	const struct mfs_instance *inst = mnode->instance;
@@ -57,5 +57,5 @@
 
 	if (block == 0) {
-		/*End of the dentries list*/
+		/* End of the dentries list */
 		r = EOK;
 		goto out_err;
@@ -79,10 +79,10 @@
 	} else {
 		const int namelen = longnames ? MFS_L_MAX_NAME_LEN :
-				    MFS_MAX_NAME_LEN;
+		    MFS_MAX_NAME_LEN;
 
 		struct mfs_dentry *d;
 
 		d = b->data + dentry_off * (longnames ? MFSL_DIRSIZE :
-					    MFS_DIRSIZE);
+		    MFS_DIRSIZE);
 		d_info->d_inum = conv16(sbi->native, d->d_inum);
 		memcpy(d_info->d_name, d->d_name, namelen);
@@ -101,7 +101,7 @@
 /**Write a directory entry on disk.
  *
- * @param d_info	Pointer to the directory entry structure to write on disk.
- *
- * @return		EOK on success or a negative error code.
+ * @param d_info Pointer to the directory entry structure to write on disk.
+ *
+ * @return	 EOK on success or a negative error code.
  */
 int
@@ -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) {
@@ -178,5 +178,6 @@
 
 		if (name_len == d_name_len &&
-				!bcmp(d_info.d_name, d_name, name_len)) {
+		    !bcmp(d_info.d_name, d_name, name_len)) {
+
 			d_info.d_inum = 0;
 			r = mfs_write_dentry(&d_info);
@@ -197,5 +198,6 @@
  */
 int
-mfs_insert_dentry(struct mfs_node *mnode, const char *d_name, fs_index_t d_inum)
+mfs_insert_dentry(struct mfs_node *mnode, const char *d_name,
+    fs_index_t d_inum)
 {
 	int r;
@@ -209,5 +211,5 @@
 		return ENAMETOOLONG;
 
-	/*Search for an empty dentry*/
+	/* Search for an empty dentry */
 	unsigned i;
 	for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
@@ -217,5 +219,5 @@
 
 		if (d_info.d_inum == 0) {
-			/*This entry is not used*/
+			/* This entry is not used */
 			empty_dentry_found = true;
 			break;
@@ -231,5 +233,5 @@
 
 		if (b == 0) {
-			/*Increase the inode size*/
+			/* Increase the inode size */
 
 			uint32_t dummy;
Index: uspace/srv/fs/mfs/mfs_inode.c
===================================================================
--- uspace/srv/fs/mfs/mfs_inode.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/mfs/mfs_inode.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -42,9 +42,9 @@
 static int
 mfs_read_inode_raw(const struct mfs_instance *instance,
-		struct mfs_ino_info **ino_ptr, uint16_t inum);
+    struct mfs_ino_info **ino_ptr, uint16_t inum);
 
 static int
 mfs2_read_inode_raw(const struct mfs_instance *instance,
-		struct mfs_ino_info **ino_ptr, uint32_t inum);
+    struct mfs_ino_info **ino_ptr, uint32_t inum);
 
 /**Read a MINIX inode from disk
@@ -59,5 +59,5 @@
 int
 mfs_get_inode(struct mfs_instance *inst, struct mfs_ino_info **ino_i,
-	  fs_index_t index)
+    fs_index_t index)
 {
 	struct mfs_sb_info *sbi = inst->sbi;
@@ -65,8 +65,8 @@
 
 	if (sbi->fs_version == MFS_VERSION_V1) {
-		/*Read a MFS V1 inode*/
+		/* Read a MFS V1 inode */
 		r = mfs_read_inode_raw(inst, ino_i, index);
 	} else {
-		/*Read a MFS V2/V3 inode*/
+		/* Read a MFS V2/V3 inode */
 		r = mfs2_read_inode_raw(inst, ino_i, index);
 	}
@@ -77,5 +77,6 @@
 static int
 mfs_read_inode_raw(const struct mfs_instance *instance,
-		struct mfs_ino_info **ino_ptr, uint16_t inum) {
+    struct mfs_ino_info **ino_ptr, uint16_t inum)
+{
 	struct mfs_inode *ino;
 	struct mfs_ino_info *ino_i = NULL;
@@ -86,5 +87,5 @@
 	sbi = instance->sbi;
 
-	/*inode 0 does not exist*/
+	/* inode 0 does not exist */
 	inum -= 1;
 
@@ -101,6 +102,7 @@
 
 	r = block_get(&b, 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)
 		goto out_err;
@@ -134,5 +136,6 @@
 static int
 mfs2_read_inode_raw(const struct mfs_instance *instance,
-		struct mfs_ino_info **ino_ptr, uint32_t inum) {
+    struct mfs_ino_info **ino_ptr, uint32_t inum)
+{
 	struct mfs2_inode *ino;
 	struct mfs_ino_info *ino_i = NULL;
@@ -150,5 +153,5 @@
 	sbi = instance->sbi;
 
-	/*inode 0 does not exist*/
+	/* inode 0 does not exist */
 	inum -= 1;
 
@@ -157,6 +160,7 @@
 
 	r = block_get(&b, 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)
 		goto out_err;
@@ -231,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)
@@ -274,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)
@@ -322,5 +326,5 @@
 
 	if (size_shrink == 0) {
-		/*File is empty*/
+		/* Nothing to be done */
 		return EOK;
 	}
@@ -333,5 +337,5 @@
 	ino_i->dirty = true;
 
-	/*Compute the number of zones to free*/
+	/* Compute the number of zones to free */
 	unsigned zones_to_free;
 
@@ -354,5 +358,5 @@
 
 		if (old_zone == 0)
-			continue; /*Sparse block*/
+			continue; /* Sparse block */
 
 		r = mfs_free_zone(mnode->instance, old_zone);
Index: uspace/srv/fs/mfs/mfs_ops.c
===================================================================
--- uspace/srv/fs/mfs/mfs_ops.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/mfs/mfs_ops.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -43,8 +43,7 @@
 
 static bool check_magic_number(uint16_t magic, bool *native,
-			       mfs_version_t *version, bool *longfilenames);
+    mfs_version_t *version, bool *longfilenames);
 static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
-			     fs_index_t index);
-
+    fs_index_t index);
 static int mfs_node_put(fs_node_t *fsnode);
 static int mfs_node_open(fs_node_t *fsnode);
@@ -64,15 +63,13 @@
 static hash_index_t open_nodes_hash(unsigned long key[]);
 static int open_nodes_compare(unsigned long key[], hash_count_t keys,
-		link_t *item);
+    link_t *item);
 static void open_nodes_remove_cb(link_t *link);
-
 static int mfs_node_get(fs_node_t **rfn, service_id_t service_id,
-			fs_index_t index);
-static int
-mfs_instance_get(service_id_t service_id, struct mfs_instance **instance);
-
-
-static LIST_INITIALIZE(inst_list);
-static FIBRIL_MUTEX_INITIALIZE(inst_list_mutex);
+    fs_index_t index);
+static int mfs_instance_get(service_id_t service_id,
+    struct mfs_instance **instance);
+static int mfs_check_sanity(struct mfs_sb_info *sbi);
+static bool is_power_of_two(uint32_t n);
+
 static hash_table_t open_nodes;
 static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
@@ -98,5 +95,6 @@
 
 /* Hash table interface for open nodes hash table */
-static hash_index_t open_nodes_hash(unsigned long key[])
+static hash_index_t
+open_nodes_hash(unsigned long key[])
 {
 	/* TODO: This is very simple and probably can be improved */
@@ -104,6 +102,7 @@
 }
 
-static int open_nodes_compare(unsigned long key[], hash_count_t keys,
-		link_t *item)
+static int
+open_nodes_compare(unsigned long key[], hash_count_t keys,
+    link_t *item)
 {
 	struct mfs_node *mnode = hash_table_get_instance(item, struct mfs_node, link);
@@ -120,5 +119,6 @@
 }
 
-static void open_nodes_remove_cb(link_t *link)
+static void
+open_nodes_remove_cb(link_t *link)
 {
 	/* We don't use remove callback for this hash table */
@@ -131,8 +131,9 @@
 };
 
-int mfs_global_init(void)
+int
+mfs_global_init(void)
 {
 	if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
-			OPEN_NODES_KEYS, &open_nodes_ops)) {
+	    OPEN_NODES_KEYS, &open_nodes_ops)) {
 		return ENOMEM;
 	}
@@ -142,11 +143,11 @@
 static int
 mfs_mounted(service_id_t service_id, const char *opts, fs_index_t *index,
-		aoff64_t *size, unsigned *linkcnt)
+    aoff64_t *size, unsigned *linkcnt)
 {
 	enum cache_mode cmode;
-	struct mfs_superblock *sb;
-	struct mfs3_superblock *sb3;
-	struct mfs_sb_info *sbi;
-	struct mfs_instance *instance;
+	struct mfs_superblock *sb = NULL;
+	struct mfs3_superblock *sb3 = NULL;
+	struct mfs_sb_info *sbi = NULL;
+	struct mfs_instance *instance = NULL;
 	bool native, longnames;
 	mfs_version_t version;
@@ -165,60 +166,47 @@
 		return rc;
 
-	/*Allocate space for generic MFS superblock*/
+	/* Allocate space for generic MFS superblock */
 	sbi = malloc(sizeof(*sbi));
 	if (!sbi) {
-		block_fini(service_id);
-		return ENOMEM;
-	}
-
-	/*Allocate space for filesystem instance*/
+		rc = ENOMEM;
+		goto out_error;
+	}
+
+	/* Allocate space for filesystem instance */
 	instance = malloc(sizeof(*instance));
 	if (!instance) {
-		free(sbi);
-		block_fini(service_id);
-		return ENOMEM;
-	}
-
-	instance->open_nodes_cnt = 0;
+		rc = ENOMEM;
+		goto out_error;
+	}
 
 	sb = malloc(MFS_SUPERBLOCK_SIZE);
 	if (!sb) {
-		free(instance);
-		free(sbi);
-		block_fini(service_id);
-		return ENOMEM;
+		rc = ENOMEM;
+		goto out_error;
 	}
 
 	/* Read the superblock */
 	rc = block_read_direct(service_id, MFS_SUPERBLOCK << 1, 2, sb);
-	if (rc != EOK) {
-		free(instance);
-		free(sbi);
-		free(sb);
-		block_fini(service_id);
-		return rc;
-	}
+	if (rc != EOK)
+		goto out_error;
 
 	sb3 = (struct mfs3_superblock *) sb;
 
 	if (check_magic_number(sb->s_magic, &native, &version, &longnames)) {
-		/*This is a V1 or V2 Minix filesystem*/
+		/* This is a V1 or V2 Minix filesystem */
 		magic = sb->s_magic;
 	} else if (check_magic_number(sb3->s_magic, &native, &version, &longnames)) {
-		/*This is a V3 Minix filesystem*/
+		/* This is a V3 Minix filesystem */
 		magic = sb3->s_magic;
 	} else {
-		/*Not recognized*/
+		/* Not recognized */
 		mfsdebug("magic number not recognized\n");
-		free(instance);
-		free(sbi);
-		free(sb);
-		block_fini(service_id);
-		return ENOTSUP;
+		rc = ENOTSUP;
+		goto out_error;
 	}
 
 	mfsdebug("magic number recognized = %04x\n", magic);
 
-	/*Fill superblock info structure*/
+	/* Fill superblock info structure */
 
 	sbi->fs_version = version;
@@ -258,29 +246,42 @@
 		sbi->dirsize = longnames ? MFSL_DIRSIZE : MFS_DIRSIZE;
 		sbi->max_name_len = longnames ? MFS_L_MAX_NAME_LEN :
-				    MFS_MAX_NAME_LEN;
-	}
+		    MFS_MAX_NAME_LEN;
+	}
+
+	if (sbi->log2_zone_size != 0) {
+		/* In MFS, file space is allocated per zones.
+		 * Zones are a collection of consecutive blocks on disk.
+		 *
+		 * The current MFS implementation supports only filesystems
+		 * where the size of a zone is equal to the
+		 * size of a block.
+		 */
+		rc = ENOTSUP;
+		goto out_error;
+	}
+
 	sbi->itable_off = 2 + sbi->ibmap_blocks + sbi->zbmap_blocks;
-
-	free(sb);
+	if ((rc = mfs_check_sanity(sbi)) != EOK) {
+		fprintf(stderr, "Filesystem corrupted, invalid superblock");
+		goto out_error;
+	}
 
 	rc = block_cache_init(service_id, sbi->block_size, 0, cmode);
 	if (rc != EOK) {
-		free(instance);
-		free(sbi);
-		free(sb);
-		block_cache_fini(service_id);
-		block_fini(service_id);
 		mfsdebug("block cache initialization failed\n");
-		return EINVAL;
-	}
-
-	/*Initialize the instance structure and add it to the list*/
-	link_initialize(&instance->link);
+		rc = EINVAL;
+		goto out_error;
+	}
+
+	/* Initialize the instance structure and remember it */
 	instance->service_id = service_id;
 	instance->sbi = sbi;
-
-	fibril_mutex_lock(&inst_list_mutex);
-	list_append(&instance->link, &inst_list);
-	fibril_mutex_unlock(&inst_list_mutex);
+	instance->open_nodes_cnt = 0;
+	rc = fs_instance_create(service_id, instance);
+	if (rc != EOK) {
+		block_cache_fini(service_id);
+		mfsdebug("fs instance creation failed\n");
+		goto out_error;
+	}
 
 	mfsdebug("mount successful\n");
@@ -295,5 +296,17 @@
 	*linkcnt = 1;
 
+	free(sb);
+
 	return mfs_node_put(fn);
+
+out_error:
+	block_fini(service_id);
+	if (sb)
+		free(sb);
+	if (sbi)
+		free(sbi);
+	if(instance)
+		free(instance);
+	return rc;
 }
 
@@ -315,9 +328,6 @@
 	block_fini(service_id);
 
-	/* Remove the instance from the list */
-	fibril_mutex_lock(&inst_list_mutex);
-	list_remove(&inst->link);
-	fibril_mutex_unlock(&inst_list_mutex);
-
+	/* Remove and destroy the instance */
+	(void) fs_instance_destroy(service_id);
 	free(inst->sbi);
 	free(inst);
@@ -325,5 +335,6 @@
 }
 
-service_id_t mfs_service_get(fs_node_t *fsnode)
+service_id_t
+mfs_service_get(fs_node_t *fsnode)
 {
 	struct mfs_node *node = fsnode->data;
@@ -331,5 +342,6 @@
 }
 
-static int mfs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
+static int
+mfs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
 {
 	int r;
@@ -345,5 +357,5 @@
 		return r;
 
-	/*Alloc a new inode*/
+	/* Alloc a new inode */
 	r = mfs_alloc_inode(inst, &inum);
 	if (r != EOK)
@@ -372,9 +384,7 @@
 	if (flags & L_DIRECTORY) {
 		ino_i->i_mode = S_IFDIR;
-		ino_i->i_nlinks = 2; /*This accounts for the '.' dentry*/
-	} else {
+		ino_i->i_nlinks = 1; /* This accounts for the '.' dentry */
+	} else
 		ino_i->i_mode = S_IFREG;
-		ino_i->i_nlinks = 1;
-	}
 
 	ino_i->i_uid = 0;
@@ -425,5 +435,6 @@
 }
 
-static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+static int
+mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
 {
 	struct mfs_node *mnode = pfn->data;
@@ -447,5 +458,5 @@
 
 		if (!d_info.d_inum) {
-			/*This entry is not used*/
+			/* This entry is not used */
 			continue;
 		}
@@ -454,8 +465,8 @@
 
 		if (comp_size == dentry_name_size &&
-			!bcmp(component, d_info.d_name, dentry_name_size)) {
-			/*Hit!*/
+		    !bcmp(component, d_info.d_name, dentry_name_size)) {
+			/* Hit! */
 			mfs_node_core_get(rfn, mnode->instance,
-					  d_info.d_inum);
+			    d_info.d_inum);
 			goto found;
 		}
@@ -466,5 +477,6 @@
 }
 
-static aoff64_t mfs_size_get(fs_node_t *node)
+static aoff64_t
+mfs_size_get(fs_node_t *node)
 {
 	const struct mfs_node *mnode = node->data;
@@ -474,5 +486,5 @@
 static int
 mfs_node_get(fs_node_t **rfn, service_id_t service_id,
-			fs_index_t index)
+    fs_index_t index)
 {
 	int rc;
@@ -518,5 +530,6 @@
 }
 
-static int mfs_node_open(fs_node_t *fsnode)
+static int
+mfs_node_open(fs_node_t *fsnode)
 {
 	/*
@@ -527,5 +540,6 @@
 }
 
-static fs_index_t mfs_index_get(fs_node_t *fsnode)
+static fs_index_t
+mfs_index_get(fs_node_t *fsnode)
 {
 	struct mfs_node *mnode = fsnode->data;
@@ -533,5 +547,6 @@
 }
 
-static unsigned mfs_lnkcnt_get(fs_node_t *fsnode)
+static unsigned
+mfs_lnkcnt_get(fs_node_t *fsnode)
 {
 	struct mfs_node *mnode = fsnode->data;
@@ -548,6 +563,7 @@
 }
 
-static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
-			     fs_index_t index)
+static int
+mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
+    fs_index_t index)
 {
 	fs_node_t *node = NULL;
@@ -621,5 +637,6 @@
 }
 
-static bool mfs_is_directory(fs_node_t *fsnode)
+static bool
+mfs_is_directory(fs_node_t *fsnode)
 {
 	const struct mfs_node *node = fsnode->data;
@@ -627,5 +644,6 @@
 }
 
-static bool mfs_is_file(fs_node_t *fsnode)
+static bool
+mfs_is_file(fs_node_t *fsnode)
 {
 	struct mfs_node *node = fsnode->data;
@@ -633,5 +651,6 @@
 }
 
-static int mfs_root_get(fs_node_t **rfn, service_id_t service_id)
+static int
+mfs_root_get(fs_node_t **rfn, service_id_t service_id)
 {
 	int rc = mfs_node_get(rfn, service_id, MFS_ROOT_INO);
@@ -639,9 +658,11 @@
 }
 
-static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+static int
+mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
 {
 	struct mfs_node *parent = pfn->data;
 	struct mfs_node *child = cfn->data;
 	struct mfs_sb_info *sbi = parent->instance->sbi;
+	bool destroy_dentry = false;
 
 	mfsdebug("%s()\n", __FUNCTION__);
@@ -652,14 +673,24 @@
 	int r = mfs_insert_dentry(parent, name, child->ino_i->index);
 	if (r != EOK)
-		goto exit_error;
+		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++;
@@ -667,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;
 }
@@ -714,5 +753,6 @@
 }
 
-static int mfs_has_children(bool *has_children, fs_node_t *fsnode)
+static int
+mfs_has_children(bool *has_children, fs_node_t *fsnode)
 {
 	struct mfs_node *mnode = fsnode->data;
@@ -735,5 +775,5 @@
 
 		if (d_info.d_inum) {
-			/*A valid entry has been found*/
+			/* A valid entry has been found */
 			*has_children = true;
 			break;
@@ -747,5 +787,5 @@
 static int
 mfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
-		size_t *rbytes)
+    size_t *rbytes)
 {
 	int rc;
@@ -777,5 +817,5 @@
 
 		if (pos < 2) {
-			/*Skip the first two dentries ('.' and '..')*/
+			/* Skip the first two dentries ('.' and '..') */
 			pos = 2;
 		}
@@ -787,5 +827,5 @@
 
 			if (d_info.d_inum) {
-				/*Dentry found!*/
+				/* Dentry found! */
 				goto found;
 			}
@@ -797,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 {
@@ -803,5 +843,5 @@
 
 		if (pos >= (size_t) ino_i->i_size) {
-			/*Trying to read beyond the end of file*/
+			/* Trying to read beyond the end of file */
 			bytes = 0;
 			(void) async_data_read_finalize(callid, NULL, 0);
@@ -820,5 +860,5 @@
 
 		if (zone == 0) {
-			/*sparse file*/
+			/* sparse file */
 			uint8_t *buf = malloc(sbi->block_size);
 			if (!buf) {
@@ -828,5 +868,5 @@
 			memset(buf, 0, sizeof(sbi->block_size));
 			async_data_read_finalize(callid,
-						 buf + pos % sbi->block_size, bytes);
+			    buf + pos % sbi->block_size, bytes);
 			free(buf);
 			goto out_success;
@@ -838,5 +878,5 @@
 
 		async_data_read_finalize(callid, b->data +
-					 pos % sbi->block_size, bytes);
+		    pos % sbi->block_size, bytes);
 
 		rc = block_put(b);
@@ -859,5 +899,5 @@
 static int
 mfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
-		size_t *wbytes, aoff64_t *nsize)
+    size_t *wbytes, aoff64_t *nsize)
 {
 	fs_node_t *fn;
@@ -883,6 +923,5 @@
 	struct mfs_ino_info *ino_i = mnode->ino_i;
 	const size_t bs = sbi->block_size;
-	size_t bytes = min(len, bs - pos % bs);
-	size_t boundary = ROUND_UP(ino_i->i_size, bs);
+	size_t bytes = min(len, bs - (pos % bs));
 	uint32_t block;
 
@@ -890,17 +929,9 @@
 		flags = BLOCK_FLAGS_NOREAD;
 
-	if (pos < boundary) {
-		r = mfs_read_map(&block, mnode, pos);
-		if (r != EOK)
-			goto out_err;
-
-		if (block == 0) {
-			/*Writing in a sparse block*/
-			r = mfs_alloc_zone(mnode->instance, &block);
-			if (r != EOK)
-				goto out_err;
-			flags = BLOCK_FLAGS_NOREAD;
-		}
-	} else {
+	r = mfs_read_map(&block, mnode, pos);
+	if (r != EOK)
+		goto out_err;
+
+	if (block == 0) {
 		uint32_t dummy;
 
@@ -908,8 +939,10 @@
 		if (r != EOK)
 			goto out_err;
-
+		
 		r = mfs_write_map(mnode, pos, block, &dummy);
 		if (r != EOK)
 			goto out_err;
+
+		flags = BLOCK_FLAGS_NOREAD;
 	}
 
@@ -919,5 +952,8 @@
 		goto out_err;
 
-	async_data_write_finalize(callid, b->data + pos % bs, bytes);
+	if (flags == BLOCK_FLAGS_NOREAD)
+		memset(b->data, 0, sbi->block_size);
+
+	async_data_write_finalize(callid, b->data + (pos % bs), bytes);
 	b->dirty = true;
 
@@ -928,8 +964,10 @@
 	}
 
-	ino_i->i_size = pos + bytes;
-	ino_i->dirty = true;
+	if (pos + bytes > ino_i->i_size) {
+		ino_i->i_size = pos + bytes;
+		ino_i->dirty = true;
+	}
 	r = mfs_node_put(fn);
-	*nsize = pos + bytes;
+	*nsize = ino_i->i_size;
 	*wbytes = bytes;
 	return r;
@@ -953,5 +991,5 @@
 		return ENOENT;
 
-	/*Destroy the inode*/
+	/* Destroy the inode */
 	return mfs_destroy_node(fn);
 }
@@ -972,10 +1010,10 @@
 	assert(!has_children);
 
-	/*Free the entire inode content*/
+	/* Free the entire inode content */
 	r = mfs_inode_shrink(mnode, mnode->ino_i->i_size);
 	if (r != EOK)
 		goto out;
 
-	/*Mark the inode as free in the bitmap*/
+	/* Mark the inode as free in the bitmap */
 	r = mfs_free_inode(mnode->instance, mnode->ino_i->index);
 
@@ -1012,32 +1050,20 @@
 mfs_instance_get(service_id_t service_id, struct mfs_instance **instance)
 {
-	struct mfs_instance *instance_ptr;
-
-	fibril_mutex_lock(&inst_list_mutex);
-
-	if (list_empty(&inst_list)) {
-		fibril_mutex_unlock(&inst_list_mutex);
-		return EINVAL;
-	}
-
-	list_foreach(inst_list, link) {
-		instance_ptr = list_get_instance(link, struct mfs_instance,
-						 link);
-
-		if (instance_ptr->service_id == service_id) {
-			*instance = instance_ptr;
-			fibril_mutex_unlock(&inst_list_mutex);
-			return EOK;
-		}
-	}
-
-	mfsdebug("Instance not found\n");
-
-	fibril_mutex_unlock(&inst_list_mutex);
-	return EINVAL;
-}
-
-static bool check_magic_number(uint16_t magic, bool *native,
-			       mfs_version_t *version, bool *longfilenames)
+	void *data;
+	int rc;
+
+	rc = fs_instance_get(service_id, &data);
+	if (rc == EOK)
+		*instance = (struct mfs_instance *) data;
+	else {
+		mfsdebug("instance not found\n");
+	}
+
+	return rc;
+}
+
+static bool
+check_magic_number(uint16_t magic, bool *native,
+		mfs_version_t *version, bool *longfilenames)
 {
 	bool rc = true;
@@ -1067,4 +1093,27 @@
 }
 
+/** Filesystem sanity check
+ *
+ * @param Pointer to the MFS superblock.
+ *
+ * @return EOK on success, ENOTSUP otherwise.
+ */
+static int
+mfs_check_sanity(struct mfs_sb_info *sbi)
+{
+	if (!is_power_of_two(sbi->block_size) ||
+	    sbi->block_size < MFS_MIN_BLOCKSIZE ||
+	    sbi->block_size > MFS_MAX_BLOCKSIZE)
+		return ENOTSUP;
+	else if (sbi->ibmap_blocks == 0 || sbi->zbmap_blocks == 0)
+		return ENOTSUP;
+	else if (sbi->ninodes == 0 || sbi->nzones == 0)
+		return ENOTSUP;
+	else if (sbi->firstdatazone == 0)
+		return ENOTSUP;
+
+	return EOK;
+}
+
 static int
 mfs_close(service_id_t service_id, fs_index_t index)
@@ -1087,4 +1136,19 @@
 
 	return mfs_node_put(fn);
+}
+
+/** Check if a given number is a power of two.
+ *
+ * @param n	The number to check.
+ *
+ * @return	true if it is a power of two, false otherwise.
+ */
+static bool
+is_power_of_two(uint32_t n)
+{
+	if (n == 0)
+		return false;
+
+	return (n & (n - 1)) == 0;
 }
 
Index: uspace/srv/fs/mfs/mfs_rw.c
===================================================================
--- uspace/srv/fs/mfs/mfs_rw.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/mfs/mfs_rw.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -31,9 +31,10 @@
  */
 
+#include <align.h>
 #include "mfs.h"
 
 static int
 rw_map_ondisk(uint32_t *b, const struct mfs_node *mnode, int rblock,
-	      bool write_mode, uint32_t w_block);
+    bool write_mode, uint32_t w_block);
 
 static int
@@ -67,9 +68,9 @@
 	const int block_size = sbi->block_size;
 
-	/*Compute relative block number in file*/
+	/* Compute relative block number in file */
 	int rblock = pos / block_size;
 
-	if (mnode->ino_i->i_size < pos) {
-		/*Trying to read beyond the end of file*/
+	if (ROUND_UP(mnode->ino_i->i_size, sbi->block_size) < pos) {
+		/* Trying to read beyond the end of file */
 		r = EOK;
 		*b = 0;
@@ -84,14 +85,14 @@
 int
 mfs_write_map(struct mfs_node *mnode, const uint32_t pos, uint32_t new_zone,
-	  uint32_t *old_zone)
+    uint32_t *old_zone)
 {
 	const struct mfs_sb_info *sbi = mnode->instance->sbi;
 
 	if (pos >= sbi->max_file_size) {
-		/*Can't write beyond the maximum file size*/
+		/* Can't write beyond the maximum file size */
 		return EINVAL;
 	}
 
-	/*Compute the relative block number in file*/
+	/* Compute the relative block number in file */
 	int rblock = pos / sbi->block_size;
 
@@ -101,5 +102,5 @@
 static int
 rw_map_ondisk(uint32_t *b, const struct mfs_node *mnode, int rblock,
-	      bool write_mode, uint32_t w_block)
+    bool write_mode, uint32_t w_block)
 {
 	int r, nr_direct;
@@ -122,5 +123,5 @@
 	}
 
-	/*Check if the wanted block is in the direct zones*/
+	/* Check if the wanted block is in the direct zones */
 	if (rblock < nr_direct) {
 		*b = ino_i->i_dzone[rblock];
@@ -135,5 +136,5 @@
 
 	if (rblock < ptrs_per_block) {
-		/*The wanted block is in the single indirect zone chain*/
+		/* The wanted block is in the single indirect zone chain */
 		if (ino_i->i_izone[0] == 0) {
 			if (write_mode && !deleting) {
@@ -146,5 +147,5 @@
 				ino_i->dirty = true;
 			} else {
-				/*Sparse block*/
+				/* Sparse block */
 				*b = 0;
 				return EOK;
@@ -167,7 +168,7 @@
 	rblock -= ptrs_per_block;
 
-	/*The wanted block is in the double indirect zone chain*/
-
-	/*read the first indirect zone of the chain*/
+	/* The wanted block is in the double indirect zone chain */
+
+	/* Read the first indirect zone of the chain */
 	if (ino_i->i_izone[1] == 0) {
 		if (write_mode && !deleting) {
@@ -180,5 +181,5 @@
 			ino_i->dirty = true;
 		} else {
-			/*Sparse block*/
+			/* Sparse block */
 			*b = 0;
 			return EOK;
@@ -191,10 +192,10 @@
 
 	/*
-	 *Compute the position of the second indirect
-	 *zone pointer in the chain.
+	 * Compute the position of the second indirect
+	 * zone pointer in the chain.
 	 */
 	uint32_t ind2_off = rblock / ptrs_per_block;
 
-	/*read the second indirect zone of the chain*/
+	/* read the second indirect zone of the chain */
 	if (ind_zone[ind2_off] == 0) {
 		if (write_mode && !deleting) {
@@ -207,5 +208,5 @@
 			write_ind_zone(inst, ino_i->i_izone[1], ind_zone);
 		} else {
-			/*Sparse block*/
+			/* Sparse block */
 			r = EOK;
 			*b = 0;
@@ -232,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.
@@ -263,5 +264,5 @@
 
 	if (rblock < nr_direct) {
-		/*free the single indirect zone*/
+		/* Free the single indirect zone */
 		if (ino_i->i_izone[0]) {
 			r = mfs_free_zone(inst, ino_i->i_izone[0]);
@@ -281,9 +282,9 @@
 		++fzone_to_free;
 
-	/*free the entire double indirect zone*/
+	/* Free the entire double indirect zone */
 	uint32_t *dbl_zone;
 
 	if (ino_i->i_izone[1] == 0) {
-		/*Nothing to be done*/
+		/* Nothing to be done */
 		return EOK;
 	}
@@ -349,5 +350,5 @@
 	block_t *b;
 	const int max_ind_zone_ptrs = (MFS_MAX_BLOCKSIZE / sizeof(uint16_t)) *
-				      sizeof(uint32_t);
+	    sizeof(uint32_t);
 
 	*ind_zone = malloc(max_ind_zone_ptrs);
Index: uspace/srv/fs/mfs/mfs_utils.c
===================================================================
--- uspace/srv/fs/mfs/mfs_utils.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/mfs/mfs_utils.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -34,5 +34,6 @@
 #include "mfs.h"
 
-uint16_t conv16(bool native, uint16_t n)
+uint16_t
+conv16(bool native, uint16_t n)
 {
 	if (native)
@@ -42,5 +43,6 @@
 }
 
-uint32_t conv32(bool native, uint32_t n)
+uint32_t
+conv32(bool native, uint32_t n)
 {
 	if (native)
@@ -50,5 +52,6 @@
 }
 
-uint64_t conv64(bool native, uint64_t n)
+uint64_t
+conv64(bool native, uint64_t n)
 {
 	if (native)
Index: uspace/srv/fs/tmpfs/tmpfs.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/fs/tmpfs/tmpfs.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -59,4 +59,5 @@
 	.concurrent_read_write = false,
 	.write_retains_size = false,
+	.instance = 0,
 };
 
@@ -64,4 +65,13 @@
 {
 	printf(NAME ": HelenOS TMPFS file system server\n");
+
+	if (argc == 3) {
+		if (!str_cmp(argv[1], "--instance"))
+			tmpfs_vfs_info.instance = strtol(argv[2], NULL, 10);
+		else {
+			printf(NAME " Unrecognized parameters");
+			return -1;
+		}
+	}
 	
 	if (!tmpfs_init()) {
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/hid/console/console.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -344,4 +344,19 @@
 }
 
+static console_t *cons_get_active_uspace(void)
+{
+	fibril_mutex_lock(&switch_mtx);
+
+	console_t *active_uspace = active_console;
+	if (active_uspace == kernel_console) {
+		active_uspace = prev_console;
+	}
+	assert(active_uspace != kernel_console);
+
+	fibril_mutex_unlock(&switch_mtx);
+
+	return active_uspace;
+}
+
 static ssize_t limit(ssize_t val, ssize_t lo, ssize_t hi)
 {
@@ -466,5 +481,14 @@
 				event->c = c;
 				
-				prodcons_produce(&active_console->input_pc, &event->link);
+				/*
+				 * Kernel console does not read events
+				 * from us, so we will redirect them
+				 * to the (last) active userspace console
+				 * if necessary.
+				 */
+				console_t *target_console = cons_get_active_uspace();
+				
+				prodcons_produce(&target_console->input_pc,
+				    &event->link);
 			}
 			
@@ -904,4 +928,5 @@
 		atomic_set(&consoles[i].refcnt, 0);
 		fibril_mutex_initialize(&consoles[i].mtx);
+		prodcons_initialize(&consoles[i].input_pc);
 		
 		if (graphics_state == GRAPHICS_FULL) {
@@ -942,5 +967,4 @@
 		}
 		
-		prodcons_initialize(&consoles[i].input_pc);
 		cons_redraw_state(&consoles[i]);
 		
Index: uspace/srv/hid/input/ctl/kbdev.c
===================================================================
--- uspace/srv/hid/input/ctl/kbdev.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/hid/input/ctl/kbdev.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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 a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/hid/input/proto/mousedev.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -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/hw/irc/apic/apic.c
===================================================================
--- uspace/srv/hw/irc/apic/apic.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/hw/irc/apic/apic.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -133,4 +133,6 @@
 	// FIXME: get the map from the kernel, even though this may work
 	//	  for simple cases
+	if (irq == 0)
+		return 2;
 	return irq;
 }
@@ -206,7 +208,10 @@
 	}
 
-	if (pio_enable((void *) IO_APIC_BASE, IO_APIC_SIZE,
-	    (void **) &io_apic) != EOK)
+	int rc = pio_enable((void *) IO_APIC_BASE, IO_APIC_SIZE,
+		(void **) &io_apic);
+	if (rc != EOK) {
+		printf("%s: Failed to enable PIO for APIC: %d\n", NAME, rc);
 		return false;	
+	}
 	
 	async_set_client_connection(apic_connection);
Index: uspace/srv/hw/netif/ne2000/Makefile
===================================================================
--- uspace/srv/hw/netif/ne2000/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,47 +1,0 @@
-#
-# Copyright (c) 2005 Martin Decky
-# Copyright (c) 2007 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.
-#
-
-USPACE_PREFIX = ../../../..
-ROOT_PATH = $(USPACE_PREFIX)/..
-LIBS = $(LIBNET_PREFIX)/libnet.a
-EXTRA_CFLAGS = -I$(LIBNET_PREFIX)/include
-
-COMMON_MAKEFILE = $(ROOT_PATH)/Makefile.common
-CONFIG_MAKEFILE = $(ROOT_PATH)/Makefile.config
-
--include $(COMMON_MAKEFILE)
--include $(CONFIG_MAKEFILE)
-
-BINARY = ne2000
-
-SOURCES = \
-	dp8390.c \
-	ne2000.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/hw/netif/ne2000/dp8390.c
===================================================================
--- uspace/srv/hw/netif/ne2000/dp8390.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,656 +1,0 @@
-/*
- * Copyright (c) 2009 Lukas Mejdrech
- * Copyright (c) 2011 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE 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.
- */
-
-/*
- * This code is based upon the NE2000 driver for MINIX,
- * distributed according to a BSD-style license.
- *
- * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
- * Copyright (c) 1992, 1994 Philip Homburg
- * Copyright (c) 1996 G. Falzoni
- *
- */
-
-/** @addtogroup ne2000
- *  @{
- */
-
-/** @file
- *
- * NE2000 (based on DP8390) network interface core implementation.
- * Only the basic NE2000 PIO (ISA) interface is supported, remote
- * DMA is completely absent from this code for simplicity.
- *
- */
-
-#include <assert.h>
-#include <byteorder.h>
-#include <errno.h>
-#include <stdio.h>
-#include <libarch/ddi.h>
-#include <net/packet.h>
-#include <packet_client.h>
-#include "dp8390.h"
-
-/** Page size */
-#define DP_PAGE  256
-
-/** 6 * DP_PAGE >= 1514 bytes */
-#define SQ_PAGES  6
-
-/* NE2000 implementation. */
-
-/** NE2000 Data Register */
-#define NE2K_DATA  0x0010
-
-/** NE2000 Reset register */
-#define NE2K_RESET  0x001f
-
-/** NE2000 data start */
-#define NE2K_START  0x4000
-
-/** NE2000 data size */
-#define NE2K_SIZE  0x4000
-
-/** NE2000 retry count */
-#define NE2K_RETRY  0x1000
-
-/** NE2000 error messages rate limiting */
-#define NE2K_ERL  10
-
-/** Minimum Ethernet packet size in bytes */
-#define ETH_MIN_PACK_SIZE  60
-
-/** Maximum Ethernet packet size in bytes */
-#define ETH_MAX_PACK_SIZE_TAGGED  1518
-
-/** Type definition of the receive header
- *
- */
-typedef struct {
-	/** Copy of RSR */
-	uint8_t status;
-	
-	/** Pointer to next packet */
-	uint8_t next;
-	
-	/** Receive Byte Count Low */
-	uint8_t rbcl;
-	
-	/** Receive Byte Count High */
-	uint8_t rbch;
-} recv_header_t;
-
-/** Read a memory block word by word.
- *
- * @param[in]  port Source address.
- * @param[out] buf  Destination buffer.
- * @param[in]  size Memory block size in bytes.
- *
- */
-static void pio_read_buf_16(void *port, void *buf, size_t size)
-{
-	size_t i;
-	
-	for (i = 0; (i << 1) < size; i++)
-		*((uint16_t *) buf + i) = pio_read_16((ioport16_t *) (port));
-}
-
-/** Write a memory block word by word.
- *
- * @param[in] port Destination address.
- * @param[in] buf  Source buffer.
- * @param[in] size Memory block size in bytes.
- *
- */
-static void pio_write_buf_16(void *port, void *buf, size_t size)
-{
-	size_t i;
-	
-	for (i = 0; (i << 1) < size; i++)
-		pio_write_16((ioport16_t *) port, *((uint16_t *) buf + i));
-}
-
-static void ne2k_download(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
-{
-	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_RSAR0, addr & 0xff);
-	pio_write_8(ne2k->port + DP_RSAR1, (addr >> 8) & 0xff);
-	pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
-	
-	if (esize != 0) {
-		pio_read_buf_16(ne2k->data_port, buf, esize);
-		size -= esize;
-		buf += esize;
-	}
-	
-	if (size) {
-		assert(size == 1);
-		
-		uint16_t word = pio_read_16(ne2k->data_port);
-		memcpy(buf, &word, 1);
-	}
-}
-
-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_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);
-	pio_write_8(ne2k->port + DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
-	
-	if (esize != 0) {
-		pio_write_buf_16(ne2k->data_port, buf, esize);
-		size -= esize;
-		buf += esize;
-	}
-	
-	if (size) {
-		assert(size == 1);
-		
-		uint16_t word = 0;
-		
-		memcpy(&word, buf, 1);
-		pio_write_16(ne2k->data_port, word);
-	}
-}
-
-static void ne2k_init(ne2k_t *ne2k)
-{
-	unsigned int i;
-	
-	/* Reset the ethernet card */
-	uint8_t val = pio_read_8(ne2k->port + NE2K_RESET);
-	usleep(2000);
-	pio_write_8(ne2k->port + NE2K_RESET, val);
-	usleep(2000);
-	
-	/* Reset the DP8390 */
-	pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
-	for (i = 0; i < NE2K_RETRY; i++) {
-		if (pio_read_8(ne2k->port + DP_ISR) != 0)
-			break;
-	}
-}
-
-/** Probe and initialize the network interface.
- *
- * @param[in,out] ne2k Network interface structure.
- * @param[in]     port Device address.
- * @param[in]     irq  Device interrupt vector.
- *
- * @return EOK on success.
- * @return EXDEV if the network interface was not recognized.
- *
- */
-int ne2k_probe(ne2k_t *ne2k, void *port, int irq)
-{
-	unsigned int i;
-	
-	/* General initialization */
-	ne2k->port = port;
-	ne2k->data_port = ne2k->port + NE2K_DATA;
-	ne2k->irq = irq;
-	ne2k->probed = false;
-	ne2k->up = false;
-	
-	ne2k_init(ne2k);
-	
-	/* Check if the DP8390 is really there */
-	uint8_t val = pio_read_8(ne2k->port + DP_CR);
-	if ((val & (CR_STP | CR_DM_ABORT)) != (CR_STP | CR_DM_ABORT))
-		return EXDEV;
-	
-	/* Disable the receiver and init TCR and DCR */
-	pio_write_8(ne2k->port + DP_RCR, RCR_MON);
-	pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
-	pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
-	
-	/* Setup a transfer to get the MAC address */
-	pio_write_8(ne2k->port + DP_RBCR0, ETH_ADDR << 1);
-	pio_write_8(ne2k->port + DP_RBCR1, 0);
-	pio_write_8(ne2k->port + DP_RSAR0, 0);
-	pio_write_8(ne2k->port + DP_RSAR1, 0);
-	pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
-	
-	for (i = 0; i < ETH_ADDR; i++)
-		ne2k->mac[i] = pio_read_16(ne2k->data_port);
-	
-	ne2k->probed = true;
-	return EOK;
-}
-
-/** Start the network interface.
- *
- * @param[in,out] ne2k Network interface structure.
- *
- * @return EOK on success.
- * @return EXDEV if the network interface is disabled.
- *
- */
-int ne2k_up(ne2k_t *ne2k)
-{
-	if (!ne2k->probed)
-		return EXDEV;
-	
-	ne2k_init(ne2k);
-	
-	/*
-	 * Setup send queue. Use the first
-	 * SQ_PAGES of NE2000 memory for the send
-	 * buffer.
-	 */
-	ne2k->sq.dirty = false;
-	ne2k->sq.page = NE2K_START / DP_PAGE;
-	fibril_mutex_initialize(&ne2k->sq_mutex);
-	fibril_condvar_initialize(&ne2k->sq_cv);
-	
-	/*
-	 * Setup receive ring buffer. Use all the rest
-	 * of the NE2000 memory (except the first SQ_PAGES
-	 * reserved for the send buffer) for the receive
-	 * ring buffer.
-	 */
-	ne2k->start_page = ne2k->sq.page + SQ_PAGES;
-	ne2k->stop_page = ne2k->sq.page + NE2K_SIZE / DP_PAGE;
-	
-	/*
-	 * Initialization of the DP8390 following the mandatory procedure
-	 * in reference manual ("DP8390D/NS32490D NIC Network Interface
-	 * Controller", National Semiconductor, July 1995, Page 29).
-	 */
-	
-	/* Step 1: */
-	pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
-	
-	/* Step 2: */
-	pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
-	
-	/* Step 3: */
-	pio_write_8(ne2k->port + DP_RBCR0, 0);
-	pio_write_8(ne2k->port + DP_RBCR1, 0);
-	
-	/* Step 4: */
-	pio_write_8(ne2k->port + DP_RCR, RCR_AB);
-	
-	/* Step 5: */
-	pio_write_8(ne2k->port + DP_TCR, TCR_INTERNAL);
-	
-	/* Step 6: */
-	pio_write_8(ne2k->port + DP_BNRY, ne2k->start_page);
-	pio_write_8(ne2k->port + DP_PSTART, ne2k->start_page);
-	pio_write_8(ne2k->port + DP_PSTOP, ne2k->stop_page);
-	
-	/* Step 7: */
-	pio_write_8(ne2k->port + DP_ISR, 0xff);
-	
-	/* Step 8: */
-	pio_write_8(ne2k->port + DP_IMR,
-	    IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
-	
-	/* Step 9: */
-	pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
-	
-	pio_write_8(ne2k->port + DP_PAR0, ne2k->mac[0]);
-	pio_write_8(ne2k->port + DP_PAR1, ne2k->mac[1]);
-	pio_write_8(ne2k->port + DP_PAR2, ne2k->mac[2]);
-	pio_write_8(ne2k->port + DP_PAR3, ne2k->mac[3]);
-	pio_write_8(ne2k->port + DP_PAR4, ne2k->mac[4]);
-	pio_write_8(ne2k->port + DP_PAR5, ne2k->mac[5]);
-	
-	pio_write_8(ne2k->port + DP_MAR0, 0xff);
-	pio_write_8(ne2k->port + DP_MAR1, 0xff);
-	pio_write_8(ne2k->port + DP_MAR2, 0xff);
-	pio_write_8(ne2k->port + DP_MAR3, 0xff);
-	pio_write_8(ne2k->port + DP_MAR4, 0xff);
-	pio_write_8(ne2k->port + DP_MAR5, 0xff);
-	pio_write_8(ne2k->port + DP_MAR6, 0xff);
-	pio_write_8(ne2k->port + DP_MAR7, 0xff);
-	
-	pio_write_8(ne2k->port + DP_CURR, ne2k->start_page + 1);
-	
-	/* Step 10: */
-	pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_DM_ABORT | CR_STA);
-	
-	/* Step 11: */
-	pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
-	
-	/* Reset counters by reading */
-	pio_read_8(ne2k->port + DP_CNTR0);
-	pio_read_8(ne2k->port + DP_CNTR1);
-	pio_read_8(ne2k->port + DP_CNTR2);
-	
-	/* Finish the initialization */
-	ne2k->up = true;
-	return EOK;
-}
-
-/** Stop the network interface.
- *
- * @param[in,out] ne2k Network interface structure.
- *
- */
-void ne2k_down(ne2k_t *ne2k)
-{
-	if ((ne2k->probed) && (ne2k->up)) {
-		pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
-		ne2k_init(ne2k);
-		ne2k->up = false;
-	}
-}
-
-/** Send a frame.
- *
- * @param[in,out] ne2k   Network interface structure.
- * @param[in]     packet Frame to be sent.
- *
- */
-void ne2k_send(ne2k_t *ne2k, packet_t *packet)
-{
-	assert(ne2k->probed);
-	assert(ne2k->up);
-	
-	fibril_mutex_lock(&ne2k->sq_mutex);
-	
-	while (ne2k->sq.dirty)
-		fibril_condvar_wait(&ne2k->sq_cv, &ne2k->sq_mutex);
-	
-	void *buf = packet_get_data(packet);
-	size_t size = packet_get_data_length(packet);
-	
-	if ((size < ETH_MIN_PACK_SIZE) || (size > ETH_MAX_PACK_SIZE_TAGGED)) {
-		fibril_mutex_unlock(&ne2k->sq_mutex);
-		fprintf(stderr, "%s: Frame dropped (invalid size %zu bytes)\n",
-		    NAME, size);
-		return;
-	}
-	
-	/* Upload the frame to the ethernet card */
-	ne2k_upload(ne2k, buf, ne2k->sq.page * DP_PAGE, size);
-	ne2k->sq.dirty = true;
-	ne2k->sq.size = size;
-	
-	/* Initialize the transfer */
-	pio_write_8(ne2k->port + DP_TPSR, ne2k->sq.page);
-	pio_write_8(ne2k->port + DP_TBCR0, size & 0xff);
-	pio_write_8(ne2k->port + DP_TBCR1, (size >> 8) & 0xff);
-	pio_write_8(ne2k->port + DP_CR, CR_TXP | CR_STA);
-	
-	fibril_mutex_unlock(&ne2k->sq_mutex);
-}
-
-static void ne2k_reset(ne2k_t *ne2k)
-{
-	unsigned int i;
-	
-	/* Stop the chip */
-	pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
-	pio_write_8(ne2k->port + DP_RBCR0, 0);
-	pio_write_8(ne2k->port + DP_RBCR1, 0);
-	
-	for (i = 0; i < NE2K_RETRY; i++) {
-		if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RST) != 0)
-			break;
-	}
-	
-	pio_write_8(ne2k->port + DP_TCR, TCR_1EXTERNAL | TCR_OFST);
-	pio_write_8(ne2k->port + DP_CR, CR_STA | CR_DM_ABORT);
-	pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
-	
-	/* Acknowledge the ISR_RDC (remote DMA) interrupt */
-	for (i = 0; i < NE2K_RETRY; i++) {
-		if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RDC) != 0)
-			break;
-	}
-	
-	uint8_t val = pio_read_8(ne2k->port + DP_ISR);
-	pio_write_8(ne2k->port + DP_ISR, val & ~ISR_RDC);
-	
-	/*
-	 * Reset the transmit ring. If we were transmitting a frame,
-	 * we pretend that the packet is processed. Higher layers will
-	 * retransmit if the packet wasn't actually sent.
-	 */
-	fibril_mutex_lock(&ne2k->sq_mutex);
-	ne2k->sq.dirty = false;
-	fibril_mutex_unlock(&ne2k->sq_mutex);
-}
-
-static frame_t *ne2k_receive_frame(ne2k_t *ne2k, uint8_t page, size_t length)
-{
-	frame_t *frame = (frame_t *) malloc(sizeof(frame_t));
-	if (frame == NULL)
-		return NULL;
-	
-	link_initialize(&frame->link);
-	
-	frame->packet = netif_packet_get_1(length);
-	if (frame->packet == NULL) {
-		free(frame);
-		return NULL;
-	}
-	
-	void *buf = packet_suffix(frame->packet, length);
-	bzero(buf, length);
-	uint8_t last = page + length / DP_PAGE;
-	
-	if (last >= ne2k->stop_page) {
-		size_t left = (ne2k->stop_page - page) * DP_PAGE
-		    - sizeof(recv_header_t);
-		
-		ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
-		    left);
-		ne2k_download(ne2k, buf + left, ne2k->start_page * DP_PAGE,
-		    length - left);
-	} else
-		ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
-		    length);
-	
-	ne2k->stats.receive_packets++;
-	return frame;
-}
-
-static list_t *ne2k_receive(ne2k_t *ne2k)
-{
-	/*
-	 * Allocate memory for the list of received frames.
-	 * If the allocation fails here we still receive the
-	 * frames from the network, but they will be lost.
-	 */
-	list_t *frames = (list_t *) malloc(sizeof(list_t));
-	if (frames != NULL)
-		list_initialize(frames);
-	
-	while (true) {
-		uint8_t boundary = pio_read_8(ne2k->port + DP_BNRY) + 1;
-		
-		if (boundary == ne2k->stop_page)
-			boundary = ne2k->start_page;
-		
-		pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_STA);
-		uint8_t current = pio_read_8(ne2k->port + DP_CURR);
-		pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STA);
-		
-		if (current == boundary)
-			/* No more frames to process */
-			break;
-		
-		recv_header_t header;
-		size_t size = sizeof(header);
-		size_t offset = boundary * DP_PAGE;
-		
-		/* Get the frame header */
-		pio_write_8(ne2k->port + DP_RBCR0, size & 0xff);
-		pio_write_8(ne2k->port + DP_RBCR1, (size >> 8) & 0xff);
-		pio_write_8(ne2k->port + DP_RSAR0, offset & 0xff);
-		pio_write_8(ne2k->port + DP_RSAR1, (offset >> 8) & 0xff);
-		pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
-		
-		pio_read_buf_16(ne2k->data_port, (void *) &header, size);
-		
-		size_t length =
-		    (((size_t) header.rbcl) | (((size_t) header.rbch) << 8)) - size;
-		uint8_t next = header.next;
-		
-		if ((length < ETH_MIN_PACK_SIZE)
-		    || (length > ETH_MAX_PACK_SIZE_TAGGED)) {
-			fprintf(stderr, "%s: Rant frame (%zu bytes)\n", NAME, length);
-			next = current;
-		} else if ((header.next < ne2k->start_page)
-		    || (header.next > ne2k->stop_page)) {
-			fprintf(stderr, "%s: Malformed next frame %u\n", NAME,
-			    header.next);
-			next = current;
-		} else if (header.status & RSR_FO) {
-			/*
-			 * This is very serious, so we issue a warning and
-			 * reset the buffers.
-			 */
-			fprintf(stderr, "%s: FIFO overrun\n", NAME);
-			ne2k->overruns++;
-			next = current;
-		} else if ((header.status & RSR_PRX) && (ne2k->up)) {
-			if (frames != NULL) {
-				frame_t *frame = ne2k_receive_frame(ne2k, boundary, length);
-				if (frame != NULL)
-					list_append(&frame->link, frames);
-			}
-		}
-		
-		/*
-		 * Update the boundary pointer
-		 * to the value of the page
-		 * prior to the next packet to
-		 * be processed.
-		 */
-		if (next == ne2k->start_page)
-			next = ne2k->stop_page - 1;
-		else
-			next--;
-		
-		pio_write_8(ne2k->port + DP_BNRY, next);
-	}
-	
-	return frames;
-}
-
-list_t *ne2k_interrupt(ne2k_t *ne2k, uint8_t isr, uint8_t tsr)
-{
-	/* List of received frames */
-	list_t *frames = NULL;
-	
-	if (isr & (ISR_PTX | ISR_TXE)) {
-		if (isr & ISR_TXE)
-			ne2k->stats.send_errors++;
-		else {
-			if (tsr & TSR_PTX)
-				ne2k->stats.send_packets++;
-			
-			if (tsr & TSR_COL)
-				ne2k->stats.collisions++;
-			
-			if (tsr & TSR_ABT)
-				ne2k->stats.send_aborted_errors++;
-			
-			if (tsr & TSR_CRS)
-				ne2k->stats.send_carrier_errors++;
-			
-			if (tsr & TSR_FU) {
-				ne2k->underruns++;
-				if (ne2k->underruns < NE2K_ERL)
-					fprintf(stderr, "%s: FIFO underrun\n", NAME);
-			}
-			
-			if (tsr & TSR_CDH) {
-				ne2k->stats.send_heartbeat_errors++;
-				if (ne2k->stats.send_heartbeat_errors < NE2K_ERL)
-					fprintf(stderr, "%s: CD heartbeat failure\n", NAME);
-			}
-			
-			if (tsr & TSR_OWC)
-				ne2k->stats.send_window_errors++;
-		}
-		
-		fibril_mutex_lock(&ne2k->sq_mutex);
-		
-		if (ne2k->sq.dirty) {
-			/* Prepare the buffer for next packet */
-			ne2k->sq.dirty = false;
-			ne2k->sq.size = 0;
-			
-			/* Signal a next frame to be sent */
-			fibril_condvar_broadcast(&ne2k->sq_cv);
-		} else {
-			ne2k->misses++;
-			if (ne2k->misses < NE2K_ERL)
-				fprintf(stderr, "%s: Spurious PTX interrupt\n", NAME);
-		}
-		
-		fibril_mutex_unlock(&ne2k->sq_mutex);
-	}
-	
-	if (isr & ISR_RXE)
-		ne2k->stats.receive_errors++;
-	
-	if (isr & ISR_CNT) {
-		ne2k->stats.receive_crc_errors +=
-		    pio_read_8(ne2k->port + DP_CNTR0);
-		ne2k->stats.receive_frame_errors +=
-		    pio_read_8(ne2k->port + DP_CNTR1);
-		ne2k->stats.receive_missed_errors +=
-		    pio_read_8(ne2k->port + DP_CNTR2);
-	}
-	
-	if (isr & ISR_PRX)
-		frames = ne2k_receive(ne2k);
-	
-	if (isr & ISR_RST) {
-		/*
-		 * The chip is stopped, and all arrived
-		 * frames are delivered.
-		 */
-		ne2k_reset(ne2k);
-	}
-	
-	/* Unmask interrupts to be processed in the next round */
-	pio_write_8(ne2k->port + DP_IMR,
-	    IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
-	
-	return frames;
-}
-
-/** @}
- */
Index: uspace/srv/hw/netif/ne2000/dp8390.h
===================================================================
--- uspace/srv/hw/netif/ne2000/dp8390.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,248 +1,0 @@
-/*
- * Copyright (c) 2009 Lukas Mejdrech
- * Copyright (c) 2011 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE 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.
- */
-
-/*
- * This code is based upon the NE2000 driver for MINIX,
- * distributed according to a BSD-style license.
- *
- * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
- * Copyright (c) 1992, 1994 Philip Homburg
- * Copyright (c) 1996 G. Falzoni
- *
- */
-
-/** @addtogroup ne2000
- *  @{
- */
-
-/** @file
- *  DP8390 network interface definitions.
- */
-
-#ifndef __NET_NETIF_DP8390_H__
-#define __NET_NETIF_DP8390_H__
-
-#include <fibril_synch.h>
-#include <adt/list.h>
-#include <net/packet.h>
-#include <netif_skel.h>
-
-/** Module name */
-#define NAME  "ne2000"
-
-/** Input/output size */
-#define NE2K_IO_SIZE  0x0020
-
-/** Ethernet address length */
-#define ETH_ADDR  6
-
-/* National Semiconductor DP8390 Network Interface Controller. */
-
-/** Page 0, for reading */
-#define DP_CR     0x00  /**< Command Register */
-#define DP_CLDA0  0x01  /**< Current Local DMA Address 0 */
-#define DP_CLDA1  0x02  /**< Current Local DMA Address 1 */
-#define DP_BNRY   0x03  /**< Boundary Pointer */
-#define DP_TSR    0x04  /**< Transmit Status Register */
-#define DP_NCR    0x05  /**< Number of Collisions Register */
-#define DP_FIFO   0x06  /**< FIFO */
-#define DP_ISR    0x07  /**< Interrupt Status Register */
-#define DP_CRDA0  0x08  /**< Current Remote DMA Address 0 */
-#define DP_CRDA1  0x09  /**< Current Remote DMA Address 1 */
-#define DP_RSR    0x0c  /**< Receive Status Register */
-#define DP_CNTR0  0x0d  /**< Tally Counter 0 */
-#define DP_CNTR1  0x0e  /**< Tally Counter 1 */
-#define DP_CNTR2  0x0f  /**< Tally Counter 2 */
-
-/** Page 0, for writing */
-#define DP_PSTART  0x01  /**< Page Start Register*/
-#define DP_PSTOP   0x02  /**< Page Stop Register */
-#define DP_TPSR    0x04  /**< Transmit Page Start Register */
-#define DP_TBCR0   0x05  /**< Transmit Byte Count Register 0 */
-#define DP_TBCR1   0x06  /**< Transmit Byte Count Register 1 */
-#define DP_RSAR0   0x08  /**< Remote Start Address Register 0 */
-#define DP_RSAR1   0x09  /**< Remote Start Address Register 1 */
-#define DP_RBCR0   0x0a  /**< Remote Byte Count Register 0 */
-#define DP_RBCR1   0x0b  /**< Remote Byte Count Register 1 */
-#define DP_RCR     0x0c  /**< Receive Configuration Register */
-#define DP_TCR     0x0d  /**< Transmit Configuration Register */
-#define DP_DCR     0x0e  /**< Data Configuration Register */
-#define DP_IMR     0x0f  /**< Interrupt Mask Register */
-
-/** Page 1, read/write */
-#define DP_PAR0  0x01  /**< Physical Address Register 0 */
-#define DP_PAR1  0x02  /**< Physical Address Register 1 */
-#define DP_PAR2  0x03  /**< Physical Address Register 2 */
-#define DP_PAR3  0x04  /**< Physical Address Register 3 */
-#define DP_PAR4  0x05  /**< Physical Address Register 4 */
-#define DP_PAR5  0x06  /**< Physical Address Register 5 */
-#define DP_CURR  0x07  /**< Current Page Register */
-#define DP_MAR0  0x08  /**< Multicast Address Register 0 */
-#define DP_MAR1  0x09  /**< Multicast Address Register 1 */
-#define DP_MAR2  0x0a  /**< Multicast Address Register 2 */
-#define DP_MAR3  0x0b  /**< Multicast Address Register 3 */
-#define DP_MAR4  0x0c  /**< Multicast Address Register 4 */
-#define DP_MAR5  0x0d  /**< Multicast Address Register 5 */
-#define DP_MAR6  0x0e  /**< Multicast Address Register 6 */
-#define DP_MAR7  0x0f  /**< Multicast Address Register 7 */
-
-/* Bits in Command Register */
-#define CR_STP       0x01  /**< Stop (software reset) */
-#define CR_STA       0x02  /**< Start (activate NIC) */
-#define CR_TXP       0x04  /**< Transmit Packet */
-#define CR_DMA       0x38  /**< Mask for DMA control */
-#define CR_DM_NOP    0x00  /**< DMA: No Operation */
-#define CR_DM_RR     0x08  /**< DMA: Remote Read */
-#define CR_DM_RW     0x10  /**< DMA: Remote Write */
-#define CR_DM_SP     0x18  /**< DMA: Send Packet */
-#define CR_DM_ABORT  0x20  /**< DMA: Abort Remote DMA Operation */
-#define CR_PS        0xc0  /**< Mask for Page Select */
-#define CR_PS_P0     0x00  /**< Register Page 0 */
-#define CR_PS_P1     0x40  /**< Register Page 1 */
-#define CR_PS_P2     0x80  /**< Register Page 2 */
-#define CR_PS_T1     0xc0  /**< Test Mode Register Map */
-
-/* Bits in Interrupt State Register */
-#define ISR_PRX  0x01  /**< Packet Received with no errors */
-#define ISR_PTX  0x02  /**< Packet Transmitted with no errors */
-#define ISR_RXE  0x04  /**< Receive Error */
-#define ISR_TXE  0x08  /**< Transmit Error */
-#define ISR_OVW  0x10  /**< Overwrite Warning */
-#define ISR_CNT  0x20  /**< Counter Overflow */
-#define ISR_RDC  0x40  /**< Remote DMA Complete */
-#define ISR_RST  0x80  /**< Reset Status */
-
-/* Bits in Interrupt Mask Register */
-#define IMR_PRXE  0x01  /**< Packet Received Interrupt Enable */
-#define IMR_PTXE  0x02  /**< Packet Transmitted Interrupt Enable */
-#define IMR_RXEE  0x04  /**< Receive Error Interrupt Enable */
-#define IMR_TXEE  0x08  /**< Transmit Error Interrupt Enable */
-#define IMR_OVWE  0x10  /**< Overwrite Warning Interrupt Enable */
-#define IMR_CNTE  0x20  /**< Counter Overflow Interrupt Enable */
-#define IMR_RDCE  0x40  /**< DMA Complete Interrupt Enable */
-
-/* Bits in Data Configuration Register */
-#define DCR_WTS        0x01  /**< Word Transfer Select */
-#define DCR_BYTEWIDE   0x00  /**< WTS: byte wide transfers */
-#define DCR_WORDWIDE   0x01  /**< WTS: word wide transfers */
-#define DCR_BOS        0x02  /**< Byte Order Select */
-#define DCR_LTLENDIAN  0x00  /**< BOS: Little Endian */
-#define DCR_BIGENDIAN  0x02  /**< BOS: Big Endian */
-#define DCR_LAS        0x04  /**< Long Address Select */
-#define DCR_BMS        0x08  /**< Burst Mode Select */
-#define DCR_AR         0x10  /**< Autoinitialize Remote */
-#define DCR_FTS        0x60  /**< Fifo Threshold Select */
-#define DCR_2BYTES     0x00  /**< 2 bytes */
-#define DCR_4BYTES     0x40  /**< 4 bytes */
-#define DCR_8BYTES     0x20  /**< 8 bytes */
-#define DCR_12BYTES    0x60  /**< 12 bytes */
-
-/* Bits in Transmit Configuration Register */
-#define TCR_CRC        0x01  /**< Inhibit CRC */
-#define TCR_ELC        0x06  /**< Encoded Loopback Control */
-#define TCR_NORMAL     0x00  /**< ELC: Normal Operation */
-#define TCR_INTERNAL   0x02  /**< ELC: Internal Loopback */
-#define TCR_0EXTERNAL  0x04  /**< ELC: External Loopback LPBK=0 */
-#define TCR_1EXTERNAL  0x06  /**< ELC: External Loopback LPBK=1 */
-#define TCR_ATD        0x08  /**< Auto Transmit Disable */
-#define TCR_OFST       0x10  /**< Collision Offset Enable (be nice) */
-
-/* Bits in Interrupt Status Register */
-#define TSR_PTX  0x01  /**< Packet Transmitted (without error) */
-#define TSR_DFR  0x02  /**< Transmit Deferred (reserved) */
-#define TSR_COL  0x04  /**< Transmit Collided */
-#define TSR_ABT  0x08  /**< Transmit Aborted */
-#define TSR_CRS  0x10  /**< Carrier Sense Lost */
-#define TSR_FU   0x20  /**< FIFO Underrun */
-#define TSR_CDH  0x40  /**< CD Heartbeat */
-#define TSR_OWC  0x80  /**< Out of Window Collision */
-
-/* Bits in Receive Configuration Register */
-#define RCR_SEP  0x01  /**< Save Errored Packets */
-#define RCR_AR   0x02  /**< Accept Runt Packets */
-#define RCR_AB   0x04  /**< Accept Broadcast */
-#define RCR_AM   0x08  /**< Accept Multicast */
-#define RCR_PRO  0x10  /**< Physical Promiscuous */
-#define RCR_MON  0x20  /**< Monitor Mode */
-
-/* Bits in Receive Status Register */
-#define RSR_PRX  0x01  /**< Packet Received Intact */
-#define RSR_CRC  0x02  /**< CRC Error */
-#define RSR_FAE  0x04  /**< Frame Alignment Error */
-#define RSR_FO   0x08  /**< FIFO Overrun */
-#define RSR_MPA  0x10  /**< Missed Packet */
-#define RSR_PHY  0x20  /**< Multicast Address Match */
-#define RSR_DIS  0x40  /**< Receiver Disabled */
-#define RSR_DFR  0x80  /**< In later manuals: Deferring */
-
-typedef struct {
-	/* Device configuration */
-	void *port;
-	void *data_port;
-	int irq;
-	uint8_t mac[ETH_ADDR];
-	
-	uint8_t start_page;  /**< Ring buffer start page */
-	uint8_t stop_page;   /**< Ring buffer stop page */
-	
-	/* Send queue */
-	struct {
-		bool dirty;    /**< Buffer contains a packet */
-		size_t size;   /**< Packet size */
-		uint8_t page;  /**< Starting page of the buffer */
-	} sq;
-	fibril_mutex_t sq_mutex;
-	fibril_condvar_t sq_cv;
-	
-	/* Driver run-time variables */
-	bool probed;
-	bool up;
-	
-	/* Device statistics */
-	device_stats_t stats;
-	uint64_t misses;     /**< Receive frame misses */
-	uint64_t underruns;  /**< FIFO underruns */
-	uint64_t overruns;   /**< FIFO overruns */
-} ne2k_t;
-
-typedef struct {
-	link_t link;
-	packet_t *packet;
-} frame_t;
-
-extern int ne2k_probe(ne2k_t *, void *, int);
-extern int ne2k_up(ne2k_t *);
-extern void ne2k_down(ne2k_t *);
-extern void ne2k_send(ne2k_t *, packet_t *);
-extern list_t *ne2k_interrupt(ne2k_t *, uint8_t, uint8_t);
-
-#endif
-
-/** @}
- */
Index: uspace/srv/hw/netif/ne2000/ne2000.c
===================================================================
--- uspace/srv/hw/netif/ne2000/ne2000.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,410 +1,0 @@
-/*
- * Copyright (c) 2009 Lukas Mejdrech
- * Copyright (c) 2011 Martin Decky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE 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 ne2000
- *  @{
- */
-
-/** @file
- *  NE2000 network interface implementation.
- */
-
-#include <assert.h>
-#include <async.h>
-#include <ddi.h>
-#include <errno.h>
-#include <err.h>
-#include <malloc.h>
-#include <sysinfo.h>
-#include <ns.h>
-#include <ipc/services.h>
-#include <ipc/irc.h>
-#include <net/modules.h>
-#include <packet_client.h>
-#include <adt/measured_strings.h>
-#include <net/device.h>
-#include <netif_skel.h>
-#include <nil_remote.h>
-#include "dp8390.h"
-
-/** Return the device from the interrupt call.
- *
- *  @param[in] call The interrupt call.
- *
- */
-#define IRQ_GET_DEVICE(call)  ((device_id_t) IPC_GET_IMETHOD(call))
-
-/** Return the ISR from the interrupt call.
- *
- * @param[in] call The interrupt call.
- *
- */
-#define IRQ_GET_ISR(call)  ((int) IPC_GET_ARG2(call))
-
-/** Return the TSR from the interrupt call.
- *
- * @param[in] call The interrupt call.
- *
- */
-#define IRQ_GET_TSR(call)  ((int) IPC_GET_ARG3(call))
-
-static bool irc_service = false;
-static async_sess_t *irc_sess = NULL;
-
-/** NE2000 kernel interrupt command sequence.
- *
- */
-static irq_cmd_t ne2k_cmds[] = {
-	{
-		/* Read Interrupt Status Register */
-		.cmd = CMD_PIO_READ_8,
-		.addr = NULL,
-		.dstarg = 2
-	},
-	{
-		/* Mask supported interrupt causes */
-		.cmd = CMD_BTEST,
-		.value = (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW |
-		    ISR_CNT | ISR_RDC),
-		.srcarg = 2,
-		.dstarg = 3,
-	},
-	{
-		/* Predicate for accepting the interrupt */
-		.cmd = CMD_PREDICATE,
-		.value = 4,
-		.srcarg = 3
-	},
-	{
-		/*
-		 * Mask future interrupts via
-		 * Interrupt Mask Register
-		 */
-		.cmd = CMD_PIO_WRITE_8,
-		.addr = NULL,
-		.value = 0
-	},
-	{
-		/* Acknowledge the current interrupt */
-		.cmd = CMD_PIO_WRITE_A_8,
-		.addr = NULL,
-		.srcarg = 3
-	},
-	{
-		/* Read Transmit Status Register */
-		.cmd = CMD_PIO_READ_8,
-		.addr = NULL,
-		.dstarg = 3
-	},
-	{
-		.cmd = CMD_ACCEPT
-	}
-};
-
-/** NE2000 kernel interrupt code.
- *
- */
-static irq_code_t ne2k_code = {
-	sizeof(ne2k_cmds) / sizeof(irq_cmd_t),
-	ne2k_cmds
-};
-
-/** Handle the interrupt notification.
- *
- * This is the interrupt notification function. It is quarantied
- * that there is only a single instance of this notification
- * function running at one time until the return from the
- * ne2k_interrupt() function (where the interrupts are unmasked
- * again).
- *
- * @param[in] iid  Interrupt notification identifier.
- * @param[in] call Interrupt notification.
- *
- */
-static void irq_handler(ipc_callid_t iid, ipc_call_t *call)
-{
-	device_id_t device_id = IRQ_GET_DEVICE(*call);
-	netif_device_t *device;
-	async_sess_t *nil_sess;
-	ne2k_t *ne2k;
-	
-	fibril_rwlock_read_lock(&netif_globals.lock);
-	
-	nil_sess = netif_globals.nil_sess;
-	
-	if (find_device(device_id, &device) == EOK)
-		ne2k = (ne2k_t *) device->specific;
-	else
-		ne2k = NULL;
-	
-	fibril_rwlock_read_unlock(&netif_globals.lock);
-	
-	if (ne2k != NULL) {
-		list_t *frames =
-		    ne2k_interrupt(ne2k, IRQ_GET_ISR(*call), IRQ_GET_TSR(*call));
-		
-		if (frames != NULL) {
-			while (!list_empty(frames)) {
-				frame_t *frame = list_get_instance(
-				    list_first(frames), frame_t, link);
-				
-				list_remove(&frame->link);
-				nil_received_msg(nil_sess, device_id, frame->packet,
-				    SERVICE_NONE);
-				free(frame);
-			}
-			
-			free(frames);
-		}
-	}
-}
-
-/** Change the network interface state.
- *
- * @param[in,out] device Network interface.
- * @param[in]     state  New state.
- *
- */
-static void change_state(netif_device_t *device, device_state_t state)
-{
-	if (device->state != state) {
-		device->state = state;
-		
-		const char *desc;
-		switch (state) {
-		case NETIF_ACTIVE:
-			desc = "active";
-			break;
-		case NETIF_STOPPED:
-			desc = "stopped";
-			break;
-		default:
-			desc = "unknown";
-		}
-		
-		printf("%s: State changed to %s\n", NAME, desc);
-	}
-}
-
-int netif_specific_message(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *count)
-{
-	return ENOTSUP;
-}
-
-int netif_get_device_stats(device_id_t device_id, device_stats_t *stats)
-{
-	if (!stats)
-		return EBADMEM;
-	
-	netif_device_t *device;
-	int rc = find_device(device_id, &device);
-	if (rc != EOK)
-		return rc;
-	
-	ne2k_t *ne2k = (ne2k_t *) device->specific;
-	
-	memcpy(stats, &ne2k->stats, sizeof(device_stats_t));
-	return EOK;
-}
-
-int netif_get_addr_message(device_id_t device_id, measured_string_t *address)
-{
-	if (!address)
-		return EBADMEM;
-	
-	netif_device_t *device;
-	int rc = find_device(device_id, &device);
-	if (rc != EOK)
-		return rc;
-	
-	ne2k_t *ne2k = (ne2k_t *) device->specific;
-	
-	address->value = ne2k->mac;
-	address->length = ETH_ADDR;
-	return EOK;
-}
-
-int netif_probe_message(device_id_t device_id, int irq, void *io)
-{
-	netif_device_t *device =
-	    (netif_device_t *) malloc(sizeof(netif_device_t));
-	if (!device)
-		return ENOMEM;
-	
-	ne2k_t *ne2k = (ne2k_t *) malloc(sizeof(ne2k_t));
-	if (!ne2k) {
-		free(device);
-		return ENOMEM;
-	}
-	
-	void *port;
-	int rc = pio_enable((void *) io, NE2K_IO_SIZE, &port);
-	if (rc != EOK) {
-		free(ne2k);
-		free(device);
-		return rc;
-	}
-	
-	bzero(device, sizeof(netif_device_t));
-	bzero(ne2k, sizeof(ne2k_t));
-	
-	device->device_id = device_id;
-	device->specific = (void *) ne2k;
-	device->state = NETIF_STOPPED;
-	
-	rc = ne2k_probe(ne2k, port, irq);
-	if (rc != EOK) {
-		printf("%s: No ethernet card found at I/O address %p\n",
-		    NAME, port);
-		free(ne2k);
-		free(device);
-		return rc;
-	}
-	
-	rc = netif_device_map_add(&netif_globals.device_map, device->device_id, device);
-	if (rc != EOK) {
-		free(ne2k);
-		free(device);
-		return rc;
-	}
-	
-	printf("%s: Ethernet card at I/O address %p, IRQ %d, MAC ",
-	    NAME, port, irq);
-	
-	unsigned int i;
-	for (i = 0; i < ETH_ADDR; i++)
-		printf("%02x%c", ne2k->mac[i], i < 5 ? ':' : '\n');
-	
-	return EOK;
-}
-
-int netif_start_message(netif_device_t *device)
-{
-	if (device->state != NETIF_ACTIVE) {
-		ne2k_t *ne2k = (ne2k_t *) device->specific;
-		
-		ne2k_cmds[0].addr = ne2k->port + DP_ISR;
-		ne2k_cmds[3].addr = ne2k->port + DP_IMR;
-		ne2k_cmds[4].addr = ne2k_cmds[0].addr;
-		ne2k_cmds[5].addr = ne2k->port + DP_TSR;
-		
-		int rc = register_irq(ne2k->irq, device->device_id,
-		    device->device_id, &ne2k_code);
-		if (rc != EOK)
-			return rc;
-		
-		rc = ne2k_up(ne2k);
-		if (rc != EOK) {
-			unregister_irq(ne2k->irq, device->device_id);
-			return rc;
-		}
-		
-		change_state(device, NETIF_ACTIVE);
-		
-		if (irc_service) {
-			async_exch_t *exch = async_exchange_begin(irc_sess);
-			async_msg_1(exch, IRC_ENABLE_INTERRUPT, ne2k->irq);
-			async_exchange_end(exch);
-		}
-	}
-	
-	return device->state;
-}
-
-int netif_stop_message(netif_device_t *device)
-{
-	if (device->state != NETIF_STOPPED) {
-		ne2k_t *ne2k = (ne2k_t *) device->specific;
-		
-		ne2k_down(ne2k);
-		unregister_irq(ne2k->irq, device->device_id);
-		change_state(device, NETIF_STOPPED);
-	}
-	
-	return device->state;
-}
-
-int netif_send_message(device_id_t device_id, packet_t *packet,
-    services_t sender)
-{
-	netif_device_t *device;
-	int rc = find_device(device_id, &device);
-	if (rc != EOK)
-		return rc;
-	
-	if (device->state != NETIF_ACTIVE) {
-		netif_pq_release(packet_get_id(packet));
-		return EFORWARD;
-	}
-	
-	ne2k_t *ne2k = (ne2k_t *) device->specific;
-	
-	/*
-	 * Process the packet queue
-	 */
-	
-	do {
-		packet_t *next = pq_detach(packet);
-		ne2k_send(ne2k, packet);
-		netif_pq_release(packet_get_id(packet));
-		packet = next;
-	} while (packet);
-	
-	return EOK;
-}
-
-int netif_initialize(void)
-{
-	sysarg_t apic;
-	sysarg_t i8259;
-	
-	if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
-	    || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259)))
-		irc_service = true;
-	
-	if (irc_service) {
-		while (!irc_sess)
-			irc_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
-			    SERVICE_IRC, 0, 0);
-	}
-	
-	async_set_interrupt_received(irq_handler);
-	
-	return service_register(SERVICE_NE2000);
-}
-
-int main(int argc, char *argv[])
-{
-	/* Start the module */
-	return netif_module_start();
-}
-
-/** @}
- */
Index: uspace/srv/loc/loc.c
===================================================================
--- uspace/srv/loc/loc.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/loc/loc.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1163,4 +1163,5 @@
 	link_initialize(&service->services);
 	link_initialize(&service->server_services);
+	list_initialize(&service->cat_memb);
 	
 	/* Get unique service ID */
@@ -1288,6 +1289,8 @@
 	cat = category_new("virtual");
 	categ_dir_add_cat(&cdir, cat);
-
-
+	
+	cat = category_new("nic");
+	categ_dir_add_cat(&cdir, cat);
+	
 	return true;
 }
Index: uspace/srv/net/cfg/lo
===================================================================
--- uspace/srv/net/cfg/lo	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,13 +1,0 @@
-# loopback configuration
-
-NAME=lo
-
-NETIF=lo
-NIL=nildummy
-IL=ip
-
-IP_CONFIG=static
-IP_ADDR=127.0.0.1
-IP_NETMASK=255.0.0.0
-
-MTU=15535
Index: uspace/srv/net/cfg/lo.nic
===================================================================
--- uspace/srv/net/cfg/lo.nic	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/srv/net/cfg/lo.nic	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,13 @@
+# loopback configuration
+
+NAME=lo
+
+HWPATH=/virt/lo/port0
+NIL=nildummy
+IL=ip
+
+IP_CONFIG=static
+IP_ADDR=127.0.0.1
+IP_NETMASK=255.0.0.0
+
+MTU=15535
Index: uspace/srv/net/cfg/ne2k
===================================================================
--- uspace/srv/net/cfg/ne2k	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,24 +1,0 @@
-# DP8390 (NE2k) configuration
-
-NAME=ne2k
-
-NETIF=ne2000
-NIL=eth
-IL=ip
-
-IRQ=5
-IO=300
-
-# 8023_2_LSAP, 8023_2_SNAP
-ETH_MODE=DIX
-ETH_DUMMY=no
-
-IP_CONFIG=static
-IP_ADDR=10.0.2.15
-IP_ROUTING=yes
-IP_NETMASK=255.255.255.0
-IP_BROADCAST=10.0.2.255
-IP_GATEWAY=10.0.2.2
-ARP=arp
-
-MTU=1500
Index: uspace/srv/net/cfg/ne2k.nic
===================================================================
--- uspace/srv/net/cfg/ne2k.nic	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/srv/net/cfg/ne2k.nic	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,21 @@
+# NE2000 configuration
+
+NAME=ne2k
+
+HWPATH=/hw/pci0/00:01.0/ne2k/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/documentation.txt
===================================================================
--- uspace/srv/net/documentation.txt	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,201 +1,0 @@
-/**
-
-\mainpage Networking and TCP/IP Stack for HelenOS system
-
-\section introduction Introduction
-
-<p>
-For the microkernel HelenOS a completely new networking stack was designed.
-The networking stack was intended to implement current basic standards of the TCP/IP Stack.
-Only the minimalistic functionality allowing the stack to function was to be implemented.
-The networking stack is written in C.
-</p>
-<p>
-Please see
-</p>
-<ul>
-	<li>\ref build</li>
-	<li>\ref software</li>
-	<li>\ref running</li>
-	<li>\ref testing</li>
-</ul>
-
-\page build Build from sources
-
-<p>
-To compile the HelenOS from sources (the cross compilers from the <code>build/</code> directory are recommended):
-</p>
-<ol>
-	<li>change the working directory to the HelenOS source directory</li>
-	<li>run <code># make config</code></li>
-	<li>check/change the configuration</li>
-	<li>save and exit the configuration tool</li>
-	<li>run <code># make</code></li>
-</ol>
-<p>
-The <code>image.iso</code> should be created on success.
-</p>
-
-\page running Running the HelenOS with networking
-
-\section netstart Starting the networking
-
-<p>
-After starting the HelenOS boot image in <em>Qemu</em>, the command line appears.
-To run <em>Qemu</em> a script <code>contrib/conf/qemu.sh</code> for Linux or <code>contrib/conf/qemu.bat</code> for Windows in the HelenOS source directory can be used.
-The provided scripts set the needed arguments:
-<br><code>-vga std -M isapc -net nic,model=ne2k_isa -net user -redir udp:8080::8080 -redir udp:8081::8081 -boot d -cdrom image.iso</code><br>
-Additional arguments may be specified on the command line, they override these set.
-</p>
-
-<p>
-The networking stack is started and initialized by running a command
-<br><code># netstart</code><br>
-The networking stack is then started and configured network interfaces are enabled.
-The current configuration is printed out.
-Since that networking applications can be run using the command line as well.
-</p>
-
-\section network Qemu network
-
-<p>
-In the common mode <em>Qemu</em> creates a simple network with a gateway and settles the guest system in.
-The network is 10.0.2.*, the gateway's address 10.0.2.2 and the guest system has 10.0.2.15.
-%Even this simple setting was a bit hard to find in the documentation.
-Therefore a static configuration is possible and no additional DHCP nor BOOTP implementations are necessary.
-On the other hand the guest system is behind a firewall.
-<em>Qemu</em> may be configured to forward some ports to the guest system and allows all outgoing traffic except ICMP and ARP protocols, so you can ping only the gateway.
-</p>
-
-\section applications Applications
-
-<p>
-A few networking applications are located in the app/ directory.
-Common functions for parsing command line arguments and printing textual networking error messages are located in that directory as well.
-The networking applications should be built with the libsocket library located in the socket/libsocket.a file.
-They can use functions and definitions from the include/socket.h header file which contains socket API and further includes:
-</p>
-<ul>
-	<li>include/byteorder.h containing byte order manipulation,</li>
-	<li>include/in.h containing IPv4 socket address structure,</li>
-	<li>include/in6.h containing IPv6 socket address structure,</li>
-	<li>include/inet.h containing socket address structure and parsing functions,</li>
-	<li>include/socket codes.h containing address and protocol families and socket types and option levels, and</li>
-	<li>include/socket errno.h containing socket and general error codes.</li>
-</ul>
-
-\page software Software prerequisites
-
-<p>
-The networking and TCP/IP stack is implemented for the ia32 architecture on top of HelenOS 0.4.1 (Escalopino), the most current stable release of HelenOS.
-So far the only one operational network interface supported is in Qemu 0.10.2 and newer.
-To run <em>Qemu</em> a script contrib/conf/qemu.sh for Linux or contrib/conf/qemu.bat for Windows in the HelenOS source directory can be used.
-The qemu and its libraries have to be installed and in the path.
-These scripts set all the necessary parameters
-with some ports redirected from the local host to the guest system.
-For testing purposes at least a low level communication application is recommended, N.E.T., netcat etc.
-</p>
-<p>
-In order to build HelenOS and the networking stack from sources a few tools are
-required:
-<ul>
-	<li>binutils in version 2.19.1,</li>
-	<li>gcc–core in version 4.3.3 11,</li>
-	<li>gcc–objc in version 4.3.3, and</li>
-	<li>gcc–g++ in version 4.3.3.</li>
-</ul>
-<p>
-All these can be downloaded and installed as cross–compilers on Linux using a script contrib/toolchain.sh in the HelenOS source directory.
-In addition rats, a static source code analyzer, and Doxygen, a documentation generator, were used.
-All development was tracked in the HelenOS subversion repository.
-</p>
-<ul>
-	<li>HelenOS website: <a href="http://www.helenos.org/" title="HelenOS website">http://www.helenos.org/</a></li>
-	<li><em>Qemu</em> website: <a href="http://www.qemu.org/" title="Qemu website">http://www.qemu.org/</a></li>
-	<li><em>binutils</em> website: <a href="http://www.gnu.org/software/binutils/" title="binutils website">http://www.gnu.org/software/binutils/</a></li>
-	<li><em>GCC</em> website: <a href="http://gcc.gnu.org/" title="GCC website">http://gcc.gnu.org/</a></li>
-	<li><em>RATS</em> website: <a href="http://www.fortify.com/security-resources/rats.jsp" title="RATS website">http://www.fortify.com/security-resources/rats.jsp</a></li>
-	<li><em>Doxygen</em> website: <a href="http://www.stack.nl/ dimitri/doxygen/index.html" title="Doxygen website">http://www.stack.nl/ dimitri/doxygen/index.html</a></li>
-	<li><em>Subversion</em> website: <a href="http://subversion.tigris.org/" title="Subversion website">http://subversion.tigris.org/</a></li>
-</ul>
-
-\page testing Testing scenarios
-
-<p>
-The scenarios contain the following shortcuts:
-</p>
-<ul>
-	<li>g for the quest system, HelenOS in <em>Qemu</em></li>
-	<li>h for the host system</li>
-	<li>n for the <em>NET</em> application</li>
-	<li>e for echo echo application run in HelenOS</li>
-</ul>
-
-\section scenarios Testing scenarios
-<ul>
-	<li>UDP
-		<ol>
-			<li>g #netstart</li>
-			<li>h wine net.exe (->n) (or net.exe)</li>
-			<li>n set 127.0.0.1:8080 address and port, BuiltinUDP protocol</li>
-			<li>n send some data (an ARP will be generated and the original packet gets lost)</li>
-			<li>n send some data (the port is unreachable and the packet is discarded)</li>
-			<li>g #echo -p 8080 -c 3 -v (->e)</li>
-			<li>g prints Listening</li>
-			<li>n send some data</li>
-			<li>e prints received data</li>
-			<li>h prints reply</li>
-			<li>n click disconnect</li>
-			<li>n set :8081 port</li>
-			<li>n send some data</li>
-			<li>n click disconnect</li>
-			<li>n set :8080 port</li>
-			<li>count-1 times:
-				<ol>
-					<li>n send some data</li>
-					<li>e prints received data</li>
-					<li>h prints reply</li>
-				</ol>
-			</li>
-			<li>e prints Exiting</li>
-			<li>e quits</li>
-			<li>n send some data (the port is unreachable and the packet is discarded)</li>
-		</ol>
-	</li>
-	<li>ICMP echo to 10.0.2.2
-		<ol>
-			<li>g #netstart</li>
-			<li>g #ping 10.0.2.2 (->p)</li>
-			<li>g prints ARP request for 10.0.2.2</li>
-			<li>g prints ARP reply from 10.0.2.2</li>
-			<li>p prints timeouted</li>
-			<li>p prints round trip time</li>
-			<li>p prints round trip time</li>
-			<li>p quits</li>
-		</ol>
-	</li>
-	<li>ICMP echo to 127.0.0.1
-		<ol>
-			<li>g #netstart</li>
-			<li>g #ping 127.0.0.1 (->p)</li>
-			<li>p prints round trip time</li>
-			<li>p prints round trip time</li>
-			<li>p prints round trip time</li>
-			<li>p quits</li>
-		</ol>
-	</li>
-	<li>ICMP with no internet on the host system (!)
-		<ol>
-			<li>g #netstart</li>
-			<li>g #ping 123.123.123.3 (->p)</li>
-			<li>g prints ARP request for 10.0.2.2</li>
-			<li>g prints ARP reply from 10.0.2.2</li>
-			<li>p prints timeouted</li>
-			<li>p prints destination unreachable</li>
-			<li>p prints destination unreachable</li>
-			<li>p quits</li>
-		</ol>
-	</li>
-</ul>
-
-*/
Index: uspace/srv/net/il/arp/arp.c
===================================================================
--- uspace/srv/net/il/arp/arp.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/il/arp/arp.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -174,12 +174,6 @@
 		    count);
 		
-		if (device) {
+		if (device)
 			arp_clear_device(device);
-			if (device->addr_data)
-				free(device->addr_data);
-			
-			if (device->broadcast_data)
-				free(device->broadcast_data);
-		}
 	}
 	
@@ -190,6 +184,6 @@
 }
 
-static int arp_clear_address_req(device_id_t device_id, services_t protocol,
-    measured_string_t *address)
+static int arp_clear_address_req(nic_device_id_t device_id,
+    services_t protocol, measured_string_t *address)
 {
 	fibril_mutex_lock(&arp_globals.lock);
@@ -218,5 +212,5 @@
 }
 
-static int arp_clear_device_req(device_id_t device_id)
+static int arp_clear_device_req(nic_device_id_t device_id)
 {
 	fibril_mutex_lock(&arp_globals.lock);
@@ -289,5 +283,5 @@
  *
  */
-static int arp_receive_message(device_id_t device_id, packet_t *packet)
+static int arp_receive_message(nic_device_id_t device_id, packet_t *packet)
 {
 	int rc;
@@ -365,5 +359,5 @@
 			memcpy(src_proto, proto->addr->value,
 			    header->protocol_length);
-			memcpy(src_hw, device->addr->value,
+			memcpy(src_hw, device->addr,
 			    device->packet_dimension.addr_len);
 			memcpy(des_hw, trans->hw_addr->value,
@@ -393,5 +387,5 @@
  *
  */
-static int arp_mtu_changed_message(device_id_t device_id, size_t mtu)
+static int arp_mtu_changed_message(nic_device_id_t device_id, size_t mtu)
 {
 	fibril_mutex_lock(&arp_globals.lock);
@@ -409,4 +403,36 @@
 	printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
 	
+	return EOK;
+}
+
+static int arp_addr_changed_message(nic_device_id_t device_id)
+{
+	uint8_t addr_buffer[NIC_MAX_ADDRESS_LENGTH];
+	size_t length;
+	ipc_callid_t data_callid;
+	if (!async_data_write_receive(&data_callid, &length)) {
+		async_answer_0(data_callid, EINVAL);
+		return EINVAL;
+	}
+	if (length > NIC_MAX_ADDRESS_LENGTH) {
+		async_answer_0(data_callid, ELIMIT);
+		return ELIMIT;
+	}
+	if (async_data_write_finalize(data_callid, addr_buffer, length) != EOK) {
+		return EINVAL;
+	}
+
+	fibril_mutex_lock(&arp_globals.lock);
+
+	arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
+	if (!device) {
+		fibril_mutex_unlock(&arp_globals.lock);
+		return ENOENT;
+	}
+
+	memcpy(device->addr, addr_buffer, length);
+	device->addr_len = length;
+
+	fibril_mutex_unlock(&arp_globals.lock);
 	return EOK;
 }
@@ -456,4 +482,7 @@
 			async_answer_0(iid, (sysarg_t) rc);
 			break;
+		case NET_IL_ADDR_CHANGED:
+			rc = arp_addr_changed_message(IPC_GET_DEVICE(*icall));
+			async_answer_0(iid, (sysarg_t) rc);
 		
 		default:
@@ -483,5 +512,5 @@
  *
  */
-static int arp_device_message(device_id_t device_id, services_t service,
+static int arp_device_message(nic_device_id_t device_id, services_t service,
     services_t protocol, measured_string_t *address)
 {
@@ -586,24 +615,26 @@
 		
 		/* Get hardware address */
-		rc = nil_get_addr_req(device->sess, device_id, &device->addr,
-		    &device->addr_data);
-		if (rc != EOK) {
+		int len = nil_get_addr_req(device->sess, device_id, device->addr,
+		    NIC_MAX_ADDRESS_LENGTH);
+		if (len < 0) {
 			fibril_mutex_unlock(&arp_globals.lock);
 			arp_protos_destroy(&device->protos, free);
 			free(device);
-			return rc;
-		}
+			return len;
+		}
+		
+		device->addr_len = len;
 		
 		/* Get broadcast address */
-		rc = nil_get_broadcast_addr_req(device->sess, device_id,
-		    &device->broadcast_addr, &device->broadcast_data);
-		if (rc != EOK) {
-			fibril_mutex_unlock(&arp_globals.lock);
-			free(device->addr);
-			free(device->addr_data);
+		len = nil_get_broadcast_addr_req(device->sess, device_id,
+		    device->broadcast_addr, NIC_MAX_ADDRESS_LENGTH);
+		if (len < 0) {
+			fibril_mutex_unlock(&arp_globals.lock);
 			arp_protos_destroy(&device->protos, free);
 			free(device);
-			return rc;
-		}
+			return len;
+		}
+		
+		device->broadcast_addr_len = len;
 		
 		rc = arp_cache_add(&arp_globals.cache, device->device_id,
@@ -611,8 +642,4 @@
 		if (rc != EOK) {
 			fibril_mutex_unlock(&arp_globals.lock);
-			free(device->addr);
-			free(device->addr_data);
-			free(device->broadcast_addr);
-			free(device->broadcast_data);
 			arp_protos_destroy(&device->protos, free);
 			free(device);
@@ -640,9 +667,9 @@
 }
 
-static int arp_send_request(device_id_t device_id, services_t protocol,
+static int arp_send_request(nic_device_id_t device_id, services_t protocol,
     measured_string_t *target, arp_device_t *device, arp_proto_t *proto)
 {
 	/* ARP packet content size = header + (address + translation) * 2 */
-	size_t length = 8 + 2 * (proto->addr->length + device->addr->length);
+	size_t length = 8 + 2 * (proto->addr->length + device->addr_len);
 	if (length > device->packet_dimension.content)
 		return ELIMIT;
@@ -661,5 +688,5 @@
 	
 	header->hardware = htons(device->hardware);
-	header->hardware_length = (uint8_t) device->addr->length;
+	header->hardware_length = (uint8_t) device->addr_len;
 	header->protocol = htons(protocol_map(device->service, protocol));
 	header->protocol_length = (uint8_t) proto->addr->length;
@@ -667,17 +694,16 @@
 	
 	length = sizeof(arp_header_t);
-	
-	memcpy(((uint8_t *) header) + length, device->addr->value,
-	    device->addr->length);
-	length += device->addr->length;
+	memcpy(((uint8_t *) header) + length, device->addr,
+	    device->addr_len);
+	length += device->addr_len;
 	memcpy(((uint8_t *) header) + length, proto->addr->value,
 	    proto->addr->length);
 	length += proto->addr->length;
-	bzero(((uint8_t *) header) + length, device->addr->length);
-	length += device->addr->length;
+	bzero(((uint8_t *) header) + length, device->addr_len);
+	length += device->addr_len;
 	memcpy(((uint8_t *) header) + length, target->value, target->length);
 	
-	int rc = packet_set_addr(packet, (uint8_t *) device->addr->value,
-	    (uint8_t *) device->broadcast_addr->value, device->addr->length);
+	int rc = packet_set_addr(packet, device->addr, device->broadcast_addr,
+	    device->addr_len);
 	if (rc != EOK) {
 		pq_release_remote(arp_globals.net_sess, packet_get_id(packet));
@@ -704,5 +730,5 @@
  *
  */
-static int arp_translate_message(device_id_t device_id, services_t protocol,
+static int arp_translate_message(nic_device_id_t device_id, services_t protocol,
     measured_string_t *target, measured_string_t **translation)
 {
Index: uspace/srv/net/il/arp/arp.h
===================================================================
--- uspace/srv/net/il/arp/arp.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/il/arp/arp.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -92,13 +92,13 @@
 struct arp_device {
 	/** Actual device hardware address. */
-	measured_string_t *addr;
-	/** Actual device hardware address data. */
-	uint8_t *addr_data;
+	uint8_t addr[NIC_MAX_ADDRESS_LENGTH];
+	/** Actual device hardware address length. */
+	size_t addr_len;
 	/** Broadcast device hardware address. */
-	measured_string_t *broadcast_addr;
-	/** Broadcast device hardware address data. */
-	uint8_t *broadcast_data;
+	uint8_t broadcast_addr[NIC_MAX_ADDRESS_LENGTH];
+	/** Broadcast device hardware address length. */
+	size_t broadcast_addr_len;
 	/** Device identifier. */
-	device_id_t device_id;
+	nic_device_id_t device_id;
 	/** Hardware type. */
 	hw_type_t hardware;
Index: uspace/srv/net/il/ip/ip.c
===================================================================
--- uspace/srv/net/il/ip/ip.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/il/ip/ip.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -354,5 +354,5 @@
 	ip_netif->routing = NET_DEFAULT_IP_ROUTING;
 	configuration = &names[0];
-
+	
 	/* Get configuration */
 	rc = net_get_device_conf_req(ip_globals.net_sess, ip_netif->device_id,
@@ -406,5 +406,5 @@
 			return ENOTSUP;
 		}
-
+		
 		if (configuration[6].value) {
 			ip_netif->arp = get_running_module(&ip_globals.modules,
@@ -417,10 +417,11 @@
 			}
 		}
+		
 		if (configuration[7].value)
 			ip_netif->routing = (configuration[7].value[0] == 'y');
-
+		
 		net_free_settings(configuration, data);
 	}
-
+	
 	/* Bind netif service which also initializes the device */
 	ip_netif->sess = nil_bind_service(ip_netif->service,
@@ -432,5 +433,5 @@
 		return ENOENT;
 	}
-
+	
 	/* Has to be after the device netif module initialization */
 	if (ip_netif->arp) {
@@ -448,5 +449,5 @@
 		}
 	}
-
+	
 	/* Get packet dimensions */
 	rc = nil_packet_size_req(ip_netif->sess, ip_netif->device_id,
@@ -461,5 +462,5 @@
 		ip_netif->packet_dimension.content = IP_MIN_CONTENT;
 	}
-
+	
 	index = ip_netifs_add(&ip_globals.netifs, ip_netif->device_id, ip_netif);
 	if (index < 0)
@@ -478,9 +479,9 @@
 		printf("%s: Default gateway (%s)\n", NAME, defgateway);
 	}
-
+	
 	return EOK;
 }
 
-static int ip_device_req_local(device_id_t device_id, services_t netif)
+static int ip_device_req_local(nic_device_id_t device_id, services_t netif)
 {
 	ip_netif_t *ip_netif;
@@ -498,9 +499,9 @@
 		return rc;
 	}
-
+	
 	ip_netif->device_id = device_id;
 	ip_netif->service = netif;
-	ip_netif->state = NETIF_STOPPED;
-
+	ip_netif->state = NIC_STATE_STOPPED;
+	
 	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
 
@@ -594,5 +595,5 @@
 	while (index >= 0) {
 		netif = ip_netifs_get_index(&ip_globals.netifs, index);
-		if (netif && (netif->state == NETIF_ACTIVE)) {
+		if (netif && (netif->state == NIC_STATE_ACTIVE)) {
 			route = ip_netif_find_route(netif, destination);
 			if (route)
@@ -1142,5 +1143,5 @@
 }
 
-static int ip_send_msg_local(device_id_t device_id, packet_t *packet,
+static int ip_send_msg_local(nic_device_id_t device_id, packet_t *packet,
     services_t sender, services_t error)
 {
@@ -1258,5 +1259,6 @@
  * @return		ENOENT if device is not found.
  */
-static int ip_device_state_message(device_id_t device_id, device_state_t state)
+static int ip_device_state_message(nic_device_id_t device_id,
+    nic_device_state_t state)
 {
 	ip_netif_t *netif;
@@ -1272,5 +1274,6 @@
 	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
 
-	printf("%s: Device %d changed state to %d\n", NAME, device_id, state);
+	printf("%s: Device %d changed state to '%s'\n", NAME, device_id,
+	    nic_device_state_to_string(state));
 
 	return EOK;
@@ -1312,5 +1315,5 @@
  *			tl_received_msg() function.
  */
-static int ip_deliver_local(device_id_t device_id, packet_t *packet,
+static int ip_deliver_local(nic_device_id_t device_id, packet_t *packet,
     ip_header_t *header, services_t error)
 {
@@ -1413,5 +1416,5 @@
  *			is disabled.
  */
-static int ip_process_packet(device_id_t device_id, packet_t *packet)
+static int ip_process_packet(nic_device_id_t device_id, packet_t *packet)
 {
 	ip_header_t *header;
@@ -1514,5 +1517,5 @@
  *
  */
-static int ip_packet_size_message(device_id_t device_id, size_t *addr_len,
+static int ip_packet_size_message(nic_device_id_t device_id, size_t *addr_len,
     size_t *prefix, size_t *content, size_t *suffix)
 {
@@ -1572,5 +1575,5 @@
  * @return		ENOENT if device is not found.
  */
-static int ip_mtu_changed_message(device_id_t device_id, size_t mtu)
+static int ip_mtu_changed_message(nic_device_id_t device_id, size_t mtu)
 {
 	ip_netif_t *netif;
@@ -1629,5 +1632,8 @@
 			async_answer_0(iid, (sysarg_t) rc);
 			break;
-		
+		case NET_IL_ADDR_CHANGED:
+			async_answer_0(iid, (sysarg_t) EOK);
+			break;
+
 		default:
 			async_answer_0(iid, (sysarg_t) ENOTSUP);
@@ -1689,5 +1695,5 @@
 }
 
-static int ip_add_route_req_local(device_id_t device_id, in_addr_t address,
+static int ip_add_route_req_local(nic_device_id_t device_id, in_addr_t address,
     in_addr_t netmask, in_addr_t gateway)
 {
@@ -1723,5 +1729,6 @@
 }
 
-static int ip_set_gateway_req_local(device_id_t device_id, in_addr_t gateway)
+static int ip_set_gateway_req_local(nic_device_id_t device_id,
+    in_addr_t gateway)
 {
 	ip_netif_t *netif;
@@ -1757,5 +1764,5 @@
  *
  */
-static int ip_received_error_msg_local(device_id_t device_id,
+static int ip_received_error_msg_local(nic_device_id_t device_id,
     packet_t *packet, services_t target, services_t error)
 {
@@ -1818,5 +1825,5 @@
 static int ip_get_route_req_local(ip_protocol_t protocol,
     const struct sockaddr *destination, socklen_t addrlen,
-    device_id_t *device_id, void **header, size_t *headerlen)
+    nic_device_id_t *device_id, void **header, size_t *headerlen)
 {
 	struct sockaddr_in *address_in;
@@ -1909,5 +1916,5 @@
 	size_t suffix;
 	size_t content;
-	device_id_t device_id;
+	nic_device_id_t device_id;
 	int rc;
 	
Index: uspace/srv/net/il/ip/ip.h
===================================================================
--- uspace/srv/net/il/ip/ip.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/il/ip/ip.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -92,5 +92,5 @@
 	in_addr_t broadcast;
 	/** Device identifier. */
-	device_id_t device_id;
+	nic_device_id_t device_id;
 	/** Indicates whether using DHCP. */
 	int dhcp;
@@ -108,5 +108,5 @@
 	services_t service;
 	/** Device state. */
-	device_state_t state;
+	nic_device_state_t state;
 };
 
Index: uspace/srv/net/net/Makefile
===================================================================
--- uspace/srv/net/net/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/net/Makefile	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -30,6 +30,6 @@
 USPACE_PREFIX = ../../..
 ROOT_PATH = $(USPACE_PREFIX)/..
-LIBS = $(LIBNET_PREFIX)/libnet.a $(LIBPACKET_PREFIX)/libpacket.a
-EXTRA_CFLAGS = -I$(LIBNET_PREFIX)/include -I$(LIBPACKET_PREFIX)/include
+LIBS = $(LIBNET_PREFIX)/libnet.a
+EXTRA_CFLAGS = -I$(LIBNET_PREFIX)/include
 
 COMMON_MAKEFILE = $(ROOT_PATH)/Makefile.common
@@ -43,5 +43,5 @@
 SOURCES = \
 	net.c \
-	net_standalone.c
+	packet_server.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/net/net/net.c
===================================================================
--- uspace/srv/net/net/net.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/net/net.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Radim Vansa
  * All rights reserved.
  *
@@ -31,16 +32,14 @@
  */
 
-/** @file
- * Networking subsystem central module implementation.
- *
- */
-
+#include <assert.h>
 #include <async.h>
 #include <ctype.h>
 #include <ddi.h>
 #include <errno.h>
+#include <str_error.h>
 #include <malloc.h>
 #include <stdio.h>
 #include <str.h>
+#include <devman.h>
 #include <str_error.h>
 #include <ns.h>
@@ -49,6 +48,6 @@
 #include <ipc/net_net.h>
 #include <ipc/il.h>
+#include <ipc/ip.h>
 #include <ipc/nil.h>
-#include <net/modules.h>
 #include <net/packet.h>
 #include <net/device.h>
@@ -57,15 +56,15 @@
 #include <adt/measured_strings.h>
 #include <adt/module_map.h>
-#include <netif_remote.h>
 #include <nil_remote.h>
 #include <net_interface.h>
 #include <ip_interface.h>
+#include <device/nic.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <cfg.h>
 #include "net.h"
-
-/** Networking module name. */
-#define NAME  "net"
-
-/** File read buffer size. */
-#define BUFFER_SIZE  256
+#include "packet_server.h"
+
+#define MAX_PATH_LENGTH  1024
 
 /** Networking module global data. */
@@ -74,6 +73,4 @@
 GENERIC_CHAR_MAP_IMPLEMENT(measured_strings, measured_string_t);
 DEVICE_MAP_IMPLEMENT(netifs, netif_t);
-
-static int startup(void);
 
 /** Add the configured setting to the configuration map.
@@ -87,6 +84,6 @@
  *
  */
-int add_configuration(measured_strings_t *configuration, const uint8_t *name,
-    const uint8_t *value)
+static int add_configuration(measured_strings_t *configuration,
+    const uint8_t *name, const uint8_t *value)
 {
 	int rc;
@@ -109,70 +106,10 @@
 /** Generate new system-unique device identifier.
  *
- * @return		The system-unique devic identifier.
- */
-static device_id_t generate_new_device_id(void)
+ * @return The system-unique devic identifier.
+ *
+ */
+static nic_device_id_t generate_new_device_id(void)
 {
 	return device_assign_devno();
-}
-
-static int parse_line(measured_strings_t *configuration, uint8_t *line)
-{
-	int rc;
-	
-	/* From the beginning */
-	uint8_t *name = line;
-	
-	/* Skip comments and blank lines */
-	if ((*name == '#') || (*name == '\0'))
-		return EOK;
-	
-	/* Skip spaces */
-	while (isspace(*name))
-		name++;
-	
-	/* Remember the name start */
-	uint8_t *value = name;
-	
-	/* Skip the name */
-	while (isalnum(*value) || (*value == '_'))
-		value++;
-	
-	if (*value == '=') {
-		/* Terminate the name */
-		*value = '\0';
-	} else {
-		/* Terminate the name */
-		*value = '\0';
-		
-		/* Skip until '=' */
-		value++;
-		while ((*value) && (*value != '='))
-			value++;
-		
-		/* Not found? */
-		if (*value != '=')
-			return EINVAL;
-	}
-	
-	value++;
-	
-	/* Skip spaces */
-	while (isspace(*value))
-		value++;
-	
-	/* Create a bulk measured string till the end */
-	measured_string_t *setting =
-	    measured_string_create_bulk(value, 0);
-	if (!setting)
-		return ENOMEM;
-	
-	/* Add the configuration setting */
-	rc = measured_strings_add(configuration, name, 0, setting);
-	if (rc != EOK) {
-		free(setting);
-		return rc;
-	}
-	
-	return EOK;
 }
 
@@ -182,50 +119,26 @@
 	printf("%s: Reading configuration file %s/%s\n", NAME, directory, filename);
 	
-	/* Construct the full filename */
-	char fname[BUFFER_SIZE];
-	if (snprintf(fname, BUFFER_SIZE, "%s/%s", directory, filename) > BUFFER_SIZE)
-		return EOVERFLOW;
-	
-	/* Open the file */
-	FILE *cfg = fopen(fname, "r");
-	if (!cfg)
+	cfg_file_t cfg;
+	int rc = cfg_load_path(directory, filename, &cfg);
+	if (rc != EOK)
+		return rc;
+	
+	if (cfg_anonymous(&cfg) == NULL) {
+		cfg_unload(&cfg);
 		return ENOENT;
-	
-	/*
-	 * Read the configuration line by line
-	 * until an error or the end of file
-	 */
-	unsigned int line_number = 0;
-	size_t index = 0;
-	uint8_t line[BUFFER_SIZE];
-	
-	while (!ferror(cfg) && !feof(cfg)) {
-		int read = fgetc(cfg);
-		if ((read > 0) && (read != '\n') && (read != '\r')) {
-			if (index >= BUFFER_SIZE) {
-				line[BUFFER_SIZE - 1] = '\0';
-				fprintf(stderr, "%s: Configuration line %u too "
-				    "long: %s\n", NAME, line_number, (char *) line);
-				
-				/* No space left in the line buffer */
-				return EOVERFLOW;
-			}
-			/* Append the character */
-			line[index] = (uint8_t) read;
-			index++;
-		} else {
-			/* On error or new line */
-			line[index] = '\0';
-			line_number++;
-			if (parse_line(configuration, line) != EOK) {
-				fprintf(stderr, "%s: Configuration error on "
-				    "line %u: %s\n", NAME, line_number, (char *) line);
-			}
-			
-			index = 0;
+	}
+	
+	cfg_section_foreach(cfg_anonymous(&cfg), link) {
+		const cfg_entry_t *entry = cfg_entry_instance(link);
+		
+		rc = add_configuration(configuration,
+		    (uint8_t *) entry->key, (uint8_t *) entry->value);
+		if (rc != EOK) {
+			cfg_unload(&cfg);
+			return rc;
 		}
 	}
 	
-	fclose(cfg);
+	cfg_unload(&cfg);
 	return EOK;
 }
@@ -255,98 +168,4 @@
 	return read_configuration_file(CONF_DIR, CONF_GENERAL_FILE,
 	    &net_globals.configuration);
-}
-
-/** Initialize the networking module.
- *
- * @param[in] client_connection The client connection processing
- *                              function. The module skeleton propagates
- *                              its own one.
- *
- * @return EOK on success.
- * @return ENOMEM if there is not enough memory left.
- *
- */
-static int net_initialize(async_client_conn_t client_connection)
-{
-	int rc;
-	
-	netifs_initialize(&net_globals.netifs);
-	char_map_initialize(&net_globals.netif_names);
-	modules_initialize(&net_globals.modules);
-	measured_strings_initialize(&net_globals.configuration);
-	
-	/* TODO: dynamic configuration */
-	rc = read_configuration();
-	if (rc != EOK)
-		return rc;
-	
-	rc = add_module(NULL, &net_globals.modules, (uint8_t *) LO_NAME,
-	    (uint8_t *) LO_FILENAME, SERVICE_LO, 0, connect_to_service);
-	if (rc != EOK)
-		return rc;
-	
-	rc = add_module(NULL, &net_globals.modules, (uint8_t *) NE2000_NAME,
-	    (uint8_t *) NE2000_FILENAME, SERVICE_NE2000, 0, connect_to_service);
-	if (rc != EOK)
-		return rc;
-	
-	rc = add_module(NULL, &net_globals.modules, (uint8_t *) ETHERNET_NAME,
-	    (uint8_t *) ETHERNET_FILENAME, SERVICE_ETHERNET, 0, connect_to_service);
-	if (rc != EOK)
-		return rc;
-	
-	rc = add_module(NULL, &net_globals.modules, (uint8_t *) NILDUMMY_NAME,
-	    (uint8_t *) NILDUMMY_FILENAME, SERVICE_NILDUMMY, 0, connect_to_service);
-	if (rc != EOK)
-		return rc;
-	
-	/* Build specific initialization */
-	return net_initialize_build(client_connection);
-}
-
-/** Start the networking module.
- *
- * Initializes the client connection serving function,
- * initializes the module, registers the module service
- * and starts the async manager, processing IPC messages
- * in an infinite loop.
- *
- * @param[in] client_connection The client connection
- *                              processing function. The
- *                              module skeleton propagates
- *                              its own one.
- *
- * @return EOK on successful module termination.
- * @return Other error codes as defined for the net_initialize() function.
- * @return Other error codes as defined for the REGISTER_ME() macro function.
- *
- */
-static int net_module_start(async_client_conn_t client_connection)
-{
-	int rc;
-	
-	async_set_client_connection(client_connection);
-	rc = pm_init();
-	if (rc != EOK)
-		return rc;
-	
-	rc = net_initialize(client_connection);
-	if (rc != EOK)
-		goto out;
-	
-	rc = service_register(SERVICE_NETWORKING);
-	if (rc != EOK)
-		goto out;
-	
-	rc = startup();
-	if (rc != EOK)
-		goto out;
-	
-	task_retval(0);
-	async_manager();
-
-out:
-	pm_destroy();
-	return rc;
 }
 
@@ -364,8 +183,8 @@
  */
 static int net_get_conf(measured_strings_t *netif_conf,
-    measured_string_t *configuration, size_t count, uint8_t **data)
-{
-	if (data)
-		*data = NULL;
+    measured_string_t *configuration, size_t count)
+{
+	if ((!configuration) || (count <= 0))
+			return EINVAL;
 	
 	size_t index;
@@ -389,28 +208,65 @@
 }
 
-static int net_get_conf_req_local(measured_string_t **configuration,
-    size_t count, uint8_t **data)
-{
-	if (!configuration || (count <= 0))
-		return EINVAL;
-	
-	return net_get_conf(NULL, *configuration, count, data);
-}
-
-static int net_get_device_conf_req_local(device_id_t device_id,
-    measured_string_t **configuration, size_t count, uint8_t **data)
-{
-	if ((!configuration) || (count == 0))
-		return EINVAL;
-
+static int net_get_device_conf(nic_device_id_t device_id,
+    measured_string_t *configuration, size_t count)
+{
 	netif_t *netif = netifs_find(&net_globals.netifs, device_id);
 	if (netif)
-		return net_get_conf(&netif->configuration, *configuration, count, data);
+		return net_get_conf(&netif->configuration, configuration, count);
 	else
-		return net_get_conf(NULL, *configuration, count, data);
-}
-
-void net_free_settings(measured_string_t *settings, uint8_t *data)
-{
+		return net_get_conf(NULL, configuration, count);
+}
+
+static int net_get_devices(measured_string_t **devices, size_t *dev_count)
+{
+	if (!devices)
+		return EBADMEM;
+	
+	size_t max_count = netifs_count(&net_globals.netifs);
+	*devices = malloc(max_count * sizeof(measured_string_t));
+	if (*devices == NULL)
+		return ENOMEM;
+	
+	size_t count = 0;
+	for (size_t i = 0; i < max_count; i++) {
+		netif_t *item = netifs_get_index(&net_globals.netifs, i);
+		if (item->sess != NULL) {
+			/* 
+			 * Use format "device_id:device_name"
+			 * FIXME: This typecasting looks really ugly
+			 */
+			(*devices)[count].length = asprintf(
+			    (char **) &((*devices)[count].value),
+			    NIC_DEVICE_PRINT_FMT ":%s", item->id,
+			    (const char *) item->name);
+			count++;
+		}
+	}
+	
+	*dev_count = (size_t) count;
+	return EOK;
+}
+
+static int net_get_devices_count()
+{
+	size_t max_count = netifs_count(&net_globals.netifs);
+	
+	size_t count = 0;
+	for (size_t i = 0; i < max_count; i++) {
+		netif_t *item = netifs_get_index(&net_globals.netifs, i);
+		if (item->sess != NULL)
+			count++;
+	}
+	
+	return count;
+}
+
+static void net_free_devices(measured_string_t *devices, size_t count)
+{
+	size_t i;
+	for (i = 0; i < count; ++i)
+		free(devices[i].value);
+	
+	free(devices);
 }
 
@@ -431,25 +287,24 @@
  *
  */
-static int start_device(netif_t *netif)
-{
-	int rc;
-	
-	/* Mandatory netif */
-	measured_string_t *setting =
-	    measured_strings_find(&netif->configuration, (uint8_t *) CONF_NETIF, 0);
-	
-	netif->driver = get_running_module(&net_globals.modules, setting->value);
-	if (!netif->driver) {
-		fprintf(stderr, "%s: Failed to start network interface driver '%s'\n",
-		    NAME, setting->value);
-		return EINVAL;
+static int init_device(netif_t *netif, devman_handle_t handle)
+{
+	printf("%s: Initializing device '%s'\n", NAME, netif->name);
+	
+	netif->handle = handle;
+	netif->sess = devman_device_connect(EXCHANGE_SERIALIZE, netif->handle,
+	    IPC_FLAG_BLOCKING);
+	if (netif->sess == NULL) {
+		printf("%s: Unable to connect to device\n", NAME);
+		return EREFUSED;
 	}
 	
 	/* Optional network interface layer */
-	setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_NIL, 0);
+	measured_string_t *setting = measured_strings_find(&netif->configuration,
+	    (uint8_t *) CONF_NIL, 0);
 	if (setting) {
-		netif->nil = get_running_module(&net_globals.modules, setting->value);
+		netif->nil = get_running_module(&net_globals.modules,
+		    setting->value);
 		if (!netif->nil) {
-			fprintf(stderr, "%s: Failed to start network interface layer '%s'\n",
+			printf("%s: Unable to connect to network interface layer '%s'\n",
 			    NAME, setting->value);
 			return EINVAL;
@@ -459,143 +314,97 @@
 	
 	/* Mandatory internet layer */
-	setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IL, 0);
-	netif->il = get_running_module(&net_globals.modules, setting->value);
+	setting = measured_strings_find(&netif->configuration,
+	    (uint8_t *) CONF_IL, 0);
+	netif->il = get_running_module(&net_globals.modules,
+	    setting->value);
 	if (!netif->il) {
-		fprintf(stderr, "%s: Failed to start internet layer '%s'\n",
+		printf("%s: Unable to connect to internet layer '%s'\n",
 		    NAME, setting->value);
 		return EINVAL;
 	}
 	
-	/* Hardware configuration */
-	setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IRQ, 0);
-	int irq = setting ? strtol((char *) setting->value, NULL, 10) : 0;
-	
-	setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_IO, 0);
-	uintptr_t io = setting ? strtol((char *) setting->value, NULL, 16) : 0;
-	
-	rc = netif_probe_req(netif->driver->sess, netif->id, irq, (void *) io);
-	if (rc != EOK)
-		return rc;
-	
 	/* Network interface layer startup */
-	services_t internet_service;
+	int rc;
+	services_t nil_service;
 	if (netif->nil) {
-		setting = measured_strings_find(&netif->configuration, (uint8_t *) CONF_MTU, 0);
+		setting = measured_strings_find(&netif->configuration,
+		    (uint8_t *) CONF_MTU, 0);
 		if (!setting)
 			setting = measured_strings_find(&net_globals.configuration,
 			    (uint8_t *) CONF_MTU, 0);
 		
-		int mtu = setting ? strtol((char *) setting->value, NULL, 10) : 0;
-		rc = nil_device_req(netif->nil->sess, netif->id, mtu,
-		    netif->driver->service);
+		int mtu = setting ?
+		    strtol((const char *) setting->value, NULL, 10) : 0;
+		rc = nil_device_req(netif->nil->sess, netif->id,
+		    netif->handle, mtu);
+		if (rc != EOK) {
+			printf("%s: Unable to start network interface layer\n",
+			    NAME);
+			return rc;
+		}
+		
+		nil_service = netif->nil->service;
+	} else
+		nil_service = -1;
+	
+	/* Inter-network layer startup */
+	switch (netif->il->service) {
+	case SERVICE_IP:
+		rc = ip_device_req(netif->il->sess, netif->id, nil_service);
+		if (rc != EOK) {
+			printf("%s: Unable to start internet layer\n", NAME);
+			return rc;
+		}
+		
+		break;
+	default:
+		return ENOENT;
+	}
+	
+	printf("%s: Activating device '%s'\n", NAME, netif->name);
+	return nic_set_state(netif->sess, NIC_STATE_ACTIVE);
+}
+
+static int net_port_ready(devman_handle_t handle)
+{
+	char hwpath[MAX_PATH_LENGTH];
+	int rc = devman_fun_get_path(handle, hwpath, MAX_PATH_LENGTH);
+	if (rc != EOK)
+		return EINVAL;
+	
+	int index = char_map_find(&net_globals.netif_hwpaths,
+	    (uint8_t *) hwpath, 0);
+	if (index == CHAR_MAP_NULL)
+		return ENOENT;
+	
+	netif_t *netif = netifs_get_index(&net_globals.netifs, index);
+	if (netif == NULL)
+		return ENOENT;
+	
+	rc = init_device(netif, handle);
+	if (rc != EOK)
+		return rc;
+	
+	/* Increment module usage */
+	if (netif->nil)
+		netif->nil->usage++;
+	
+	netif->il->usage++;
+	
+	return EOK;
+}
+
+static int net_driver_ready_local(devman_handle_t handle)
+{
+	devman_handle_t *funs;
+	size_t count;
+	int rc = devman_dev_get_functions(handle, &funs, &count);
+	if (rc != EOK)
+		return rc;
+	
+	for (size_t i = 0; i < count; i++) {
+		rc = net_port_ready(funs[i]);
 		if (rc != EOK)
 			return rc;
-		
-		internet_service = netif->nil->service;
-	} else
-		internet_service = netif->driver->service;
-	
-	/* Inter-network layer startup */
-	rc = ip_device_req(netif->il->sess, netif->id, internet_service);
-	if (rc != EOK)
-		return rc;
-	
-	return netif_start_req(netif->driver->sess, netif->id);
-}
-
-/** Read the configuration and start all network interfaces.
- *
- * @return EOK on success.
- * @return EXDEV if there is no available system-unique device identifier.
- * @return EINVAL if any of the network interface names are not configured.
- * @return ENOMEM if there is not enough memory left.
- * @return Other error codes as defined for the read_configuration()
- *         function.
- * @return Other error codes as defined for the read_netif_configuration()
- *         function.
- * @return Other error codes as defined for the start_device() function.
- *
- */
-static int startup(void)
-{
-	const char *conf_files[] = {
-		"lo",
-		"ne2k"
-	};
-	size_t count = sizeof(conf_files) / sizeof(char *);
-	int rc;
-	
-	size_t i;
-	for (i = 0; i < count; i++) {
-		netif_t *netif = (netif_t *) malloc(sizeof(netif_t));
-		if (!netif)
-			return ENOMEM;
-		
-		netif->id = generate_new_device_id();
-		if (!netif->id)
-			return EXDEV;
-		
-		rc = measured_strings_initialize(&netif->configuration);
-		if (rc != EOK)
-			return rc;
-		
-		/* Read configuration files */
-		rc = read_netif_configuration(conf_files[i], netif);
-		if (rc != EOK) {
-			measured_strings_destroy(&netif->configuration, free);
-			free(netif);
-			return rc;
-		}
-		
-		/* Mandatory name */
-		measured_string_t *setting =
-		    measured_strings_find(&netif->configuration, (uint8_t *) CONF_NAME, 0);
-		if (!setting) {
-			fprintf(stderr, "%s: Network interface name is missing\n", NAME);
-			measured_strings_destroy(&netif->configuration, free);
-			free(netif);
-			return EINVAL;
-		}
-		netif->name = setting->value;
-		
-		/* Add to the netifs map */
-		int index = netifs_add(&net_globals.netifs, netif->id, netif);
-		if (index < 0) {
-			measured_strings_destroy(&netif->configuration, free);
-			free(netif);
-			return index;
-		}
-		
-		/*
-		 * Add to the netif names map and start network interfaces
-		 * and needed modules.
-		 */
-		rc = char_map_add(&net_globals.netif_names, netif->name, 0,
-		    index);
-		if (rc != EOK) {
-			measured_strings_destroy(&netif->configuration, free);
-			netifs_exclude_index(&net_globals.netifs, index, free);
-			return rc;
-		}
-		
-		rc = start_device(netif);
-		if (rc != EOK) {
-			printf("%s: Ignoring failed interface %s (%s)\n", NAME,
-			    netif->name, str_error(rc));
-			measured_strings_destroy(&netif->configuration, free);
-			netifs_exclude_index(&net_globals.netifs, index, free);
-			continue;
-		}
-		
-		/* Increment modules' usage */
-		netif->driver->usage++;
-		if (netif->nil)
-			netif->nil->usage++;
-		netif->il->usage++;
-		
-		printf("%s: Network interface started (name: %s, id: %d, driver: %s, "
-		    "nil: %s, il: %s)\n", NAME, netif->name, netif->id,
-		    netif->driver->name, netif->nil ? (char *) netif->nil->name : "[none]",
-		    netif->il->name);
 	}
 	
@@ -618,10 +427,11 @@
  *
  */
-int net_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
-    size_t *answer_count)
+static int net_message(ipc_callid_t callid, ipc_call_t *call,
+    ipc_call_t *answer, size_t *answer_count)
 {
 	measured_string_t *strings;
 	uint8_t *data;
 	int rc;
+	size_t count;
 	
 	*answer_count = 0;
@@ -636,12 +446,11 @@
 		if (rc != EOK)
 			return rc;
-		net_get_device_conf_req_local(IPC_GET_DEVICE(*call), &strings,
-		    IPC_GET_COUNT(*call), NULL);
-		
-		/* Strings should not contain received data anymore */
-		free(data);
+		
+		net_get_device_conf(IPC_GET_DEVICE(*call), strings,
+		    IPC_GET_COUNT(*call));
 		
 		rc = measured_strings_reply(strings, IPC_GET_COUNT(*call));
 		free(strings);
+		free(data);
 		return rc;
 	case NET_NET_GET_CONF:
@@ -650,17 +459,31 @@
 		if (rc != EOK)
 			return rc;
-		net_get_conf_req_local(&strings, IPC_GET_COUNT(*call), NULL);
-		
-		/* Strings should not contain received data anymore */
-		free(data);
+		
+		net_get_conf(NULL, strings, IPC_GET_COUNT(*call));
 		
 		rc = measured_strings_reply(strings, IPC_GET_COUNT(*call));
 		free(strings);
-		return rc;
-	case NET_NET_STARTUP:
-		return startup();
-	}
-	
-	return ENOTSUP;
+		free(data);
+		return rc;
+	case NET_NET_GET_DEVICES_COUNT:
+		count = (size_t) net_get_devices_count();
+		IPC_SET_ARG1(*answer, count);
+		*answer_count = 1;
+		return EOK;
+	case NET_NET_GET_DEVICES:
+		rc = net_get_devices(&strings, &count);
+		if (rc != EOK)
+			return rc;
+		
+		rc = measured_strings_reply(strings, count);
+		net_free_devices(strings, count);
+		return rc;
+	case NET_NET_DRIVER_READY:
+		rc = net_driver_ready_local(IPC_GET_ARG1(*call));
+		*answer_count = 0;
+		return rc;
+	default:
+		return ENOTSUP;
+	}
 }
 
@@ -684,6 +507,6 @@
 		/* Clear the answer structure */
 		ipc_call_t answer;
-		size_t answer_count;
-		refresh_answer(&answer, &answer_count);
+		size_t count;
+		refresh_answer(&answer, &count);
 		
 		/* Fetch the next message */
@@ -692,5 +515,9 @@
 		
 		/* Process the message */
-		int res = net_module_message(callid, &call, &answer, &answer_count);
+		int res;
+		if (IS_NET_PACKET_MESSAGE(call))
+			res = packet_server_message(callid, &call, &answer, &count);
+		else
+			res = net_message(callid, &call, &answer, &count);
 		
 		/* End if told to either by the message or the processing result */
@@ -699,5 +526,5 @@
 		
 		/* Answer the message */
-		answer_call(callid, res, &answer, answer_count);
+		answer_call(callid, res, &answer, count);
 	}
 }
@@ -705,5 +532,172 @@
 int main(int argc, char *argv[])
 {
-	return net_module_start(net_client_connection);
+	netifs_initialize(&net_globals.netifs);
+	char_map_initialize(&net_globals.netif_hwpaths);
+	modules_initialize(&net_globals.modules);
+	measured_strings_initialize(&net_globals.configuration);
+	async_set_client_connection(net_client_connection);
+	
+	int rc = pm_init();
+	if (rc != EOK) {
+		printf("%s: Unable to initialize packet management\n", NAME);
+		return rc;
+	}
+	
+	rc = packet_server_init();
+	if (rc != EOK) {
+		printf("%s: Unable to initialize packet server\n", NAME);
+		pm_destroy();
+		return rc;
+	}
+	
+	rc = read_configuration();
+	if (rc != EOK) {
+		printf("%s: Error reading configuration\n", NAME);
+		pm_destroy();
+		return rc;
+	}
+	
+	DIR *config_dir = opendir(CONF_DIR);
+	if (config_dir != NULL) {
+		struct dirent *dir_entry;
+		while ((dir_entry = readdir(config_dir))) {
+			/* Ignore files without the CONF_EXT extension */
+			if ((str_size(dir_entry->d_name) < str_size(CONF_EXT)) ||
+			    (str_cmp(dir_entry->d_name + str_size(dir_entry->d_name) -
+			    str_size(CONF_EXT), CONF_EXT) != 0))
+				continue;
+			
+			
+			netif_t *netif = (netif_t *) malloc(sizeof(netif_t));
+			if (!netif)
+				continue;
+			
+			netif->handle = -1;
+			netif->sess = NULL;
+			
+			netif->id = generate_new_device_id();
+			if (!netif->id) {
+				free(netif);
+				continue;
+			}
+			
+			rc = measured_strings_initialize(&netif->configuration);
+			if (rc != EOK) {
+				free(netif);
+				continue;
+			}
+			
+			rc = read_netif_configuration(dir_entry->d_name, netif);
+			if (rc != EOK) {
+				printf("%s: Error reading configuration %s\n", NAME,
+				    dir_entry->d_name);
+				free(netif);
+				continue;
+			}
+			
+			measured_string_t *name = measured_strings_find(&netif->configuration,
+			    (uint8_t *) CONF_NAME, 0);
+			if (!name) {
+				printf("%s: Network interface name is missing in %s\n",
+				    NAME, dir_entry->d_name);
+				measured_strings_destroy(&netif->configuration, free);
+				free(netif);
+				continue;
+			}
+			
+			netif->name = name->value;
+			
+			/* Mandatory hardware path */
+			measured_string_t *hwpath = measured_strings_find(
+			    &netif->configuration, (const uint8_t *) CONF_HWPATH, 0);
+			if (!hwpath) {
+				printf("%s: Hardware path is missing in %s\n",
+				    NAME, dir_entry->d_name);
+				measured_strings_destroy(&netif->configuration, free);
+				free(netif);
+				continue;
+			}
+			
+			int index = netifs_add(&net_globals.netifs, netif->id, netif);
+			if (index < 0) {
+				measured_strings_destroy(&netif->configuration, free);
+				free(netif);
+				continue;
+			}
+			
+			/*
+			 * Add to the hardware paths map and init network interfaces
+			 * and needed modules.
+			 */
+			rc = char_map_add(&net_globals.netif_hwpaths, hwpath->value, 0, index);
+			if (rc != EOK) {
+				measured_strings_destroy(&netif->configuration, free);
+				netifs_exclude_index(&net_globals.netifs, index, free);
+				continue;
+			}
+		}
+		
+		closedir(config_dir);
+	}
+	
+	rc = add_module(NULL, &net_globals.modules, (uint8_t *) ETHERNET_NAME,
+	    (uint8_t *) ETHERNET_FILENAME, SERVICE_ETHERNET, 0, connect_to_service);
+	if (rc != EOK) {
+		printf("%s: Error adding module '%s'\n", NAME, ETHERNET_NAME);
+		pm_destroy();
+		return rc;
+	}
+	
+	rc = add_module(NULL, &net_globals.modules, (uint8_t *) NILDUMMY_NAME,
+	    (uint8_t *) NILDUMMY_FILENAME, SERVICE_NILDUMMY, 0, connect_to_service);
+	if (rc != EOK) {
+		printf("%s: Error adding module '%s'\n", NAME, NILDUMMY_NAME);
+		pm_destroy();
+		return rc;
+	}
+	
+	task_id_t task_id = net_spawn((uint8_t *) IP_FILENAME);
+	if (!task_id) {
+		printf("%s: Error spawning IP module\n", NAME);
+		pm_destroy();
+		return EINVAL;
+	}
+	
+	rc = add_module(NULL, &net_globals.modules, (uint8_t *) IP_NAME,
+	    (uint8_t *) IP_FILENAME, SERVICE_IP, task_id, ip_connect_module);
+	if (rc != EOK) {
+		printf("%s: Error adding module '%s'\n", NAME, IP_NAME);
+		pm_destroy();
+		return rc;
+	}
+	
+	if (!net_spawn((uint8_t *) "/srv/icmp")) {
+		printf("%s: Error spawning ICMP module\n", NAME);
+		pm_destroy();
+		return EINVAL;
+	}
+	
+	if (!net_spawn((uint8_t *) "/srv/udp")) {
+		printf("%s: Error spawning UDP module\n", NAME);
+		pm_destroy();
+		return EINVAL;
+	}
+	
+	if (!net_spawn((uint8_t *) "/srv/tcp")) {
+		printf("%s: Error spawning TCP module\n", NAME);
+		pm_destroy();
+		return EINVAL;
+	}
+	
+	rc = service_register(SERVICE_NETWORKING);
+	if (rc != EOK) {
+		printf("%s: Error registering service\n", NAME);
+		pm_destroy();
+		return rc;
+	}
+	
+	task_retval(0);
+	async_manager();
+	return 0;
 }
 
Index: uspace/srv/net/net/net.h
===================================================================
--- uspace/srv/net/net/net.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/net/net.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Radim Vansa
  * All rights reserved.
  *
@@ -31,9 +32,4 @@
  */
 
-/** @file
- * Networking subsystem central module.
- *
- */
-
 #ifndef NET_NET_H_
 #define NET_NET_H_
@@ -45,11 +41,7 @@
 #include <adt/module_map.h>
 #include <net/packet.h>
+#include <devman.h>
 
-/** @name Modules definitions
- * @{
- */
-
-#define NE2000_FILENAME  "/srv/ne2000"
-#define NE2000_NAME      "ne2000"
+#define NAME  "net"
 
 #define ETHERNET_FILENAME  "/srv/eth"
@@ -58,7 +50,4 @@
 #define IP_FILENAME  "/srv/ip"
 #define IP_NAME      "ip"
-
-#define LO_FILENAME  "/srv/lo"
-#define LO_NAME      "lo"
 
 #define NILDUMMY_FILENAME  "/srv/nildummy"
@@ -77,5 +66,5 @@
 #define CONF_MTU    "MTU"    /**< Maximum transmission unit configuration label. */
 #define CONF_NAME   "NAME"   /**< Network interface name configuration label. */
-#define CONF_NETIF  "NETIF"  /**< Network interface module name configuration label. */
+#define CONF_HWPATH "HWPATH" /**< Network interface hardware pathname label. */
 #define CONF_NIL    "NIL"    /**< Network interface layer module name configuration label. */
 
@@ -85,4 +74,5 @@
 #define CONF_DIR           "/cfg/net"  /**< Configuration directory. */
 #define CONF_GENERAL_FILE  "general"   /**< General configuration file. */
+#define CONF_EXT           ".nic"      /**< Extension for NIC's configuration files. */
 
 /** Configuration settings.
@@ -98,13 +88,17 @@
  */
 typedef struct {
-	measured_strings_t configuration;  /**< Configuration. */
+	/** System-unique network interface name. */
+	uint8_t *name;
+	/** System-unique network interface identifier. */
+	nic_device_id_t id;
+	/** Configuration. */
+	measured_strings_t configuration;
 	
 	/** Serving network interface driver module index. */
-	module_t *driver;
+	devman_handle_t handle;  /**< Handle for devman */
+	async_sess_t *sess;      /**< Driver session. */
 	
-	device_id_t id;  /**< System-unique network interface identifier. */
-	module_t *il;    /**< Serving internet layer module index. */
-	uint8_t *name;   /**< System-unique network interface name. */
-	module_t *nil;   /**< Serving link layer module index. */
+	module_t *nil;  /**< Serving link layer module index. */
+	module_t *il;   /**< Serving internet layer module index. */
 } netif_t;
 
@@ -124,6 +118,6 @@
 	modules_t modules;                 /**< Available modules. */
 	
-	/** Network interface structure indices by names. */
-	char_map_t netif_names;
+	/** Network interface structure indices by hardware path. */
+	char_map_t netif_hwpaths;
 	
 	/** Present network interfaces. */
@@ -131,10 +125,4 @@
 } net_globals_t;
 
-extern int add_configuration(measured_strings_t *, const uint8_t *,
-    const uint8_t *);
-extern int net_module_message(ipc_callid_t, ipc_call_t *, ipc_call_t *, size_t *);
-extern int net_initialize_build(async_client_conn_t);
-extern int net_message(ipc_callid_t, ipc_call_t *, ipc_call_t *, size_t *);
-
 #endif
 
Index: uspace/srv/net/net/net_standalone.c
===================================================================
--- uspace/srv/net/net/net_standalone.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,110 +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 net
- * @{
- */
-
-/** @file
- * Wrapper for the standalone networking module.
- */
-
-#include "net.h"
-
-#include <str.h>
-#include <adt/measured_strings.h>
-#include <adt/module_map.h>
-#include <ipc/net.h>
-#include <errno.h>
-
-#include <ip_interface.h>
-#include <packet_server.h>
-
-/** Networking module global data. */
-extern net_globals_t net_globals;
-
-/** Initialize the networking module for the chosen subsystem build type.
- *
- *  @param[in] client_connection The client connection processing function.
- *                               The module skeleton propagates its own one.
- *
- *  @return EOK on success.
- *  @return ENOMEM if there is not enough memory left.
- *
- */
-int net_initialize_build(async_client_conn_t client_connection)
-{
-	int rc;
-	
-	task_id_t task_id = net_spawn((uint8_t *) "/srv/ip");
-	if (!task_id)
-		return EINVAL;
-	
-	rc = add_module(NULL, &net_globals.modules, (uint8_t *) IP_NAME,
-	    (uint8_t *) IP_FILENAME, SERVICE_IP, task_id, ip_connect_module);
-	if (rc != EOK)
-		return rc;
-	
-	if (!net_spawn((uint8_t *) "/srv/icmp"))
-		return EINVAL;
-	
-	if (!net_spawn((uint8_t *) "/srv/udp"))
-		return EINVAL;
-	
-	if (!net_spawn((uint8_t *) "/srv/tcp"))
-		return EINVAL;
-	
-	return EOK;
-}
-
-/** Process the module message.
- *
- * Distribute the message to the right module.
- *
- * @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.
- * @return Other error codes.
- *
- */
-int net_module_message(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *count)
-{
-	if (IS_NET_PACKET_MESSAGE(*call))
-		return packet_server_message(callid, call, answer, count);
-	
-	return net_message(callid, call, answer, count);
-}
-
-/** @}
- */
Index: uspace/srv/net/net/packet_server.c
===================================================================
--- uspace/srv/net/net/packet_server.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/srv/net/net/packet_server.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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.
+ */
+
+/** @addtogroup libpacket
+ *  @{
+ */
+
+/** @file
+ * Packet server implementation.
+ */
+
+#include <align.h>
+#include <assert.h>
+#include <async.h>
+#include <errno.h>
+#include <str_error.h>
+#include <stdio.h>
+#include <fibril_synch.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <ipc/packet.h>
+#include <ipc/net.h>
+#include <net/packet.h>
+#include <net/packet_header.h>
+
+#include "packet_server.h"
+
+#define PACKET_SERVER_PROFILE 1
+
+/** Number of queues cacheing the unused packets */
+#define FREE_QUEUES_COUNT	7
+/** Maximum number of packets in each queue */
+#define FREE_QUEUE_MAX_LENGTH	16
+
+/** The default address length reserved for new packets. */
+#define DEFAULT_ADDR_LEN	32
+
+/** The default prefix reserved for new packets. */
+#define DEFAULT_PREFIX		64
+
+/** The default suffix reserved for new packets. */
+#define DEFAULT_SUFFIX		64
+
+/** The queue with unused packets */
+typedef struct packet_queue {
+	packet_t *first;	/**< First packet in the queue */
+	size_t packet_size; /**< Maximal size of the packets in this queue */
+	int count;			/**< Length of the queue */
+} packet_queue_t;
+
+/** Packet server global data. */
+static struct {
+	/** Safety lock. */
+	fibril_mutex_t lock;
+	/** Free packet queues. */
+	packet_queue_t free_queues[FREE_QUEUES_COUNT];
+	
+	/** Total packets allocated. */
+	packet_id_t next_id;
+} ps_globals = {
+	.lock = FIBRIL_MUTEX_INITIALIZER(ps_globals.lock),
+	.free_queues = {
+		{ NULL, PAGE_SIZE, 0},
+		{ NULL, PAGE_SIZE * 2, 0},
+		{ NULL, PAGE_SIZE * 4, 0},
+		{ NULL, PAGE_SIZE * 8, 0},
+		{ NULL, PAGE_SIZE * 16, 0},
+		{ NULL, PAGE_SIZE * 32, 0},
+		{ NULL, PAGE_SIZE * 64, 0},
+	},
+	.next_id = 1
+};
+
+/** Clears and initializes the packet according to the given dimensions.
+ *
+ * @param[in] packet	The packet to be initialized.
+ * @param[in] addr_len	The source and destination addresses maximal length in
+ *			bytes.
+ * @param[in] max_prefix The maximal prefix length in bytes.
+ * @param[in] max_content The maximal content length in bytes.
+ * @param[in] max_suffix The maximal suffix length in bytes.
+ */
+static void packet_init(packet_t *packet,
+	size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix)
+{
+	/* Clear the packet content */
+	bzero(((void *) packet) + sizeof(packet_t),
+	    packet->length - sizeof(packet_t));
+	
+	/* Clear the packet header */
+	packet->order = 0;
+	packet->metric = 0;
+	packet->previous = 0;
+	packet->next = 0;
+	packet->offload_info = 0;
+	packet->offload_mask = 0;
+	packet->addr_len = 0;
+	packet->src_addr = sizeof(packet_t);
+	packet->dest_addr = packet->src_addr + addr_len;
+	packet->max_prefix = max_prefix;
+	packet->max_content = max_content;
+	packet->data_start = packet->dest_addr + addr_len + packet->max_prefix;
+	packet->data_end = packet->data_start;
+}
+
+/**
+ * Releases the memory allocated for the packet
+ *
+ * @param[in] packet Pointer to the memory where the packet was allocated
+ */
+static void packet_dealloc(packet_t *packet)
+{
+	pm_remove(packet);
+	munmap(packet, packet->length);
+}
+
+/** Creates a new packet of dimensions at least as given.
+ *
+ * @param[in] length	The total length of the packet, including the header,
+ *			the addresses and the data of the packet.
+ * @param[in] addr_len	The source and destination addresses maximal length in
+ *			bytes.
+ * @param[in] max_prefix The maximal prefix length in bytes.
+ * @param[in] max_content The maximal content length in bytes.
+ * @param[in] max_suffix The maximal suffix length in bytes.
+ * @return		The packet of dimensions at least as given.
+ * @return		NULL if there is not enough memory left.
+ */
+static packet_t *packet_alloc(size_t length, size_t addr_len,
+	size_t max_prefix, size_t max_content, size_t max_suffix)
+{
+	packet_t *packet;
+	int rc;
+
+	/* Global lock is locked */
+	assert(fibril_mutex_is_locked(&ps_globals.lock));
+	/* The length is some multiple of PAGE_SIZE */
+	assert(!(length & (PAGE_SIZE - 1)));
+
+	packet = (packet_t *) mmap(NULL, length, PROTO_READ | PROTO_WRITE,
+		MAP_SHARED | MAP_ANONYMOUS, 0, 0);
+	if (packet == MAP_FAILED)
+		return NULL;
+	
+	/* Using 32bit packet_id the id could overflow */
+	packet_id_t pid;
+	do {
+		pid = ps_globals.next_id;
+		ps_globals.next_id++;
+	} while (!pid || pm_find(pid));
+	packet->packet_id = pid;
+
+	packet->length = length;
+	packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
+	packet->magic_value = PACKET_MAGIC_VALUE;
+	rc = pm_add(packet);
+	if (rc != EOK) {
+		packet_dealloc(packet);
+		return NULL;
+	}
+	
+	return packet;
+}
+
+/** Return the packet of dimensions at least as given.
+ *
+ * Try to reuse free packets first.
+ * Create a new packet aligned to the memory page size if none available.
+ * Lock the global data during its processing.
+ *
+ * @param[in] addr_len	The source and destination addresses maximal length in
+ *			bytes.
+ * @param[in] max_prefix The maximal prefix length in bytes.
+ * @param[in] max_content The maximal content length in bytes.
+ * @param[in] max_suffix The maximal suffix length in bytes.
+ * @return		The packet of dimensions at least as given.
+ * @return		NULL if there is not enough memory left.
+ */
+static packet_t *packet_get_local(size_t addr_len,
+	size_t max_prefix, size_t max_content, size_t max_suffix)
+{
+	size_t length = ALIGN_UP(sizeof(packet_t) + 2 * addr_len
+		+ max_prefix + max_content + max_suffix, PAGE_SIZE);
+	
+	if (length > PACKET_MAX_LENGTH)
+		return NULL;
+
+	fibril_mutex_lock(&ps_globals.lock);
+	
+	packet_t *packet;
+	unsigned int index;
+	
+	for (index = 0; index < FREE_QUEUES_COUNT; index++) {
+		if ((length > ps_globals.free_queues[index].packet_size) &&
+			(index < FREE_QUEUES_COUNT - 1))
+			continue;
+		
+		packet = ps_globals.free_queues[index].first;
+		while (packet_is_valid(packet) && (packet->length < length))
+			packet = pm_find(packet->next);
+		
+		if (packet_is_valid(packet)) {
+			ps_globals.free_queues[index].count--;
+			if (packet == ps_globals.free_queues[index].first) {
+				ps_globals.free_queues[index].first = pq_detach(packet);
+			} else {
+				pq_detach(packet);
+			}
+			
+			packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
+			fibril_mutex_unlock(&ps_globals.lock);
+			
+			return packet;
+		}
+	}
+	
+	packet = packet_alloc(length, addr_len,
+		max_prefix, max_content, max_suffix);
+	
+	fibril_mutex_unlock(&ps_globals.lock);
+	
+	return packet;
+}
+
+/** Release the packet and returns it to the appropriate free packet queue.
+ *
+ * @param[in] packet	The packet to be released.
+ *
+ */
+static void packet_release(packet_t *packet)
+{
+	int index;
+	int result;
+
+	assert(fibril_mutex_is_locked(&ps_globals.lock));
+
+	for (index = 0; (index < FREE_QUEUES_COUNT - 1) &&
+	    (packet->length > ps_globals.free_queues[index].packet_size); index++) {
+		;
+	}
+	
+	ps_globals.free_queues[index].count++;
+	result = pq_add(&ps_globals.free_queues[index].first, packet,
+		packet->length,	packet->length);
+	assert(result == EOK);
+}
+
+/** Releases the packet queue.
+ *
+ * @param[in] packet_id	The first packet identifier.
+ * @return		EOK on success.
+ * @return		ENOENT if there is no such packet.
+ */
+static int packet_release_wrapper(packet_id_t packet_id)
+{
+	packet_t *packet;
+
+	packet = pm_find(packet_id);
+	if (!packet_is_valid(packet))
+		return ENOENT;
+
+	fibril_mutex_lock(&ps_globals.lock);
+	pq_destroy(packet, packet_release);
+	fibril_mutex_unlock(&ps_globals.lock);
+
+	return EOK;
+}
+
+/** Shares the packet memory block.
+ * @param[in] packet	The packet to be shared.
+ * @return		EOK on success.
+ * @return		EINVAL if the packet is not valid.
+ * @return		EINVAL if the calling module does not accept the memory.
+ * @return		ENOMEM if the desired and actual sizes differ.
+ * @return		Other error codes as defined for the
+ *			async_share_in_finalize() function.
+ */
+static int packet_reply(packet_t *packet)
+{
+	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);
+		return ENOMEM;
+	}
+	
+	return async_share_in_finalize(callid, packet,
+	    PROTO_READ | PROTO_WRITE);
+}
+
+/** Processes the packet server 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		ENOMEM if there is not enough memory left.
+ * @return		ENOENT if there is no such packet as in the packet
+ *			message parameter.
+ * @return		ENOTSUP if the message is not known.
+ * @return		Other error codes as defined for the
+ *			packet_release_wrapper() function.
+ */
+int packet_server_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
+    size_t *answer_count)
+{
+	packet_t *packet;
+	
+	if (!IPC_GET_IMETHOD(*call))
+		return EOK;
+	
+	*answer_count = 0;
+	switch (IPC_GET_IMETHOD(*call)) {
+	case NET_PACKET_CREATE_1:
+		packet = packet_get_local(DEFAULT_ADDR_LEN, DEFAULT_PREFIX,
+			IPC_GET_CONTENT(*call), DEFAULT_SUFFIX);
+		if (!packet)
+			return ENOMEM;
+		*answer_count = 2;
+		IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
+		IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
+		return EOK;
+	
+	case NET_PACKET_CREATE_4:
+		packet = packet_get_local(
+			((DEFAULT_ADDR_LEN < IPC_GET_ADDR_LEN(*call)) ?
+		    IPC_GET_ADDR_LEN(*call) : DEFAULT_ADDR_LEN),
+		    DEFAULT_PREFIX + IPC_GET_PREFIX(*call),
+		    IPC_GET_CONTENT(*call),
+		    DEFAULT_SUFFIX + IPC_GET_SUFFIX(*call));
+		if (!packet)
+			return ENOMEM;
+		*answer_count = 2;
+		IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
+		IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
+		return EOK;
+	
+	case NET_PACKET_GET:
+		packet = pm_find(IPC_GET_ID(*call));
+		if (!packet_is_valid(packet)) {
+			return ENOENT;
+		}
+		return packet_reply(packet);
+	
+	case NET_PACKET_GET_SIZE:
+		packet = pm_find(IPC_GET_ID(*call));
+		if (!packet_is_valid(packet))
+			return ENOENT;
+		IPC_SET_ARG1(*answer, (sysarg_t) packet->length);
+		*answer_count = 1;
+		return EOK;
+	
+	case NET_PACKET_RELEASE:
+		return packet_release_wrapper(IPC_GET_ID(*call));
+	}
+	
+	return ENOTSUP;
+}
+
+int packet_server_init()
+{
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/srv/net/net/packet_server.h
===================================================================
--- uspace/srv/net/net/packet_server.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
+++ uspace/srv/net/net/packet_server.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * 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.
+ */
+
+/** @addtogroup libpacket
+ * @{
+ */
+
+/** @file
+ * Packet server.
+ * The hosting module has to be compiled with both the packet.c and the
+ * packet_server.c source files. To function correctly, initialization of the
+ * packet map by the pm_init() function has to happen at the first place. Then
+ * the packet messages have to be processed by the packet_server_message()
+ * function. The packet map should be released by the pm_destroy() function
+ * during the module termination.
+ * @see IS_NET_PACKET_MESSAGE()
+ */
+
+#ifndef NET_PACKET_SERVER_H_
+#define NET_PACKET_SERVER_H_
+
+#include <ipc/common.h>
+
+extern int packet_server_init(void);
+extern int packet_server_message(ipc_callid_t, ipc_call_t *, ipc_call_t *,
+    size_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/netif/lo/Makefile
===================================================================
--- uspace/srv/net/netif/lo/Makefile	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,46 +1,0 @@
-#
-# Copyright (c) 2005 Martin Decky
-# Copyright (c) 2007 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.
-#
-
-USPACE_PREFIX = ../../../..
-ROOT_PATH = $(USPACE_PREFIX)/..
-LIBS = $(LIBNET_PREFIX)/libnet.a
-EXTRA_CFLAGS = -I$(LIBNET_PREFIX)/include
-
-COMMON_MAKEFILE = $(ROOT_PATH)/Makefile.common
-CONFIG_MAKEFILE = $(ROOT_PATH)/Makefile.config
-
--include $(COMMON_MAKEFILE)
--include $(CONFIG_MAKEFILE)
-
-BINARY = lo
-
-SOURCES = \
-	lo.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/net/netif/lo/lo.c
===================================================================
--- uspace/srv/net/netif/lo/lo.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ 	(revision )
@@ -1,231 +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 lo
- * @{
- */
-
-/** @file
- * Loopback network interface implementation.
- */
-
-#include <async.h>
-#include <errno.h>
-#include <stdio.h>
-#include <str.h>
-#include <ns.h>
-#include <ipc/services.h>
-#include <ipc/nil.h>
-#include <net/modules.h>
-#include <adt/measured_strings.h>
-#include <packet_client.h>
-#include <net/device.h>
-#include <netif_skel.h>
-#include <nil_remote.h>
-
-/** Default address length. */
-#define DEFAULT_ADDR_LEN  6
-
-/** Loopback module name. */
-#define NAME  "lo"
-
-static uint8_t default_addr[DEFAULT_ADDR_LEN] =
-    {0, 0, 0, 0, 0, 0};
-
-int netif_specific_message(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *count)
-{
-	return ENOTSUP;
-}
-
-int netif_get_addr_message(device_id_t device_id, measured_string_t *address)
-{
-	if (!address)
-		return EBADMEM;
-	
-	address->value = default_addr;
-	address->length = DEFAULT_ADDR_LEN;
-	
-	return EOK;
-}
-
-int netif_get_device_stats(device_id_t device_id, device_stats_t *stats)
-{
-	if (!stats)
-		return EBADMEM;
-	
-	netif_device_t *device;
-	int rc = find_device(device_id, &device);
-	if (rc != EOK)
-		return rc;
-	
-	memcpy(stats, (device_stats_t *) device->specific,
-	    sizeof(device_stats_t));
-	
-	return EOK;
-}
-
-/** Change the loopback state.
- *
- * @param[in] device The device structure.
- * @param[in] state  The new device state.
- *
- * @return New state if changed.
- * @return EOK otherwise.
- *
- */
-static void change_state_message(netif_device_t *device, device_state_t state)
-{
-	if (device->state != state) {
-		device->state = state;
-		
-		const char *desc;
-		switch (state) {
-		case NETIF_ACTIVE:
-			desc = "active";
-			break;
-		case NETIF_STOPPED:
-			desc = "stopped";
-			break;
-		default:
-			desc = "unknown";
-		}
-		
-		printf("%s: State changed to %s\n", NAME, desc);
-	}
-}
-
-/** Create and return the loopback network interface structure.
- *
- * @param[in]  device_id New devce identifier.
- * @param[out] device    Device structure.
- *
- * @return EOK on success.
- * @return EXDEV if one loopback network interface already exists.
- * @return ENOMEM if there is not enough memory left.
- *
- */
-static int lo_create(device_id_t device_id, netif_device_t **device)
-{
-	if (netif_device_map_count(&netif_globals.device_map) > 0)
-		return EXDEV;
-	
-	*device = (netif_device_t *) malloc(sizeof(netif_device_t));
-	if (!*device)
-		return ENOMEM;
-	
-	(*device)->specific = (device_stats_t *) malloc(sizeof(device_stats_t));
-	if (!(*device)->specific) {
-		free(*device);
-		return ENOMEM;
-	}
-	
-	null_device_stats((device_stats_t *) (*device)->specific);
-	(*device)->device_id = device_id;
-	(*device)->state = NETIF_STOPPED;
-	int index = netif_device_map_add(&netif_globals.device_map,
-	    (*device)->device_id, *device);
-	
-	if (index < 0) {
-		free(*device);
-		free((*device)->specific);
-		*device = NULL;
-		return index;
-	}
-	
-	return EOK;
-}
-
-int netif_initialize(void)
-{
-	return service_register(SERVICE_LO);
-}
-
-int netif_probe_message(device_id_t device_id, int irq, void *io)
-{
-	/* Create a new device */
-	netif_device_t *device;
-	int rc = lo_create(device_id, &device);
-	if (rc != EOK)
-		return rc;
-	
-	printf("%s: Device created (id: %d)\n", NAME, device->device_id);
-	return EOK;
-}
-
-int netif_send_message(device_id_t device_id, packet_t *packet, services_t sender)
-{
-	netif_device_t *device;
-	int rc = find_device(device_id, &device);
-	if (rc != EOK)
-		return EOK;
-	
-	if (device->state != NETIF_ACTIVE) {
-		netif_pq_release(packet_get_id(packet));
-		return EFORWARD;
-	}
-	
-	packet_t *next = packet;
-	do {
-		((device_stats_t *) device->specific)->send_packets++;
-		((device_stats_t *) device->specific)->receive_packets++;
-		size_t length = packet_get_data_length(next);
-		((device_stats_t *) device->specific)->send_bytes += length;
-		((device_stats_t *) device->specific)->receive_bytes += length;
-		next = pq_next(next);
-	} while (next);
-	
-	async_sess_t *nil_sess = netif_globals.nil_sess;
-	fibril_rwlock_write_unlock(&netif_globals.lock);
-	
-	nil_received_msg(nil_sess, device_id, packet, sender);
-	
-	fibril_rwlock_write_lock(&netif_globals.lock);
-	return EOK;
-}
-
-int netif_start_message(netif_device_t *device)
-{
-	change_state_message(device, NETIF_ACTIVE);
-	return device->state;
-}
-
-int netif_stop_message(netif_device_t *device)
-{
-	change_state_message(device, NETIF_STOPPED);
-	return device->state;
-}
-
-int main(int argc, char *argv[])
-{
-	/* Start the module */
-	return netif_module_start();
-}
-
-/** @}
- */
Index: uspace/srv/net/nil/eth/eth.c
===================================================================
--- uspace/srv/net/nil/eth/eth.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/nil/eth/eth.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Radim Vansa
  * All rights reserved.
  *
@@ -36,4 +37,5 @@
  */
 
+#include <assert.h>
 #include <async.h>
 #include <malloc.h>
@@ -52,5 +54,4 @@
 #include <protocol_map.h>
 #include <net/device.h>
-#include <netif_remote.h>
 #include <net_interface.h>
 #include <il_remote.h>
@@ -58,4 +59,5 @@
 #include <packet_client.h>
 #include <packet_remote.h>
+#include <device/nic.h>
 #include <nil_skel.h>
 #include "eth.h"
@@ -167,5 +169,5 @@
 INT_MAP_IMPLEMENT(eth_protos, eth_proto_t);
 
-int nil_device_state_msg_local(device_id_t device_id, sysarg_t state)
+int nil_device_state_msg_local(nic_device_id_t device_id, sysarg_t state)
 {
 	int index;
@@ -195,12 +197,8 @@
 	fibril_rwlock_write_lock(&eth_globals.devices_lock);
 	fibril_rwlock_write_lock(&eth_globals.protos_lock);
+	
 	eth_globals.net_sess = sess;
-
-	eth_globals.broadcast_addr =
-	    measured_string_create_bulk((uint8_t *) "\xFF\xFF\xFF\xFF\xFF\xFF", ETH_ADDR);
-	if (!eth_globals.broadcast_addr) {
-		rc = ENOMEM;
-		goto out;
-	}
+	memcpy(eth_globals.broadcast_addr, "\xFF\xFF\xFF\xFF\xFF\xFF",
+			ETH_ADDR);
 
 	rc = eth_devices_initialize(&eth_globals.devices);
@@ -215,4 +213,5 @@
 		eth_devices_destroy(&eth_globals.devices, free);
 	}
+	
 out:
 	fibril_rwlock_write_unlock(&eth_globals.protos_lock);
@@ -222,59 +221,18 @@
 }
 
-/** Process IPC messages from the registered device driver modules in an
- * infinite loop.
- *
- * @param[in]     iid   Message identifier.
- * @param[in,out] icall Message parameters.
- * @param[in]     arg   Local argument.
- *
- */
-static void eth_receiver(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	packet_t *packet;
-	int rc;
-
-	while (true) {
-		switch (IPC_GET_IMETHOD(*icall)) {
-		case NET_NIL_DEVICE_STATE:
-			nil_device_state_msg_local(IPC_GET_DEVICE(*icall),
-			    IPC_GET_STATE(*icall));
-			async_answer_0(iid, EOK);
-			break;
-		case NET_NIL_RECEIVED:
-			rc = packet_translate_remote(eth_globals.net_sess,
-			    &packet, IPC_GET_PACKET(*icall));
-			if (rc == EOK)
-				rc = nil_received_msg_local(IPC_GET_DEVICE(*icall),
-				    packet, 0);
-			
-			async_answer_0(iid, (sysarg_t) rc);
-			break;
-		default:
-			async_answer_0(iid, (sysarg_t) ENOTSUP);
-		}
-		
-		iid = async_get_call(icall);
-	}
-}
-
-/** Registers new device or updates the MTU of an existing one.
- *
- * Determines the device local hardware address.
- *
- * @param[in] device_id	The new device identifier.
- * @param[in] service	The device driver service.
- * @param[in] mtu	The device maximum transmission unit.
- * @return		EOK on success.
- * @return		EEXIST if the device with the different service exists.
- * @return		ENOMEM if there is not enough memory left.
- * @return		Other error codes as defined for the
- *			net_get_device_conf_req() function.
- * @return		Other error codes as defined for the
- *			netif_bind_service() function.
- * @return		Other error codes as defined for the
- *			netif_get_addr_req() function.
- */
-static int eth_device_message(device_id_t device_id, services_t service,
+/** Register new device or updates the MTU of an existing one.
+ *
+ * Determine the device local hardware address.
+ *
+ * @param[in] device_id New device identifier.
+ * @param[in] handle    Device driver handle.
+ * @param[in] mtu       Device maximum transmission unit.
+ *
+ * @return EOK on success.
+ * @return EEXIST if the device with the different service exists.
+ * @return ENOMEM if there is not enough memory left.
+ *
+ */
+static int eth_device_message(nic_device_id_t device_id, devman_handle_t handle,
     size_t mtu)
 {
@@ -301,5 +259,5 @@
 	device = eth_devices_find(&eth_globals.devices, device_id);
 	if (device) {
-		if (device->service != service) {
+		if (device->handle != handle) {
 			printf("Device %d already exists\n", device->device_id);
 			fibril_rwlock_write_unlock(&eth_globals.devices_lock);
@@ -340,5 +298,5 @@
 
 	device->device_id = device_id;
-	device->service = service;
+	device->handle = handle;
 	device->flags = 0;
 	if ((mtu > 0) && (mtu <= ETH_MAX_TAGGED_CONTENT(device->flags)))
@@ -377,6 +335,6 @@
 	
 	/* Bind the device driver */
-	device->sess = netif_bind_service(device->service, device->device_id,
-	    SERVICE_ETHERNET, eth_receiver);
+	device->sess = devman_device_connect(EXCHANGE_SERIALIZE, handle,
+	    IPC_FLAG_BLOCKING);
 	if (device->sess == NULL) {
 		fibril_rwlock_write_unlock(&eth_globals.devices_lock);
@@ -385,7 +343,8 @@
 	}
 	
+	nic_connect_to_nil(device->sess, SERVICE_ETHERNET, device_id);
+	
 	/* Get hardware address */
-	rc = netif_get_addr_req(device->sess, device->device_id, &device->addr,
-	    &device->addr_data);
+	rc = nic_get_address(device->sess, &device->addr);
 	if (rc != EOK) {
 		fibril_rwlock_write_unlock(&eth_globals.devices_lock);
@@ -399,16 +358,12 @@
 	if (index < 0) {
 		fibril_rwlock_write_unlock(&eth_globals.devices_lock);
-		free(device->addr);
-		free(device->addr_data);
 		free(device);
 		return index;
 	}
 	
-	printf("%s: Device registered (id: %d, service: %d: mtu: %zu, "
-	    "mac: %02x:%02x:%02x:%02x:%02x:%02x, flags: 0x%x)\n",
-	    NAME, device->device_id, device->service, device->mtu,
-	    device->addr_data[0], device->addr_data[1],
-	    device->addr_data[2], device->addr_data[3],
-	    device->addr_data[4], device->addr_data[5], device->flags);
+	printf("%s: Device registered (id: %d, handle: %zu: mtu: %zu, "
+	    "mac: " PRIMAC ", flags: 0x%x)\n", NAME,
+	    device->device_id, device->handle, device->mtu,
+	    ARGSMAC(device->addr.address), device->flags);
 
 	fibril_rwlock_write_unlock(&eth_globals.devices_lock);
@@ -456,5 +411,5 @@
 		fcs = (eth_fcs_t *) data + length - sizeof(eth_fcs_t);
 		length -= sizeof(eth_fcs_t);
-	} else if(type <= ETH_MAX_CONTENT) {
+	} else if (type <= ETH_MAX_CONTENT) {
 		/* Translate "LSAP" values */
 		if ((header->lsap.dsap == ETH_LSAP_GLSAP) &&
@@ -462,5 +417,5 @@
 			/* Raw packet -- discard */
 			return NULL;
-		} else if((header->lsap.dsap == ETH_LSAP_SNAP) &&
+		} else if ((header->lsap.dsap == ETH_LSAP_SNAP) &&
 		    (header->lsap.ssap == ETH_LSAP_SNAP)) {
 			/*
@@ -469,12 +424,10 @@
 			 */
 			type = ntohs(header->snap.ethertype);
-			prefix = sizeof(eth_header_t) +
-			    sizeof(eth_header_lsap_t) +
+			prefix = sizeof(eth_header_t) + sizeof(eth_header_lsap_t) +
 			    sizeof(eth_header_snap_t);
 		} else {
 			/* IEEE 802.3 + 802.2 LSAP */
 			type = lsap_map(header->lsap.dsap);
-			prefix = sizeof(eth_header_t) +
-			    sizeof(eth_header_lsap_t);
+			prefix = sizeof(eth_header_t) + sizeof(eth_header_lsap_t);
 		}
 
@@ -506,6 +459,5 @@
 }
 
-int nil_received_msg_local(device_id_t device_id, packet_t *packet,
-    services_t target)
+int nil_received_msg_local(nic_device_id_t device_id, packet_t *packet)
 {
 	eth_proto_t *proto;
@@ -523,6 +475,6 @@
 	flags = device->flags;
 	fibril_rwlock_read_unlock(&eth_globals.devices_lock);
-	
 	fibril_rwlock_read_lock(&eth_globals.protos_lock);
+	
 	do {
 		next = pq_detach(packet);
@@ -537,5 +489,5 @@
 		}
 		packet = next;
-	} while(packet);
+	} while (packet);
 
 	fibril_rwlock_read_unlock(&eth_globals.protos_lock);
@@ -554,5 +506,5 @@
  * @return		ENOENT if there is no such device.
  */
-static int eth_packet_space_message(device_id_t device_id, size_t *addr_len,
+static int eth_packet_space_message(nic_device_id_t device_id, size_t *addr_len,
     size_t *prefix, size_t *content, size_t *suffix)
 {
@@ -579,24 +531,22 @@
 }
 
-/** Returns the device hardware address.
+/** Send the device hardware address.
  *
  * @param[in] device_id	The device identifier.
  * @param[in] type	Type of the desired address.
- * @param[out] address	The device hardware address.
  * @return		EOK on success.
  * @return		EBADMEM if the address parameter is NULL.
  * @return		ENOENT if there no such device.
  */
-static int eth_addr_message(device_id_t device_id, eth_addr_type_t type,
-    measured_string_t **address)
-{
-	eth_device_t *device;
-
-	if (!address)
-		return EBADMEM;
-
-	if (type == ETH_BROADCAST_ADDR) {
-		*address = eth_globals.broadcast_addr;
-	} else {
+static int eth_addr_message(nic_device_id_t device_id, eth_addr_type_t type)
+{
+	eth_device_t *device = NULL;
+	uint8_t *address;
+	size_t max_len;
+	ipc_callid_t callid;
+	
+	if (type == ETH_BROADCAST_ADDR)
+		address = eth_globals.broadcast_addr;
+	else {
 		fibril_rwlock_read_lock(&eth_globals.devices_lock);
 		device = eth_devices_find(&eth_globals.devices, device_id);
@@ -605,9 +555,30 @@
 			return ENOENT;
 		}
-		*address = device->addr;
+		
+		address = (uint8_t *) &device->addr.address;
+	}
+	
+	int rc = EOK;
+	if (!async_data_read_receive(&callid, &max_len)) {
+		rc = EREFUSED;
+		goto end;
+	}
+	
+	if (max_len < ETH_ADDR) {
+		async_data_read_finalize(callid, NULL, 0);
+		rc = ELIMIT;
+		goto end;
+	}
+	
+	rc = async_data_read_finalize(callid, address, ETH_ADDR);
+	if (rc != EOK)
+		goto end;
+	
+end:
+	
+	if (type == ETH_LOCAL_ADDR)
 		fibril_rwlock_read_unlock(&eth_globals.devices_lock);
-	}
-	
-	return (*address) ? EOK : ENOENT;
+	
+	return rc;
 }
 
@@ -659,5 +630,5 @@
 	}
 	
-	printf("%s: Protocol registered (protocol: %d, service: %d)\n",
+	printf("%s: Protocol registered (protocol: %d, service: %#x)\n",
 	    NAME, proto->protocol, proto->service);
 	
@@ -697,6 +668,14 @@
 	if (i < 0)
 		return i;
+	
 	if (i != ETH_ADDR)
 		return EINVAL;
+	
+	for (i = 0; i < ETH_ADDR; i++) {
+		if (src[i]) {
+			src_addr = src;
+			break;
+		}
+	}
 
 	length = packet_get_data_length(packet);
@@ -722,5 +701,5 @@
 		memcpy(header_dix->destination_address, dest, ETH_ADDR);
 		src = &header_dix->destination_address[0];
-	} else if(IS_8023_2_LSAP(flags)) {
+	} else if (IS_8023_2_LSAP(flags)) {
 		header_lsap = PACKET_PREFIX(packet, eth_header_lsap_t);
 		if (!header_lsap)
@@ -735,5 +714,5 @@
 		memcpy(header_lsap->header.destination_address, dest, ETH_ADDR);
 		src = &header_lsap->header.destination_address[0];
-	} else if(IS_8023_2_SNAP(flags)) {
+	} else if (IS_8023_2_SNAP(flags)) {
 		header = PACKET_PREFIX(packet, eth_header_snap_t);
 		if (!header)
@@ -746,5 +725,5 @@
 		header->lsap.ctrl = IEEE_8023_2_UI;
 		
-		for (i = 0; i < 3; ++ i)
+		for (i = 0; i < 3; i++)
 			header->snap.protocol[i] = 0;
 		
@@ -760,5 +739,5 @@
 			return ENOMEM;
 		
-		for (i = 0; i < 7; ++ i)
+		for (i = 0; i < 7; i++)
 			preamble->preamble[i] = ETH_PREAMBLE;
 		
@@ -787,5 +766,5 @@
  * @return		EINVAL if the service parameter is not known.
  */
-static int eth_send_message(device_id_t device_id, packet_t *packet,
+static int eth_send_message(nic_device_id_t device_id, packet_t *packet,
     services_t sender)
 {
@@ -813,5 +792,5 @@
 	do {
 		rc = eth_prepare_packet(device->flags, next,
-		    (uint8_t *) device->addr->value, ethertype, device->mtu);
+		    (uint8_t *) &device->addr.address, ethertype, device->mtu);
 		if (rc != EOK) {
 			/* Release invalid packet */
@@ -825,20 +804,61 @@
 			next = pq_next(next);
 		}
-	} while(next);
+	} while (next);
 	
 	/* Send packet queue */
-	if (packet) {
-		netif_send_msg(device->sess, device_id, packet,
-		    SERVICE_ETHERNET);
-	}
-
+	if (packet)
+		nic_send_message(device->sess, packet_get_id(packet));
+	
 	fibril_rwlock_read_unlock(&eth_globals.devices_lock);
 	return EOK;
 }
 
+static int eth_addr_changed(nic_device_id_t device_id)
+{
+	nic_address_t address;
+	size_t length;
+	ipc_callid_t data_callid;
+	if (!async_data_write_receive(&data_callid, &length)) {
+		async_answer_0(data_callid, EINVAL);
+		return EINVAL;
+	}
+	if (length > sizeof (nic_address_t)) {
+		async_answer_0(data_callid, ELIMIT);
+		return ELIMIT;
+	}
+	if (async_data_write_finalize(data_callid, &address, length) != EOK) {
+		return EINVAL;
+	}
+
+	fibril_rwlock_write_lock(&eth_globals.devices_lock);
+	/* An existing device? */
+	eth_device_t *device = eth_devices_find(&eth_globals.devices, device_id);
+	if (device) {
+		printf("Device %d changing address from " PRIMAC " to " PRIMAC "\n",
+			device_id, ARGSMAC(device->addr.address), ARGSMAC(address.address));
+		memcpy(&device->addr, &address, sizeof (nic_address_t));
+		fibril_rwlock_write_unlock(&eth_globals.devices_lock);
+
+		/* Notify all upper layer modules */
+		fibril_rwlock_read_lock(&eth_globals.protos_lock);
+		int index;
+		for (index = 0; index < eth_protos_count(&eth_globals.protos); index++) {
+			eth_proto_t *proto = eth_protos_get_index(&eth_globals.protos, index);
+			if (proto->sess != NULL) {
+				il_addr_changed_msg(proto->sess, device->device_id,
+						ETH_ADDR, address.address);
+			}
+		}
+
+		fibril_rwlock_read_unlock(&eth_globals.protos_lock);
+		return EOK;
+	} else {
+		return ENOENT;
+	}
+}
+
 int nil_module_message(ipc_callid_t callid, ipc_call_t *call,
     ipc_call_t *answer, size_t *answer_count)
 {
-	measured_string_t *address;
 	packet_t *packet;
 	size_t addrlen;
@@ -861,5 +881,5 @@
 	case NET_NIL_DEVICE:
 		return eth_device_message(IPC_GET_DEVICE(*call),
-		    IPC_GET_SERVICE(*call), IPC_GET_MTU(*call));
+		    IPC_GET_DEVICE_HANDLE(*call), IPC_GET_MTU(*call));
 	case NET_NIL_SEND:
 		rc = packet_translate_remote(eth_globals.net_sess, &packet,
@@ -867,4 +887,5 @@
 		if (rc != EOK)
 			return rc;
+		
 		return eth_send_message(IPC_GET_DEVICE(*call), packet,
 		    IPC_GET_SERVICE(*call));
@@ -874,4 +895,5 @@
 		if (rc != EOK)
 			return rc;
+		
 		IPC_SET_ADDR(*answer, addrlen);
 		IPC_SET_PREFIX(*answer, prefix);
@@ -879,17 +901,40 @@
 		IPC_SET_SUFFIX(*answer, suffix);
 		*answer_count = 4;
+		
 		return EOK;
 	case NET_NIL_ADDR:
-		rc = eth_addr_message(IPC_GET_DEVICE(*call), ETH_LOCAL_ADDR,
-		    &address);
+		rc = eth_addr_message(IPC_GET_DEVICE(*call), ETH_LOCAL_ADDR);
 		if (rc != EOK)
 			return rc;
-		return measured_strings_reply(address, 1);
+		
+		IPC_SET_ADDR(*answer, ETH_ADDR);
+		*answer_count = 1;
+		
+		return EOK;
 	case NET_NIL_BROADCAST_ADDR:
-		rc = eth_addr_message(IPC_GET_DEVICE(*call), ETH_BROADCAST_ADDR,
-		    &address);
+		rc = eth_addr_message(IPC_GET_DEVICE(*call), ETH_BROADCAST_ADDR);
 		if (rc != EOK)
-			return EOK;
-		return measured_strings_reply(address, 1);
+			return rc;
+		
+		IPC_SET_ADDR(*answer, ETH_ADDR);
+		*answer_count = 1;
+		
+		return EOK;
+	case NET_NIL_DEVICE_STATE:
+		nil_device_state_msg_local(IPC_GET_DEVICE(*call), IPC_GET_STATE(*call));
+		async_answer_0(callid, EOK);
+		return EOK;
+	case NET_NIL_RECEIVED:
+		rc = packet_translate_remote(eth_globals.net_sess, &packet,
+		    IPC_GET_ARG2(*call));
+		if (rc == EOK)
+			rc = nil_received_msg_local(IPC_GET_ARG1(*call), packet);
+		
+		async_answer_0(callid, (sysarg_t) rc);
+		return rc;
+	case NET_NIL_ADDR_CHANGED:
+		rc = eth_addr_changed(IPC_GET_DEVICE(*call));
+		async_answer_0(callid, (sysarg_t) rc);
+		return rc;
 	}
 	
Index: uspace/srv/net/nil/eth/eth.h
===================================================================
--- uspace/srv/net/nil/eth/eth.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/nil/eth/eth.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Radim Vansa
  * All rights reserved.
  *
@@ -43,4 +44,5 @@
 #include <net/device.h>
 #include <adt/measured_strings.h>
+#include <devman.h>
 
 /** Ethernet address length. */
@@ -220,7 +222,7 @@
 struct eth_device {
 	/** Device identifier. */
-	device_id_t device_id;
-	/** Device driver service. */
-	services_t service;
+	nic_device_id_t device_id;
+	/** Device handle */
+	devman_handle_t handle;
 	/** Driver session. */
 	async_sess_t *sess;
@@ -236,8 +238,5 @@
 	
 	/** Actual device hardware address. */
-	measured_string_t *addr;
-	
-	/** Actual device hardware address data. */
-	uint8_t *addr_data;
+	nic_address_t addr;
 };
 
@@ -270,5 +269,5 @@
 	
 	/** Broadcast device hardware address. */
-	measured_string_t *broadcast_addr;
+	uint8_t broadcast_addr[ETH_ADDR];
 };
 
Index: uspace/srv/net/nil/nildummy/nildummy.c
===================================================================
--- uspace/srv/net/nil/nildummy/nildummy.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/nil/nildummy/nildummy.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Radim Vansa
  * All rights reserved.
  *
@@ -36,4 +37,5 @@
  */
 
+#include <assert.h>
 #include <async.h>
 #include <malloc.h>
@@ -50,5 +52,7 @@
 #include <net/packet.h>
 #include <packet_remote.h>
-#include <netif_remote.h>
+#include <packet_client.h>
+#include <devman.h>
+#include <device/nic.h>
 #include <nil_skel.h>
 #include "nildummy.h"
@@ -65,5 +69,5 @@
 DEVICE_MAP_IMPLEMENT(nildummy_devices, nildummy_device_t);
 
-int nil_device_state_msg_local(device_id_t device_id, sysarg_t state)
+int nil_device_state_msg_local(nic_device_id_t device_id, sysarg_t state)
 {
 	fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
@@ -91,42 +95,4 @@
 	
 	return rc;
-}
-
-/** Process IPC messages from the registered device driver modules
- *
- * @param[in]     iid   Message identifier.
- * @param[in,out] icall Message parameters.
- * @param[in]     arg    Local argument.
- *
- */
-static void nildummy_receiver(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	packet_t *packet;
-	int rc;
-	
-	while (true) {
-		switch (IPC_GET_IMETHOD(*icall)) {
-		case NET_NIL_DEVICE_STATE:
-			rc = nil_device_state_msg_local(IPC_GET_DEVICE(*icall),
-			    IPC_GET_STATE(*icall));
-			async_answer_0(iid, (sysarg_t) rc);
-			break;
-		
-		case NET_NIL_RECEIVED:
-			rc = packet_translate_remote(nildummy_globals.net_sess,
-			    &packet, IPC_GET_PACKET(*icall));
-			if (rc == EOK)
-				rc = nil_received_msg_local(IPC_GET_DEVICE(*icall),
-				    packet, 0);
-			
-			async_answer_0(iid, (sysarg_t) rc);
-			break;
-		
-		default:
-			async_answer_0(iid, (sysarg_t) ENOTSUP);
-		}
-		
-		iid = async_get_call(icall);
-	}
 }
 
@@ -148,6 +114,6 @@
  *
  */
-static int nildummy_device_message(device_id_t device_id, services_t service,
-    size_t mtu)
+static int nildummy_device_message(nic_device_id_t device_id,
+    devman_handle_t handle, size_t mtu)
 {
 	fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
@@ -157,8 +123,8 @@
 	    nildummy_devices_find(&nildummy_globals.devices, device_id);
 	if (device) {
-		if (device->service != service) {
-			printf("Device %d already exists\n", device->device_id);
-			fibril_rwlock_write_unlock(
-			    &nildummy_globals.devices_lock);
+		if (device->handle != handle) {
+			printf("Device %d exists, handles do not match\n",
+			    device->device_id);
+			fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
 			return EEXIST;
 		}
@@ -170,6 +136,6 @@
 			device->mtu = NET_DEFAULT_MTU;
 		
-		printf("Device %d already exists:\tMTU\t= %zu\n",
-		    device->device_id, device->mtu);
+		printf("Device %d already exists (mtu: %zu)\n", device->device_id,
+		    device->mtu);
 		fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
 		
@@ -192,13 +158,13 @@
 	
 	device->device_id = device_id;
-	device->service = service;
+	device->handle = handle;
 	if (mtu > 0)
 		device->mtu = mtu;
 	else
 		device->mtu = NET_DEFAULT_MTU;
-
+	
 	/* Bind the device driver */
-	device->sess = netif_bind_service(device->service, device->device_id,
-	    SERVICE_ETHERNET, nildummy_receiver);
+	device->sess = devman_device_connect(EXCHANGE_SERIALIZE, handle,
+	    IPC_FLAG_BLOCKING);
 	if (device->sess == NULL) {
 		fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
@@ -207,7 +173,8 @@
 	}
 	
+	nic_connect_to_nil(device->sess, SERVICE_NILDUMMY, device_id);
+	
 	/* Get hardware address */
-	int rc = netif_get_addr_req(device->sess, device->device_id,
-	    &device->addr, &device->addr_data);
+	int rc = nic_get_address(device->sess, &device->addr);
 	if (rc != EOK) {
 		fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
@@ -215,4 +182,6 @@
 		return rc;
 	}
+	
+	device->addr_len = ETH_ADDR;
 	
 	/* Add to the cache */
@@ -221,12 +190,10 @@
 	if (index < 0) {
 		fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
-		free(device->addr);
-		free(device->addr_data);
 		free(device);
 		return index;
 	}
 	
-	printf("%s: Device registered (id: %d, service: %d, mtu: %zu)\n",
-	    NAME, device->device_id, device->service, device->mtu);
+	printf("%s: Device registered (id: %d, mtu: %zu)\n", NAME,
+	    device->device_id, device->mtu);
 	fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
 	return EOK;
@@ -243,8 +210,7 @@
  *
  */
-static int nildummy_addr_message(device_id_t device_id,
-    measured_string_t **address)
-{
-	if (!address)
+static int nildummy_addr_message(nic_device_id_t device_id, size_t *addrlen)
+{
+	if (!addrlen)
 		return EBADMEM;
 	
@@ -258,9 +224,28 @@
 	}
 	
-	*address = device->addr;
+	ipc_callid_t callid;
+	size_t max_len;
+	if (!async_data_read_receive(&callid, &max_len)) {
+		fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
+		return EREFUSED;
+	}
+	
+	if (max_len < device->addr_len) {
+		fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
+		async_data_read_finalize(callid, NULL, 0);
+		return ELIMIT;
+	}
+	
+	int rc = async_data_read_finalize(callid,
+	    (uint8_t *) &device->addr.address, device->addr_len);
+	if (rc != EOK) {
+		fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
+		return rc;
+	}
+	
+	*addrlen = device->addr_len;
 	
 	fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
-	
-	return (*address) ? EOK : ENOENT;
+	return EOK;
 }
 
@@ -278,6 +263,6 @@
  *
  */
-static int nildummy_packet_space_message(device_id_t device_id, size_t *addr_len,
-    size_t *prefix, size_t *content, size_t *suffix)
+static int nildummy_packet_space_message(nic_device_id_t device_id,
+    size_t *addr_len, size_t *prefix, size_t *content, size_t *suffix)
 {
 	if ((!addr_len) || (!prefix) || (!content) || (!suffix))
@@ -303,6 +288,5 @@
 }
 
-int nil_received_msg_local(device_id_t device_id, packet_t *packet,
-    services_t target)
+int nil_received_msg_local(nic_device_id_t device_id, packet_t *packet)
 {
 	fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
@@ -340,5 +324,5 @@
 	nildummy_globals.proto.sess = sess;
 	
-	printf("%s: Protocol registered (service: %d)\n",
+	printf("%s: Protocol registered (service: %#x)\n",
 	    NAME, nildummy_globals.proto.service);
 	
@@ -358,5 +342,5 @@
  *
  */
-static int nildummy_send_message(device_id_t device_id, packet_t *packet,
+static int nildummy_send_message(nic_device_id_t device_id, packet_t *packet,
     services_t sender)
 {
@@ -372,6 +356,5 @@
 	/* Send packet queue */
 	if (packet)
-		netif_send_msg(device->sess, device_id, packet,
-		    SERVICE_NILDUMMY);
+		nic_send_message(device->sess, packet_get_id(packet));
 	
 	fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
@@ -383,5 +366,4 @@
     ipc_call_t *answer, size_t *answer_count)
 {
-	measured_string_t *address;
 	packet_t *packet;
 	size_t addrlen;
@@ -404,5 +386,5 @@
 	case NET_NIL_DEVICE:
 		return nildummy_device_message(IPC_GET_DEVICE(*call),
-		    IPC_GET_SERVICE(*call), IPC_GET_MTU(*call));
+		    IPC_GET_DEVICE_HANDLE(*call), IPC_GET_MTU(*call));
 	
 	case NET_NIL_SEND:
@@ -427,14 +409,26 @@
 	
 	case NET_NIL_ADDR:
-		rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &address);
+	case NET_NIL_BROADCAST_ADDR:
+		rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &addrlen);
 		if (rc != EOK)
 			return rc;
-		return measured_strings_reply(address, 1);
-	
-	case NET_NIL_BROADCAST_ADDR:
-		rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &address);
-		if (rc != EOK)
-			return rc;
-		return measured_strings_reply(address, 1);
+		
+		IPC_SET_ADDR(*answer, addrlen);
+		*answer_count = 1;
+		return rc;
+	case NET_NIL_DEVICE_STATE:
+		rc = nil_device_state_msg_local(IPC_GET_DEVICE(*call),
+		    IPC_GET_STATE(*call));
+		async_answer_0(callid, (sysarg_t) rc);
+		return rc;
+	
+	case NET_NIL_RECEIVED:
+		rc = packet_translate_remote(nildummy_globals.net_sess, &packet,
+		    IPC_GET_ARG2(*call));
+		if (rc == EOK)
+			rc = nil_received_msg_local(IPC_GET_ARG1(*call), packet);
+		
+		async_answer_0(callid, (sysarg_t) rc);
+		return rc;
 	}
 	
Index: uspace/srv/net/nil/nildummy/nildummy.h
===================================================================
--- uspace/srv/net/nil/nildummy/nildummy.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/nil/nildummy/nildummy.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Radim Vansa
  * All rights reserved.
  *
@@ -41,6 +42,6 @@
 #include <fibril_synch.h>
 #include <ipc/services.h>
+#include <ipc/devman.h>
 #include <net/device.h>
-#include <adt/measured_strings.h>
 
 /** Type definition of the dummy nil global data.
@@ -76,9 +77,7 @@
 struct nildummy_device {
 	/** Device identifier. */
-	device_id_t device_id;
-	
-	/** Device driver service. */
-	services_t service;
-	
+	nic_device_id_t device_id;
+	/** Device driver handle. */
+	devman_handle_t handle;
 	/** Driver session. */
 	async_sess_t *sess;
@@ -88,8 +87,7 @@
 	
 	/** Actual device hardware address. */
-	measured_string_t *addr;
-	
-	/** Actual device hardware address data. */
-	uint8_t *addr_data;
+	nic_address_t addr;
+	/** Actual device hardware address length. */
+	size_t addr_len;
 };
 
Index: uspace/srv/net/tl/icmp/icmp.c
===================================================================
--- uspace/srv/net/tl/icmp/icmp.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/tl/icmp/icmp.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -753,5 +753,5 @@
 			return rc;
 		
-		rc = icmp_echo(icmp_id, icmp_seq, ICMP_GET_SIZE(*call),	
+		rc = icmp_echo(icmp_id, icmp_seq, ICMP_GET_SIZE(*call),
 		    ICMP_GET_TIMEOUT(*call), ICMP_GET_TTL(*call),
 		    ICMP_GET_TOS(*call), ICMP_GET_DONT_FRAGMENT(*call),
Index: uspace/srv/net/tl/tcp/sock.c
===================================================================
--- uspace/srv/net/tl/tcp/sock.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/tl/tcp/sock.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -215,5 +215,5 @@
 	tcp_sock_t lsocket;
 	tcp_sock_t fsocket;
-	device_id_t dev_id;
+	nic_device_id_t dev_id;
 	tcp_phdr_t *phdr;
 	size_t phdr_len;
Index: uspace/srv/net/tl/tcp/tcp.c
===================================================================
--- uspace/srv/net/tl/tcp/tcp.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/tl/tcp/tcp.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -114,5 +114,5 @@
 
 /** Process packet received from network layer. */
-static int tcp_received_msg(device_id_t device_id, packet_t *packet,
+static int tcp_received_msg(nic_device_id_t device_id, packet_t *packet,
     services_t error)
 {
@@ -262,5 +262,5 @@
 {
 	struct sockaddr_in dest;
-	device_id_t dev_id;
+	nic_device_id_t dev_id;
 	void *phdr;
 	size_t phdr_len;
Index: uspace/srv/net/tl/udp/udp.c
===================================================================
--- uspace/srv/net/tl/udp/udp.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/net/tl/udp/udp.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -124,5 +124,5 @@
  *			ip_client_process_packet() function.
  */
-static int udp_process_packet(device_id_t device_id, packet_t *packet,
+static int udp_process_packet(nic_device_id_t device_id, packet_t *packet,
     services_t error)
 {
@@ -322,5 +322,5 @@
  *			udp_process_packet() function.
  */
-static int udp_received_msg(device_id_t device_id, packet_t *packet,
+static int udp_received_msg(nic_device_id_t device_id, packet_t *packet,
     services_t receiver, services_t error)
 {
@@ -499,5 +499,5 @@
 	void *ip_header;
 	size_t headerlen;
-	device_id_t device_id;
+	nic_device_id_t device_id;
 	packet_dimension_t *packet_dimension;
 	size_t size;
@@ -617,7 +617,6 @@
 		    htons(flip_checksum(compact_checksum(checksum)));
 		free(ip_header);
-	} else {
-		device_id = DEVICE_INVALID_ID;
-	}
+	} else
+		device_id = NIC_DEVICE_INVALID_ID;
 
 	/* Prepare the first packet fragment */
@@ -806,5 +805,5 @@
 			size = MAX_UDP_FRAGMENT_SIZE;
 			if (tl_get_ip_packet_dimension(udp_globals.ip_sess,
-			    &udp_globals.dimensions, DEVICE_INVALID_ID,
+			    &udp_globals.dimensions, NIC_DEVICE_INVALID_ID,
 			    &packet_dimension) == EOK) {
 				if (packet_dimension->content < size)
Index: uspace/srv/vfs/vfs.c
===================================================================
--- uspace/srv/vfs/vfs.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/vfs/vfs.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -127,4 +127,7 @@
 			vfs_wait_handle(callid, &call);
 			break;
+		case VFS_IN_MTAB_GET:
+			vfs_get_mtab(callid, &call);
+			break;
 		default:
 			async_answer_0(callid, ENOTSUP);
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/vfs/vfs.h	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -150,4 +150,7 @@
 extern list_t fs_list;		/**< List of registered file systems. */
 
+extern fibril_mutex_t fs_mntlist_lock;
+extern list_t fs_mntlist;	/**< List of mounted file systems. */
+
 extern vfs_pair_t rootfs;	/**< Root file system. */
 
@@ -163,6 +166,4 @@
 extern list_t plb_entries;	/**< List of active PLB entries. */
 
-#define MAX_MNTOPTS_LEN		256
-
 /** Holding this rwlock prevents changes in file system namespace. */ 
 extern fibril_rwlock_t namespace_rwlock;
@@ -171,5 +172,5 @@
 extern void vfs_exchange_release(async_exch_t *);
 
-extern fs_handle_t fs_name_to_handle(char *, bool);
+extern fs_handle_t fs_name_to_handle(unsigned int instance, char *, bool);
 extern vfs_info_t *fs_handle_to_info(fs_handle_t);
 
@@ -219,4 +220,5 @@
 extern void vfs_rename(ipc_callid_t, ipc_call_t *);
 extern void vfs_wait_handle(ipc_callid_t, ipc_call_t *);
+extern void vfs_get_mtab(ipc_callid_t, ipc_call_t *);
 
 #endif
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/vfs/vfs_ops.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -52,4 +52,9 @@
 #include <assert.h>
 #include <vfs/canonify.h>
+#include <vfs/vfs_mtab.h>
+
+FIBRIL_MUTEX_INITIALIZE(mtab_list_lock);
+LIST_INITIALIZE(mtab_list);
+static size_t mtab_size = 0;
 
 /* Forward declarations of static functions. */
@@ -68,5 +73,5 @@
 };
 
-static void vfs_mount_internal(ipc_callid_t rid, service_id_t service_id,
+static int vfs_mount_internal(ipc_callid_t rid, service_id_t service_id,
     fs_handle_t fs_handle, char *mp, char *opts)
 {
@@ -91,5 +96,5 @@
 			fibril_rwlock_write_unlock(&namespace_rwlock);
 			async_answer_0(rid, EBUSY);
-			return;
+			return EBUSY;
 		}
 		
@@ -99,5 +104,5 @@
 			fibril_rwlock_write_unlock(&namespace_rwlock);
 			async_answer_0(rid, rc);
-			return;
+			return rc;
 		}
 		
@@ -106,5 +111,5 @@
 			fibril_rwlock_write_unlock(&namespace_rwlock);
 			async_answer_0(rid, ENOMEM);
-			return;
+			return ENOMEM;
 		}
 		
@@ -135,5 +140,5 @@
 				fibril_rwlock_write_unlock(&namespace_rwlock);
 				async_answer_0(rid, rc);
-				return;
+				return rc;
 			}
 			async_wait_for(msg, &rc);
@@ -142,9 +147,10 @@
 				fibril_rwlock_write_unlock(&namespace_rwlock);
 				async_answer_0(rid, rc);
-				return;
+				return rc;
 			}
 
 			rindex = (fs_index_t) IPC_GET_ARG1(answer);
-			rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
+			rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
+			    IPC_GET_ARG3(answer));
 			rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
 			
@@ -165,5 +171,5 @@
 			fibril_rwlock_write_unlock(&namespace_rwlock);
 			async_answer_0(rid, rc);
-			return;
+			return rc;
 		} else {
 			/*
@@ -173,5 +179,5 @@
 			fibril_rwlock_write_unlock(&namespace_rwlock);
 			async_answer_0(rid, ENOENT);
-			return;
+			return ENOENT;
 		}
 	}
@@ -206,5 +212,5 @@
 		async_answer_0(rid, rc);
 		fibril_rwlock_write_unlock(&namespace_rwlock);
-		return;
+		return rc;
 	}
 	
@@ -221,5 +227,5 @@
 		fibril_rwlock_write_unlock(&namespace_rwlock);
 		async_answer_0(rid, rc);
-		return;
+		return rc;
 	}
 	
@@ -257,4 +263,5 @@
 	async_answer_0(rid, rc);
 	fibril_rwlock_write_unlock(&namespace_rwlock);
+	return rc;
 }
 
@@ -276,8 +283,8 @@
 	
 	/*
-	 * For now, don't make use of ARG3, but it can be used to
-	 * carry mount options in the future.
-	 */
-	
+	 * Instance number is passed as ARG3.
+	 */
+	unsigned int instance = IPC_GET_ARG3(*request);
+
 	/* We want the client to send us the mount point. */
 	char *mp;
@@ -335,5 +342,5 @@
 	fs_handle_t fs_handle;
 recheck:
-	fs_handle = fs_name_to_handle(fs_name, false);
+	fs_handle = fs_name_to_handle(instance, fs_name, false);
 	if (!fs_handle) {
 		if (flags & IPC_FLAG_BLOCKING) {
@@ -351,13 +358,49 @@
 	}
 	fibril_mutex_unlock(&fs_list_lock);
-	
-	/* Acknowledge that we know fs_name. */
-	async_answer_0(callid, EOK);
-	
+
+	/* Add the filesystem info to the list of mounted filesystems */
+	mtab_ent_t *mtab_ent = malloc(sizeof(mtab_ent_t));
+	if (!mtab_ent) {
+		async_answer_0(callid, ENOMEM);
+		async_answer_0(rid, ENOMEM);
+		free(mp);
+		free(fs_name);
+		free(opts);
+		return;
+	}
+
 	/* Do the mount */
-	vfs_mount_internal(rid, service_id, fs_handle, mp, opts);
+	rc = vfs_mount_internal(rid, service_id, fs_handle, mp, opts);
+	if (rc != EOK) {
+		async_answer_0(callid, ENOTSUP);
+		async_answer_0(rid, ENOTSUP);
+		free(mtab_ent);
+		free(mp);
+		free(opts);
+		free(fs_name);
+		return;
+	}
+
+	/* Add the filesystem info to the list of mounted filesystems */
+
+	str_cpy(mtab_ent->mp, MAX_PATH_LEN, mp);
+	str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name);
+	str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts);
+	mtab_ent->instance = instance;
+	mtab_ent->service_id = service_id;
+
+	link_initialize(&mtab_ent->link);
+
+	fibril_mutex_lock(&mtab_list_lock);
+	list_append(&mtab_ent->link, &mtab_list);
+	mtab_size++;
+	fibril_mutex_unlock(&mtab_list_lock);
+
 	free(mp);
 	free(fs_name);
 	free(opts);
+
+	/* Acknowledge that we know fs_name. */
+	async_answer_0(callid, EOK);
 }
 
@@ -432,6 +475,4 @@
 		 */
 		
-		free(mp);
-		
 		exch = vfs_exchange_grab(mr_node->fs_handle);
 		rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
@@ -441,4 +482,5 @@
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
+			free(mp);
 			vfs_node_put(mr_node);
 			async_answer_0(rid, rc);
@@ -458,7 +500,7 @@
 		
 		rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
-		free(mp);
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
+			free(mp);
 			vfs_node_put(mr_node);
 			async_answer_0(rid, rc);
@@ -469,4 +511,5 @@
 		if (!mp_node) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
+			free(mp);
 			vfs_node_put(mr_node);
 			async_answer_0(rid, ENOMEM);
@@ -481,4 +524,5 @@
 		if (rc != EOK) {
 			fibril_rwlock_write_unlock(&namespace_rwlock);
+			free(mp);
 			vfs_node_put(mp_node);
 			vfs_node_put(mr_node);
@@ -498,6 +542,27 @@
 	 */
 	vfs_node_forget(mr_node);
-	
 	fibril_rwlock_write_unlock(&namespace_rwlock);
+
+	fibril_mutex_lock(&mtab_list_lock);
+
+	int found = 0;
+
+	list_foreach(mtab_list, cur) {
+		mtab_ent_t *mtab_ent = list_get_instance(cur, mtab_ent_t,
+		    link);
+
+		if (str_cmp(mtab_ent->mp, mp) == 0) {
+			list_remove(&mtab_ent->link);
+			mtab_size--;
+			free(mtab_ent);
+			found = 1;
+			break;
+		}
+	}
+	assert(found);
+	fibril_mutex_unlock(&mtab_list_lock);
+
+	free(mp);
+
 	async_answer_0(rid, EOK);
 }
@@ -1288,4 +1353,69 @@
 }
 
+void vfs_get_mtab(ipc_callid_t rid, ipc_call_t *request)
+{
+	ipc_callid_t callid;
+	ipc_call_t data;
+	sysarg_t rc = EOK;
+	size_t len;
+
+	fibril_mutex_lock(&mtab_list_lock);
+
+	/* Send to the caller the number of mounted filesystems */
+	callid = async_get_call(&data);
+	if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
+		rc = ENOTSUP;
+		async_answer_0(callid, rc);
+		goto exit;
+	}
+	async_answer_1(callid, EOK, mtab_size);
+
+	list_foreach(mtab_list, cur) {
+		mtab_ent_t *mtab_ent = list_get_instance(cur, mtab_ent_t,
+		    link);
+
+		rc = ENOTSUP;
+
+		if (!async_data_read_receive(&callid, &len)) {
+			async_answer_0(callid, rc);
+			goto exit;
+		}
+
+		(void) async_data_read_finalize(callid, mtab_ent->mp,
+		    str_size(mtab_ent->mp));
+
+		if (!async_data_read_receive(&callid, &len)) {
+			async_answer_0(callid, rc);
+			goto exit;
+		}
+
+		(void) async_data_read_finalize(callid, mtab_ent->opts,
+		    str_size(mtab_ent->opts));
+
+		if (!async_data_read_receive(&callid, &len)) {
+			async_answer_0(callid, rc);
+			goto exit;
+		}
+
+		(void) async_data_read_finalize(callid, mtab_ent->fs_name,
+		    str_size(mtab_ent->fs_name));
+
+		callid = async_get_call(&data);
+
+		if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
+			async_answer_0(callid, rc);
+			goto exit;
+		}
+
+		rc = EOK;
+		async_answer_2(callid, rc, mtab_ent->instance,
+		    mtab_ent->service_id);
+	}
+
+exit:
+	fibril_mutex_unlock(&mtab_list_lock);
+	async_answer_0(rid, rc);
+}
+
 /**
  * @}
Index: uspace/srv/vfs/vfs_register.c
===================================================================
--- uspace/srv/vfs/vfs_register.c	(revision a52de0ea49d86563c5209f5780a0c9d431c14235)
+++ uspace/srv/vfs/vfs_register.c	(revision 77b1c1a02dd99e5b498edea1b825ebd8bbf04b8b)
@@ -154,5 +154,6 @@
 	 * Check for duplicit registrations.
 	 */
-	if (fs_name_to_handle(fs_info->vfs_info.name, false)) {
+	if (fs_name_to_handle(fs_info->vfs_info.instance,
+	    fs_info->vfs_info.name, false)) {
 		/*
 		 * We already register a fs like this.
@@ -297,5 +298,5 @@
  *
  */
-fs_handle_t fs_name_to_handle(char *name, bool lock)
+fs_handle_t fs_name_to_handle(unsigned int instance, char *name, bool lock)
 {
 	int handle = 0;
@@ -306,5 +307,6 @@
 	list_foreach(fs_list, cur) {
 		fs_info_t *fs = list_get_instance(cur, fs_info_t, fs_link);
-		if (str_cmp(fs->vfs_info.name, name) == 0) {
+		if (str_cmp(fs->vfs_info.name, name) == 0 &&
+		    instance == fs->vfs_info.instance) {
 			handle = fs->fs_handle;
 			break;
