Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ boot/Makefile.common	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -73,5 +73,5 @@
 	$(USPACE_PATH)/srv/loader/loader \
 	$(USPACE_PATH)/app/init/init \
-	$(USPACE_PATH)/srv/devmap/devmap \
+	$(USPACE_PATH)/srv/loc/loc \
 	$(USPACE_PATH)/srv/bd/rd/rd \
 	$(USPACE_PATH)/srv/vfs/vfs
@@ -93,5 +93,5 @@
 	$(USPACE_PATH)/srv/hid/input/input \
 	$(USPACE_PATH)/srv/hid/console/console \
-	$(USPACE_PATH)/srv/fs/devfs/devfs
+	$(USPACE_PATH)/srv/fs/locfs/locfs
 
 RD_SRVS_NON_ESSENTIAL = \
@@ -150,4 +150,5 @@
 	$(USPACE_PATH)/app/kill/kill \
 	$(USPACE_PATH)/app/killall/killall \
+	$(USPACE_PATH)/app/locinfo/locinfo \
 	$(USPACE_PATH)/app/mkfat/mkfat \
 	$(USPACE_PATH)/app/lsusb/lsusb \
Index: contrib/bazaar/bzreml/__init__.py
===================================================================
--- contrib/bazaar/bzreml/__init__.py	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ contrib/bazaar/bzreml/__init__.py	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -134,42 +134,10 @@
 				body.write("New Revision: %s%s\n" % (revision_ac_no, merge_marker(revision_ac)))
 				body.write("New Id: %s\n" % revision_ac_id)
-				
-				body.write("\n")
-				
 				for parent_id in revision_ac.parent_ids:
 					body.write("Parent: %s\n" % parent_id)
-					
-					tree_old = branch.repository.revision_tree(parent_id)
-					tree_ac = branch.repository.revision_tree(revision_ac_id)
-					
-					delta = tree_ac.changes_from(tree_old)
-					
-					if (len(delta.added) > 0):
-						body.write("Added:\n")
-						for item in delta.added:
-							body.write("    %s\n" % item[0])
-					
-					if (len(delta.removed) > 0):
-						body.write("Removed:\n")
-						for item in delta.removed:
-							body.write("    %s\n" % item[0])
-					
-					if (len(delta.renamed) > 0):
-						body.write("Renamed:\n")
-						for item in delta.renamed:
-							body.write("    %s -> %s\n" % (item[0], item[1]))
-					
-					if (len(delta.kind_changed) > 0):
-						body.write("Changed:\n")
-						for item in delta.kind_changed:
-							body.write("    %s\n" % item[0])
-						
-					if (len(delta.modified) > 0):
-						body.write("Modified:\n")
-						for item in delta.modified:
-							body.write("    %s\n" % item[0])
-					
-					body.write("\n")
-				
+				
+				body.write("\n")
+				
+				commit_message = ""
 				body.write("Log:\n")
 				if (not revision_ac.message):
@@ -179,4 +147,9 @@
 					for line in log.split("\n"):
 						body.write("%s\n" % line)
+						if (commit_message == ""):
+							commit_message = line
+				
+				if (commit_message == ""):
+					commit_message = "(empty)"
 				
 				body.write("\n")
@@ -184,4 +157,34 @@
 			tree_old = branch.repository.revision_tree(revision_old_id)
 			tree_new = branch.repository.revision_tree(revision_new_id)
+			
+			revision_new_no = branch.revision_id_to_revno(revision_new_id)
+			delta = tree_new.changes_from(tree_old)
+			
+			if (len(delta.added) > 0):
+				body.write("Added:\n")
+				for item in delta.added:
+					body.write("    %s\n" % item[0])
+			
+			if (len(delta.removed) > 0):
+				body.write("Removed:\n")
+				for item in delta.removed:
+					body.write("    %s\n" % item[0])
+			
+			if (len(delta.renamed) > 0):
+				body.write("Renamed:\n")
+				for item in delta.renamed:
+					body.write("    %s -> %s\n" % (item[0], item[1]))
+			
+			if (len(delta.kind_changed) > 0):
+				body.write("Changed:\n")
+				for item in delta.kind_changed:
+					body.write("    %s\n" % item[0])
+			
+			if (len(delta.modified) > 0):
+				body.write("Modified:\n")
+				for item in delta.modified:
+					body.write("    %s\n" % item[0])
+			
+			body.write("\n")
 			
 			tree_old.lock_read()
@@ -196,25 +199,5 @@
 				tree_old.unlock()
 			
-			revision_new_no = branch.revision_id_to_revno(revision_new_id)
-			
-			delta = tree_new.changes_from(tree_old)
-			files = []
-			
-			for item in delta.added:
-				files.append(item[0])
-			
-			for item in delta.removed:
-				files.append(item[0])
-			
-			for item in delta.renamed:
-				files.append(item[0])
-			
-			for item in delta.kind_changed:
-				files.append(item[0])
-			
-			for item in delta.modified:
-				files.append(item[0])
-			
-			subject = "r%d - %s" % (revision_new_no, " ".join(files))
+			subject = "r%d - %s" % (revision_new_no, commit_message)
 			
 			send_smtp("localhost", config_sender(config), config_to(config), subject, body.getvalue())
Index: contrib/bazaar/bzreml/setup.py
===================================================================
--- contrib/bazaar/bzreml/setup.py	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ contrib/bazaar/bzreml/setup.py	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -7,5 +7,5 @@
 	description = 'Commit email plugin for Bazaar',
 	keywords = 'plugin bzr email',
-	version = '1.0',
+	version = '1.2',
 	url = 'http://www.decky.cz/',
 	license = 'BSD',
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/Makefile	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -44,4 +44,5 @@
 	app/killall \
 	app/klog \
+	app/locinfo \
 	app/lsusb \
 	app/mkfat \
@@ -65,5 +66,5 @@
 	app/mkbd \
 	srv/clip \
-	srv/devmap \
+	srv/loc \
 	srv/devman \
 	srv/loader \
@@ -79,5 +80,5 @@
 	srv/fs/fat \
 	srv/fs/tmpfs \
-	srv/fs/devfs \
+	srv/fs/locfs \
 	srv/fs/ext2fs \
 	srv/hid/console \
Index: uspace/app/bdsh/cmds/modules/bdd/bdd.c
===================================================================
--- uspace/app/bdsh/cmds/modules/bdd/bdd.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/bdsh/cmds/modules/bdd/bdd.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -39,5 +39,5 @@
 
 #include <libblock.h>
-#include <devmap.h>
+#include <loc.h>
 #include <errno.h>
 #include <assert.h>
@@ -69,5 +69,5 @@
 	unsigned int argc;
 	unsigned int i, j;
-	devmap_handle_t handle;
+	service_id_t service_id;
 	aoff64_t offset;
 	uint8_t *blk;
@@ -96,5 +96,5 @@
 		size = 256;
 
-	rc = devmap_device_get_handle(argv[1], &handle, 0);
+	rc = loc_service_get_id(argv[1], &service_id, 0);
 	if (rc != EOK) {
 		printf("%s: Error resolving device `%s'.\n", cmdname, argv[1]);
@@ -102,5 +102,5 @@
 	}
 
-	rc = block_init(EXCHANGE_SERIALIZE, handle, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, service_id, 2048);
 	if (rc != EOK)  {
 		printf("%s: Error initializing libblock.\n", cmdname);
@@ -108,5 +108,5 @@
 	}
 
-	rc = block_get_bsize(handle, &block_size);
+	rc = block_get_bsize(service_id, &block_size);
 	if (rc != EOK) {
 		printf("%s: Error determining device block size.\n", cmdname);
@@ -117,5 +117,5 @@
 	if (blk == NULL) {
 		printf("%s: Error allocating memory.\n", cmdname);
-		block_fini(handle);
+		block_fini(service_id);
 		return CMD_FAILURE;
 	}
@@ -124,9 +124,9 @@
 
 	while (size > 0) {
-		rc = block_read_direct(handle, ba, 1, blk);
+		rc = block_read_direct(service_id, ba, 1, blk);
 		if (rc != EOK) {
 			printf("%s: Error reading block %" PRIuOFF64 "\n", cmdname, ba);
 			free(blk);
-			block_fini(handle);
+			block_fini(service_id);
 			return CMD_FAILURE;
 		}
@@ -170,5 +170,5 @@
 
 	free(blk);
-	block_fini(handle);
+	block_fini(service_id);
 
 	return CMD_SUCCESS;
Index: uspace/app/blkdump/blkdump.c
===================================================================
--- uspace/app/blkdump/blkdump.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/blkdump/blkdump.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -42,5 +42,5 @@
 #include <libblock.h>
 #include <mem.h>
-#include <devmap.h>
+#include <loc.h>
 #include <byteorder.h>
 #include <sys/types.h>
@@ -59,5 +59,5 @@
 	int rc;
 	char *dev_path;
-	devmap_handle_t handle;
+	service_id_t service_id;
 	size_t block_size;
 	char *endptr;
@@ -128,5 +128,5 @@
 	dev_path = *argv;
 
-	rc = devmap_device_get_handle(dev_path, &handle, 0);
+	rc = loc_service_get_id(dev_path, &service_id, 0);
 	if (rc != EOK) {
 		printf(NAME ": Error resolving device `%s'.\n", dev_path);
@@ -134,5 +134,5 @@
 	}
 
-	rc = block_init(EXCHANGE_SERIALIZE, handle, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, service_id, 2048);
 	if (rc != EOK)  {
 		printf(NAME ": Error initializing libblock.\n");
@@ -140,5 +140,5 @@
 	}
 
-	rc = block_get_bsize(handle, &block_size);
+	rc = block_get_bsize(service_id, &block_size);
 	if (rc != EOK) {
 		printf(NAME ": Error determining device block size.\n");
@@ -146,5 +146,5 @@
 	}
 
-	rc = block_get_nblocks(handle, &dev_nblocks);
+	rc = block_get_nblocks(service_id, &dev_nblocks);
 	if (rc != EOK) {
 		printf(NAME ": Warning, failed to obtain block device size.\n");
@@ -156,5 +156,5 @@
 	if (data == NULL) {
 		printf(NAME ": Error allocating data buffer of %" PRIuOFF64 " bytes", (aoff64_t) block_size);
-		block_fini(handle);
+		block_fini(service_id);
 		return 3;
 	}
@@ -162,5 +162,5 @@
 	limit = block_offset + block_count;
 	for (current = block_offset; current < limit; current++) {
-		rc = block_read_direct(handle, current, 1, data);
+		rc = block_read_direct(service_id, current, 1, data);
 		if (rc != EOK) {
 			printf(NAME ": Error reading block at %" PRIuOFF64 " \n", current);
@@ -186,5 +186,5 @@
 	free(data);
 
-	block_fini(handle);
+	block_fini(service_id);
 
 	return 0;
Index: uspace/app/bnchmark/bnchmark.c
===================================================================
--- uspace/app/bnchmark/bnchmark.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/bnchmark/bnchmark.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -41,5 +41,5 @@
 #include <stdlib.h>
 #include <mem.h>
-#include <devmap.h>
+#include <loc.h>
 #include <byteorder.h>
 #include <sys/types.h>
Index: uspace/app/ext2info/ext2info.c
===================================================================
--- uspace/app/ext2info/ext2info.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/ext2info/ext2info.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -42,5 +42,5 @@
 #include <libblock.h>
 #include <mem.h>
-#include <devmap.h>
+#include <loc.h>
 #include <byteorder.h>
 #include <sys/types.h>
@@ -81,5 +81,5 @@
 	char *endptr;
 	char *dev_path;
-	devmap_handle_t handle;
+	service_id_t service_id;
 	ext2_filesystem_t filesystem;
 	int arg_flags;
@@ -178,5 +178,5 @@
 	dev_path = *argv;
 
-	rc = devmap_device_get_handle(dev_path, &handle, 0);
+	rc = loc_service_get_id(dev_path, &service_id, 0);
 	if (rc != EOK) {
 		printf(NAME ": Error resolving device `%s'.\n", dev_path);
@@ -184,5 +184,5 @@
 	}
 
-	rc = ext2_filesystem_init(&filesystem, handle);
+	rc = ext2_filesystem_init(&filesystem, service_id);
 	if (rc != EOK)  {
 		printf(NAME ": Error initializing libext2.\n");
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/init/init.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -46,5 +46,5 @@
 #include <macros.h>
 #include <str.h>
-#include <devmap.h>
+#include <loc.h>
 #include <str_error.h>
 #include "init.h"
@@ -53,6 +53,6 @@
 #define ROOT_MOUNT_POINT  "/"
 
-#define DEVFS_FS_TYPE      "devfs"
-#define DEVFS_MOUNT_POINT  "/dev"
+#define LOCFS_FS_TYPE      "locfs"
+#define LOCFS_MOUNT_POINT  "/loc"
 
 #define TMPFS_FS_TYPE      "tmpfs"
@@ -66,4 +66,5 @@
 #define APP_GETTERM  "/app/getterm"
 
+/** Print banner */
 static void info_print(void)
 {
@@ -71,4 +72,5 @@
 }
 
+/** Report mount operation success */
 static bool mount_report(const char *desc, const char *mntpt,
     const char *fstype, const char *dev, int rc)
@@ -100,4 +102,15 @@
 }
 
+/** Mount root filesystem
+ *
+ * The operation blocks until the root filesystem
+ * server is ready for mounting.
+ *
+ * @param[in] fstype Root filesystem type.
+ *
+ * @return True on success.
+ * @return False on failure.
+ *
+ */
 static bool mount_root(const char *fstype)
 {
@@ -113,10 +126,19 @@
 }
 
-static bool mount_devfs(void)
-{
-	int rc = mount(DEVFS_FS_TYPE, DEVFS_MOUNT_POINT, "", "",
+/** Mount locfs filesystem
+ *
+ * The operation blocks until the locfs filesystem
+ * server is ready for mounting.
+ *
+ * @return True on success.
+ * @return False on failure.
+ *
+ */
+static bool mount_locfs(void)
+{
+	int rc = mount(LOCFS_FS_TYPE, LOCFS_MOUNT_POINT, "", "",
 	    IPC_FLAG_BLOCKING);
-	return mount_report("Device filesystem", DEVFS_MOUNT_POINT, DEVFS_FS_TYPE,
-	    NULL, rc);
+	return mount_report("Location service filesystem", LOCFS_MOUNT_POINT,
+	    LOCFS_FS_TYPE, NULL, rc);
 }
 
@@ -157,5 +179,5 @@
 	rc = task_wait(id, &texit, &retval);
 	if (rc != EOK) {
-		printf("%s: Error waiting for %s (%s(\n", NAME, fname,
+		printf("%s: Error waiting for %s (%s)\n", NAME, fname,
 		    str_error(rc));
 		return;
@@ -174,36 +196,36 @@
 }
 
-static void console(const char *dev)
-{
-	printf("%s: Spawning %s %s\n", NAME, SRV_CONSOLE, dev);
-	
-	/* Wait for the input device to be ready */
-	devmap_handle_t handle;
-	int rc = devmap_device_get_handle(dev, &handle, IPC_FLAG_BLOCKING);
-	if (rc != EOK) {
-		printf("%s: Error waiting on %s (%s)\n", NAME, dev,
-		    str_error(rc));
-		return;
-	}
-	
-	rc = task_spawnl(NULL, SRV_CONSOLE, SRV_CONSOLE, dev, NULL);
+static void console(const char *svc)
+{
+	printf("%s: Spawning %s %s\n", NAME, SRV_CONSOLE, svc);
+	
+	/* Wait for the input service to be ready */
+	service_id_t service_id;
+	int rc = loc_service_get_id(svc, &service_id, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		printf("%s: Error waiting on %s (%s)\n", NAME, svc,
+		    str_error(rc));
+		return;
+	}
+	
+	rc = task_spawnl(NULL, SRV_CONSOLE, SRV_CONSOLE, svc, NULL);
 	if (rc != EOK) {
 		printf("%s: Error spawning %s %s (%s)\n", NAME, SRV_CONSOLE,
-		    dev, str_error(rc));
-	}
-}
-
-static void getterm(const char *dev, const char *app, bool wmsg)
-{
-	char term[DEVMAP_NAME_MAXLEN];
+		    svc, str_error(rc));
+	}
+}
+
+static void getterm(const char *svc, const char *app, bool wmsg)
+{
+	char term[LOC_NAME_MAXLEN];
 	int rc;
 	
-	snprintf(term, DEVMAP_NAME_MAXLEN, "%s/%s", DEVFS_MOUNT_POINT, dev);
+	snprintf(term, LOC_NAME_MAXLEN, "%s/%s", LOCFS_MOUNT_POINT, svc);
 	
 	printf("%s: Spawning %s %s %s\n", NAME, APP_GETTERM, term, app);
 	
-	/* Wait for the terminal device to be ready */
-	devmap_handle_t handle;
-	rc = devmap_device_get_handle(dev, &handle, IPC_FLAG_BLOCKING);
+	/* Wait for the terminal service to be ready */
+	service_id_t service_id;
+	rc = loc_service_get_id(svc, &service_id, IPC_FLAG_BLOCKING);
 	if (rc != EOK) {
 		printf("%s: Error waiting on %s (%s)\n", NAME, term,
@@ -257,8 +279,8 @@
 	}
 	
-	spawn("/srv/devfs");
+	spawn("/srv/locfs");
 	spawn("/srv/taskmon");
 	
-	if (!mount_devfs()) {
+	if (!mount_locfs()) {
 		printf("%s: Exiting\n", NAME);
 		return -2;
Index: uspace/app/locinfo/Makefile
===================================================================
--- uspace/app/locinfo/Makefile	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/app/locinfo/Makefile	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2011 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+EXTRA_CFLAGS = -Iinclude
+BINARY = locinfo
+
+SOURCES = \
+	locinfo.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/locinfo/locinfo.c
===================================================================
--- uspace/app/locinfo/locinfo.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/app/locinfo/locinfo.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup locinfo
+ * @{
+ */
+/** @file locinfo.c Print information from location service.
+ */
+
+#include <errno.h>
+#include <loc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <str.h>
+#include <sys/types.h>
+#include <sys/typefmt.h>
+
+#define NAME "locinfo"
+
+int main(int argc, char *argv[])
+{
+	category_id_t *cat_ids;
+	size_t cat_cnt;
+	service_id_t *svc_ids;
+	size_t svc_cnt;
+
+	size_t i, j;
+	char *cat_name;
+	char *svc_name;
+	int rc;
+
+	rc = loc_get_categories(&cat_ids, &cat_cnt);
+	if (rc != EOK) {
+		printf(NAME ": Error getting list of categories.\n");
+		return 1;
+	}
+
+	for (i = 0; i < cat_cnt; i++) {
+		rc = loc_category_get_name(cat_ids[i], &cat_name);
+		if (rc != EOK)
+			cat_name = str_dup("<unknown>");
+
+		if (cat_name == NULL) {
+			printf(NAME ": Error allocating memory.\n");
+			return 1;
+		}
+
+		printf("%s (%" PRIun "):\n", cat_name, cat_ids[i]);
+
+		rc = loc_category_get_svcs(cat_ids[i], &svc_ids, &svc_cnt);
+		if (rc != EOK) {
+			printf(NAME ": Failed getting list of services in "
+			    "category %s, skipping.\n", cat_name);
+			free(cat_name);
+			continue;
+		}
+
+		for (j = 0; j < svc_cnt; j++) {
+			rc = loc_service_get_name(svc_ids[j], &svc_name);
+			if (rc != EOK) {
+				printf(NAME ": Unknown service name (SID %"
+				    PRIun ").\n", svc_ids[j]);
+				continue;
+			}
+			printf("\t%s (%" PRIun ")\n", svc_name, svc_ids[j]);
+		}
+
+		free(svc_ids);
+		free(cat_name);
+	}
+
+	free(cat_ids);
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/lsusb/main.c
===================================================================
--- uspace/app/lsusb/main.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/lsusb/main.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -43,5 +43,5 @@
 #include <getopt.h>
 #include <devman.h>
-#include <devmap.h>
+#include <loc.h>
 #include <usb/dev/hub.h>
 #include <usb/hc.h>
@@ -50,15 +50,12 @@
 
 #define MAX_USB_ADDRESS USB11_ADDRESS_MAX
-#define MAX_FAILED_ATTEMPTS 10
 #define MAX_PATH_LENGTH 1024
 
-static void print_found_hc(size_t class_index, const char *path)
+static void print_found_hc(service_id_t sid, const char *path)
 {
-	// printf(NAME ": host controller %zu is `%s'.\n", class_index, path);
-	printf("Bus %02zu: %s\n", class_index, path);
+	printf("Bus %" PRIun ": %s\n", sid, path);
 }
 static void print_found_dev(usb_address_t addr, const char *path)
 {
-	// printf(NAME ":     device with address %d is `%s'.\n", addr, path);
 	printf("  Device %02d: %s\n", addr, path);
 }
@@ -95,13 +92,29 @@
 int main(int argc, char *argv[])
 {
-	size_t class_index = 0;
-	size_t failed_attempts = 0;
+	category_id_t usbhc_cat;
+	service_id_t *svcs;
+	size_t count;
+	size_t i;
+	int rc;
 
-	while (failed_attempts < MAX_FAILED_ATTEMPTS) {
-		class_index++;
+	rc = loc_category_get_id(USB_HC_CATEGORY, &usbhc_cat, 0);
+	if (rc != EOK) {
+		printf(NAME ": Error resolving category '%s'",
+		    USB_HC_CATEGORY);
+		return 1;
+	}
+
+	rc = loc_category_get_svcs(usbhc_cat, &svcs, &count);
+	if (rc != EOK) {
+		printf(NAME ": Error getting list of host controllers.\n");
+		return 1;
+	}
+
+	for (i = 0; i < count; i++) {
 		devman_handle_t hc_handle = 0;
-		int rc = usb_ddf_get_hc_handle_by_class(class_index, &hc_handle);
+		int rc = usb_ddf_get_hc_handle_by_sid(svcs[i], &hc_handle);
 		if (rc != EOK) {
-			failed_attempts++;
+			printf(NAME ": Error resolving handle of HC with SID %"
+			    PRIun ", skipping.\n", svcs[i]);
 			continue;
 		}
@@ -109,9 +122,13 @@
 		rc = devman_get_device_path(hc_handle, path, MAX_PATH_LENGTH);
 		if (rc != EOK) {
+			printf(NAME ": Error resolving path of HC with SID %"
+			    PRIun ", skipping.\n", svcs[i]);
 			continue;
 		}
-		print_found_hc(class_index, path);
+		print_found_hc(svcs[i], path);
 		print_hc_devices(hc_handle);
 	}
+
+	free(svcs);
 
 	return 0;
Index: uspace/app/mkbd/main.c
===================================================================
--- uspace/app/mkbd/main.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/mkbd/main.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -43,5 +43,5 @@
 #include <getopt.h>
 #include <devman.h>
-#include <devmap.h>
+#include <loc.h>
 #include <usb/dev/hub.h>
 #include <usb/hid/iface.h>
Index: uspace/app/mkfat/mkfat.c
===================================================================
--- uspace/app/mkfat/mkfat.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/mkfat/mkfat.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -42,5 +42,5 @@
 #include <libblock.h>
 #include <mem.h>
-#include <devmap.h>
+#include <loc.h>
 #include <byteorder.h>
 #include <sys/types.h>
@@ -85,5 +85,5 @@
     struct fat_params *par);
 static int fat_blocks_write(struct fat_params const *par,
-    devmap_handle_t handle);
+    service_id_t service_id);
 static void fat_bootsec_create(struct fat_params const *par, struct fat_bs *bs);
 
@@ -95,5 +95,5 @@
 	int rc;
 	char *dev_path;
-	devmap_handle_t handle;
+	service_id_t service_id;
 	size_t block_size;
 	char *endptr;
@@ -138,5 +138,5 @@
 	dev_path = *argv;
 
-	rc = devmap_device_get_handle(dev_path, &handle, 0);
+	rc = loc_service_get_id(dev_path, &service_id, 0);
 	if (rc != EOK) {
 		printf(NAME ": Error resolving device `%s'.\n", dev_path);
@@ -144,5 +144,5 @@
 	}
 
-	rc = block_init(EXCHANGE_SERIALIZE, handle, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, service_id, 2048);
 	if (rc != EOK)  {
 		printf(NAME ": Error initializing libblock.\n");
@@ -150,5 +150,5 @@
 	}
 
-	rc = block_get_bsize(handle, &block_size);
+	rc = block_get_bsize(service_id, &block_size);
 	if (rc != EOK) {
 		printf(NAME ": Error determining device block size.\n");
@@ -156,5 +156,5 @@
 	}
 
-	rc = block_get_nblocks(handle, &dev_nblocks);
+	rc = block_get_nblocks(service_id, &dev_nblocks);
 	if (rc != EOK) {
 		printf(NAME ": Warning, failed to obtain block device size.\n");
@@ -183,5 +183,5 @@
 	}
 
-	rc = fat_blocks_write(&par, handle);
+	rc = fat_blocks_write(&par, service_id);
 	if (rc != EOK) {
 		printf(NAME ": Error writing device.\n");
@@ -189,5 +189,5 @@
 	}
 
-	block_fini(handle);
+	block_fini(service_id);
 	printf("Success.\n");
 
@@ -234,5 +234,5 @@
 
 /** Create file system with the given parameters. */
-static int fat_blocks_write(struct fat_params const *par, devmap_handle_t handle)
+static int fat_blocks_write(struct fat_params const *par, service_id_t service_id)
 {
 	aoff64_t addr;
@@ -245,5 +245,5 @@
 	fat_bootsec_create(par, &bs);
 
-	rc = block_write_direct(handle, BS_BLOCK, 1, &bs);
+	rc = block_write_direct(service_id, BS_BLOCK, 1, &bs);
 	if (rc != EOK)
 		return EIO;
@@ -257,5 +257,5 @@
 	/* Reserved sectors */
 	for (i = 0; i < par->reserved_sectors - 1; ++i) {
-		rc = block_write_direct(handle, addr, 1, buffer);
+		rc = block_write_direct(service_id, addr, 1, buffer);
 		if (rc != EOK)
 			return EIO;
@@ -277,5 +277,5 @@
 			}
 
-			rc = block_write_direct(handle, addr, 1, buffer);
+			rc = block_write_direct(service_id, addr, 1, buffer);
 			if (rc != EOK)
 				return EIO;
@@ -291,5 +291,5 @@
 	/* Root directory */
 	for (i = 0; i < par->rootdir_sectors; ++i) {
-		rc = block_write_direct(handle, addr, 1, buffer);
+		rc = block_write_direct(service_id, addr, 1, buffer);
 		if (rc != EOK)
 			return EIO;
Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/tester/Makefile	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -56,6 +56,4 @@
 	mm/malloc3.c \
 	mm/mapping1.c \
-	devs/devman1.c \
-	devs/devman2.c \
 	hw/misc/virtchar1.c \
 	hw/serial/serial1.c \
Index: pace/app/tester/devs/devman1.c
===================================================================
--- uspace/app/tester/devs/devman1.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,89 +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 tester
- * @brief Test devman service.
- * @{
- */
-/**
- * @file
- */
-
-#include <inttypes.h>
-#include <errno.h>
-#include <str_error.h>
-#include <sys/types.h>
-#include <async.h>
-#include <devman.h>
-#include <str.h>
-#include <vfs/vfs.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include "../tester.h"
-
-#define DEVICE_PATH_NORMAL "/virt/null/a"
-#define DEVICE_CLASS "virt-null"
-#define DEVICE_CLASS_NAME "1"
-#define DEVICE_PATH_CLASSES DEVICE_CLASS "/" DEVICE_CLASS_NAME
-
-const char *test_devman1(void)
-{
-	devman_handle_t handle_primary;
-	devman_handle_t handle_class;
-	
-	int rc;
-	
-	TPRINTF("Asking for handle of `%s'...\n", DEVICE_PATH_NORMAL);
-	rc = devman_device_get_handle(DEVICE_PATH_NORMAL, &handle_primary, 0);
-	if (rc != EOK) {
-		TPRINTF(" ...failed: %s.\n", str_error(rc));
-		if (rc == ENOENT) {
-			TPRINTF("Have you compiled the test drivers?\n");
-		}
-		return "Failed getting device handle";
-	}
-
-	TPRINTF("Asking for handle of `%s' by class..\n", DEVICE_PATH_CLASSES);
-	rc = devman_device_get_handle_by_class(DEVICE_CLASS, DEVICE_CLASS_NAME,
-	    &handle_class, 0);
-	if (rc != EOK) {
-		TPRINTF(" ...failed: %s.\n", str_error(rc));
-		return "Failed getting device class handle";
-	}
-
-	TPRINTF("Received handles %" PRIun " and %" PRIun ".\n",
-	    handle_primary, handle_class);
-	if (handle_primary != handle_class) {
-		return "Retrieved different handles for the same device";
-	}
-
-	return NULL;
-}
-
-/** @}
- */
Index: pace/app/tester/devs/devman1.def
===================================================================
--- uspace/app/tester/devs/devman1.def	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,6 +1,0 @@
-{
-	"devman1",
-	"devman test",
-	&test_devman1,
-	false
-},
Index: pace/app/tester/devs/devman2.c
===================================================================
--- uspace/app/tester/devs/devman2.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,94 +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 tester
- * @brief Test devman service.
- * @{
- */
-/**
- * @file
- */
-
-#include <inttypes.h>
-#include <errno.h>
-#include <str_error.h>
-#include <sys/types.h>
-#include <async.h>
-#include <devman.h>
-#include <str.h>
-#include <async.h>
-#include <vfs/vfs.h>
-#include <vfs/vfs_sess.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include "../tester.h"
-
-#define DEVICE_CLASS "test3"
-
-const char *test_devman2(void)
-{
-	size_t idx = 1;
-	int rc = EOK;
-	const char *err_msg = NULL;
-	char *path = NULL;
-	while (rc == EOK) {
-		rc = asprintf(&path, "/dev/class/%s\\%zu", DEVICE_CLASS, idx);
-		if (rc < 0) {
-			continue;
-		}
-		int fd = open(path, O_RDONLY);
-		if (fd < 0) {
-			TPRINTF("Failed opening `%s': %s.\n",
-			    path, str_error(fd));
-			rc = fd;
-			err_msg = "Failed opening file";
-			continue;
-		}
-		async_sess_t *sess = fd_session(EXCHANGE_SERIALIZE, fd);
-		close(fd);
-		if (sess == NULL) {
-			TPRINTF("Failed opening phone: %s.\n", str_error(errno));
-			rc = errno;
-			err_msg = "Failed opening file descriptor phone";
-			continue;
-		}
-		async_hangup(sess);
-		TPRINTF("Path `%s' okay.\n", path);
-		free(path);
-		idx++;
-		rc = EOK;
-	}
-	
-	if (path != NULL)
-		free(path);
-	
-	return err_msg;
-}
-
-/** @}
- */
Index: pace/app/tester/devs/devman2.def
===================================================================
--- uspace/app/tester/devs/devman2.def	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,6 +1,0 @@
-{
-	"devman2",
-	"devman test",
-	&test_devman2,
-	false
-},
Index: uspace/app/tester/hw/misc/virtchar1.c
===================================================================
--- uspace/app/tester/hw/misc/virtchar1.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/tester/hw/misc/virtchar1.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -48,6 +48,5 @@
 #include "../../tester.h"
 
-#define DEVICE_PATH_NORMAL "/dev/devices/\\virt\\null\\a"
-#define DEVICE_PATH_CLASSES "/dev/class/virt-null\\1"
+#define DEVICE_PATH_NORMAL "/loc/devices/\\virt\\null\\a"
 #define BUFFER_SIZE 64
 
@@ -105,9 +104,4 @@
 	}
 
-	res = test_virtchar1_internal(DEVICE_PATH_CLASSES);
-	if (res != NULL) {
-		return res;
-	}
-
 	return NULL;
 }
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/tester/tester.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -68,6 +68,4 @@
 #include "hw/misc/virtchar1.def"
 #include "libext2/libext2_1.def"
-#include "devs/devman1.def"
-#include "devs/devman2.def"
 	{NULL, NULL, NULL, false}
 };
Index: uspace/app/tester/vfs/vfs1.c
===================================================================
--- uspace/app/tester/vfs/vfs1.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/tester/vfs/vfs1.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -35,5 +35,5 @@
 #include <fcntl.h>
 #include <dirent.h>
-#include <devmap.h>
+#include <loc.h>
 #include <sys/types.h>
 #include <sys/stat.h>
Index: uspace/app/testread/testread.c
===================================================================
--- uspace/app/testread/testread.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/testread/testread.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -50,5 +50,5 @@
 #include <stdlib.h>
 #include <mem.h>
-#include <devmap.h>
+#include <loc.h>
 #include <byteorder.h>
 #include <sys/types.h>
Index: uspace/app/usbinfo/main.c
===================================================================
--- uspace/app/usbinfo/main.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/app/usbinfo/main.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -42,5 +42,5 @@
 #include <getopt.h>
 #include <devman.h>
-#include <devmap.h>
+#include <loc.h>
 #include <usb/hc.h>
 #include <usb/dev/pipes.h>
Index: uspace/doc/doxygroups.h
===================================================================
--- uspace/doc/doxygroups.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/doc/doxygroups.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -322,6 +322,6 @@
 	 * The purpose of this driver is to simplify querying of unknown
 	 * devices from within HelenOS (without a driver, no node at all
-	 * may appear under /dev/devices).
-	 */
-
-
+	 * may appear under /loc/devices).
+	 */
+
+
Index: uspace/drv/bus/usb/ehci/main.c
===================================================================
--- uspace/drv/bus/usb/ehci/main.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/bus/usb/ehci/main.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -101,5 +101,5 @@
 	    "Failed to bind EHCI function: %s.\n",
 	    str_error(ret));
-	ret = ddf_fun_add_to_class(hc_fun, USB_HC_DDF_CLASS_NAME);
+	ret = ddf_fun_add_to_category(hc_fun, USB_HC_CATEGORY);
 	CHECK_RET_RETURN(ret,
 	    "Failed to add EHCI to HC class: %s.\n",
Index: uspace/drv/bus/usb/ohci/ohci.c
===================================================================
--- uspace/drv/bus/usb/ohci/ohci.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/bus/usb/ohci/ohci.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -244,5 +244,5 @@
 	    "Failed to bind OHCI device function: %s.\n", str_error(ret));
 
-	ret = ddf_fun_add_to_class(instance->hc_fun, USB_HC_DDF_CLASS_NAME);
+	ret = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
 	CHECK_RET_FINI_RETURN(ret,
 	    "Failed to add OHCI to HC class: %s.\n", str_error(ret));
Index: uspace/drv/bus/usb/uhci/uhci.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/bus/usb/uhci/uhci.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -267,5 +267,5 @@
 	    str_error(ret));
 
-	ret = ddf_fun_add_to_class(instance->hc_fun, USB_HC_DDF_CLASS_NAME);
+	ret = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
 	CHECK_RET_FINI_RETURN(ret,
 	    "Failed to add UHCI to HC class: %s.\n", str_error(ret));
Index: uspace/drv/bus/usb/usbhid/generic/hiddev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/generic/hiddev.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/bus/usb/usbhid/generic/hiddev.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -192,5 +192,5 @@
 static int usb_generic_hid_create_function(usb_hid_dev_t *hid_dev)
 {	
-	/* Create the function exposed under /dev/devices. */
+	/* Create the exposed function. */
 	/** @todo Generate numbers for the devices? */
 	usb_log_debug("Creating DDF function %s...\n", HID_GENERIC_FUN_NAME);
Index: uspace/drv/bus/usb/usbhid/kbd/kbddev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbddev.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/bus/usb/usbhid/kbd/kbddev.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -102,5 +102,5 @@
 
 const char *HID_KBD_FUN_NAME = "keyboard";
-const char *HID_KBD_CLASS_NAME = "keyboard";
+const char *HID_KBD_CATEGORY_NAME = "keyboard";
 
 static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev);
@@ -524,5 +524,5 @@
 	assert(kbd_dev != NULL);
 	
-	/* Create the function exposed under /dev/devices. */
+	/* 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, 
@@ -551,10 +551,10 @@
 	    HID_KBD_FUN_NAME, fun->handle);
 	
-	usb_log_debug("Adding DDF function to class %s...\n", 
+	usb_log_debug("Adding DDF function to category %s...\n", 
 	    HID_KBD_CLASS_NAME);
-	rc = ddf_fun_add_to_class(fun, HID_KBD_CLASS_NAME);
+	rc = ddf_fun_add_to_category(fun, HID_KBD_CATEGORY_NAME);
 	if (rc != EOK) {
 		usb_log_error(
-		    "Could not add DDF function to class %s: %s.\n",
+		    "Could not add DDF function to category %s: %s.\n",
 		    HID_KBD_CLASS_NAME, str_error(rc));
 		ddf_fun_destroy(fun);
Index: uspace/drv/bus/usb/usbhid/mouse/mousedev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -74,6 +74,6 @@
 const char *HID_MOUSE_FUN_NAME = "mouse";
 const char *HID_MOUSE_WHEEL_FUN_NAME = "mouse-wheel";
-const char *HID_MOUSE_CLASS_NAME = "mouse";
-const char *HID_MOUSE_WHEEL_CLASS_NAME = "keyboard";
+const char *HID_MOUSE_CATEGORY = "mouse";
+const char *HID_MOUSE_WHEEL_CATEGORY = "keyboard";
 
 /** Default idle rate for mouses. */
@@ -325,5 +325,5 @@
 	assert(mouse != NULL);
 	
-	/* Create the function exposed under /dev/devices. */
+	/* 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, 
@@ -345,11 +345,11 @@
 	}
 	
-	usb_log_debug("Adding DDF function to class %s...\n", 
-	    HID_MOUSE_CLASS_NAME);
-	rc = ddf_fun_add_to_class(fun, HID_MOUSE_CLASS_NAME);
+	usb_log_debug("Adding DDF function to category %s...\n", 
+	    HID_MOUSE_CATEGORY);
+	rc = ddf_fun_add_to_category(fun, HID_MOUSE_CATEGORY);
 	if (rc != EOK) {
 		usb_log_error(
-		    "Could not add DDF function to class %s: %s.\n",
-		    HID_MOUSE_CLASS_NAME, str_error(rc));
+		    "Could not add DDF function to category %s: %s.\n",
+		    HID_MOUSE_CATEGORY, str_error(rc));
 		ddf_fun_destroy(fun);
 		return rc;
@@ -383,11 +383,11 @@
 	}
 	
-	usb_log_debug("Adding DDF function to class %s...\n", 
-	    HID_MOUSE_WHEEL_CLASS_NAME);
-	rc = ddf_fun_add_to_class(fun, HID_MOUSE_WHEEL_CLASS_NAME);
+	usb_log_debug("Adding DDF function to category %s...\n", 
+	    HID_MOUSE_WHEEL_CATEGORY);
+	rc = ddf_fun_add_to_category(fun, HID_MOUSE_WHEEL_CATEGORY);
 	if (rc != EOK) {
 		usb_log_error(
-		    "Could not add DDF function to class %s: %s.\n",
-		    HID_MOUSE_WHEEL_CLASS_NAME, str_error(rc));
+		    "Could not add DDF function to category %s: %s.\n",
+		    HID_MOUSE_WHEEL_CATEGORY, str_error(rc));
 		ddf_fun_destroy(fun);
 		return rc;
Index: uspace/drv/bus/usb/usbhid/mouse/mousedev.h
===================================================================
--- uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -59,5 +59,5 @@
 
 const char *HID_MOUSE_FUN_NAME;
-const char *HID_MOUSE_CLASS_NAME;
+const char *HID_MOUSE_CATEGORY;
 
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/usbhid/multimedia/multimedia.c
===================================================================
--- uspace/drv/bus/usb/usbhid/multimedia/multimedia.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/bus/usb/usbhid/multimedia/multimedia.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -185,5 +185,5 @@
     usb_multimedia_t *multim_dev)
 {
-	/* Create the function exposed under /dev/devices. */
+	/* Create the exposed function. */
 	ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
 	    NAME);
@@ -205,11 +205,11 @@
 	}
 	
-	usb_log_debug("%s function created (jandle: %" PRIun ").\n",
+	usb_log_debug("%s function created (handle: %" PRIun ").\n",
 	    NAME, fun->handle);
 	
-	rc = ddf_fun_add_to_class(fun, "keyboard");
+	rc = ddf_fun_add_to_category(fun, "keyboard");
 	if (rc != EOK) {
 		usb_log_error(
-		    "Could not add DDF function to class 'keyboard': %s.\n",
+		    "Could not add DDF function to category 'keyboard': %s.\n",
 		    str_error(rc));
 		// TODO: Can / should I destroy the DDF function?
Index: uspace/drv/bus/usb/usbhub/usbhub.c
===================================================================
--- uspace/drv/bus/usb/usbhub/usbhub.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/bus/usb/usbhub/usbhub.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -131,5 +131,5 @@
 	opResult = ddf_fun_bind(hub_fun);
 	assert(opResult == EOK);
-	opResult = ddf_fun_add_to_class(hub_fun, "hub");
+	opResult = ddf_fun_add_to_category(hub_fun, "hub");
 	assert(opResult == EOK);
 
Index: uspace/drv/bus/usb/usbmouse/init.c
===================================================================
--- uspace/drv/bus/usb/usbmouse/init.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/bus/usb/usbmouse/init.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -116,5 +116,5 @@
 	
 	/* Add the function to mouse class. */
-	rc = ddf_fun_add_to_class(mouse->mouse_fun, "mouse");
+	rc = ddf_fun_add_to_category(mouse->mouse_fun, "mouse");
 	if (rc != EOK)
 		goto leave;
Index: uspace/drv/bus/usb/vhc/main.c
===================================================================
--- uspace/drv/bus/usb/vhc/main.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/bus/usb/vhc/main.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -34,5 +34,5 @@
  */
 
-#include <devmap.h>
+#include <loc.h>
 #include <async.h>
 #include <unistd.h>
@@ -104,5 +104,5 @@
 	}
 
-	rc = ddf_fun_add_to_class(hc, USB_HC_DDF_CLASS_NAME);
+	rc = ddf_fun_add_to_category(hc, USB_HC_CATEGORY);
 	if (rc != EOK) {
 		usb_log_fatal("Failed to add function to HC class: %s.\n",
Index: uspace/drv/char/ns8250/ns8250.c
===================================================================
--- uspace/drv/char/ns8250/ns8250.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/char/ns8250/ns8250.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -781,5 +781,5 @@
 	ns->fun = fun;
 	
-	ddf_fun_add_to_class(fun, "serial");
+	ddf_fun_add_to_category(fun, "serial");
 	
 	ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
Index: uspace/drv/test/test1/test1.c
===================================================================
--- uspace/drv/test/test1/test1.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/test/test1/test1.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -143,9 +143,9 @@
 	}
 
-	ddf_fun_add_to_class(fun_a, "virtual");
+	ddf_fun_add_to_category(fun_a, "virtual");
 
 	if (str_cmp(dev->name, "null") == 0) {
 		fun_a->ops = &char_device_ops;
-		ddf_fun_add_to_class(fun_a, "virt-null");
+		ddf_fun_add_to_category(fun_a, "virt-null");
 	} else if (str_cmp(dev->name, "test1") == 0) {
 		(void) register_fun_verbose(dev,
Index: uspace/drv/test/test2/test2.c
===================================================================
--- uspace/drv/test/test2/test2.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/test/test2/test2.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -123,5 +123,5 @@
 	}
 
-	ddf_fun_add_to_class(fun_a, "virtual");
+	ddf_fun_add_to_category(fun_a, "virtual");
 
 	return EOK;
Index: uspace/drv/test/test3/test3.c
===================================================================
--- uspace/drv/test/test3/test3.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/drv/test/test3/test3.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -50,5 +50,5 @@
 };
 
-static int register_fun_and_add_to_class(ddf_dev_t *parent,
+static int register_fun_and_add_to_category(ddf_dev_t *parent,
      const char *base_name, size_t index, const char *class_name)
 {
@@ -77,5 +77,5 @@
 	}
 	
-	ddf_fun_add_to_class(fun, class_name);
+	ddf_fun_add_to_category(fun, class_name);
 
 	ddf_msg(LVL_NOTE, "Registered exposed function `%s'.", fun_name);
@@ -100,5 +100,5 @@
 	size_t i;
 	for (i = 0; i < 20; i++) {
-		rc = register_fun_and_add_to_class(dev,
+		rc = register_fun_and_add_to_category(dev,
 		    "test3_", i, "test3");
 		if (rc != EOK) {
Index: uspace/lib/block/libblock.c
===================================================================
--- uspace/lib/block/libblock.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/block/libblock.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -39,5 +39,5 @@
 #include "libblock.h"
 #include "../../srv/vfs/vfs.h"
-#include <ipc/devmap.h>
+#include <ipc/loc.h>
 #include <ipc/bd.h>
 #include <ipc/services.h>
@@ -78,5 +78,5 @@
 typedef struct {
 	link_t link;
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 	async_sess_t *sess;
 	fibril_mutex_t comm_area_lock;
@@ -95,5 +95,5 @@
 static aoff64_t ba_ltop(devcon_t *, aoff64_t);
 
-static devcon_t *devcon_search(devmap_handle_t devmap_handle)
+static devcon_t *devcon_search(service_id_t service_id)
 {
 	fibril_mutex_lock(&dcl_lock);
@@ -101,5 +101,5 @@
 	list_foreach(dcl, cur) {
 		devcon_t *devcon = list_get_instance(cur, devcon_t, link);
-		if (devcon->devmap_handle == devmap_handle) {
+		if (devcon->service_id == service_id) {
 			fibril_mutex_unlock(&dcl_lock);
 			return devcon;
@@ -111,5 +111,5 @@
 }
 
-static int devcon_add(devmap_handle_t devmap_handle, async_sess_t *sess,
+static int devcon_add(service_id_t service_id, async_sess_t *sess,
     size_t bsize, void *comm_area, size_t comm_size)
 {
@@ -124,5 +124,5 @@
 	
 	link_initialize(&devcon->link);
-	devcon->devmap_handle = devmap_handle;
+	devcon->service_id = service_id;
 	devcon->sess = sess;
 	fibril_mutex_initialize(&devcon->comm_area_lock);
@@ -137,5 +137,5 @@
 	list_foreach(dcl, cur) {
 		devcon_t *d = list_get_instance(cur, devcon_t, link);
-		if (d->devmap_handle == devmap_handle) {
+		if (d->service_id == service_id) {
 			fibril_mutex_unlock(&dcl_lock);
 			free(devcon);
@@ -155,5 +155,5 @@
 }
 
-int block_init(exch_mgmt_t mgmt, devmap_handle_t devmap_handle,
+int block_init(exch_mgmt_t mgmt, service_id_t service_id,
     size_t comm_size)
 {
@@ -163,5 +163,5 @@
 		return ENOMEM;
 	
-	async_sess_t *sess = devmap_device_connect(mgmt, devmap_handle,
+	async_sess_t *sess = loc_service_connect(mgmt, service_id,
 	    IPC_FLAG_BLOCKING);
 	if (!sess) {
@@ -190,5 +190,5 @@
 	}
 	
-	rc = devcon_add(devmap_handle, sess, bsize, comm_area, comm_size);
+	rc = devcon_add(service_id, sess, bsize, comm_area, comm_size);
 	if (rc != EOK) {
 		munmap(comm_area, comm_size);
@@ -200,11 +200,11 @@
 }
 
-void block_fini(devmap_handle_t devmap_handle)
-{
-	devcon_t *devcon = devcon_search(devmap_handle);
+void block_fini(service_id_t service_id)
+{
+	devcon_t *devcon = devcon_search(service_id);
 	assert(devcon);
 	
 	if (devcon->cache)
-		(void) block_cache_fini(devmap_handle);
+		(void) block_cache_fini(service_id);
 	
 	devcon_remove(devcon);
@@ -219,10 +219,10 @@
 }
 
-int block_bb_read(devmap_handle_t devmap_handle, aoff64_t ba)
+int block_bb_read(service_id_t service_id, aoff64_t ba)
 {
 	void *bb_buf;
 	int rc;
 
-	devcon_t *devcon = devcon_search(devmap_handle);
+	devcon_t *devcon = devcon_search(service_id);
 	if (!devcon)
 		return ENOENT;
@@ -249,7 +249,7 @@
 }
 
-void *block_bb_get(devmap_handle_t devmap_handle)
-{
-	devcon_t *devcon = devcon_search(devmap_handle);
+void *block_bb_get(service_id_t service_id)
+{
+	devcon_t *devcon = devcon_search(service_id);
 	assert(devcon);
 	return devcon->bb_buf;
@@ -277,8 +277,8 @@
 };
 
-int block_cache_init(devmap_handle_t devmap_handle, size_t size, unsigned blocks,
+int block_cache_init(service_id_t service_id, size_t size, unsigned blocks,
     enum cache_mode mode)
 {
-	devcon_t *devcon = devcon_search(devmap_handle);
+	devcon_t *devcon = devcon_search(service_id);
 	cache_t *cache;
 	if (!devcon)
@@ -315,7 +315,7 @@
 }
 
-int block_cache_fini(devmap_handle_t devmap_handle)
-{
-	devcon_t *devcon = devcon_search(devmap_handle);
+int block_cache_fini(service_id_t service_id)
+{
+	devcon_t *devcon = devcon_search(service_id);
 	cache_t *cache;
 	int rc;
@@ -387,5 +387,5 @@
  * @param block			Pointer to where the function will store the
  * 				block pointer on success.
- * @param devmap_handle		Device handle of the block device.
+ * @param service_id		Service ID of the block device.
  * @param ba			Block address (logical).
  * @param flags			If BLOCK_FLAGS_NOREAD is specified, block_get()
@@ -395,5 +395,5 @@
  * @return			EOK on success or a negative error code.
  */
-int block_get(block_t **block, devmap_handle_t devmap_handle, aoff64_t ba, int flags)
+int block_get(block_t **block, service_id_t service_id, aoff64_t ba, int flags)
 {
 	devcon_t *devcon;
@@ -408,5 +408,5 @@
 	int rc;
 	
-	devcon = devcon_search(devmap_handle);
+	devcon = devcon_search(service_id);
 
 	assert(devcon);
@@ -536,5 +536,5 @@
 
 		block_initialize(b);
-		b->devmap_handle = devmap_handle;
+		b->service_id = service_id;
 		b->size = cache->lblock_size;
 		b->lba = ba;
@@ -586,5 +586,5 @@
 int block_put(block_t *block)
 {
-	devcon_t *devcon = devcon_search(block->devmap_handle);
+	devcon_t *devcon = devcon_search(block->service_id);
 	cache_t *cache;
 	unsigned blocks_cached;
@@ -687,5 +687,5 @@
 /** Read sequential data from a block device.
  *
- * @param devmap_handle	Device handle of the block device.
+ * @param service_id	Service ID of the block device.
  * @param bufpos	Pointer to the first unread valid offset within the
  * 			communication buffer.
@@ -699,5 +699,5 @@
  * @return		EOK on success or a negative return code on failure.
  */
-int block_seqread(devmap_handle_t devmap_handle, size_t *bufpos, size_t *buflen,
+int block_seqread(service_id_t service_id, size_t *bufpos, size_t *buflen,
     aoff64_t *pos, void *dst, size_t size)
 {
@@ -707,5 +707,5 @@
 	devcon_t *devcon;
 
-	devcon = devcon_search(devmap_handle);
+	devcon = devcon_search(service_id);
 	assert(devcon);
 	block_size = devcon->pblock_size;
@@ -753,5 +753,5 @@
 /** Read blocks directly from device (bypass cache).
  *
- * @param devmap_handle	Device handle of the block device.
+ * @param service_id	Service ID of the block device.
  * @param ba		Address of first block (physical).
  * @param cnt		Number of blocks.
@@ -760,10 +760,10 @@
  * @return		EOK on success or negative error code on failure.
  */
-int block_read_direct(devmap_handle_t devmap_handle, aoff64_t ba, size_t cnt, void *buf)
+int block_read_direct(service_id_t service_id, aoff64_t ba, size_t cnt, void *buf)
 {
 	devcon_t *devcon;
 	int rc;
 
-	devcon = devcon_search(devmap_handle);
+	devcon = devcon_search(service_id);
 	assert(devcon);
 	
@@ -781,5 +781,5 @@
 /** Write blocks directly to device (bypass cache).
  *
- * @param devmap_handle	Device handle of the block device.
+ * @param service_id	Service ID of the block device.
  * @param ba		Address of first block (physical).
  * @param cnt		Number of blocks.
@@ -788,5 +788,5 @@
  * @return		EOK on success or negative error code on failure.
  */
-int block_write_direct(devmap_handle_t devmap_handle, aoff64_t ba, size_t cnt,
+int block_write_direct(service_id_t service_id, aoff64_t ba, size_t cnt,
     const void *data)
 {
@@ -794,5 +794,5 @@
 	int rc;
 
-	devcon = devcon_search(devmap_handle);
+	devcon = devcon_search(service_id);
 	assert(devcon);
 	
@@ -809,14 +809,14 @@
 /** Get device block size.
  *
- * @param devmap_handle	Device handle of the block device.
+ * @param service_id	Service ID of the block device.
  * @param bsize		Output block size.
  *
  * @return		EOK on success or negative error code on failure.
  */
-int block_get_bsize(devmap_handle_t devmap_handle, size_t *bsize)
+int block_get_bsize(service_id_t service_id, size_t *bsize)
 {
 	devcon_t *devcon;
 
-	devcon = devcon_search(devmap_handle);
+	devcon = devcon_search(service_id);
 	assert(devcon);
 	
@@ -826,12 +826,12 @@
 /** Get number of blocks on device.
  *
- * @param devmap_handle	Device handle of the block device.
+ * @param service_id	Service ID of the block device.
  * @param nblocks	Output number of blocks.
  *
  * @return		EOK on success or negative error code on failure.
  */
-int block_get_nblocks(devmap_handle_t devmap_handle, aoff64_t *nblocks)
-{
-	devcon_t *devcon = devcon_search(devmap_handle);
+int block_get_nblocks(service_id_t service_id, aoff64_t *nblocks)
+{
+	devcon_t *devcon = devcon_search(service_id);
 	assert(devcon);
 	
@@ -841,5 +841,5 @@
 /** Read bytes directly from the device (bypass cache)
  * 
- * @param devmap_handle	Device handle of the block device.
+ * @param service_id	Service ID of the block device.
  * @param abs_offset	Absolute offset in bytes where to start reading
  * @param bytes			Number of bytes to read
@@ -848,5 +848,5 @@
  * @return		EOK on success or negative error code on failure.
  */
-int block_read_bytes_direct(devmap_handle_t devmap_handle, aoff64_t abs_offset,
+int block_read_bytes_direct(service_id_t service_id, aoff64_t abs_offset,
     size_t bytes, void *data)
 {
@@ -860,5 +860,5 @@
 	size_t offset;
 	
-	rc = block_get_bsize(devmap_handle, &phys_block_size);
+	rc = block_get_bsize(service_id, &phys_block_size);
 	if (rc != EOK) {
 		return rc;
@@ -878,5 +878,5 @@
 	}
 	
-	rc = block_read_direct(devmap_handle, first_block, blocks, buffer);
+	rc = block_read_direct(service_id, first_block, blocks, buffer);
 	if (rc != EOK) {
 		free(buffer);
@@ -912,5 +912,5 @@
 		printf("Error %d reading %zu blocks starting at block %" PRIuOFF64
 		    " from device handle %" PRIun "\n", rc, cnt, ba,
-		    devcon->devmap_handle);
+		    devcon->service_id);
 #ifndef NDEBUG
 		stacktrace_print();
@@ -941,5 +941,5 @@
 	if (rc != EOK) {
 		printf("Error %d writing %zu blocks starting at block %" PRIuOFF64
-		    " to device handle %" PRIun "\n", rc, cnt, ba, devcon->devmap_handle);
+		    " to device handle %" PRIun "\n", rc, cnt, ba, devcon->service_id);
 #ifndef NDEBUG
 		stacktrace_print();
Index: uspace/lib/block/libblock.h
===================================================================
--- uspace/lib/block/libblock.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/block/libblock.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2008 Jakub Jermar
- * Copyright (c) 2008 Martin Decky 
- * Copyright (c) 2011 Martin Sucha 
+ * Copyright (c) 2008 Martin Decky
+ * Copyright (c) 2011 Martin Sucha
  * All rights reserved.
  *
@@ -73,6 +73,6 @@
 	/** Readers / Writer lock protecting the contents of the block. */
 	fibril_rwlock_t contents_lock;
-	/** Handle of the device where the block resides. */
-	devmap_handle_t devmap_handle;
+	/** Service ID of service providing the block device. */
+	service_id_t service_id;
 	/** Logical block address */
 	aoff64_t lba;
@@ -97,24 +97,24 @@
 };
 
-extern int block_init(exch_mgmt_t, devmap_handle_t, size_t);
-extern void block_fini(devmap_handle_t);
+extern int block_init(exch_mgmt_t, service_id_t, size_t);
+extern void block_fini(service_id_t);
 
-extern int block_bb_read(devmap_handle_t, aoff64_t);
-extern void *block_bb_get(devmap_handle_t);
+extern int block_bb_read(service_id_t, aoff64_t);
+extern void *block_bb_get(service_id_t);
 
-extern int block_cache_init(devmap_handle_t, size_t, unsigned, enum cache_mode);
-extern int block_cache_fini(devmap_handle_t);
+extern int block_cache_init(service_id_t, size_t, unsigned, enum cache_mode);
+extern int block_cache_fini(service_id_t);
 
-extern int block_get(block_t **, devmap_handle_t, aoff64_t, int);
+extern int block_get(block_t **, service_id_t, aoff64_t, int);
 extern int block_put(block_t *);
 
-extern int block_seqread(devmap_handle_t, size_t *, size_t *, aoff64_t *, void *,
+extern int block_seqread(service_id_t, size_t *, size_t *, aoff64_t *, void *,
     size_t);
 
-extern int block_get_bsize(devmap_handle_t, size_t *);
-extern int block_get_nblocks(devmap_handle_t, aoff64_t *);
-extern int block_read_direct(devmap_handle_t, aoff64_t, size_t, void *);
-extern int block_read_bytes_direct(devmap_handle_t, aoff64_t, size_t, void *);
-extern int block_write_direct(devmap_handle_t, aoff64_t, size_t, const void *);
+extern int block_get_bsize(service_id_t, size_t *);
+extern int block_get_nblocks(service_id_t, aoff64_t *);
+extern int block_read_direct(service_id_t, aoff64_t, size_t, void *);
+extern int block_read_bytes_direct(service_id_t, aoff64_t, size_t, void *);
+extern int block_write_direct(service_id_t, aoff64_t, size_t, const void *);
 
 #endif
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/c/Makefile	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -64,5 +64,4 @@
 	generic/cap.c \
 	generic/clipboard.c \
-	generic/devmap.c \
 	generic/devman.c \
 	generic/device/hw_res.c \
@@ -71,4 +70,5 @@
 	generic/event.c \
 	generic/errno.c \
+	generic/loc.c \
 	generic/mem.c \
 	generic/str.c \
Index: uspace/lib/c/generic/devman.c
===================================================================
--- uspace/lib/c/generic/devman.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/c/generic/devman.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -271,14 +271,14 @@
 }
 
-int devman_add_device_to_class(devman_handle_t devman_handle,
-    const char *class_name)
+int devman_add_device_to_category(devman_handle_t devman_handle,
+    const char *cat_name)
 {
 	async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
 	
 	ipc_call_t answer;
-	aid_t req = async_send_1(exch, DEVMAN_ADD_DEVICE_TO_CLASS,
+	aid_t req = async_send_1(exch, DEVMAN_ADD_DEVICE_TO_CATEGORY,
 	    devman_handle, &answer);
-	sysarg_t retval = async_data_write_start(exch, class_name,
-	    str_size(class_name));
+	sysarg_t retval = async_data_write_start(exch, cat_name,
+	    str_size(cat_name));
 	
 	devman_exchange_end(exch);
@@ -308,4 +308,23 @@
 }
 
+/** Remove function from device.
+ *
+ * Request devman to remove function owned by this driver task.
+ * @param funh      Devman handle of the function
+ *
+ * @return EOK on success or negative error code.
+ */
+int devman_remove_function(devman_handle_t funh)
+{
+	async_exch_t *exch;
+	sysarg_t retval;
+	
+	exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
+	retval = async_req_1_0(exch, DEVMAN_REMOVE_FUNCTION, (sysarg_t) funh);
+	devman_exchange_end(exch);
+	
+	return (int) retval;
+}
+
 async_sess_t *devman_parent_device_connect(exch_mgmt_t mgmt,
     devman_handle_t handle, unsigned int flags)
@@ -333,5 +352,5 @@
 		exch = devman_exchange_begin(DEVMAN_CLIENT);
 		if (exch == NULL)
-			return errno;
+			return ENOMEM;
 	}
 	
@@ -364,59 +383,9 @@
 }
 
-int devman_device_get_handle_by_class(const char *classname,
-    const char *devname, devman_handle_t *handle, unsigned int flags)
-{
-	async_exch_t *exch;
-	
-	if (flags & IPC_FLAG_BLOCKING)
-		exch = devman_exchange_begin_blocking(DEVMAN_CLIENT);
-	else {
-		exch = devman_exchange_begin(DEVMAN_CLIENT);
-		if (exch == NULL)
-			return errno;
-	}
-	
-	ipc_call_t answer;
-	aid_t req = async_send_1(exch, DEVMAN_DEVICE_GET_HANDLE_BY_CLASS,
-	    flags, &answer);
-	sysarg_t retval = async_data_write_start(exch, classname,
-	    str_size(classname));
-	
-	if (retval != EOK) {
-		devman_exchange_end(exch);
-		async_wait_for(req, NULL);
-		return retval;
-	}
-	
-	retval = async_data_write_start(exch, devname,
-	    str_size(devname));
-	
-	devman_exchange_end(exch);
-	
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		return retval;
-	}
-	
-	async_wait_for(req, &retval);
-	
-	if (retval != EOK) {
-		if (handle != NULL)
-			*handle = (devman_handle_t) -1;
-		
-		return retval;
-	}
-	
-	if (handle != NULL)
-		*handle = (devman_handle_t) IPC_GET_ARG1(answer);
-	
-	return retval;
-}
-
 int devman_get_device_path(devman_handle_t handle, char *path, size_t path_size)
 {
 	async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
 	if (exch == NULL)
-		return errno;
+		return ENOMEM;
 	
 	ipc_call_t answer;
@@ -463,4 +432,17 @@
 }
 
+int devman_fun_sid_to_handle(service_id_t sid, devman_handle_t *handle)
+{
+	async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
+	if (exch == NULL)
+		return ENOMEM;
+	
+	sysarg_t retval = async_req_1_1(exch, DEVMAN_FUN_SID_TO_HANDLE,
+	    sid, handle);
+	
+	devman_exchange_end(exch);
+	return (int) retval;
+}
+
 /** @}
  */
Index: pace/lib/c/generic/devmap.c
===================================================================
--- uspace/lib/c/generic/devmap.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,521 +1,0 @@
-/*
- * Copyright (c) 2007 Josef Cejka
- * Copyright (c) 2009 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <str.h>
-#include <ipc/services.h>
-#include <ns.h>
-#include <ipc/devmap.h>
-#include <devmap.h>
-#include <fibril_synch.h>
-#include <async.h>
-#include <errno.h>
-#include <malloc.h>
-#include <bool.h>
-
-static FIBRIL_MUTEX_INITIALIZE(devmap_driver_block_mutex);
-static FIBRIL_MUTEX_INITIALIZE(devmap_client_block_mutex);
-
-static FIBRIL_MUTEX_INITIALIZE(devmap_driver_mutex);
-static FIBRIL_MUTEX_INITIALIZE(devmap_client_mutex);
-
-static async_sess_t *devmap_driver_block_sess = NULL;
-static async_sess_t *devmap_client_block_sess = NULL;
-
-static async_sess_t *devmap_driver_sess = NULL;
-static async_sess_t *devmap_client_sess = NULL;
-
-static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
-    async_sess_t **dst)
-{
-	fibril_mutex_lock(mtx);
-	
-	if ((*dst == NULL) && (src != NULL))
-		*dst = src;
-	
-	fibril_mutex_unlock(mtx);
-}
-
-/** Start an async exchange on the devmap session (blocking).
- *
- * @param iface Device mapper interface to choose
- *
- * @return New exchange.
- *
- */
-async_exch_t *devmap_exchange_begin_blocking(devmap_interface_t iface)
-{
-	switch (iface) {
-	case DEVMAP_DRIVER:
-		fibril_mutex_lock(&devmap_driver_block_mutex);
-		
-		while (devmap_driver_block_sess == NULL) {
-			clone_session(&devmap_driver_mutex, devmap_driver_sess,
-			    &devmap_driver_block_sess);
-			
-			if (devmap_driver_block_sess == NULL)
-				devmap_driver_block_sess =
-				    service_connect_blocking(EXCHANGE_SERIALIZE,
-				    SERVICE_DEVMAP, DEVMAP_DRIVER, 0);
-		}
-		
-		fibril_mutex_unlock(&devmap_driver_block_mutex);
-		
-		clone_session(&devmap_driver_mutex, devmap_driver_block_sess,
-		    &devmap_driver_sess);
-		
-		return async_exchange_begin(devmap_driver_block_sess);
-	case DEVMAP_CLIENT:
-		fibril_mutex_lock(&devmap_client_block_mutex);
-		
-		while (devmap_client_block_sess == NULL) {
-			clone_session(&devmap_client_mutex, devmap_client_sess,
-			    &devmap_client_block_sess);
-			
-			if (devmap_client_block_sess == NULL)
-				devmap_client_block_sess =
-				    service_connect_blocking(EXCHANGE_SERIALIZE,
-				    SERVICE_DEVMAP, DEVMAP_CLIENT, 0);
-		}
-		
-		fibril_mutex_unlock(&devmap_client_block_mutex);
-		
-		clone_session(&devmap_client_mutex, devmap_client_block_sess,
-		    &devmap_client_sess);
-		
-		return async_exchange_begin(devmap_client_block_sess);
-	default:
-		return NULL;
-	}
-}
-
-/** Start an async exchange on the devmap session.
- *
- * @param iface Device mapper interface to choose
- *
- * @return New exchange.
- *
- */
-async_exch_t *devmap_exchange_begin(devmap_interface_t iface)
-{
-	switch (iface) {
-	case DEVMAP_DRIVER:
-		fibril_mutex_lock(&devmap_driver_mutex);
-		
-		if (devmap_driver_sess == NULL)
-			devmap_driver_sess =
-			    service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAP,
-			    DEVMAP_DRIVER, 0);
-		
-		fibril_mutex_unlock(&devmap_driver_mutex);
-		
-		if (devmap_driver_sess == NULL)
-			return NULL;
-		
-		return async_exchange_begin(devmap_driver_sess);
-	case DEVMAP_CLIENT:
-		fibril_mutex_lock(&devmap_client_mutex);
-		
-		if (devmap_client_sess == NULL)
-			devmap_client_sess =
-			    service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAP,
-			    DEVMAP_CLIENT, 0);
-		
-		fibril_mutex_unlock(&devmap_client_mutex);
-		
-		if (devmap_client_sess == NULL)
-			return NULL;
-		
-		return async_exchange_begin(devmap_client_sess);
-	default:
-		return NULL;
-	}
-}
-
-/** Finish an async exchange on the devmap session.
- *
- * @param exch Exchange to be finished.
- *
- */
-void devmap_exchange_end(async_exch_t *exch)
-{
-	async_exchange_end(exch);
-}
-
-/** Register new driver with devmap. */
-int devmap_driver_register(const char *name, async_client_conn_t conn)
-{
-	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_DRIVER);
-	
-	ipc_call_t answer;
-	aid_t req = async_send_2(exch, DEVMAP_DRIVER_REGISTER, 0, 0, &answer);
-	sysarg_t retval = async_data_write_start(exch, name, str_size(name));
-	
-	devmap_exchange_end(exch);
-	
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		return retval;
-	}
-	
-	async_set_client_connection(conn);
-	
-	exch = devmap_exchange_begin(DEVMAP_DRIVER);
-	async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
-	devmap_exchange_end(exch);
-	
-	async_wait_for(req, &retval);
-	return retval;
-}
-
-/** Register new device.
- *
- * The @p interface is used when forwarding connection to the driver.
- * If not 0, the first argument is the interface and the second argument
- * is the devmap handle of the device.
- *
- * When the interface is zero (default), the first argument is directly
- * the handle (to ensure backward compatibility).
- *
- * @param      fqdn      Fully qualified device name.
- * @param[out] handle    Handle to the created instance of device.
- * @param      interface Interface when forwarding.
- *
- */
-int devmap_device_register_with_iface(const char *fqdn,
-    devmap_handle_t *handle, sysarg_t interface)
-{
-	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_DRIVER);
-	
-	ipc_call_t answer;
-	aid_t req = async_send_2(exch, DEVMAP_DEVICE_REGISTER, interface, 0,
-	    &answer);
-	sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
-	
-	devmap_exchange_end(exch);
-	
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		return retval;
-	}
-	
-	async_wait_for(req, &retval);
-	
-	if (retval != EOK) {
-		if (handle != NULL)
-			*handle = -1;
-		
-		return retval;
-	}
-	
-	if (handle != NULL)
-		*handle = (devmap_handle_t) IPC_GET_ARG1(answer);
-	
-	return retval;
-}
-
-/** Register new device.
- *
- * @param fqdn   Fully qualified device name.
- * @param handle Output: Handle to the created instance of device.
- *
- */
-int devmap_device_register(const char *fqdn, devmap_handle_t *handle)
-{
-	return devmap_device_register_with_iface(fqdn, handle, 0);
-}
-
-int devmap_device_get_handle(const char *fqdn, devmap_handle_t *handle,
-    unsigned int flags)
-{
-	async_exch_t *exch;
-	
-	if (flags & IPC_FLAG_BLOCKING)
-		exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
-	else {
-		exch = devmap_exchange_begin(DEVMAP_CLIENT);
-		if (exch == NULL)
-			return errno;
-	}
-	
-	ipc_call_t answer;
-	aid_t req = async_send_2(exch, DEVMAP_DEVICE_GET_HANDLE, flags, 0,
-	    &answer);
-	sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
-	
-	devmap_exchange_end(exch);
-	
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		return retval;
-	}
-	
-	async_wait_for(req, &retval);
-	
-	if (retval != EOK) {
-		if (handle != NULL)
-			*handle = (devmap_handle_t) -1;
-		
-		return retval;
-	}
-	
-	if (handle != NULL)
-		*handle = (devmap_handle_t) IPC_GET_ARG1(answer);
-	
-	return retval;
-}
-
-int devmap_namespace_get_handle(const char *name, devmap_handle_t *handle,
-    unsigned int flags)
-{
-	async_exch_t *exch;
-	
-	if (flags & IPC_FLAG_BLOCKING)
-		exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
-	else {
-		exch = devmap_exchange_begin(DEVMAP_CLIENT);
-		if (exch == NULL)
-			return errno;
-	}
-	
-	ipc_call_t answer;
-	aid_t req = async_send_2(exch, DEVMAP_NAMESPACE_GET_HANDLE, flags, 0,
-	    &answer);
-	sysarg_t retval = async_data_write_start(exch, name, str_size(name));
-	
-	devmap_exchange_end(exch);
-	
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		return retval;
-	}
-	
-	async_wait_for(req, &retval);
-	
-	if (retval != EOK) {
-		if (handle != NULL)
-			*handle = (devmap_handle_t) -1;
-		
-		return retval;
-	}
-	
-	if (handle != NULL)
-		*handle = (devmap_handle_t) IPC_GET_ARG1(answer);
-	
-	return retval;
-}
-
-devmap_handle_type_t devmap_handle_probe(devmap_handle_t handle)
-{
-	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
-	
-	sysarg_t type;
-	int retval = async_req_1_1(exch, DEVMAP_HANDLE_PROBE, handle, &type);
-	
-	devmap_exchange_end(exch);
-	
-	if (retval != EOK)
-		return DEV_HANDLE_NONE;
-	
-	return (devmap_handle_type_t) type;
-}
-
-async_sess_t *devmap_device_connect(exch_mgmt_t mgmt, devmap_handle_t handle,
-    unsigned int flags)
-{
-	async_sess_t *sess;
-	
-	if (flags & IPC_FLAG_BLOCKING)
-		sess = service_connect_blocking(mgmt, SERVICE_DEVMAP,
-		    DEVMAP_CONNECT_TO_DEVICE, handle);
-	else
-		sess = service_connect(mgmt, SERVICE_DEVMAP,
-		    DEVMAP_CONNECT_TO_DEVICE, handle);
-	
-	return sess;
-}
-
-int devmap_null_create(void)
-{
-	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
-	
-	sysarg_t null_id;
-	int retval = async_req_0_1(exch, DEVMAP_NULL_CREATE, &null_id);
-	
-	devmap_exchange_end(exch);
-	
-	if (retval != EOK)
-		return -1;
-	
-	return (int) null_id;
-}
-
-void devmap_null_destroy(int null_id)
-{
-	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
-	async_req_1_0(exch, DEVMAP_NULL_DESTROY, (sysarg_t) null_id);
-	devmap_exchange_end(exch);
-}
-
-static size_t devmap_count_namespaces_internal(async_exch_t *exch)
-{
-	sysarg_t count;
-	int retval = async_req_0_1(exch, DEVMAP_GET_NAMESPACE_COUNT, &count);
-	if (retval != EOK)
-		return 0;
-	
-	return count;
-}
-
-static size_t devmap_count_devices_internal(async_exch_t *exch,
-    devmap_handle_t ns_handle)
-{
-	sysarg_t count;
-	int retval = async_req_1_1(exch, DEVMAP_GET_DEVICE_COUNT, ns_handle,
-	    &count);
-	if (retval != EOK)
-		return 0;
-	
-	return count;
-}
-
-size_t devmap_count_namespaces(void)
-{
-	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
-	size_t size = devmap_count_namespaces_internal(exch);
-	devmap_exchange_end(exch);
-	
-	return size;
-}
-
-size_t devmap_count_devices(devmap_handle_t ns_handle)
-{
-	async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
-	size_t size = devmap_count_devices_internal(exch, ns_handle);
-	devmap_exchange_end(exch);
-	
-	return size;
-}
-
-size_t devmap_get_namespaces(dev_desc_t **data)
-{
-	/* Loop until namespaces read succesful */
-	while (true) {
-		async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
-		size_t count = devmap_count_namespaces_internal(exch);
-		devmap_exchange_end(exch);
-		
-		if (count == 0)
-			return 0;
-		
-		dev_desc_t *devs = (dev_desc_t *) calloc(count, sizeof(dev_desc_t));
-		if (devs == NULL)
-			return 0;
-		
-		exch = devmap_exchange_begin(DEVMAP_CLIENT);
-		
-		ipc_call_t answer;
-		aid_t req = async_send_0(exch, DEVMAP_GET_NAMESPACES, &answer);
-		int rc = async_data_read_start(exch, devs, count * sizeof(dev_desc_t));
-		
-		devmap_exchange_end(exch);
-		
-		if (rc == EOVERFLOW) {
-			/*
-			 * Number of namespaces has changed since
-			 * the last call of DEVMAP_DEVICE_GET_NAMESPACE_COUNT
-			 */
-			free(devs);
-			continue;
-		}
-		
-		if (rc != EOK) {
-			async_wait_for(req, NULL);
-			free(devs);
-			return 0;
-		}
-		
-		sysarg_t retval;
-		async_wait_for(req, &retval);
-		
-		if (retval != EOK)
-			return 0;
-		
-		*data = devs;
-		return count;
-	}
-}
-
-size_t devmap_get_devices(devmap_handle_t ns_handle, dev_desc_t **data)
-{
-	/* Loop until devices read succesful */
-	while (true) {
-		async_exch_t *exch = devmap_exchange_begin_blocking(DEVMAP_CLIENT);
-		size_t count = devmap_count_devices_internal(exch, ns_handle);
-		devmap_exchange_end(exch);
-		
-		if (count == 0)
-			return 0;
-		
-		dev_desc_t *devs = (dev_desc_t *) calloc(count, sizeof(dev_desc_t));
-		if (devs == NULL)
-			return 0;
-		
-		exch = devmap_exchange_begin(DEVMAP_CLIENT);
-		
-		ipc_call_t answer;
-		aid_t req = async_send_1(exch, DEVMAP_GET_DEVICES, ns_handle, &answer);
-		int rc = async_data_read_start(exch, devs, count * sizeof(dev_desc_t));
-		
-		devmap_exchange_end(exch);
-		
-		if (rc == EOVERFLOW) {
-			/*
-			 * Number of devices has changed since
-			 * the last call of DEVMAP_DEVICE_GET_DEVICE_COUNT
-			 */
-			free(devs);
-			continue;
-		}
-		
-		if (rc != EOK) {
-			async_wait_for(req, NULL);
-			free(devs);
-			return 0;
-		}
-		
-		sysarg_t retval;
-		async_wait_for(req, &retval);
-		
-		if (retval != EOK)
-			return 0;
-		
-		*data = devs;
-		return count;
-	}
-}
Index: uspace/lib/c/generic/io/io.c
===================================================================
--- uspace/lib/c/generic/io/io.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/c/generic/io/io.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -45,5 +45,5 @@
 #include <vfs/vfs.h>
 #include <vfs/vfs_sess.h>
-#include <ipc/devmap.h>
+#include <ipc/loc.h>
 #include <adt/list.h>
 #include "../private/io.h"
Index: uspace/lib/c/generic/loc.c
===================================================================
--- uspace/lib/c/generic/loc.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/lib/c/generic/loc.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,876 @@
+/*
+ * Copyright (c) 2007 Josef Cejka
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <str.h>
+#include <ipc/services.h>
+#include <ns.h>
+#include <ipc/loc.h>
+#include <loc.h>
+#include <fibril_synch.h>
+#include <async.h>
+#include <errno.h>
+#include <malloc.h>
+#include <bool.h>
+
+static FIBRIL_MUTEX_INITIALIZE(loc_supp_block_mutex);
+static FIBRIL_MUTEX_INITIALIZE(loc_cons_block_mutex);
+
+static FIBRIL_MUTEX_INITIALIZE(loc_supplier_mutex);
+static FIBRIL_MUTEX_INITIALIZE(loc_consumer_mutex);
+
+static FIBRIL_MUTEX_INITIALIZE(loc_callback_mutex);
+static bool loc_callback_created = false;
+
+static async_sess_t *loc_supp_block_sess = NULL;
+static async_sess_t *loc_cons_block_sess = NULL;
+
+static async_sess_t *loc_supplier_sess = NULL;
+static async_sess_t *loc_consumer_sess = NULL;
+
+static loc_cat_change_cb_t cat_change_cb = NULL;
+
+static void loc_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	loc_cat_change_cb_t cb_fun;
+	
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call)) {
+			/* TODO: Handle hangup */
+			return;
+		}
+		
+		int retval;
+		
+		switch (IPC_GET_IMETHOD(call)) {
+		case LOC_EVENT_CAT_CHANGE:
+			fibril_mutex_lock(&loc_callback_mutex);
+			cb_fun = cat_change_cb;
+			if (cb_fun != NULL) {
+				(*cb_fun)();
+			}
+			fibril_mutex_unlock(&loc_callback_mutex);
+			retval = 0;
+			break;
+		default:
+			retval = ENOTSUP;
+		}
+		
+		async_answer_0(callid, retval);
+	}
+}
+
+
+static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
+    async_sess_t **dst)
+{
+	fibril_mutex_lock(mtx);
+	
+	if ((*dst == NULL) && (src != NULL))
+		*dst = src;
+	
+	fibril_mutex_unlock(mtx);
+}
+
+static int loc_callback_create(void)
+{
+	async_exch_t *exch;
+	sysarg_t retval;
+	int rc = EOK;
+
+	fibril_mutex_lock(&loc_callback_mutex);
+	
+	if (!loc_callback_created) {
+		exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+		
+		ipc_call_t answer;
+		aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
+		async_connect_to_me(exch, 0, 0, 0, loc_cb_conn, NULL);
+		loc_exchange_end(exch);
+		
+		async_wait_for(req, &retval);
+		if (rc != EOK)
+			goto done;
+		
+		if (retval != EOK) {
+			rc = retval;
+			goto done;
+		}
+		
+		loc_callback_created = true;
+	}
+	
+	rc = EOK;
+done:
+	fibril_mutex_unlock(&loc_callback_mutex);
+	return rc;
+}
+
+/** Start an async exchange on the loc session (blocking).
+ *
+ * @param iface Location service interface to choose
+ *
+ * @return New exchange.
+ *
+ */
+async_exch_t *loc_exchange_begin_blocking(loc_interface_t iface)
+{
+	switch (iface) {
+	case LOC_PORT_SUPPLIER:
+		fibril_mutex_lock(&loc_supp_block_mutex);
+		
+		while (loc_supp_block_sess == NULL) {
+			clone_session(&loc_supplier_mutex, loc_supplier_sess,
+			    &loc_supp_block_sess);
+			
+			if (loc_supp_block_sess == NULL)
+				loc_supp_block_sess =
+				    service_connect_blocking(EXCHANGE_SERIALIZE,
+				    SERVICE_LOC, LOC_PORT_SUPPLIER, 0);
+		}
+		
+		fibril_mutex_unlock(&loc_supp_block_mutex);
+		
+		clone_session(&loc_supplier_mutex, loc_supp_block_sess,
+		    &loc_supplier_sess);
+		
+		return async_exchange_begin(loc_supp_block_sess);
+	case LOC_PORT_CONSUMER:
+		fibril_mutex_lock(&loc_cons_block_mutex);
+		
+		while (loc_cons_block_sess == NULL) {
+			clone_session(&loc_consumer_mutex, loc_consumer_sess,
+			    &loc_cons_block_sess);
+			
+			if (loc_cons_block_sess == NULL)
+				loc_cons_block_sess =
+				    service_connect_blocking(EXCHANGE_SERIALIZE,
+				    SERVICE_LOC, LOC_PORT_CONSUMER, 0);
+		}
+		
+		fibril_mutex_unlock(&loc_cons_block_mutex);
+		
+		clone_session(&loc_consumer_mutex, loc_cons_block_sess,
+		    &loc_consumer_sess);
+		
+		return async_exchange_begin(loc_cons_block_sess);
+	default:
+		return NULL;
+	}
+}
+
+/** Start an async exchange on the loc session.
+ *
+ * @param iface Location service interface to choose
+ *
+ * @return New exchange.
+ *
+ */
+async_exch_t *loc_exchange_begin(loc_interface_t iface)
+{
+	switch (iface) {
+	case LOC_PORT_SUPPLIER:
+		fibril_mutex_lock(&loc_supplier_mutex);
+		
+		if (loc_supplier_sess == NULL)
+			loc_supplier_sess =
+			    service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
+			    LOC_PORT_SUPPLIER, 0);
+		
+		fibril_mutex_unlock(&loc_supplier_mutex);
+		
+		if (loc_supplier_sess == NULL)
+			return NULL;
+		
+		return async_exchange_begin(loc_supplier_sess);
+	case LOC_PORT_CONSUMER:
+		fibril_mutex_lock(&loc_consumer_mutex);
+		
+		if (loc_consumer_sess == NULL)
+			loc_consumer_sess =
+			    service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
+			    LOC_PORT_CONSUMER, 0);
+		
+		fibril_mutex_unlock(&loc_consumer_mutex);
+		
+		if (loc_consumer_sess == NULL)
+			return NULL;
+		
+		return async_exchange_begin(loc_consumer_sess);
+	default:
+		return NULL;
+	}
+}
+
+/** Finish an async exchange on the loc session.
+ *
+ * @param exch Exchange to be finished.
+ *
+ */
+void loc_exchange_end(async_exch_t *exch)
+{
+	async_exchange_end(exch);
+}
+
+/** Register new driver with loc. */
+int loc_server_register(const char *name, async_client_conn_t conn)
+{
+	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_2(exch, LOC_SERVER_REGISTER, 0, 0, &answer);
+	sysarg_t retval = async_data_write_start(exch, name, str_size(name));
+	
+	loc_exchange_end(exch);
+	
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		return retval;
+	}
+	
+	async_set_client_connection(conn);
+	
+	exch = loc_exchange_begin(LOC_PORT_SUPPLIER);
+	async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
+	loc_exchange_end(exch);
+	
+	async_wait_for(req, &retval);
+	return retval;
+}
+
+/** Register new service.
+ *
+ * The @p interface is used when forwarding connection to the server.
+ * If not 0, the first argument is the interface and the second argument
+ * is the service ID.
+ *
+ * When the interface is zero (default), the first argument is directly
+ * the handle (to ensure backward compatibility).
+ *
+ * @param      fqsn      Fully qualified service name
+ * @param[out] sid       Service ID of new service
+ * @param      interface Interface when forwarding
+ *
+ */
+int loc_service_register_with_iface(const char *fqsn,
+    service_id_t *sid, sysarg_t interface)
+{
+	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_2(exch, LOC_SERVICE_REGISTER, interface, 0,
+	    &answer);
+	sysarg_t retval = async_data_write_start(exch, fqsn, str_size(fqsn));
+	
+	loc_exchange_end(exch);
+	
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		return retval;
+	}
+	
+	async_wait_for(req, &retval);
+	
+	if (retval != EOK) {
+		if (sid != NULL)
+			*sid = -1;
+		
+		return retval;
+	}
+	
+	if (sid != NULL)
+		*sid = (service_id_t) IPC_GET_ARG1(answer);
+	
+	return retval;
+}
+
+/** Register new service.
+ *
+ * @param fqsn	Fully qualified service name
+ * @param sid	Output: ID of new service
+ *
+ */
+int loc_service_register(const char *fqdn, service_id_t *sid)
+{
+	return loc_service_register_with_iface(fqdn, sid, 0);
+}
+
+/** Unregister service.
+ *
+ * @param sid	Service ID
+ */
+int loc_service_unregister(service_id_t sid)
+{
+	async_exch_t *exch;
+	sysarg_t retval;
+	
+	exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
+	retval = async_req_1_0(exch, LOC_SERVICE_UNREGISTER, sid);
+	loc_exchange_end(exch);
+	
+	return (int)retval;
+}
+
+int loc_service_get_id(const char *fqdn, service_id_t *handle,
+    unsigned int flags)
+{
+	async_exch_t *exch;
+	
+	if (flags & IPC_FLAG_BLOCKING)
+		exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	else {
+		exch = loc_exchange_begin(LOC_PORT_CONSUMER);
+		if (exch == NULL)
+			return errno;
+	}
+	
+	ipc_call_t answer;
+	aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
+	    &answer);
+	sysarg_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
+	
+	loc_exchange_end(exch);
+	
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		return retval;
+	}
+	
+	async_wait_for(req, &retval);
+	
+	if (retval != EOK) {
+		if (handle != NULL)
+			*handle = (service_id_t) -1;
+		
+		return retval;
+	}
+	
+	if (handle != NULL)
+		*handle = (service_id_t) IPC_GET_ARG1(answer);
+	
+	return retval;
+}
+
+/** Get object name.
+ *
+ * Provided ID of an object, return its name.
+ *
+ * @param method	IPC method
+ * @param id		Object ID
+ * @param name		Place to store pointer to new string. Caller should
+ *			free it using free().
+ * @return		EOK on success or negative error code
+ */
+static int loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
+{
+	async_exch_t *exch;
+	char name_buf[LOC_NAME_MAXLEN + 1];
+	ipc_call_t dreply;
+	size_t act_size;
+	sysarg_t dretval;
+	
+	*name = NULL;
+	exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_1(exch, method, id, &answer);
+	aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
+	    &dreply);
+	async_wait_for(dreq, &dretval);
+	
+	loc_exchange_end(exch);
+	
+	if (dretval != EOK) {
+		async_wait_for(req, NULL);
+		return dretval;
+	}
+	
+	sysarg_t retval;
+	async_wait_for(req, &retval);
+	
+	if (retval != EOK)
+		return retval;
+	
+	act_size = IPC_GET_ARG2(dreply);
+	assert(act_size <= LOC_NAME_MAXLEN);
+	name_buf[act_size] = '\0';
+
+	*name = str_dup(name_buf);
+	if (*name == NULL)
+		return ENOMEM;
+	
+	return EOK;
+}
+
+/** Get category name.
+ *
+ * Provided ID of a service, return its name.
+ *
+ * @param cat_id	Category ID
+ * @param name		Place to store pointer to new string. Caller should
+ *			free it using free().
+ * @return		EOK on success or negative error code
+ */
+int loc_category_get_name(category_id_t cat_id, char **name)
+{
+	return loc_get_name_internal(LOC_CATEGORY_GET_NAME, cat_id, name);
+}
+
+/** Get service name.
+ *
+ * Provided ID of a service, return its name.
+ *
+ * @param svc_id	Service ID
+ * @param name		Place to store pointer to new string. Caller should
+ *			free it using free().
+ * @return		EOK on success or negative error code
+ */
+int loc_service_get_name(service_id_t svc_id, char **name)
+{
+	return loc_get_name_internal(LOC_SERVICE_GET_NAME, svc_id, name);
+}
+
+int loc_namespace_get_id(const char *name, service_id_t *handle,
+    unsigned int flags)
+{
+	async_exch_t *exch;
+	
+	if (flags & IPC_FLAG_BLOCKING)
+		exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	else {
+		exch = loc_exchange_begin(LOC_PORT_CONSUMER);
+		if (exch == NULL)
+			return errno;
+	}
+	
+	ipc_call_t answer;
+	aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
+	    &answer);
+	sysarg_t retval = async_data_write_start(exch, name, str_size(name));
+	
+	loc_exchange_end(exch);
+	
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		return retval;
+	}
+	
+	async_wait_for(req, &retval);
+	
+	if (retval != EOK) {
+		if (handle != NULL)
+			*handle = (service_id_t) -1;
+		
+		return retval;
+	}
+	
+	if (handle != NULL)
+		*handle = (service_id_t) IPC_GET_ARG1(answer);
+	
+	return retval;
+}
+
+/** Get category ID.
+ *
+ * Provided name of a category, return its ID.
+ *
+ * @param name		Category name
+ * @param cat_id	Place to store ID
+ * @param flags		IPC_FLAG_BLOCKING to wait for location service to start
+ * @return		EOK on success or negative error code
+ */
+int loc_category_get_id(const char *name, category_id_t *cat_id,
+    unsigned int flags)
+{
+	async_exch_t *exch;
+	
+	if (flags & IPC_FLAG_BLOCKING)
+		exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	else {
+		exch = loc_exchange_begin(LOC_PORT_CONSUMER);
+		if (exch == NULL)
+			return errno;
+	}
+	
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
+	    &answer);
+	sysarg_t retval = async_data_write_start(exch, name, str_size(name));
+	
+	loc_exchange_end(exch);
+	
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		return retval;
+	}
+	
+	async_wait_for(req, &retval);
+	
+	if (retval != EOK) {
+		if (cat_id != NULL)
+			*cat_id = (category_id_t) -1;
+		
+		return retval;
+	}
+	
+	if (cat_id != NULL)
+		*cat_id = (category_id_t) IPC_GET_ARG1(answer);
+	
+	return retval;
+}
+
+
+loc_object_type_t loc_id_probe(service_id_t handle)
+{
+	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	
+	sysarg_t type;
+	int retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
+	
+	loc_exchange_end(exch);
+	
+	if (retval != EOK)
+		return LOC_OBJECT_NONE;
+	
+	return (loc_object_type_t) type;
+}
+
+async_sess_t *loc_service_connect(exch_mgmt_t mgmt, service_id_t handle,
+    unsigned int flags)
+{
+	async_sess_t *sess;
+	
+	if (flags & IPC_FLAG_BLOCKING)
+		sess = service_connect_blocking(mgmt, SERVICE_LOC,
+		    LOC_CONNECT_TO_SERVICE, handle);
+	else
+		sess = service_connect(mgmt, SERVICE_LOC,
+		    LOC_CONNECT_TO_SERVICE, handle);
+	
+	return sess;
+}
+
+int loc_null_create(void)
+{
+	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	
+	sysarg_t null_id;
+	int retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
+	
+	loc_exchange_end(exch);
+	
+	if (retval != EOK)
+		return -1;
+	
+	return (int) null_id;
+}
+
+void loc_null_destroy(int null_id)
+{
+	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
+	loc_exchange_end(exch);
+}
+
+static size_t loc_count_namespaces_internal(async_exch_t *exch)
+{
+	sysarg_t count;
+	int retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
+	if (retval != EOK)
+		return 0;
+	
+	return count;
+}
+
+/** Add service to category.
+ *
+ * @param svc_id	Service ID
+ * @param cat_id	Category ID
+ * @return		EOK on success or negative error code
+ */
+int loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
+{
+	async_exch_t *exch;
+	sysarg_t retval;
+	
+	exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
+	retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
+	loc_exchange_end(exch);
+	
+	return retval;
+}
+
+static size_t loc_count_services_internal(async_exch_t *exch,
+    service_id_t ns_handle)
+{
+	sysarg_t count;
+	int retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
+	    &count);
+	if (retval != EOK)
+		return 0;
+	
+	return count;
+}
+
+size_t loc_count_namespaces(void)
+{
+	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	size_t size = loc_count_namespaces_internal(exch);
+	loc_exchange_end(exch);
+	
+	return size;
+}
+
+size_t loc_count_services(service_id_t ns_handle)
+{
+	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	size_t size = loc_count_services_internal(exch, ns_handle);
+	loc_exchange_end(exch);
+	
+	return size;
+}
+
+size_t loc_get_namespaces(loc_sdesc_t **data)
+{
+	/* Loop until read is succesful */
+	while (true) {
+		async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+		size_t count = loc_count_namespaces_internal(exch);
+		loc_exchange_end(exch);
+		
+		if (count == 0)
+			return 0;
+		
+		loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
+		if (devs == NULL)
+			return 0;
+		
+		exch = loc_exchange_begin(LOC_PORT_CONSUMER);
+		
+		ipc_call_t answer;
+		aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
+		int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
+		
+		loc_exchange_end(exch);
+		
+		if (rc == EOVERFLOW) {
+			/*
+			 * Number of namespaces has changed since
+			 * the last call of LOC_GET_NAMESPACE_COUNT
+			 */
+			free(devs);
+			continue;
+		}
+		
+		if (rc != EOK) {
+			async_wait_for(req, NULL);
+			free(devs);
+			return 0;
+		}
+		
+		sysarg_t retval;
+		async_wait_for(req, &retval);
+		
+		if (retval != EOK)
+			return 0;
+		
+		*data = devs;
+		return count;
+	}
+}
+
+size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
+{
+	/* Loop until read is succesful */
+	while (true) {
+		async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+		size_t count = loc_count_services_internal(exch, ns_handle);
+		loc_exchange_end(exch);
+		
+		if (count == 0)
+			return 0;
+		
+		loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
+		if (devs == NULL)
+			return 0;
+		
+		exch = loc_exchange_begin(LOC_PORT_CONSUMER);
+		
+		ipc_call_t answer;
+		aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
+		int rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
+		
+		loc_exchange_end(exch);
+		
+		if (rc == EOVERFLOW) {
+			/*
+			 * Number of services has changed since
+			 * the last call of LOC_GET_SERVICE_COUNT
+			 */
+			free(devs);
+			continue;
+		}
+		
+		if (rc != EOK) {
+			async_wait_for(req, NULL);
+			free(devs);
+			return 0;
+		}
+		
+		sysarg_t retval;
+		async_wait_for(req, &retval);
+		
+		if (retval != EOK)
+			return 0;
+		
+		*data = devs;
+		return count;
+	}
+}
+
+static int loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
+    sysarg_t *id_buf, size_t buf_size, size_t *act_size)
+{
+	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+
+	ipc_call_t answer;
+	aid_t req = async_send_1(exch, method, arg1, &answer);
+	int rc = async_data_read_start(exch, id_buf, buf_size);
+	
+	loc_exchange_end(exch);
+	
+	if (rc != EOK) {
+		async_wait_for(req, NULL);
+		return rc;
+	}
+	
+	sysarg_t retval;
+	async_wait_for(req, &retval);
+	
+	if (retval != EOK) {
+		return retval;
+	}
+	
+	*act_size = IPC_GET_ARG1(answer);
+	return EOK;
+}
+
+/** Get list of IDs.
+ *
+ * Returns an allocated array of service IDs.
+ *
+ * @param method	IPC method
+ * @param arg1		IPC argument 1
+ * @param data		Place to store pointer to array of IDs
+ * @param count		Place to store number of IDs
+ * @return 		EOK on success or negative error code
+ */
+static int loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
+    sysarg_t **data, size_t *count)
+{
+	service_id_t *ids;
+	size_t act_size;
+	size_t alloc_size;
+	int rc;
+
+	*data = NULL;
+	act_size = 0;	/* silence warning */
+
+	rc = loc_category_get_ids_once(method, arg1, NULL, 0,
+	    &act_size);
+	if (rc != EOK)
+		return rc;
+
+	alloc_size = act_size;
+	ids = malloc(alloc_size);
+	if (ids == NULL)
+		return ENOMEM;
+
+	while (true) {
+		rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
+		    &act_size);
+		if (rc != EOK)
+			return rc;
+
+		if (act_size <= alloc_size)
+			break;
+
+		alloc_size *= 2;
+		free(ids);
+
+		ids = malloc(alloc_size);
+		if (ids == NULL)
+			return ENOMEM;
+	}
+
+	*count = act_size / sizeof(category_id_t);
+	*data = ids;
+	return EOK;
+}
+
+/** Get list of services in category.
+ *
+ * Returns an allocated array of service IDs.
+ *
+ * @param cat_id	Category ID
+ * @param data		Place to store pointer to array of IDs
+ * @param count		Place to store number of IDs
+ * @return 		EOK on success or negative error code
+ */
+int loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
+    size_t *count)
+{
+	return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
+	    data, count);
+}
+
+/** Get list of categories.
+ *
+ * Returns an allocated array of category IDs.
+ *
+ * @param data		Place to store pointer to array of IDs
+ * @param count		Place to store number of IDs
+ * @return 		EOK on success or negative error code
+ */
+int loc_get_categories(category_id_t **data, size_t *count)
+{
+	return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
+	    data, count);
+}
+
+int loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun)
+{
+	if (loc_callback_create() != EOK)
+		return EIO;
+
+	cat_change_cb = cb_fun;
+	return EOK;
+}
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -51,7 +51,7 @@
 #include <assert.h>
 #include <str.h>
-#include <devmap.h>
+#include <loc.h>
 #include <ipc/vfs.h>
-#include <ipc/devmap.h>
+#include <ipc/loc.h>
 
 static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
@@ -142,27 +142,27 @@
 }
 
-int mount(const char *fs_name, const char *mp, const char *fqdn,
+int mount(const char *fs_name, const char *mp, const char *fqsn,
     const char *opts, unsigned int flags)
 {
 	int null_id = -1;
-	char null[DEVMAP_NAME_MAXLEN];
-	
-	if (str_cmp(fqdn, "") == 0) {
+	char null[LOC_NAME_MAXLEN];
+	
+	if (str_cmp(fqsn, "") == 0) {
 		/* No device specified, create a fresh
 		   null/%d device instead */
-		null_id = devmap_null_create();
+		null_id = loc_null_create();
 		
 		if (null_id == -1)
 			return ENOMEM;
 		
-		snprintf(null, DEVMAP_NAME_MAXLEN, "null/%d", null_id);
-		fqdn = null;
-	}
-	
-	devmap_handle_t devmap_handle;
-	int res = devmap_device_get_handle(fqdn, &devmap_handle, flags);
+		snprintf(null, LOC_NAME_MAXLEN, "null/%d", null_id);
+		fqsn = null;
+	}
+	
+	service_id_t service_id;
+	int res = loc_service_get_id(fqsn, &service_id, flags);
 	if (res != EOK) {
 		if (null_id != -1)
-			devmap_null_destroy(null_id);
+			loc_null_destroy(null_id);
 		
 		return res;
@@ -173,5 +173,5 @@
 	if (!mpa) {
 		if (null_id != -1)
-			devmap_null_destroy(null_id);
+			loc_null_destroy(null_id);
 		
 		return ENOMEM;
@@ -181,5 +181,5 @@
 
 	sysarg_t rc_orig;
-	aid_t req = async_send_2(exch, VFS_IN_MOUNT, devmap_handle, flags, NULL);
+	aid_t req = async_send_2(exch, VFS_IN_MOUNT, service_id, flags, NULL);
 	sysarg_t rc = async_data_write_start(exch, (void *) mpa, mpa_size);
 	if (rc != EOK) {
@@ -189,5 +189,5 @@
 		
 		if (null_id != -1)
-			devmap_null_destroy(null_id);
+			loc_null_destroy(null_id);
 		
 		if (rc_orig == EOK)
@@ -204,5 +204,5 @@
 		
 		if (null_id != -1)
-			devmap_null_destroy(null_id);
+			loc_null_destroy(null_id);
 		
 		if (rc_orig == EOK)
@@ -219,5 +219,5 @@
 		
 		if (null_id != -1)
-			devmap_null_destroy(null_id);
+			loc_null_destroy(null_id);
 		
 		if (rc_orig == EOK)
@@ -235,5 +235,5 @@
 		
 		if (null_id != -1)
-			devmap_null_destroy(null_id);
+			loc_null_destroy(null_id);
 		
 		if (rc_orig == EOK)
@@ -248,5 +248,5 @@
 	
 	if ((rc != EOK) && (null_id != -1))
-		devmap_null_destroy(null_id);
+		loc_null_destroy(null_id);
 	
 	return (int) rc;
@@ -792,10 +792,10 @@
 	}
 	
-	if (!stat.device) {
+	if (!stat.service) {
 		errno = ENOENT;
 		return NULL;
 	}
 	
-	return devmap_device_connect(mgmt, stat.device, 0);
+	return loc_service_connect(mgmt, stat.service, 0);
 }
 
Index: uspace/lib/c/include/devman.h
===================================================================
--- uspace/lib/c/include/devman.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/c/include/devman.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -38,4 +38,5 @@
 
 #include <ipc/devman.h>
+#include <ipc/loc.h>
 #include <async.h>
 #include <bool.h>
@@ -48,4 +49,5 @@
 extern int devman_add_function(const char *, fun_type_t, match_id_list_t *,
     devman_handle_t, devman_handle_t *);
+extern int devman_remove_function(devman_handle_t);
 
 extern async_sess_t *devman_device_connect(exch_mgmt_t, devman_handle_t,
@@ -56,9 +58,8 @@
 extern int devman_device_get_handle(const char *, devman_handle_t *,
     unsigned int);
-extern int devman_device_get_handle_by_class(const char *, const char *,
-    devman_handle_t *, unsigned int);
 extern int devman_get_device_path(devman_handle_t, char *, size_t);
 
-extern int devman_add_device_to_class(devman_handle_t, const char *);
+extern int devman_add_device_to_category(devman_handle_t, const char *);
+extern int devman_fun_sid_to_handle(service_id_t, devman_handle_t *);
 
 #endif
Index: pace/lib/c/include/devmap.h
===================================================================
--- uspace/lib/c/include/devmap.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,72 +1,0 @@
-/*
- * Copyright (c) 2009 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libc
- * @{
- */
-/** @file
- */
-
-#ifndef LIBC_DEVMAP_H_
-#define LIBC_DEVMAP_H_
-
-#include <ipc/devmap.h>
-#include <async.h>
-#include <bool.h>
-
-extern async_exch_t *devmap_exchange_begin_blocking(devmap_interface_t);
-extern async_exch_t *devmap_exchange_begin(devmap_interface_t);
-extern void devmap_exchange_end(async_exch_t *);
-
-extern int devmap_driver_register(const char *, async_client_conn_t);
-extern int devmap_device_register(const char *, devmap_handle_t *);
-extern int devmap_device_register_with_iface(const char *, devmap_handle_t *,
-    sysarg_t);
-
-extern int devmap_device_get_handle(const char *, devmap_handle_t *,
-    unsigned int);
-extern int devmap_namespace_get_handle(const char *, devmap_handle_t *,
-    unsigned int);
-extern devmap_handle_type_t devmap_handle_probe(devmap_handle_t);
-
-extern async_sess_t *devmap_device_connect(exch_mgmt_t, devmap_handle_t,
-    unsigned int);
-
-extern int devmap_null_create(void);
-extern void devmap_null_destroy(int);
-
-extern size_t devmap_count_namespaces(void);
-extern size_t devmap_count_devices(devmap_handle_t);
-
-extern size_t devmap_get_namespaces(dev_desc_t **);
-extern size_t devmap_get_devices(devmap_handle_t, dev_desc_t **);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/c/include/ipc/devman.h
===================================================================
--- uspace/lib/c/include/ipc/devman.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/c/include/ipc/devman.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -130,5 +130,5 @@
 	DEVMAN_CLIENT,
 	DEVMAN_CONNECT_TO_DEVICE,
-	DEVMAN_CONNECT_FROM_DEVMAP,
+	DEVMAN_CONNECT_FROM_LOC,
 	DEVMAN_CONNECT_TO_PARENTS_DEVICE
 } devman_interface_t;
@@ -138,6 +138,6 @@
 	DEVMAN_ADD_FUNCTION,
 	DEVMAN_ADD_MATCH_ID,
-	DEVMAN_ADD_DEVICE_TO_CLASS
-
+	DEVMAN_ADD_DEVICE_TO_CATEGORY,
+	DEVMAN_REMOVE_FUNCTION
 } driver_to_devman_t;
 
@@ -149,6 +149,6 @@
 typedef enum {
 	DEVMAN_DEVICE_GET_HANDLE = IPC_FIRST_USER_METHOD,
-	DEVMAN_DEVICE_GET_HANDLE_BY_CLASS,
-	DEVMAN_DEVICE_GET_DEVICE_PATH
+	DEVMAN_DEVICE_GET_DEVICE_PATH,
+	DEVMAN_FUN_SID_TO_HANDLE
 } client_to_devman_t;
 
Index: pace/lib/c/include/ipc/devmap.h
===================================================================
--- uspace/lib/c/include/ipc/devmap.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,85 +1,0 @@
-/*
- * Copyright (c) 2007 Josef Cejka
- * 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 devmap
- * @{
- */
-
-#ifndef LIBC_IPC_DEVMAP_H_
-#define LIBC_IPC_DEVMAP_H_
-
-#include <ipc/common.h>
-
-#define DEVMAP_NAME_MAXLEN  255
-
-typedef sysarg_t devmap_handle_t;
-
-typedef enum {
-	DEV_HANDLE_NONE,
-	DEV_HANDLE_NAMESPACE,
-	DEV_HANDLE_DEVICE
-} devmap_handle_type_t;
-
-typedef enum {
-	DEVMAP_DRIVER_REGISTER = IPC_FIRST_USER_METHOD,
-	DEVMAP_DRIVER_UNREGISTER,
-	DEVMAP_DEVICE_REGISTER,
-	DEVMAP_DEVICE_UNREGISTER,
-	DEVMAP_DEVICE_GET_HANDLE,
-	DEVMAP_NAMESPACE_GET_HANDLE,
-	DEVMAP_HANDLE_PROBE,
-	DEVMAP_NULL_CREATE,
-	DEVMAP_NULL_DESTROY,
-	DEVMAP_GET_NAMESPACE_COUNT,
-	DEVMAP_GET_DEVICE_COUNT,
-	DEVMAP_GET_NAMESPACES,
-	DEVMAP_GET_DEVICES
-} devmap_request_t;
-
-/** Interface provided by devmap.
- *
- * Every process that connects to devmap must ask one of following
- * interfaces otherwise connection will be refused.
- *
- */
-typedef enum {
-	/** Connect as device driver */
-	DEVMAP_DRIVER = 1,
-	/** Connect as client */
-	DEVMAP_CLIENT,
-	/** Create new connection to instance of device that
-	    is specified by second argument of call. */
-	DEVMAP_CONNECT_TO_DEVICE
-} devmap_interface_t;
-
-typedef struct {
-	devmap_handle_t handle;
-	char name[DEVMAP_NAME_MAXLEN + 1];
-} dev_desc_t;
-
-#endif
Index: uspace/lib/c/include/ipc/loc.h
===================================================================
--- uspace/lib/c/include/ipc/loc.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/lib/c/include/ipc/loc.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2007 Josef Cejka
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup loc
+ * @{
+ */
+
+#ifndef LIBC_IPC_LOC_H_
+#define LIBC_IPC_LOC_H_
+
+#include <ipc/common.h>
+
+#define LOC_NAME_MAXLEN  255
+
+typedef sysarg_t service_id_t;
+typedef sysarg_t category_id_t;
+
+typedef enum {
+	LOC_OBJECT_NONE,
+	LOC_OBJECT_NAMESPACE,
+	LOC_OBJECT_SERVICE
+} loc_object_type_t;
+
+typedef enum {
+	LOC_SERVER_REGISTER = IPC_FIRST_USER_METHOD,
+	LOC_SERVER_UNREGISTER,
+	LOC_SERVICE_ADD_TO_CAT,
+	LOC_SERVICE_REGISTER,
+	LOC_SERVICE_UNREGISTER,
+	LOC_SERVICE_GET_ID,
+	LOC_SERVICE_GET_NAME,
+	LOC_NAMESPACE_GET_ID,
+	LOC_CALLBACK_CREATE,
+	LOC_CATEGORY_GET_ID,
+	LOC_CATEGORY_GET_NAME,
+	LOC_CATEGORY_GET_SVCS,
+	LOC_ID_PROBE,
+	LOC_NULL_CREATE,
+	LOC_NULL_DESTROY,
+	LOC_GET_NAMESPACE_COUNT,
+	LOC_GET_SERVICE_COUNT,
+	LOC_GET_CATEGORIES,
+	LOC_GET_NAMESPACES,
+	LOC_GET_SERVICES
+} loc_request_t;
+
+typedef enum {
+	LOC_EVENT_CAT_CHANGE = IPC_FIRST_USER_METHOD
+} loc_event_t;
+
+/** Ports provided by location service.
+ *
+ * Every process that connects to loc must ask one of following
+ * ports, otherwise connection will be refused.
+ *
+ */
+typedef enum {
+	/** Service supplier (server) port */
+	LOC_PORT_SUPPLIER = 1,
+	/** Service consumer (client) port */
+	LOC_PORT_CONSUMER,
+	/** Create new connection to instance of device that
+	    is specified by second argument of call. */
+	LOC_CONNECT_TO_SERVICE
+} loc_interface_t;
+
+typedef struct {
+	service_id_t id;
+	char name[LOC_NAME_MAXLEN + 1];
+} loc_sdesc_t;
+
+#endif
Index: uspace/lib/c/include/ipc/services.h
===================================================================
--- uspace/lib/c/include/ipc/services.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/c/include/ipc/services.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -45,5 +45,5 @@
 	SERVICE_VIDEO      = FOURCC('v', 'i', 'd', ' '),
 	SERVICE_VFS        = FOURCC('v', 'f', 's', ' '),
-	SERVICE_DEVMAP     = FOURCC('d', 'e', 'v', 'p'),
+	SERVICE_LOC        = FOURCC('l', 'o', 'c', ' '),
 	SERVICE_DEVMAN     = FOURCC('d', 'e', 'v', 'n'),
 	SERVICE_IRC        = FOURCC('i', 'r', 'c', ' '),
Index: uspace/lib/c/include/loc.h
===================================================================
--- uspace/lib/c/include/loc.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/lib/c/include/loc.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_LOC_H_
+#define LIBC_LOC_H_
+
+#include <ipc/loc.h>
+#include <async.h>
+#include <bool.h>
+
+typedef void (*loc_cat_change_cb_t)(void);
+
+extern async_exch_t *loc_exchange_begin_blocking(loc_interface_t);
+extern async_exch_t *loc_exchange_begin(loc_interface_t);
+extern void loc_exchange_end(async_exch_t *);
+
+extern int loc_server_register(const char *, async_client_conn_t);
+extern int loc_service_register(const char *, service_id_t *);
+extern int loc_service_register_with_iface(const char *, service_id_t *,
+    sysarg_t);
+extern int loc_service_unregister(service_id_t);
+extern int loc_service_add_to_cat(service_id_t, category_id_t);
+
+extern int loc_service_get_id(const char *, service_id_t *,
+    unsigned int);
+extern int loc_service_get_name(service_id_t, char **);
+extern int loc_namespace_get_id(const char *, service_id_t *,
+    unsigned int);
+extern int loc_category_get_id(const char *, category_id_t *,
+    unsigned int);
+extern int loc_category_get_name(category_id_t, char **);
+extern int loc_category_get_svcs(category_id_t, category_id_t **, size_t *);
+extern loc_object_type_t loc_id_probe(service_id_t);
+
+extern async_sess_t *loc_service_connect(exch_mgmt_t, service_id_t,
+    unsigned int);
+
+extern int loc_null_create(void);
+extern void loc_null_destroy(int);
+
+extern size_t loc_count_namespaces(void);
+extern size_t loc_count_services(service_id_t);
+
+extern size_t loc_get_namespaces(loc_sdesc_t **);
+extern size_t loc_get_services(service_id_t, loc_sdesc_t **);
+extern int loc_get_categories(category_id_t **, size_t *);
+extern int loc_register_cat_change_cb(loc_cat_change_cb_t);
+
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/sys/stat.h
===================================================================
--- uspace/lib/c/include/sys/stat.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/c/include/sys/stat.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -39,9 +39,9 @@
 #include <bool.h>
 #include <ipc/vfs.h>
-#include <ipc/devmap.h>
+#include <ipc/loc.h>
 
 struct stat {
 	fs_handle_t fs_handle;
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 	fs_index_t index;
 	unsigned int lnkcnt;
@@ -49,5 +49,5 @@
 	bool is_directory;
 	aoff64_t size;
-	devmap_handle_t device;
+	service_id_t service;
 };
 
Index: uspace/lib/c/include/vfs/vfs.h
===================================================================
--- uspace/lib/c/include/vfs/vfs.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/c/include/vfs/vfs.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -38,5 +38,5 @@
 #include <sys/types.h>
 #include <ipc/vfs.h>
-#include <ipc/devmap.h>
+#include <ipc/loc.h>
 #include <stdio.h>
 #include <async.h>
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/drv/generic/driver.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -582,4 +582,5 @@
 int ddf_fun_bind(ddf_fun_t *fun)
 {
+	assert(fun->bound == false);
 	assert(fun->name != NULL);
 	
@@ -598,4 +599,29 @@
 }
 
+/** Unbind a function node.
+ *
+ * Unbind the specified function from the system. This effectively makes
+ * the function invisible to the system.
+ *
+ * @param fun		Function to bind
+ * @return		EOK on success or negative error code
+ */
+int ddf_fun_unbind(ddf_fun_t *fun)
+{
+	int res;
+	
+	assert(fun->bound == true);
+	
+	add_to_functions_list(fun);
+	res = devman_remove_function(fun->handle);
+	if (res != EOK)
+		return res;
+
+	remove_from_functions_list(fun);
+	
+	fun->bound = false;
+	return EOK;
+}
+
 /** Add single match ID to inner function.
  *
@@ -635,14 +661,14 @@
 }
 
-/** Add exposed function to class.
+/** Add exposed function to category.
  *
  * Must only be called when the function is bound.
  */
-int ddf_fun_add_to_class(ddf_fun_t *fun, const char *class_name)
+int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name)
 {
 	assert(fun->bound == true);
 	assert(fun->ftype == fun_exposed);
 	
-	return devman_add_device_to_class(fun->handle, class_name);
+	return devman_add_device_to_category(fun->handle, cat_name);
 }
 
Index: uspace/lib/drv/include/ddf/driver.h
===================================================================
--- uspace/lib/drv/include/ddf/driver.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/drv/include/ddf/driver.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -149,7 +149,8 @@
 extern void ddf_fun_destroy(ddf_fun_t *);
 extern int ddf_fun_bind(ddf_fun_t *);
+extern int ddf_fun_unbind(ddf_fun_t *);
 extern int ddf_fun_add_match_id(ddf_fun_t *, const char *, int);
 
-extern int ddf_fun_add_to_class(ddf_fun_t *, const char *);
+extern int ddf_fun_add_to_category(ddf_fun_t *, const char *);
 
 #endif
Index: uspace/lib/ext2/libext2_filesystem.c
===================================================================
--- uspace/lib/ext2/libext2_filesystem.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/ext2/libext2_filesystem.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -50,9 +50,9 @@
  * 
  * @param fs			Pointer to ext2_filesystem_t to initialize
- * @param devmap_handle	Device handle of the block device
- * 
- * @return 		EOK on success or negative error code on failure
- */
-int ext2_filesystem_init(ext2_filesystem_t *fs, devmap_handle_t devmap_handle)
+ * @param service_id	Service ID of the block device
+ * 
+ * @return 		EOK on success or negative error code on failure
+ */
+int ext2_filesystem_init(ext2_filesystem_t *fs, service_id_t service_id)
 {
 	int rc;
@@ -60,5 +60,5 @@
 	size_t block_size;
 	
-	fs->device = devmap_handle;
+	fs->device = service_id;
 	
 	rc = block_init(EXCHANGE_SERIALIZE, fs->device, 2048);
@@ -80,5 +80,5 @@
 	}
 	
-	rc = block_cache_init(devmap_handle, block_size, 0, CACHE_MODE_WT);
+	rc = block_cache_init(service_id, block_size, 0, CACHE_MODE_WT);
 	if (rc != EOK) {
 		block_fini(fs->device);
Index: uspace/lib/ext2/libext2_filesystem.h
===================================================================
--- uspace/lib/ext2/libext2_filesystem.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/ext2/libext2_filesystem.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -43,5 +43,5 @@
 
 typedef struct ext2_filesystem {
-	devmap_handle_t		device;
+	service_id_t		device;
 	ext2_superblock_t *	superblock;
 } ext2_filesystem_t;
@@ -59,5 +59,5 @@
 #define EXT2_SUPPORTED_READ_ONLY_FEATURES 0
 
-extern int ext2_filesystem_init(ext2_filesystem_t *, devmap_handle_t);
+extern int ext2_filesystem_init(ext2_filesystem_t *, service_id_t);
 extern int ext2_filesystem_check_sanity(ext2_filesystem_t *);
 extern int ext2_filesystem_check_flags(ext2_filesystem_t *, bool *);
Index: uspace/lib/ext2/libext2_superblock.c
===================================================================
--- uspace/lib/ext2/libext2_superblock.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/ext2/libext2_superblock.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -321,10 +321,10 @@
 /** Read a superblock directly from device (i.e. no libblock cache)
  * 
- * @param devmap_handle	Device handle of the block device.
+ * @param service_id	Service ID of the block device.
  * @param superblock	Pointer where to store pointer to new superblock
  * 
  * @return		EOK on success or negative error code on failure.
  */
-int ext2_superblock_read_direct(devmap_handle_t devmap_handle,
+int ext2_superblock_read_direct(service_id_t service_id,
     ext2_superblock_t **superblock)
 {
@@ -337,5 +337,5 @@
 	}
 	
-	rc = block_read_bytes_direct(devmap_handle, EXT2_SUPERBLOCK_OFFSET,
+	rc = block_read_bytes_direct(service_id, EXT2_SUPERBLOCK_OFFSET,
 	    EXT2_SUPERBLOCK_SIZE, data);
 	if (rc != EOK) {
Index: uspace/lib/ext2/libext2_superblock.h
===================================================================
--- uspace/lib/ext2/libext2_superblock.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/ext2/libext2_superblock.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -110,5 +110,5 @@
 extern uint32_t	ext2_superblock_get_features_read_only(ext2_superblock_t *);
 
-extern int ext2_superblock_read_direct(devmap_handle_t, ext2_superblock_t **);
+extern int ext2_superblock_read_direct(service_id_t, ext2_superblock_t **);
 extern int ext2_superblock_check_sanity(ext2_superblock_t *);
 
Index: uspace/lib/fs/libfs.c
===================================================================
--- uspace/lib/fs/libfs.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/fs/libfs.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -77,5 +77,5 @@
 static void vfs_out_mounted(ipc_callid_t rid, ipc_call_t *req)
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
 	char *opts;
 	int rc;
@@ -91,5 +91,5 @@
 	aoff64_t size;
 	unsigned lnkcnt;
-	rc = vfs_out_ops->mounted(devmap_handle, opts, &index, &size, &lnkcnt);
+	rc = vfs_out_ops->mounted(service_id, opts, &index, &size, &lnkcnt);
 
 	if (rc == EOK)
@@ -109,8 +109,8 @@
 static void vfs_out_unmounted(ipc_callid_t rid, ipc_call_t *req)
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
 	int rc; 
 
-	rc = vfs_out_ops->unmounted(devmap_handle);
+	rc = vfs_out_ops->unmounted(service_id);
 
 	async_answer_0(rid, rc);
@@ -130,5 +130,5 @@
 static void vfs_out_read(ipc_callid_t rid, ipc_call_t *req)
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
 	aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
@@ -137,5 +137,5 @@
 	int rc;
 
-	rc = vfs_out_ops->read(devmap_handle, index, pos, &rbytes);
+	rc = vfs_out_ops->read(service_id, index, pos, &rbytes);
 
 	if (rc == EOK)
@@ -147,5 +147,5 @@
 static void vfs_out_write(ipc_callid_t rid, ipc_call_t *req)
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
 	aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
@@ -155,5 +155,5 @@
 	int rc;
 
-	rc = vfs_out_ops->write(devmap_handle, index, pos, &wbytes, &nsize);
+	rc = vfs_out_ops->write(service_id, index, pos, &wbytes, &nsize);
 
 	if (rc == EOK)
@@ -165,5 +165,5 @@
 static void vfs_out_truncate(ipc_callid_t rid, ipc_call_t *req)
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
 	aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
@@ -171,5 +171,5 @@
 	int rc;
 
-	rc = vfs_out_ops->truncate(devmap_handle, index, size);
+	rc = vfs_out_ops->truncate(service_id, index, size);
 
 	async_answer_0(rid, rc);
@@ -178,9 +178,9 @@
 static void vfs_out_close(ipc_callid_t rid, ipc_call_t *req)
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
 	int rc;
 
-	rc = vfs_out_ops->close(devmap_handle, index);
+	rc = vfs_out_ops->close(service_id, index);
 
 	async_answer_0(rid, rc);
@@ -189,9 +189,9 @@
 static void vfs_out_destroy(ipc_callid_t rid, ipc_call_t *req)
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
 	int rc;
 
-	rc = vfs_out_ops->destroy(devmap_handle, index);
+	rc = vfs_out_ops->destroy(service_id, index);
 
 	async_answer_0(rid, rc);
@@ -210,9 +210,9 @@
 static void vfs_out_sync(ipc_callid_t rid, ipc_call_t *req)
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
 	int rc;
 
-	rc = vfs_out_ops->sync(devmap_handle, index);
+	rc = vfs_out_ops->sync(service_id, index);
 
 	async_answer_0(rid, rc);
@@ -380,8 +380,8 @@
     ipc_call_t *req)
 {
-	devmap_handle_t mp_devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req);
 	fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
 	fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*req);
-	devmap_handle_t mr_devmap_handle = (devmap_handle_t) IPC_GET_ARG4(*req);
+	service_id_t mr_service_id = (service_id_t) IPC_GET_ARG4(*req);
 	
 	async_sess_t *mountee_sess = async_clone_receive(EXCHANGE_PARALLEL);
@@ -392,5 +392,5 @@
 	
 	fs_node_t *fn;
-	int res = ops->node_get(&fn, mp_devmap_handle, mp_fs_index);
+	int res = ops->node_get(&fn, mp_service_id, mp_fs_index);
 	if ((res != EOK) || (!fn)) {
 		async_hangup(mountee_sess);
@@ -422,5 +422,5 @@
 	ipc_call_t answer;
 	int rc = async_data_write_forward_1_1(exch, VFS_OUT_MOUNTED,
-	    mr_devmap_handle, &answer);
+	    mr_service_id, &answer);
 	async_exchange_end(exch);
 	
@@ -428,5 +428,5 @@
 		fn->mp_data.mp_active = true;
 		fn->mp_data.fs_handle = mr_fs_handle;
-		fn->mp_data.devmap_handle = mr_devmap_handle;
+		fn->mp_data.service_id = mr_service_id;
 		fn->mp_data.sess = mountee_sess;
 	}
@@ -441,10 +441,10 @@
 void libfs_unmount(libfs_ops_t *ops, ipc_callid_t rid, ipc_call_t *req)
 {
-	devmap_handle_t mp_devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*req);
+	service_id_t mp_service_id = (service_id_t) IPC_GET_ARG1(*req);
 	fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*req);
 	fs_node_t *fn;
 	int res;
 
-	res = ops->node_get(&fn, mp_devmap_handle, mp_fs_index);
+	res = ops->node_get(&fn, mp_service_id, mp_fs_index);
 	if ((res != EOK) || (!fn)) {
 		async_answer_0(rid, combine_rc(res, ENOENT));
@@ -465,5 +465,5 @@
 	 */
 	async_exch_t *exch = async_exchange_begin(fn->mp_data.sess);
-	res = async_req_1_0(exch, VFS_OUT_UNMOUNTED, fn->mp_data.devmap_handle);
+	res = async_req_1_0(exch, VFS_OUT_UNMOUNTED, fn->mp_data.service_id);
 	async_exchange_end(exch);
 
@@ -475,5 +475,5 @@
 		fn->mp_data.mp_active = false;
 		fn->mp_data.fs_handle = 0;
-		fn->mp_data.devmap_handle = 0;
+		fn->mp_data.service_id = 0;
 		fn->mp_data.sess = NULL;
 		
@@ -510,5 +510,5 @@
 	unsigned int last = IPC_GET_ARG2(*req);
 	unsigned int next = first;
-	devmap_handle_t devmap_handle = IPC_GET_ARG3(*req);
+	service_id_t service_id = IPC_GET_ARG3(*req);
 	int lflag = IPC_GET_ARG4(*req);
 	fs_index_t index = IPC_GET_ARG5(*req);
@@ -524,5 +524,5 @@
 	fs_node_t *tmp = NULL;
 	
-	rc = ops->root_get(&cur, devmap_handle);
+	rc = ops->root_get(&cur, service_id);
 	on_error(rc, goto out_with_answer);
 	
@@ -530,5 +530,5 @@
 		async_exch_t *exch = async_exchange_begin(cur->mp_data.sess);
 		async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next, last,
-		    cur->mp_data.devmap_handle, lflag, index,
+		    cur->mp_data.service_id, lflag, index,
 		    IPC_FF_ROUTE_FROM_ME);
 		async_exchange_end(exch);
@@ -591,5 +591,5 @@
 			async_exch_t *exch = async_exchange_begin(tmp->mp_data.sess);
 			async_forward_slow(rid, exch, VFS_OUT_LOOKUP, next,
-			    last, tmp->mp_data.devmap_handle, lflag, index,
+			    last, tmp->mp_data.service_id, lflag, index,
 			    IPC_FF_ROUTE_FROM_ME);
 			async_exchange_end(exch);
@@ -620,8 +620,8 @@
 				fs_node_t *fn;
 				if (lflag & L_CREATE)
-					rc = ops->create(&fn, devmap_handle,
+					rc = ops->create(&fn, service_id,
 					    lflag);
 				else
-					rc = ops->node_get(&fn, devmap_handle,
+					rc = ops->node_get(&fn, service_id,
 					    index);
 				on_error(rc, goto out_with_answer);
@@ -638,5 +638,5 @@
 						aoff64_t size = ops->size_get(fn);
 						async_answer_5(rid, fs_handle,
-						    devmap_handle,
+						    service_id,
 						    ops->index_get(fn),
 						    LOWER32(size),
@@ -706,7 +706,7 @@
 			fs_node_t *fn;
 			if (lflag & L_CREATE)
-				rc = ops->create(&fn, devmap_handle, lflag);
+				rc = ops->create(&fn, service_id, lflag);
 			else
-				rc = ops->node_get(&fn, devmap_handle, index);
+				rc = ops->node_get(&fn, service_id, index);
 			on_error(rc, goto out_with_answer);
 			
@@ -722,5 +722,5 @@
 					aoff64_t size = ops->size_get(fn);
 					async_answer_5(rid, fs_handle,
-					    devmap_handle,
+					    service_id,
 					    ops->index_get(fn),
 					    LOWER32(size),
@@ -748,5 +748,5 @@
 		if (rc == EOK) {
 			aoff64_t size = ops->size_get(cur);
-			async_answer_5(rid, fs_handle, devmap_handle,
+			async_answer_5(rid, fs_handle, service_id,
 			    ops->index_get(cur), LOWER32(size), UPPER32(size),
 			    old_lnkcnt);
@@ -786,5 +786,5 @@
 		if (rc == EOK) {
 			aoff64_t size = ops->size_get(cur);
-			async_answer_5(rid, fs_handle, devmap_handle,
+			async_answer_5(rid, fs_handle, service_id,
 			    ops->index_get(cur), LOWER32(size), UPPER32(size),
 			    ops->lnkcnt_get(cur));
@@ -810,9 +810,9 @@
     ipc_call_t *request)
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
 	
 	fs_node_t *fn;
-	int rc = ops->node_get(&fn, devmap_handle, index);
+	int rc = ops->node_get(&fn, service_id, index);
 	on_error(rc, answer_and_return(rid, rc));
 	
@@ -831,5 +831,5 @@
 	
 	stat.fs_handle = fs_handle;
-	stat.devmap_handle = devmap_handle;
+	stat.service_id = service_id;
 	stat.index = index;
 	stat.lnkcnt = ops->lnkcnt_get(fn);
@@ -837,5 +837,5 @@
 	stat.is_directory = ops->is_directory(fn);
 	stat.size = ops->size_get(fn);
-	stat.device = ops->device_get(fn);
+	stat.service = ops->device_get(fn);
 	
 	ops->node_put(fn);
@@ -856,9 +856,9 @@
     ipc_call_t *request)
 {
-	devmap_handle_t devmap_handle = IPC_GET_ARG1(*request);
+	service_id_t service_id = IPC_GET_ARG1(*request);
 	fs_index_t index = IPC_GET_ARG2(*request);
 	
 	fs_node_t *fn;
-	int rc = ops->node_get(&fn, devmap_handle, index);
+	int rc = ops->node_get(&fn, service_id, index);
 	on_error(rc, answer_and_return(rid, rc));
 	
Index: uspace/lib/fs/libfs.h
===================================================================
--- uspace/lib/fs/libfs.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/fs/libfs.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -40,17 +40,17 @@
 #include <stdint.h>
 #include <async.h>
-#include <devmap.h>
+#include <loc.h>
 
 typedef struct {
-	int (* mounted)(devmap_handle_t, const char *, fs_index_t *, aoff64_t *,
+	int (* mounted)(service_id_t, const char *, fs_index_t *, aoff64_t *,
 	    unsigned *);
-	int (* unmounted)(devmap_handle_t);
-	int (* read)(devmap_handle_t, fs_index_t, aoff64_t, size_t *);
-	int (* write)(devmap_handle_t, fs_index_t, aoff64_t, size_t *,
+	int (* unmounted)(service_id_t);
+	int (* read)(service_id_t, fs_index_t, aoff64_t, size_t *);
+	int (* write)(service_id_t, fs_index_t, aoff64_t, size_t *,
 	    aoff64_t *);
-	int (* truncate)(devmap_handle_t, fs_index_t, aoff64_t);
-	int (* close)(devmap_handle_t, fs_index_t);
-	int (* destroy)(devmap_handle_t, fs_index_t);
-	int (* sync)(devmap_handle_t, fs_index_t);
+	int (* truncate)(service_id_t, fs_index_t, aoff64_t);
+	int (* close)(service_id_t, fs_index_t);
+	int (* destroy)(service_id_t, fs_index_t);
+	int (* sync)(service_id_t, fs_index_t);
 } vfs_out_ops_t;
 
@@ -59,5 +59,5 @@
 	async_sess_t *sess;
 	fs_handle_t fs_handle;
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 } mp_data_t;
 
@@ -73,10 +73,10 @@
 	 * argument holds the output argument.
 	 */
-	int (* root_get)(fs_node_t **, devmap_handle_t);
+	int (* root_get)(fs_node_t **, service_id_t);
 	int (* match)(fs_node_t **, fs_node_t *, const char *);
-	int (* node_get)(fs_node_t **, devmap_handle_t, fs_index_t);
+	int (* node_get)(fs_node_t **, service_id_t, fs_index_t);
 	int (* node_open)(fs_node_t *);
 	int (* node_put)(fs_node_t *);
-	int (* create)(fs_node_t **, devmap_handle_t, int);
+	int (* create)(fs_node_t **, service_id_t, int);
 	int (* destroy)(fs_node_t *);
 	int (* link)(fs_node_t *, fs_node_t *, const char *);
@@ -92,5 +92,5 @@
 	bool (* is_directory)(fs_node_t *);
 	bool (* is_file)(fs_node_t *);
-	devmap_handle_t (* device_get)(fs_node_t *);
+	service_id_t (* device_get)(fs_node_t *);
 } libfs_ops_t;
 
Index: uspace/lib/usb/include/usb/hc.h
===================================================================
--- uspace/lib/usb/include/usb/hc.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/usb/include/usb/hc.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -38,4 +38,5 @@
 #include <sys/types.h>
 #include <ipc/devman.h>
+#include <ipc/loc.h>
 #include <ddf/driver.h>
 #include <bool.h>
@@ -68,5 +69,5 @@
     devman_handle_t *);
 
-int usb_ddf_get_hc_handle_by_class(size_t, devman_handle_t *);
+int usb_ddf_get_hc_handle_by_sid(service_id_t, devman_handle_t *);
 
 
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/usb/include/usb/usb.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -174,6 +174,6 @@
 } usb_packet_id;
 
-/** Class name for USB host controllers. */
-#define USB_HC_DDF_CLASS_NAME "usbhc"
+/** Category for USB host controllers. */
+#define USB_HC_CATEGORY "usbhc"
 
 #endif
Index: uspace/lib/usb/src/hc.c
===================================================================
--- uspace/lib/usb/src/hc.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/usb/src/hc.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -201,32 +201,19 @@
 /** Get host controller handle by its class index.
  *
- * @param class_index Class index for the host controller.
+ * @param sid Service ID of the HC function.
  * @param hc_handle Where to store the HC handle
  *	(can be NULL for existence test only).
  * @return Error code.
  */
-int usb_ddf_get_hc_handle_by_class(size_t class_index,
-    devman_handle_t *hc_handle)
-{
-	char *class_index_str;
-	devman_handle_t hc_handle_tmp;
+int usb_ddf_get_hc_handle_by_sid(service_id_t sid, devman_handle_t *hc_handle)
+{
+	devman_handle_t handle;
 	int rc;
-
-	rc = asprintf(&class_index_str, "%zu", class_index);
-	if (rc < 0) {
-		return ENOMEM;
-	}
-	rc = devman_device_get_handle_by_class("usbhc", class_index_str,
-	    &hc_handle_tmp, 0);
-	free(class_index_str);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	if (hc_handle != NULL) {
-		*hc_handle = hc_handle_tmp;
-	}
-
-	return EOK;
+	
+	rc = devman_fun_sid_to_handle(sid, &handle);
+	if (hc_handle != NULL)
+		*hc_handle = handle;
+	
+	return rc;
 }
 
Index: uspace/lib/usb/src/resolve.c
===================================================================
--- uspace/lib/usb/src/resolve.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/lib/usb/src/resolve.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -46,10 +46,10 @@
     devman_handle_t *out_hc_handle, usb_address_t *out_device_address)
 {
-	size_t class_index;
+	uint64_t sid;
 	size_t address;
 	int rc;
 	char *ptr;
 
-	rc = str_size_t(path, &ptr, 10, false, &class_index);
+	rc = str_uint64(path, &ptr, 10, false, &sid);
 	if (rc != EOK) {
 		return false;
@@ -64,5 +64,5 @@
 		return false;
 	}
-	rc = usb_ddf_get_hc_handle_by_class(class_index, out_hc_handle);
+	rc = usb_ddf_get_hc_handle_by_sid(sid, out_hc_handle);
 	if (rc != EOK) {
 		return false;
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -57,5 +57,5 @@
 #include <stdint.h>
 #include <str.h>
-#include <devmap.h>
+#include <loc.h>
 #include <sys/types.h>
 #include <inttypes.h>
@@ -176,5 +176,5 @@
 		
 		snprintf(name, 16, "%s/ata%udisk%d", NAMESPACE, ctl_num, i);
-		rc = devmap_device_register(name, &disk[i].devmap_handle);
+		rc = loc_service_register(name, &disk[i].service_id);
 		if (rc != EOK) {
 			printf(NAME ": Unable to register device %s.\n", name);
@@ -244,5 +244,5 @@
 	int rc;
 
-	rc = devmap_driver_register(NAME, ata_bd_connection);
+	rc = loc_server_register(NAME, ata_bd_connection);
 	if (rc < 0) {
 		printf(NAME ": Unable to register driver.\n");
@@ -277,5 +277,5 @@
 	ipc_call_t call;
 	sysarg_t method;
-	devmap_handle_t dh;
+	service_id_t dsid;
 	size_t comm_size;	/**< Size of the communication area. */
 	unsigned int flags;
@@ -285,11 +285,11 @@
 	int disk_id, i;
 
-	/* Get the device handle. */
-	dh = IPC_GET_ARG1(*icall);
+	/* Get the device service ID. */
+	dsid = IPC_GET_ARG1(*icall);
 
 	/* Determine which disk device is the client connecting to. */
 	disk_id = -1;
 	for (i = 0; i < MAX_DISKS; i++)
-		if (disk[i].devmap_handle == dh)
+		if (disk[i].service_id == dsid)
 			disk_id = i;
 
Index: uspace/srv/bd/ata_bd/ata_bd.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/bd/ata_bd/ata_bd.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -116,5 +116,5 @@
 
 	fibril_mutex_t lock;
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 } disk_t;
 
Index: uspace/srv/bd/file_bd/file_bd.c
===================================================================
--- uspace/srv/bd/file_bd/file_bd.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -45,5 +45,5 @@
 #include <as.h>
 #include <fibril_synch.h>
-#include <devmap.h>
+#include <loc.h>
 #include <sys/types.h>
 #include <sys/typefmt.h>
@@ -61,5 +61,5 @@
 static FILE *img;
 
-static devmap_handle_t devmap_handle;
+static service_id_t service_id;
 static fibril_mutex_t dev_lock;
 
@@ -117,5 +117,5 @@
 		return -1;
 
-	rc = devmap_device_register(device_name, &devmap_handle);
+	rc = loc_service_register(device_name, &service_id);
 	if (rc != EOK) {
 		printf(NAME ": Unable to register device '%s'.\n",
@@ -142,5 +142,5 @@
 	long img_size;
 
-	rc = devmap_driver_register(NAME, file_bd_connection);
+	rc = loc_server_register(NAME, file_bd_connection);
 	if (rc < 0) {
 		printf(NAME ": Unable to register driver.\n");
Index: uspace/srv/bd/gxe_bd/gxe_bd.c
===================================================================
--- uspace/srv/bd/gxe_bd/gxe_bd.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -43,5 +43,5 @@
 #include <as.h>
 #include <fibril_synch.h>
-#include <devmap.h>
+#include <loc.h>
 #include <sys/types.h>
 #include <errno.h>
@@ -92,5 +92,5 @@
 static gxe_bd_t *dev;
 
-static devmap_handle_t devmap_handle[MAX_DISKS];
+static service_id_t service_id[MAX_DISKS];
 
 static fibril_mutex_t dev_lock[MAX_DISKS];
@@ -126,5 +126,5 @@
 	char name[16];
 
-	rc = devmap_driver_register(NAME, gxe_bd_connection);
+	rc = loc_server_register(NAME, gxe_bd_connection);
 	if (rc < 0) {
 		printf(NAME ": Unable to register driver.\n");
@@ -142,5 +142,5 @@
 	for (i = 0; i < MAX_DISKS; i++) {
 		snprintf(name, 16, "%s/disk%d", NAMESPACE, i);
-		rc = devmap_device_register(name, &devmap_handle[i]);
+		rc = loc_service_register(name, &service_id[i]);
 		if (rc != EOK) {
 			printf(NAME ": Unable to register device %s.\n", name);
@@ -159,5 +159,5 @@
 	ipc_call_t call;
 	sysarg_t method;
-	devmap_handle_t dh;
+	service_id_t dsid;
 	unsigned int flags;
 	int retval;
@@ -167,10 +167,10 @@
 
 	/* Get the device handle. */
-	dh = IPC_GET_ARG1(*icall);
+	dsid = IPC_GET_ARG1(*icall);
 
 	/* Determine which disk device is the client connecting to. */
 	disk_id = -1;
 	for (i = 0; i < MAX_DISKS; i++)
-		if (devmap_handle[i] == dh)
+		if (service_id[i] == dsid)
 			disk_id = i;
 
Index: uspace/srv/bd/part/guid_part/guid_part.c
===================================================================
--- uspace/srv/bd/part/guid_part/guid_part.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/bd/part/guid_part/guid_part.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -51,10 +51,10 @@
 #include <as.h>
 #include <fibril_synch.h>
-#include <devmap.h>
+#include <loc.h>
 #include <sys/types.h>
 #include <sys/typefmt.h>
 #include <inttypes.h>
 #include <libblock.h>
-#include <devmap.h>
+#include <loc.h>
 #include <errno.h>
 #include <bool.h>
@@ -81,6 +81,6 @@
 	/** Number of blocks */
 	aoff64_t length;
-	/** Device representing the partition (outbound device) */
-	devmap_handle_t dev;
+	/** Service representing the partition (outbound device) */
+	service_id_t dsid;
 	/** Points to next partition structure. */
 	struct part *next;
@@ -90,5 +90,5 @@
 
 /** Partitioned device (inbound device) */
-static devmap_handle_t indev_handle;
+static service_id_t indev_sid;
 
 /** List of partitions. This structure is an empty head. */
@@ -129,9 +129,9 @@
 	int i;
 	char *name;
-	devmap_handle_t dev;
+	service_id_t dsid;
 	uint64_t size_mb;
 	part_t *part;
 
-	rc = devmap_device_get_handle(dev_name, &indev_handle, 0);
+	rc = loc_service_get_id(dev_name, &indev_sid, 0);
 	if (rc != EOK) {
 		printf(NAME ": could not resolve device `%s'.\n", dev_name);
@@ -139,5 +139,5 @@
 	}
 
-	rc = block_init(EXCHANGE_SERIALIZE, indev_handle, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, indev_sid, 2048);
 	if (rc != EOK)  {
 		printf(NAME ": could not init libblock.\n");
@@ -147,5 +147,5 @@
 	/* Determine and verify block size. */
 
-	rc = block_get_bsize(indev_handle, &block_size);
+	rc = block_get_bsize(indev_sid, &block_size);
 	if (rc != EOK) {
 		printf(NAME ": error getting block size.\n");
@@ -163,8 +163,8 @@
 		return rc;
 
-	/* Register the driver with device mapper. */
-	rc = devmap_driver_register(NAME, gpt_connection);
+	/* Register server with location service. */
+	rc = loc_server_register(NAME, gpt_connection);
 	if (rc != EOK) {
-		printf(NAME ": Unable to register driver.\n");
+		printf(NAME ": Unable to register server.\n");
 		return rc;
 	}
@@ -188,7 +188,7 @@
 			return ENOMEM;
 
-		rc = devmap_device_register(name, &dev);
+		rc = loc_service_register(name, &dsid);
 		if (rc != EOK) {
-			printf(NAME ": Unable to register device %s.\n", name);
+			printf(NAME ": Unable to register service %s.\n", name);
 			return rc;
 		}
@@ -199,5 +199,5 @@
 		    "%" PRIuOFF64 " MB.\n", name, part->length, size_mb);
 
-		part->dev = dev;
+		part->dsid = dsid;
 		free(name);
 
@@ -228,5 +228,5 @@
 	}
 
-	rc = block_read_direct(indev_handle, GPT_HDR_BA, 1, gpt_hdr);
+	rc = block_read_direct(indev_sid, GPT_HDR_BA, 1, gpt_hdr);
 	if (rc != EOK) {
 		printf(NAME ": Failed reading GPT header block.\n");
@@ -256,5 +256,5 @@
 	}
 
-	rc = block_read_direct(indev_handle, ba, bcnt, etable);
+	rc = block_read_direct(indev_sid, ba, bcnt, etable);
 	if (rc != EOK) {
 		printf(NAME ": Failed reading GPT entries.\n");
@@ -303,5 +303,5 @@
 	}
 
-	part->dev = 0;
+	part->dsid = 0;
 	part->next = NULL;
 }
@@ -314,5 +314,5 @@
 	ipc_call_t call;
 	sysarg_t method;
-	devmap_handle_t dh;
+	service_id_t dh;
 	unsigned int flags;
 	int retval;
@@ -330,5 +330,5 @@
 	 */
 	part = plist_head.next;
-	while (part != NULL && part->dev != dh)
+	while (part != NULL && part->dsid != dh)
 		part = part->next;
 
@@ -410,5 +410,5 @@
 		return ELIMIT;
 
-	return block_read_direct(indev_handle, gba, cnt, buf);
+	return block_read_direct(indev_sid, gba, cnt, buf);
 }
 
@@ -421,5 +421,5 @@
 		return ELIMIT;
 
-	return block_write_direct(indev_handle, gba, cnt, buf);
+	return block_write_direct(indev_sid, gba, cnt, buf);
 }
 
Index: uspace/srv/bd/part/mbr_part/mbr_part.c
===================================================================
--- uspace/srv/bd/part/mbr_part/mbr_part.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/bd/part/mbr_part/mbr_part.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -61,10 +61,9 @@
 #include <as.h>
 #include <fibril_synch.h>
-#include <devmap.h>
+#include <loc.h>
 #include <sys/types.h>
 #include <sys/typefmt.h>
 #include <inttypes.h>
 #include <libblock.h>
-#include <devmap.h>
 #include <errno.h>
 #include <bool.h>
@@ -100,5 +99,5 @@
 	aoff64_t length;
 	/** Device representing the partition (outbound device) */
-	devmap_handle_t dev;
+	service_id_t dsid;
 	/** Points to next partition structure. */
 	struct part *next;
@@ -141,5 +140,5 @@
 
 /** Partitioned device (inbound device) */
-static devmap_handle_t indev_handle;
+static service_id_t indef_sid;
 
 /** List of partitions. This structure is an empty head. */
@@ -180,9 +179,9 @@
 	int i;
 	char *name;
-	devmap_handle_t dev;
+	service_id_t dsid;
 	uint64_t size_mb;
 	part_t *part;
 
-	rc = devmap_device_get_handle(dev_name, &indev_handle, 0);
+	rc = loc_service_get_id(dev_name, &indef_sid, 0);
 	if (rc != EOK) {
 		printf(NAME ": could not resolve device `%s'.\n", dev_name);
@@ -190,5 +189,5 @@
 	}
 
-	rc = block_init(EXCHANGE_SERIALIZE, indev_handle, 2048);
+	rc = block_init(EXCHANGE_SERIALIZE, indef_sid, 2048);
 	if (rc != EOK)  {
 		printf(NAME ": could not init libblock.\n");
@@ -198,5 +197,5 @@
 	/* Determine and verify block size. */
 
-	rc = block_get_bsize(indev_handle, &block_size);
+	rc = block_get_bsize(indef_sid, &block_size);
 	if (rc != EOK) {
 		printf(NAME ": error getting block size.\n");
@@ -214,8 +213,8 @@
 		return rc;
 
-	/* Register the driver with device mapper. */
-	rc = devmap_driver_register(NAME, mbr_connection);
+	/* Register server with location service. */
+	rc = loc_server_register(NAME, mbr_connection);
 	if (rc != EOK) {
-		printf(NAME ": Unable to register driver.\n");
+		printf(NAME ": Unable to register server.\n");
 		return rc;
 	}
@@ -239,7 +238,7 @@
 			return ENOMEM;
 
-		rc = devmap_device_register(name, &dev);
+		rc = loc_service_register(name, &dsid);
 		if (rc != EOK) {
-			printf(NAME ": Unable to register device %s.\n", name);
+			printf(NAME ": Unable to register service %s.\n", name);
 			return rc;
 		}
@@ -250,5 +249,5 @@
 		    "%" PRIu64 " MB.\n", name, part->length, size_mb);
 
-		part->dev = dev;
+		part->dsid = dsid;
 		free(name);
 
@@ -281,5 +280,5 @@
 	 */
 
-	rc = block_read_direct(indev_handle, 0, 1, brb);
+	rc = block_read_direct(indef_sid, 0, 1, brb);
 	if (rc != EOK) {
 		printf(NAME ": Failed reading MBR block.\n");
@@ -332,5 +331,5 @@
 		 */
 		ba = cp.start_addr;
-		rc = block_read_direct(indev_handle, ba, 1, brb);
+		rc = block_read_direct(indef_sid, ba, 1, brb);
 		if (rc != EOK) {
 			printf(NAME ": Failed reading EBR block at %"
@@ -381,5 +380,5 @@
 	part->present = (pte->ptype != PT_UNUSED) ? true : false;
 
-	part->dev = 0;
+	part->dsid = 0;
 	part->next = NULL;
 }
@@ -392,5 +391,5 @@
 	ipc_call_t call;
 	sysarg_t method;
-	devmap_handle_t dh;
+	service_id_t dh;
 	unsigned int flags;
 	int retval;
@@ -408,5 +407,5 @@
 	 */
 	part = plist_head.next;
-	while (part != NULL && part->dev != dh)
+	while (part != NULL && part->dsid != dh)
 		part = part->next;
 
@@ -488,5 +487,5 @@
 		return ELIMIT;
 
-	return block_read_direct(indev_handle, gba, cnt, buf);
+	return block_read_direct(indef_sid, gba, cnt, buf);
 }
 
@@ -499,5 +498,5 @@
 		return ELIMIT;
 
-	return block_write_direct(indev_handle, gba, cnt, buf);
+	return block_write_direct(indef_sid, gba, cnt, buf);
 }
 
Index: uspace/srv/bd/rd/rd.c
===================================================================
--- uspace/srv/bd/rd/rd.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/bd/rd/rd.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -52,5 +52,5 @@
 #include <fibril_synch.h>
 #include <stdio.h>
-#include <devmap.h>
+#include <loc.h>
 #include <ipc/bd.h>
 #include <macros.h>
@@ -235,5 +235,5 @@
 	    (void *) rd_ph_addr, rd_size);
 	
-	int rc = devmap_driver_register(NAME, rd_connection);
+	int rc = loc_server_register(NAME, rd_connection);
 	if (rc < 0) {
 		printf("%s: Unable to register driver (%d)\n", NAME, rc);
@@ -241,7 +241,7 @@
 	}
 	
-	devmap_handle_t devmap_handle;
-	if (devmap_device_register("bd/initrd", &devmap_handle) != EOK) {
-		printf("%s: Unable to register device\n", NAME);
+	service_id_t service_id;
+	if (loc_service_register("bd/initrd", &service_id) != EOK) {
+		printf("%s: Unable to register device service\n", NAME);
 		return false;
 	}
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/devman/devman.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -37,5 +37,5 @@
 #include <ipc/driver.h>
 #include <ipc/devman.h>
-#include <devmap.h>
+#include <loc.h>
 #include <str_error.h>
 #include <stdio.h>
@@ -66,19 +66,9 @@
 }
 
-static int devmap_functions_compare(unsigned long key[], hash_count_t keys,
+static int loc_functions_compare(unsigned long key[], hash_count_t keys,
     link_t *item)
 {
-	fun_node_t *fun = hash_table_get_instance(item, fun_node_t, devmap_fun);
-	return (fun->devmap_handle == (devmap_handle_t) key[0]);
-}
-
-static int devmap_devices_class_compare(unsigned long key[], hash_count_t keys,
-    link_t *item)
-{
-	dev_class_info_t *class_info
-	    = hash_table_get_instance(item, dev_class_info_t, devmap_link);
-	assert(class_info != NULL);
-
-	return (class_info->devmap_handle == (devmap_handle_t) key[0]);
+	fun_node_t *fun = hash_table_get_instance(item, fun_node_t, loc_fun);
+	return (fun->service_id == (service_id_t) key[0]);
 }
 
@@ -99,13 +89,7 @@
 };
 
-static hash_table_operations_t devmap_devices_ops = {
+static hash_table_operations_t loc_devices_ops = {
 	.hash = devices_hash,
-	.compare = devmap_functions_compare,
-	.remove_callback = devices_remove_callback
-};
-
-static hash_table_operations_t devmap_devices_class_ops = {
-	.hash = devices_hash,
-	.compare = devmap_devices_class_compare,
+	.compare = loc_functions_compare,
 	.remove_callback = devices_remove_callback
 };
@@ -701,30 +685,30 @@
 }
 
-/** Create devmap path and name for the function. */
-void devmap_register_tree_function(fun_node_t *fun, dev_tree_t *tree)
-{
-	char *devmap_pathname = NULL;
-	char *devmap_name = NULL;
-	
-	asprintf(&devmap_name, "%s", fun->pathname);
-	if (devmap_name == NULL)
+/** Create loc path and name for the function. */
+void loc_register_tree_function(fun_node_t *fun, dev_tree_t *tree)
+{
+	char *loc_pathname = NULL;
+	char *loc_name = NULL;
+	
+	asprintf(&loc_name, "%s", fun->pathname);
+	if (loc_name == NULL)
 		return;
 	
-	replace_char(devmap_name, '/', DEVMAP_SEPARATOR);
-	
-	asprintf(&devmap_pathname, "%s/%s", DEVMAP_DEVICE_NAMESPACE,
-	    devmap_name);
-	if (devmap_pathname == NULL) {
-		free(devmap_name);
+	replace_char(loc_name, '/', LOC_SEPARATOR);
+	
+	asprintf(&loc_pathname, "%s/%s", LOC_DEVICE_NAMESPACE,
+	    loc_name);
+	if (loc_pathname == NULL) {
+		free(loc_name);
 		return;
 	}
 	
-	devmap_device_register_with_iface(devmap_pathname,
-	    &fun->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
-	
-	tree_add_devmap_function(tree, fun);
-	
-	free(devmap_name);
-	free(devmap_pathname);
+	loc_service_register_with_iface(loc_pathname,
+	    &fun->service_id, DEVMAN_CONNECT_FROM_LOC);
+	
+	tree_add_loc_function(tree, fun);
+	
+	free(loc_name);
+	free(loc_pathname);
 }
 
@@ -856,6 +840,6 @@
 	hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1,
 	    &devman_functions_ops);
-	hash_table_create(&tree->devmap_functions, DEVICE_BUCKETS, 1,
-	    &devmap_devices_ops);
+	hash_table_create(&tree->loc_functions, DEVICE_BUCKETS, 1,
+	    &loc_devices_ops);
 	
 	fibril_rwlock_initialize(&tree->rwlock);
@@ -950,7 +934,6 @@
 		link_initialize(&res->dev_functions);
 		list_initialize(&res->match_ids.ids);
-		list_initialize(&res->classes);
 		link_initialize(&res->devman_fun);
-		link_initialize(&res->devmap_fun);
+		link_initialize(&res->loc_fun);
 	}
 	
@@ -1115,4 +1098,24 @@
 	
 	return true;
+}
+
+/** Remove function from device tree.
+ *
+ * @param tree		Device tree
+ * @param node		Function node to remove
+ */
+void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
+{
+	assert(tree != NULL);
+	assert(fun != NULL);
+	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
+	
+	/* Remove the node from the handle-to-node map. */
+	unsigned long key = fun->handle;
+	hash_table_remove(&tree->devman_functions, &key, 1);
+	
+	/* Remove the node from the list of its parent's children. */
+	if (fun->dev != NULL)
+		list_remove(&fun->dev_functions);
 }
 
@@ -1193,34 +1196,4 @@
 }
 
-/** Find function node by its class name and index. */
-fun_node_t *find_fun_node_by_class(class_list_t *class_list,
-    const char *class_name, const char *dev_name)
-{
-	assert(class_list != NULL);
-	assert(class_name != NULL);
-	assert(dev_name != NULL);
-
-	fibril_rwlock_read_lock(&class_list->rwlock);
-
-	dev_class_t *cl = find_dev_class_no_lock(class_list, class_name);
-	if (cl == NULL) {
-		fibril_rwlock_read_unlock(&class_list->rwlock);
-		return NULL;
-	}
-
-	dev_class_info_t *dev = find_dev_in_class(cl, dev_name);
-	if (dev == NULL) {
-		fibril_rwlock_read_unlock(&class_list->rwlock);
-		return NULL;
-	}
-
-	fun_node_t *fun = dev->fun;
-
-	fibril_rwlock_read_unlock(&class_list->rwlock);
-
-	return fun;
-}
-
-
 /** Find child function node with a specified name.
  *
@@ -1236,199 +1209,16 @@
 }
 
-/* Device classes */
-
-/** Create device class.
- *
- * @return	Device class.
- */
-dev_class_t *create_dev_class(void)
-{
-	dev_class_t *cl;
-	
-	cl = (dev_class_t *) malloc(sizeof(dev_class_t));
-	if (cl != NULL) {
-		memset(cl, 0, sizeof(dev_class_t));
-		list_initialize(&cl->devices);
-		fibril_mutex_initialize(&cl->mutex);
-	}
-	
-	return cl;
-}
-
-/** Create device class info.
- *
- * @return		Device class info.
- */
-dev_class_info_t *create_dev_class_info(void)
-{
-	dev_class_info_t *info;
-	
-	info = (dev_class_info_t *) malloc(sizeof(dev_class_info_t));
-	if (info != NULL) {
-		memset(info, 0, sizeof(dev_class_info_t));
-		link_initialize(&info->dev_classes);
-		link_initialize(&info->devmap_link);
-		link_initialize(&info->link);
-	}
-	
-	return info;
-}
-
-size_t get_new_class_dev_idx(dev_class_t *cl)
-{
-	size_t dev_idx;
-	
-	fibril_mutex_lock(&cl->mutex);
-	dev_idx = ++cl->curr_dev_idx;
-	fibril_mutex_unlock(&cl->mutex);
-	
-	return dev_idx;
-}
-
-
-/** Create unique device name within the class.
- *
- * @param cl		The class.
- * @param base_dev_name	Contains the base name for the device if it was
- *			specified by the driver when it registered the device by
- *			the class; NULL if driver specified no base name.
- * @return		The unique name for the device within the class.
- */
-char *create_dev_name_for_class(dev_class_t *cl, const char *base_dev_name)
-{
-	char *dev_name;
-	const char *base_name;
-	
-	if (base_dev_name != NULL)
-		base_name = base_dev_name;
-	else
-		base_name = cl->base_dev_name;
-	
-	size_t idx = get_new_class_dev_idx(cl);
-	asprintf(&dev_name, "%s%zu", base_name, idx);
-	
-	return dev_name;
-}
-
-/** Add the device function to the class.
- *
- * The device may be added to multiple classes and a class may contain multiple
- * devices. The class and the device are associated with each other by the
- * dev_class_info_t structure.
- *
- * @param dev		The device.
- * @param class		The class.
- * @param base_dev_name	The base name of the device within the class if
- *			specified by the driver, NULL otherwise.
- * @return		dev_class_info_t structure which associates the device
- *			with the class.
- */
-dev_class_info_t *add_function_to_class(fun_node_t *fun, dev_class_t *cl,
-    const char *base_dev_name)
-{
-	dev_class_info_t *info;
-
-	assert(fun != NULL);
-	assert(cl != NULL);
-
-	info = create_dev_class_info();
-
-	
-	if (info != NULL) {
-		info->dev_class = cl;
-		info->fun = fun;
-		
-		/* Add the device to the class. */
-		fibril_mutex_lock(&cl->mutex);
-		list_append(&info->link, &cl->devices);
-		fibril_mutex_unlock(&cl->mutex);
-		
-		/* Add the class to the device. */
-		list_append(&info->dev_classes, &fun->classes);
-		
-		/* Create unique name for the device within the class. */
-		info->dev_name = create_dev_name_for_class(cl, base_dev_name);
-	}
-	
-	return info;
-}
-
-dev_class_t *get_dev_class(class_list_t *class_list, char *class_name)
-{
-	dev_class_t *cl;
-	
-	fibril_rwlock_write_lock(&class_list->rwlock);
-	cl = find_dev_class_no_lock(class_list, class_name);
-	if (cl == NULL) {
-		cl = create_dev_class();
-		if (cl != NULL) {
-			cl->name = class_name;
-			cl->base_dev_name = "";
-			add_dev_class_no_lock(class_list, cl);
-		}
-	}
-
-	fibril_rwlock_write_unlock(&class_list->rwlock);
-	return cl;
-}
-
-dev_class_t *find_dev_class_no_lock(class_list_t *class_list,
-    const char *class_name)
-{
-	dev_class_t *cl;
-	
-	list_foreach(class_list->classes, link) {
-		cl = list_get_instance(link, dev_class_t, link);
-		if (str_cmp(cl->name, class_name) == 0) {
-			return cl;
-		}
-	}
-	
-	return NULL;
-}
-
-void add_dev_class_no_lock(class_list_t *class_list, dev_class_t *cl)
-{
-	list_append(&cl->link, &class_list->classes);
-}
-
-dev_class_info_t *find_dev_in_class(dev_class_t *dev_class, const char *dev_name)
-{
-	assert(dev_class != NULL);
-	assert(dev_name != NULL);
-
-	list_foreach(dev_class->devices, link) {
-		dev_class_info_t *dev = list_get_instance(link,
-		    dev_class_info_t, link);
-
-		if (str_cmp(dev->dev_name, dev_name) == 0) {
-			return dev;
-		}
-	}
-
-	return NULL;
-}
-
-void init_class_list(class_list_t *class_list)
-{
-	list_initialize(&class_list->classes);
-	fibril_rwlock_initialize(&class_list->rwlock);
-	hash_table_create(&class_list->devmap_functions, DEVICE_BUCKETS, 1,
-	    &devmap_devices_class_ops);
-}
-
-
-/* Devmap devices */
-
-fun_node_t *find_devmap_tree_function(dev_tree_t *tree, devmap_handle_t devmap_handle)
+/* loc devices */
+
+fun_node_t *find_loc_tree_function(dev_tree_t *tree, service_id_t service_id)
 {
 	fun_node_t *fun = NULL;
 	link_t *link;
-	unsigned long key = (unsigned long) devmap_handle;
+	unsigned long key = (unsigned long) service_id;
 	
 	fibril_rwlock_read_lock(&tree->rwlock);
-	link = hash_table_find(&tree->devmap_functions, &key);
+	link = hash_table_find(&tree->loc_functions, &key);
 	if (link != NULL)
-		fun = hash_table_get_instance(link, fun_node_t, devmap_fun);
+		fun = hash_table_get_instance(link, fun_node_t, loc_fun);
 	fibril_rwlock_read_unlock(&tree->rwlock);
 	
@@ -1436,40 +1226,9 @@
 }
 
-fun_node_t *find_devmap_class_function(class_list_t *classes,
-    devmap_handle_t devmap_handle)
-{
-	fun_node_t *fun = NULL;
-	dev_class_info_t *cli;
-	link_t *link;
-	unsigned long key = (unsigned long)devmap_handle;
-	
-	fibril_rwlock_read_lock(&classes->rwlock);
-	link = hash_table_find(&classes->devmap_functions, &key);
-	if (link != NULL) {
-		cli = hash_table_get_instance(link, dev_class_info_t,
-		    devmap_link);
-		fun = cli->fun;
-	}
-	fibril_rwlock_read_unlock(&classes->rwlock);
-	
-	return fun;
-}
-
-void class_add_devmap_function(class_list_t *class_list, dev_class_info_t *cli)
-{
-	unsigned long key = (unsigned long) cli->devmap_handle;
-	
-	fibril_rwlock_write_lock(&class_list->rwlock);
-	hash_table_insert(&class_list->devmap_functions, &key, &cli->devmap_link);
-	fibril_rwlock_write_unlock(&class_list->rwlock);
-
-	assert(find_devmap_class_function(class_list, cli->devmap_handle) != NULL);
-}
-
-void tree_add_devmap_function(dev_tree_t *tree, fun_node_t *fun)
-{
-	unsigned long key = (unsigned long) fun->devmap_handle;
+void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
+{
+	unsigned long key = (unsigned long) fun->service_id;
 	fibril_rwlock_write_lock(&tree->rwlock);
-	hash_table_insert(&tree->devmap_functions, &key, &fun->devmap_fun);
+	hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
 	fibril_rwlock_write_unlock(&tree->rwlock);
 }
Index: uspace/srv/devman/devman.h
===================================================================
--- uspace/srv/devman/devman.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/devman/devman.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2010 Lenka Trochtova
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -41,5 +42,5 @@
 #include <adt/hash_table.h>
 #include <ipc/devman.h>
-#include <ipc/devmap.h>
+#include <ipc/loc.h>
 #include <fibril_synch.h>
 #include <atomic.h>
@@ -53,7 +54,6 @@
 #define DEVICE_BUCKETS 256
 
-#define DEVMAP_CLASS_NAMESPACE "class"
-#define DEVMAP_DEVICE_NAMESPACE "devices"
-#define DEVMAP_SEPARATOR '\\'
+#define LOC_DEVICE_NAMESPACE "devices"
+#define LOC_SEPARATOR '\\'
 
 struct dev_node;
@@ -155,4 +155,6 @@
 	/** Name of the function, assigned by the device driver */
 	char *name;
+	/** Function type */
+	fun_type_t ftype;
 	
 	/** Full path and name of the device in device hierarchy */
@@ -170,8 +172,6 @@
 	match_id_list_t match_ids;
 	
-	/** List of device classes to which this device function belongs. */
-	list_t classes;
-	/** Devmap handle if the device function is registered by devmap. */
-	devmap_handle_t devmap_handle;
+	/** Service ID if the device function is registered with loc. */
+	service_id_t service_id;
 	
 	/**
@@ -181,7 +181,7 @@
 	
 	/**
-	 * Used by the hash table of functions indexed by devmap device handles.
-	 */
-	link_t devmap_fun;
+	 * Used by the hash table of functions indexed by service IDs.
+	 */
+	link_t loc_fun;
 };
 
@@ -208,87 +208,9 @@
 	
 	/**
-	 * Hash table of devices registered by devmapper, indexed by devmap
-	 * handles.
-	 */
-	hash_table_t devmap_functions;
+	 * Hash table of services registered with location service, indexed by
+	 * service IDs.
+	 */
+	hash_table_t loc_functions;
 } dev_tree_t;
-
-typedef struct dev_class {
-	/** The name of the class. */
-	const char *name;
-	
-	/**
-	 * Pointer to the previous and next class in the list of registered
-	 * classes.
-	 */
-	link_t link;
-	
-	/**
-	 * List of dev_class_info structures - one for each device registered by
-	 * this class.
-	 */
-	list_t devices;
-	
-	/**
-	 * Default base name for the device within the class, might be overrided
-	 * by the driver.
-	 */
-	const char *base_dev_name;
-	
-	/** Unique numerical identifier of the newly added device. */
-	size_t curr_dev_idx;
-	/** Synchronize access to the list of devices in this class. */
-	fibril_mutex_t mutex;
-} dev_class_t;
-
-/**
- * Provides n-to-m mapping between function nodes and classes - each function
- * can register in an arbitrary number of classes and each class can contain
- * an arbitrary number of device functions.
- */
-typedef struct dev_class_info {
-	/** The class. */
-	dev_class_t *dev_class;
-	/** The device. */
-	fun_node_t *fun;
-	
-	/**
-	 * Pointer to the previous and next class info in the list of devices
-	 * registered by the class.
-	 */
-	link_t link;
-	
-	/**
-	 * Pointer to the previous and next class info in the list of classes
-	 * by which the device is registered.
-	 */
-	link_t dev_classes;
-	
-	/** The name of the device function within the class. */
-	char *dev_name;
-	/** The handle of the device by device mapper in the class namespace. */
-	devmap_handle_t devmap_handle;
-	
-	/**
-	 * Link in the hash table of devices registered by the devmapper using
-	 * their class names.
-	 */
-	link_t devmap_link;
-} dev_class_info_t;
-
-/** The list of device classes. */
-typedef struct class_list {
-	/** List of classes. */
-	list_t classes;
-	
-	/**
-	 * Hash table of devices registered by devmapper using their class name,
-	 * indexed by devmap handles.
-	 */
-	hash_table_t devmap_functions;
-	
-	/** Fibril mutex for list of classes. */
-	fibril_rwlock_t rwlock;
-} class_list_t;
 
 /* Match ids and scores */
@@ -339,5 +261,4 @@
 extern fun_node_t *find_fun_node_by_path(dev_tree_t *, char *);
 extern fun_node_t *find_fun_node_in_device(dev_node_t *, const char *);
-extern fun_node_t *find_fun_node_by_class(class_list_t *, const char *, const char *);
 
 /* Device tree */
@@ -347,30 +268,13 @@
 extern bool insert_dev_node(dev_tree_t *, dev_node_t *, fun_node_t *);
 extern bool insert_fun_node(dev_tree_t *, fun_node_t *, char *, dev_node_t *);
-
-/* Device classes */
-
-extern dev_class_t *create_dev_class(void);
-extern dev_class_info_t *create_dev_class_info(void);
-extern size_t get_new_class_dev_idx(dev_class_t *);
-extern char *create_dev_name_for_class(dev_class_t *, const char *);
-extern dev_class_info_t *add_function_to_class(fun_node_t *, dev_class_t *,
-    const char *);
-
-extern void init_class_list(class_list_t *);
-
-extern dev_class_t *get_dev_class(class_list_t *, char *);
-extern dev_class_t *find_dev_class_no_lock(class_list_t *, const char *);
-extern dev_class_info_t *find_dev_in_class(dev_class_t *, const char *);
-extern void add_dev_class_no_lock(class_list_t *, dev_class_t *);
-
-/* Devmap devices */
-
-extern void devmap_register_tree_function(fun_node_t *, dev_tree_t *);
-
-extern fun_node_t *find_devmap_tree_function(dev_tree_t *, devmap_handle_t);
-extern fun_node_t *find_devmap_class_function(class_list_t *, devmap_handle_t);
-
-extern void class_add_devmap_function(class_list_t *, dev_class_info_t *);
-extern void tree_add_devmap_function(dev_tree_t *, fun_node_t *);
+extern void remove_fun_node(dev_tree_t *, fun_node_t *);
+
+/* Loc services */
+
+extern void loc_register_tree_function(fun_node_t *, dev_tree_t *);
+
+extern fun_node_t *find_loc_tree_function(dev_tree_t *, service_id_t);
+
+extern void tree_add_loc_function(dev_tree_t *, fun_node_t *);
 
 #endif
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/devman/main.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -56,5 +56,5 @@
 #include <ipc/driver.h>
 #include <thread.h>
-#include <devmap.h>
+#include <loc.h>
 
 #include "devman.h"
@@ -64,5 +64,4 @@
 static driver_list_t drivers_list;
 static dev_tree_t device_tree;
-static class_list_t class_list;
 
 /** Register running driver. */
@@ -279,6 +278,8 @@
 		return;
 	}
-
+	
 	fun_node_t *fun = create_fun_node();
+	fun->ftype = ftype;
+	
 	if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
 		fibril_rwlock_write_unlock(&tree->rwlock);
@@ -326,5 +327,5 @@
 		}
 	} else {
-		devmap_register_tree_function(fun, tree);
+		loc_register_tree_function(fun, tree);
 	}
 	
@@ -333,37 +334,13 @@
 }
 
-static void devmap_register_class_dev(dev_class_info_t *cli)
-{
-	/* Create devmap path and name for the device. */
-	char *devmap_pathname = NULL;
-
-	asprintf(&devmap_pathname, "%s/%s%c%s", DEVMAP_CLASS_NAMESPACE,
-	    cli->dev_class->name, DEVMAP_SEPARATOR, cli->dev_name);
-	if (devmap_pathname == NULL)
-		return;
-	
-	/*
-	 * Register the device by the device mapper and remember its devmap
-	 * handle.
-	 */
-	devmap_device_register_with_iface(devmap_pathname,
-	    &cli->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
-	
-	/*
-	 * Add device to the hash map of class devices registered by device
-	 * mapper.
-	 */
-	class_add_devmap_function(&class_list, cli);
-	
-	free(devmap_pathname);
-}
-
-static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call)
+static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
 {
 	devman_handle_t handle = IPC_GET_ARG1(*call);
-	
-	/* Get class name. */
-	char *class_name;
-	int rc = async_data_write_accept((void **) &class_name, true,
+	category_id_t cat_id;
+	int rc;
+	
+	/* Get category name. */
+	char *cat_name;
+	rc = async_data_write_accept((void **) &cat_name, true,
 	    0, 0, 0, 0);
 	if (rc != EOK) {
@@ -378,13 +355,57 @@
 	}
 	
-	dev_class_t *cl = get_dev_class(&class_list, class_name);
-	dev_class_info_t *class_info = add_function_to_class(fun, cl, NULL);
-	
-	/* Register the device's class alias by devmapper. */
-	devmap_register_class_dev(class_info);
-	
-	log_msg(LVL_NOTE, "Function `%s' added to class `%s' as `%s'.",
-	    fun->pathname, class_name, class_info->dev_name);
-
+	rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
+	if (rc == EOK) {
+		loc_service_add_to_cat(fun->service_id, cat_id);
+	} else {
+		log_msg(LVL_ERROR, "Failed adding function `%s' to category "
+		    "`%s'.", fun->pathname, cat_name);
+	}
+	
+	log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",
+	    fun->pathname, cat_name);
+
+	async_answer_0(callid, EOK);
+}
+
+/** Remove function. */
+static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
+{
+	devman_handle_t fun_handle = IPC_GET_ARG1(*call);
+	dev_tree_t *tree = &device_tree;
+	int rc;
+	
+	fibril_rwlock_write_lock(&tree->rwlock);
+	
+	fun_node_t *fun = find_fun_node_no_lock(&device_tree, fun_handle);
+	if (fun == NULL) {
+		fibril_rwlock_write_unlock(&tree->rwlock);
+		async_answer_0(callid, ENOENT);
+		return;
+	}
+	
+	log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
+	
+	if (fun->ftype == fun_inner) {
+		/* Handle possible descendants */
+		/* TODO */
+		log_msg(LVL_WARN, "devman_remove_function(): not handling "
+		    "descendants\n");
+	} else {
+		/* Unregister from location service */
+		rc = loc_service_unregister(fun->service_id);
+		if (rc != EOK) {
+			log_msg(LVL_ERROR, "Failed unregistering tree service.");
+			fibril_rwlock_write_unlock(&tree->rwlock);
+			async_answer_0(callid, EIO);
+			return;
+		}
+	}
+	
+	remove_fun_node(&device_tree, fun);
+	fibril_rwlock_write_unlock(&tree->rwlock);
+	delete_fun_node(fun);
+	
+	log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
 	async_answer_0(callid, EOK);
 }
@@ -439,6 +460,9 @@
 			devman_add_function(callid, &call);
 			break;
-		case DEVMAN_ADD_DEVICE_TO_CLASS:
-			devman_add_function_to_class(callid, &call);
+		case DEVMAN_ADD_DEVICE_TO_CATEGORY:
+			devman_add_function_to_cat(callid, &call);
+			break;
+		case DEVMAN_REMOVE_FUNCTION:
+			devman_remove_function(callid, &call);
 			break;
 		default:
@@ -464,38 +488,4 @@
 	
 	free(pathname);
-
-	if (fun == NULL) {
-		async_answer_0(iid, ENOENT);
-		return;
-	}
-
-	async_answer_1(iid, EOK, fun->handle);
-}
-
-/** Find handle for the device instance identified by device class name. */
-static void devman_function_get_handle_by_class(ipc_callid_t iid,
-    ipc_call_t *icall)
-{
-	char *classname;
-	char *devname;
-
-	int rc = async_data_write_accept((void **) &classname, true, 0, 0, 0, 0);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-	rc = async_data_write_accept((void **) &devname, true, 0, 0, 0, 0);
-	if (rc != EOK) {
-		free(classname);
-		async_answer_0(iid, rc);
-		return;
-	}
-
-
-	fun_node_t *fun = find_fun_node_by_class(&class_list,
-	    classname, devname);
-
-	free(classname);
-	free(devname);
 
 	if (fun == NULL) {
@@ -544,4 +534,18 @@
 }
 
+/** Find handle for the function instance identified by its service ID. */
+static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)
+{
+	fun_node_t *fun;
+
+	fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall));
+	
+	if (fun == NULL) {
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+
+	async_answer_1(iid, EOK, fun->handle);
+}
 
 /** Function for handling connections from a client to the device manager. */
@@ -562,9 +566,9 @@
 			devman_function_get_handle(callid, &call);
 			break;
-		case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS:
-			devman_function_get_handle_by_class(callid, &call);
-			break;
 		case DEVMAN_DEVICE_GET_DEVICE_PATH:
 			devman_get_device_path_by_handle(callid, &call);
+			break;
+		case DEVMAN_FUN_SID_TO_HANDLE:
+			devman_fun_sid_to_handle(callid, &call);
 			break;
 		default:
@@ -659,17 +663,17 @@
 }
 
-/** Function for handling connections from a client forwarded by the device
- * mapper to the device manager. */
-static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall)
-{
-	devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall);
+/** Function for handling connections from a client forwarded by the location
+ * service to the device manager. */
+static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall)
+{
+	service_id_t service_id = IPC_GET_ARG2(*icall);
 	fun_node_t *fun;
 	dev_node_t *dev;
 
-	fun = find_devmap_tree_function(&device_tree, devmap_handle);
-	if (fun == NULL)
-		fun = find_devmap_class_function(&class_list, devmap_handle);
+	fun = find_loc_tree_function(&device_tree, service_id);
 	
 	if (fun == NULL || fun->dev->drv == NULL) {
+		log_msg(LVL_WARN, "devman_connection_loc(): function "
+		    "not found.\n");
 		async_answer_0(iid, ENOENT);
 		return;
@@ -677,9 +681,4 @@
 	
 	dev = fun->dev;
-	
-	if ((dev->state != DEVICE_USABLE) || (!dev->drv->sess)) {
-		async_answer_0(iid, EINVAL);
-		return;
-	}
 	
 	async_exch_t *exch = async_exchange_begin(dev->drv->sess);
@@ -689,5 +688,5 @@
 	
 	log_msg(LVL_DEBUG,
-	    "Forwarding devmapper request for `%s' function to driver `%s'.",
+	    "Forwarding loc service request for `%s' function to driver `%s'.",
 	    fun->pathname, dev->drv->name);
 }
@@ -708,7 +707,7 @@
 		devman_forward(iid, icall, false);
 		break;
-	case DEVMAN_CONNECT_FROM_DEVMAP:
-		/* Someone connected through devmap node. */
-		devman_connection_devmapper(iid, icall);
+	case DEVMAN_CONNECT_FROM_LOC:
+		/* Someone connected through loc node. */
+		devman_connection_loc(iid, icall);
 		break;
 	case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
@@ -743,13 +742,11 @@
 	}
 
-	init_class_list(&class_list);
-	
 	/*
-	 * !!! devman_connection ... as the device manager is not a real devmap
+	 * !!! devman_connection ... as the device manager is not a real loc
 	 * driver (it uses a completely different ipc protocol than an ordinary
-	 * devmap driver) forwarding a connection from client to the devman by
-	 * devmapper would not work.
+	 * loc driver) forwarding a connection from client to the devman by
+	 * location service would not work.
 	 */
-	devmap_driver_register(NAME, devman_connection);
+	loc_server_register(NAME, devman_connection);
 	
 	return true;
@@ -760,5 +757,5 @@
 	printf(NAME ": HelenOS Device Manager\n");
 
-	if (log_init(NAME, LVL_ERROR) != EOK) {
+	if (log_init(NAME, LVL_WARN) != EOK) {
 		printf(NAME ": Error initializing logging subsystem.\n");
 		return -1;
Index: pace/srv/devmap/Makefile
===================================================================
--- uspace/srv/devmap/Makefile	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(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 = ../..
-BINARY = devmap
-STATIC_NEEDED = y
-
-SOURCES = \
-	devmap.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: pace/srv/devmap/devmap.c
===================================================================
--- uspace/srv/devmap/devmap.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,1163 +1,0 @@
-/*
- * Copyright (c) 2007 Josef Cejka
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @defgroup devmap Device mapper.
- * @brief HelenOS device mapper.
- * @{
- */
-
-/** @file
- */
-
-#include <ipc/services.h>
-#include <ns.h>
-#include <async.h>
-#include <stdio.h>
-#include <errno.h>
-#include <bool.h>
-#include <fibril_synch.h>
-#include <stdlib.h>
-#include <str.h>
-#include <ipc/devmap.h>
-#include <assert.h>
-
-#define NAME          "devmap"
-#define NULL_DEVICES  256
-
-/** Representation of device driver.
- *
- * Each driver is responsible for a set of devices.
- *
- */
-typedef struct {
-	/** Link to drivers_list */
-	link_t drivers;
-	
-	/** List of devices controlled by this driver */
-	list_t devices;
-	
-	/** Session asociated with this driver */
-	async_sess_t *sess;
-	
-	/** Device driver name */
-	char *name;
-	
-	/** Fibril mutex for list of devices owned by this driver */
-	fibril_mutex_t devices_mutex;
-} devmap_driver_t;
-
-/** Info about registered namespaces
- *
- */
-typedef struct {
-	/** Link to namespaces_list */
-	link_t namespaces;
-	
-	/** Unique namespace identifier */
-	devmap_handle_t handle;
-	
-	/** Namespace name */
-	char *name;
-	
-	/** Reference count */
-	size_t refcnt;
-} devmap_namespace_t;
-
-/** Info about registered device
- *
- */
-typedef struct {
-	/** Link to global list of devices (devices_list) */
-	link_t devices;
-	/** Link to driver list of devices (devmap_driver_t.devices) */
-	link_t driver_devices;
-	/** Unique device identifier */
-	devmap_handle_t handle;
-	/** Device namespace */
-	devmap_namespace_t *namespace;
-	/** Device name */
-	char *name;
-	/** Device driver handling this device */
-	devmap_driver_t *driver;
-	/** Use this interface when forwarding to driver. */
-	sysarg_t forward_interface;
-} devmap_device_t;
-
-LIST_INITIALIZE(devices_list);
-LIST_INITIALIZE(namespaces_list);
-LIST_INITIALIZE(drivers_list);
-
-/* Locking order:
- *  drivers_list_mutex
- *  devices_list_mutex
- *  (devmap_driver_t *)->devices_mutex
- *  create_handle_mutex
- **/
-
-static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex);
-static FIBRIL_CONDVAR_INITIALIZE(devices_list_cv);
-static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex);
-static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex);
-static FIBRIL_MUTEX_INITIALIZE(null_devices_mutex);
-
-static devmap_handle_t last_handle = 0;
-static devmap_device_t *null_devices[NULL_DEVICES];
-
-/*
- * Dummy list for null devices. This is necessary so that null devices can
- * be used just as any other devices, e.g. in devmap_device_unregister_core().
- */
-static LIST_INITIALIZE(dummy_null_driver_devices);
-
-static devmap_handle_t devmap_create_handle(void)
-{
-	/* TODO: allow reusing old handles after their unregistration
-	 * and implement some version of LRU algorithm, avoid overflow
-	 */
-	
-	fibril_mutex_lock(&create_handle_mutex);
-	last_handle++;
-	fibril_mutex_unlock(&create_handle_mutex);
-	
-	return last_handle;
-}
-
-/** Convert fully qualified device name to namespace and device name.
- *
- * A fully qualified device name can be either a plain device name
- * (then the namespace is considered to be an empty string) or consist
- * of two components separated by a slash. No more than one slash
- * is allowed.
- *
- */
-static bool devmap_fqdn_split(const char *fqdn, char **ns_name, char **name)
-{
-	size_t cnt = 0;
-	size_t slash_offset = 0;
-	size_t slash_after = 0;
-	
-	size_t offset = 0;
-	size_t offset_prev = 0;
-	wchar_t c;
-	
-	while ((c = str_decode(fqdn, &offset, STR_NO_LIMIT)) != 0) {
-		if (c == '/') {
-			cnt++;
-			slash_offset = offset_prev;
-			slash_after = offset;
-		}
-		offset_prev = offset;
-	}
-	
-	/* More than one slash */
-	if (cnt > 1)
-		return false;
-	
-	/* No slash -> namespace is empty */
-	if (cnt == 0) {
-		*ns_name = str_dup("");
-		if (*ns_name == NULL)
-			return false;
-		
-		*name = str_dup(fqdn);
-		if (*name == NULL) {
-			free(*ns_name);
-			return false;
-		}
-		
-		if (str_cmp(*name, "") == 0) {
-			free(*name);
-			free(*ns_name);
-			return false;
-		}
-		
-		return true;
-	}
-	
-	/* Exactly one slash */
-	*ns_name = str_ndup(fqdn, slash_offset);
-	if (*ns_name == NULL)
-		return false;
-	
-	*name = str_dup(fqdn + slash_after);
-	if (*name == NULL) {
-		free(*ns_name);
-		return false;
-	}
-	
-	if (str_cmp(*name, "") == 0) {
-		free(*name);
-		free(*ns_name);
-		return false;
-	}
-	
-	return true;
-}
-
-/** Find namespace with given name. */
-static devmap_namespace_t *devmap_namespace_find_name(const char *name)
-{
-	assert(fibril_mutex_is_locked(&devices_list_mutex));
-	
-	list_foreach(namespaces_list, item) {
-		devmap_namespace_t *namespace =
-		    list_get_instance(item, devmap_namespace_t, namespaces);
-		if (str_cmp(namespace->name, name) == 0)
-			return namespace;
-	}
-	
-	return NULL;
-}
-
-/** Find namespace with given handle.
- *
- * @todo: use hash table
- *
- */
-static devmap_namespace_t *devmap_namespace_find_handle(devmap_handle_t handle)
-{
-	assert(fibril_mutex_is_locked(&devices_list_mutex));
-	
-	list_foreach(namespaces_list, item) {
-		devmap_namespace_t *namespace =
-		    list_get_instance(item, devmap_namespace_t, namespaces);
-		if (namespace->handle == handle)
-			return namespace;
-	}
-	
-	return NULL;
-}
-
-/** Find device with given name. */
-static devmap_device_t *devmap_device_find_name(const char *ns_name,
-    const char *name)
-{
-	assert(fibril_mutex_is_locked(&devices_list_mutex));
-	
-	list_foreach(devices_list, item) {
-		devmap_device_t *device =
-		    list_get_instance(item, devmap_device_t, devices);
-		if ((str_cmp(device->namespace->name, ns_name) == 0)
-		    && (str_cmp(device->name, name) == 0))
-			return device;
-	}
-	
-	return NULL;
-}
-
-/** Find device with given handle.
- *
- * @todo: use hash table
- *
- */
-static devmap_device_t *devmap_device_find_handle(devmap_handle_t handle)
-{
-	assert(fibril_mutex_is_locked(&devices_list_mutex));
-	
-	list_foreach(devices_list, item) {
-		devmap_device_t *device =
-		    list_get_instance(item, devmap_device_t, devices);
-		if (device->handle == handle)
-			return device;
-	}
-	
-	return NULL;
-}
-
-/** Create a namespace (if not already present). */
-static devmap_namespace_t *devmap_namespace_create(const char *ns_name)
-{
-	devmap_namespace_t *namespace;
-	
-	assert(fibril_mutex_is_locked(&devices_list_mutex));
-	
-	namespace = devmap_namespace_find_name(ns_name);
-	if (namespace != NULL)
-		return namespace;
-	
-	namespace = (devmap_namespace_t *) malloc(sizeof(devmap_namespace_t));
-	if (namespace == NULL)
-		return NULL;
-	
-	namespace->name = str_dup(ns_name);
-	if (namespace->name == NULL) {
-		free(namespace);
-		return NULL;
-	}
-	
-	namespace->handle = devmap_create_handle();
-	namespace->refcnt = 0;
-	
-	/*
-	 * Insert new namespace into list of registered namespaces
-	 */
-	list_append(&(namespace->namespaces), &namespaces_list);
-	
-	return namespace;
-}
-
-/** Destroy a namespace (if it is no longer needed). */
-static void devmap_namespace_destroy(devmap_namespace_t *namespace)
-{
-	assert(fibril_mutex_is_locked(&devices_list_mutex));
-
-	if (namespace->refcnt == 0) {
-		list_remove(&(namespace->namespaces));
-		
-		free(namespace->name);
-		free(namespace);
-	}
-}
-
-/** Increase namespace reference count by including device. */
-static void devmap_namespace_addref(devmap_namespace_t *namespace,
-    devmap_device_t *device)
-{
-	assert(fibril_mutex_is_locked(&devices_list_mutex));
-
-	device->namespace = namespace;
-	namespace->refcnt++;
-}
-
-/** Decrease namespace reference count. */
-static void devmap_namespace_delref(devmap_namespace_t *namespace)
-{
-	assert(fibril_mutex_is_locked(&devices_list_mutex));
-
-	namespace->refcnt--;
-	devmap_namespace_destroy(namespace);
-}
-
-/** Unregister device and free it. */
-static void devmap_device_unregister_core(devmap_device_t *device)
-{
-	assert(fibril_mutex_is_locked(&devices_list_mutex));
-
-	devmap_namespace_delref(device->namespace);
-	list_remove(&(device->devices));
-	list_remove(&(device->driver_devices));
-	
-	free(device->name);
-	free(device);
-}
-
-/**
- * Read info about new driver and add it into linked list of registered
- * drivers.
- */
-static devmap_driver_t *devmap_driver_register(void)
-{
-	ipc_call_t icall;
-	ipc_callid_t iid = async_get_call(&icall);
-	
-	if (IPC_GET_IMETHOD(icall) != DEVMAP_DRIVER_REGISTER) {
-		async_answer_0(iid, EREFUSED);
-		return NULL;
-	}
-	
-	devmap_driver_t *driver =
-	    (devmap_driver_t *) malloc(sizeof(devmap_driver_t));
-	if (driver == NULL) {
-		async_answer_0(iid, ENOMEM);
-		return NULL;
-	}
-	
-	/*
-	 * Get driver name
-	 */
-	int rc = async_data_write_accept((void **) &driver->name, true, 0,
-	    DEVMAP_NAME_MAXLEN, 0, NULL);
-	if (rc != EOK) {
-		free(driver);
-		async_answer_0(iid, rc);
-		return NULL;
-	}
-	
-	/*
-	 * Create connection to the driver
-	 */
-	driver->sess = async_callback_receive(EXCHANGE_SERIALIZE);
-	if (!driver->sess) {
-		free(driver->name);
-		free(driver);
-		async_answer_0(iid, ENOTSUP);
-		return NULL;
-	}
-	
-	/*
-	 * Initialize mutex for list of devices
-	 * owned by this driver
-	 */
-	fibril_mutex_initialize(&driver->devices_mutex);
-	
-	/*
-	 * Initialize list of asociated devices
-	 */
-	list_initialize(&driver->devices);
-
-	link_initialize(&driver->drivers);
-	
-	fibril_mutex_lock(&drivers_list_mutex);
-	
-	/* TODO:
-	 * Check that no driver with name equal to
-	 * driver->name is registered
-	 */
-	
-	/*
-	 * Insert new driver into list of registered drivers
-	 */
-	list_append(&(driver->drivers), &drivers_list);
-	fibril_mutex_unlock(&drivers_list_mutex);
-	
-	async_answer_0(iid, EOK);
-	
-	return driver;
-}
-
-/**
- * Unregister device driver, unregister all its devices and free driver
- * structure.
- *
- */
-static int devmap_driver_unregister(devmap_driver_t *driver)
-{
-	if (driver == NULL)
-		return EEXISTS;
-	
-	fibril_mutex_lock(&drivers_list_mutex);
-	
-	if (driver->sess)
-		async_hangup(driver->sess);
-	
-	/* Remove it from list of drivers */
-	list_remove(&(driver->drivers));
-	
-	/* Unregister all its devices */
-	fibril_mutex_lock(&devices_list_mutex);
-	fibril_mutex_lock(&driver->devices_mutex);
-	
-	while (!list_empty(&driver->devices)) {
-		devmap_device_t *device = list_get_instance(
-		    list_first(&driver->devices), devmap_device_t,
-		    driver_devices);
-		devmap_device_unregister_core(device);
-	}
-	
-	fibril_mutex_unlock(&driver->devices_mutex);
-	fibril_mutex_unlock(&devices_list_mutex);
-	fibril_mutex_unlock(&drivers_list_mutex);
-	
-	/* Free name and driver */
-	if (driver->name != NULL)
-		free(driver->name);
-	
-	free(driver);
-	
-	return EOK;
-}
-
-/** Register instance of device
- *
- */
-static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
-    devmap_driver_t *driver)
-{
-	if (driver == NULL) {
-		async_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	/* Create new device entry */
-	devmap_device_t *device =
-	    (devmap_device_t *) malloc(sizeof(devmap_device_t));
-	if (device == NULL) {
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
-	/* Set the interface, if any. */
-	device->forward_interface = IPC_GET_ARG1(*icall);
-
-	/* Get fqdn */
-	char *fqdn;
-	int rc = async_data_write_accept((void **) &fqdn, true, 0,
-	    DEVMAP_NAME_MAXLEN, 0, NULL);
-	if (rc != EOK) {
-		free(device);
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	char *ns_name;
-	if (!devmap_fqdn_split(fqdn, &ns_name, &device->name)) {
-		free(fqdn);
-		free(device);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	free(fqdn);
-	
-	fibril_mutex_lock(&devices_list_mutex);
-	
-	devmap_namespace_t *namespace = devmap_namespace_create(ns_name);
-	free(ns_name);
-	if (namespace == NULL) {
-		fibril_mutex_unlock(&devices_list_mutex);
-		free(device->name);
-		free(device);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
-	link_initialize(&device->devices);
-	link_initialize(&device->driver_devices);
-	
-	/* Check that device is not already registered */
-	if (devmap_device_find_name(namespace->name, device->name) != NULL) {
-		printf("%s: Device '%s/%s' already registered\n", NAME,
-		    namespace->name, device->name);
-		devmap_namespace_destroy(namespace);
-		fibril_mutex_unlock(&devices_list_mutex);
-		free(device->name);
-		free(device);
-		async_answer_0(iid, EEXISTS);
-		return;
-	}
-	
-	/* Get unique device handle */
-	device->handle = devmap_create_handle();
-
-	devmap_namespace_addref(namespace, device);
-	device->driver = driver;
-	
-	/* Insert device into list of all devices  */
-	list_append(&device->devices, &devices_list);
-	
-	/* Insert device into list of devices that belog to one driver */
-	fibril_mutex_lock(&device->driver->devices_mutex);
-	
-	list_append(&device->driver_devices, &device->driver->devices);
-	
-	fibril_mutex_unlock(&device->driver->devices_mutex);
-	fibril_condvar_broadcast(&devices_list_cv);
-	fibril_mutex_unlock(&devices_list_mutex);
-	
-	async_answer_1(iid, EOK, device->handle);
-}
-
-/**
- *
- */
-static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall, 
-    devmap_driver_t *driver)
-{
-	/* TODO */
-	return EOK;
-}
-
-/** Connect client to the device.
- *
- * Find device driver owning requested device and forward
- * the message to it.
- *
- */
-static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
-{
-	fibril_mutex_lock(&devices_list_mutex);
-	
-	/*
-	 * Get handle from request
-	 */
-	devmap_handle_t handle = IPC_GET_ARG2(*call);
-	devmap_device_t *dev = devmap_device_find_handle(handle);
-	
-	if ((dev == NULL) || (dev->driver == NULL) || (!dev->driver->sess)) {
-		fibril_mutex_unlock(&devices_list_mutex);
-		async_answer_0(callid, ENOENT);
-		return;
-	}
-	
-	async_exch_t *exch = async_exchange_begin(dev->driver->sess);
-	
-	if (dev->forward_interface == 0)
-		async_forward_fast(callid, exch, dev->handle, 0, 0, IPC_FF_NONE);
-	else
-		async_forward_fast(callid, exch, dev->forward_interface,
-		    dev->handle, 0, IPC_FF_NONE);
-	
-	async_exchange_end(exch);
-	
-	fibril_mutex_unlock(&devices_list_mutex);
-}
-
-/** Find handle for device instance identified by name.
- *
- * In answer will be send EOK and device handle in arg1 or a error
- * code from errno.h.
- *
- */
-static void devmap_device_get_handle(ipc_callid_t iid, ipc_call_t *icall)
-{
-	char *fqdn;
-	
-	/* Get fqdn */
-	int rc = async_data_write_accept((void **) &fqdn, true, 0,
-	    DEVMAP_NAME_MAXLEN, 0, NULL);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	char *ns_name;
-	char *name;
-	if (!devmap_fqdn_split(fqdn, &ns_name, &name)) {
-		free(fqdn);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	free(fqdn);
-	
-	fibril_mutex_lock(&devices_list_mutex);
-	const devmap_device_t *dev;
-	
-recheck:
-	
-	/*
-	 * Find device name in the list of known devices.
-	 */
-	dev = devmap_device_find_name(ns_name, name);
-	
-	/*
-	 * Device was not found.
-	 */
-	if (dev == NULL) {
-		if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
-			/* Blocking lookup */
-			fibril_condvar_wait(&devices_list_cv,
-			    &devices_list_mutex);
-			goto recheck;
-		}
-		
-		async_answer_0(iid, ENOENT);
-		free(ns_name);
-		free(name);
-		fibril_mutex_unlock(&devices_list_mutex);
-		return;
-	}
-	
-	async_answer_1(iid, EOK, dev->handle);
-	
-	fibril_mutex_unlock(&devices_list_mutex);
-	free(ns_name);
-	free(name);
-}
-
-/** Find handle for namespace identified by name.
- *
- * In answer will be send EOK and device handle in arg1 or a error
- * code from errno.h.
- *
- */
-static void devmap_namespace_get_handle(ipc_callid_t iid, ipc_call_t *icall)
-{
-	char *name;
-	
-	/* Get device name */
-	int rc = async_data_write_accept((void **) &name, true, 0,
-	    DEVMAP_NAME_MAXLEN, 0, NULL);
-	if (rc != EOK) {
-		async_answer_0(iid, rc);
-		return;
-	}
-	
-	fibril_mutex_lock(&devices_list_mutex);
-	const devmap_namespace_t *namespace;
-	
-recheck:
-	
-	/*
-	 * Find namespace name in the list of known namespaces.
-	 */
-	namespace = devmap_namespace_find_name(name);
-	
-	/*
-	 * Namespace was not found.
-	 */
-	if (namespace == NULL) {
-		if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
-			/* Blocking lookup */
-			fibril_condvar_wait(&devices_list_cv,
-			    &devices_list_mutex);
-			goto recheck;
-		}
-		
-		async_answer_0(iid, ENOENT);
-		free(name);
-		fibril_mutex_unlock(&devices_list_mutex);
-		return;
-	}
-	
-	async_answer_1(iid, EOK, namespace->handle);
-	
-	fibril_mutex_unlock(&devices_list_mutex);
-	free(name);
-}
-
-static void devmap_handle_probe(ipc_callid_t iid, ipc_call_t *icall)
-{
-	fibril_mutex_lock(&devices_list_mutex);
-	
-	devmap_namespace_t *namespace =
-	    devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
-	if (namespace == NULL) {
-		devmap_device_t *dev =
-		    devmap_device_find_handle(IPC_GET_ARG1(*icall));
-		if (dev == NULL)
-			async_answer_1(iid, EOK, DEV_HANDLE_NONE);
-		else
-			async_answer_1(iid, EOK, DEV_HANDLE_DEVICE);
-	} else
-		async_answer_1(iid, EOK, DEV_HANDLE_NAMESPACE);
-	
-	fibril_mutex_unlock(&devices_list_mutex);
-}
-
-static void devmap_get_namespace_count(ipc_callid_t iid, ipc_call_t *icall)
-{
-	fibril_mutex_lock(&devices_list_mutex);
-	async_answer_1(iid, EOK, list_count(&namespaces_list));
-	fibril_mutex_unlock(&devices_list_mutex);
-}
-
-static void devmap_get_device_count(ipc_callid_t iid, ipc_call_t *icall)
-{
-	fibril_mutex_lock(&devices_list_mutex);
-	
-	devmap_namespace_t *namespace =
-	    devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
-	if (namespace == NULL)
-		async_answer_0(iid, EEXISTS);
-	else
-		async_answer_1(iid, EOK, namespace->refcnt);
-	
-	fibril_mutex_unlock(&devices_list_mutex);
-}
-
-static void devmap_get_namespaces(ipc_callid_t iid, ipc_call_t *icall)
-{
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_read_receive(&callid, &size)) {
-		async_answer_0(callid, EREFUSED);
-		async_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	if ((size % sizeof(dev_desc_t)) != 0) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	fibril_mutex_lock(&devices_list_mutex);
-	
-	size_t count = size / sizeof(dev_desc_t);
-	if (count != list_count(&namespaces_list)) {
-		fibril_mutex_unlock(&devices_list_mutex);
-		async_answer_0(callid, EOVERFLOW);
-		async_answer_0(iid, EOVERFLOW);
-		return;
-	}
-	
-	dev_desc_t *desc = (dev_desc_t *) malloc(size);
-	if (desc == NULL) {
-		fibril_mutex_unlock(&devices_list_mutex);
-		async_answer_0(callid, ENOMEM);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
-	size_t pos = 0;
-	list_foreach(namespaces_list, item) {
-		devmap_namespace_t *namespace =
-		    list_get_instance(item, devmap_namespace_t, namespaces);
-		
-		desc[pos].handle = namespace->handle;
-		str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, namespace->name);
-		pos++;
-	}
-	
-	sysarg_t retval = async_data_read_finalize(callid, desc, size);
-	
-	free(desc);
-	fibril_mutex_unlock(&devices_list_mutex);
-	
-	async_answer_0(iid, retval);
-}
-
-static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
-{
-	/* FIXME: Use faster algorithm which can make better use
-	   of namespaces */
-	
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_read_receive(&callid, &size)) {
-		async_answer_0(callid, EREFUSED);
-		async_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	if ((size % sizeof(dev_desc_t)) != 0) {
-		async_answer_0(callid, EINVAL);
-		async_answer_0(iid, EINVAL);
-		return;
-	}
-	
-	fibril_mutex_lock(&devices_list_mutex);
-	
-	devmap_namespace_t *namespace =
-	    devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
-	if (namespace == NULL) {
-		fibril_mutex_unlock(&devices_list_mutex);
-		async_answer_0(callid, ENOENT);
-		async_answer_0(iid, ENOENT);
-		return;
-	}
-	
-	size_t count = size / sizeof(dev_desc_t);
-	if (count != namespace->refcnt) {
-		fibril_mutex_unlock(&devices_list_mutex);
-		async_answer_0(callid, EOVERFLOW);
-		async_answer_0(iid, EOVERFLOW);
-		return;
-	}
-	
-	dev_desc_t *desc = (dev_desc_t *) malloc(size);
-	if (desc == NULL) {
-		fibril_mutex_unlock(&devices_list_mutex);
-		async_answer_0(callid, ENOMEM);
-		async_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	size_t pos = 0;
-	list_foreach(devices_list, item) {
-		devmap_device_t *device =
-		    list_get_instance(item, devmap_device_t, devices);
-		
-		if (device->namespace == namespace) {
-			desc[pos].handle = device->handle;
-			str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
-			pos++;
-		}
-	}
-	
-	sysarg_t retval = async_data_read_finalize(callid, desc, size);
-	
-	free(desc);
-	fibril_mutex_unlock(&devices_list_mutex);
-	
-	async_answer_0(iid, retval);
-}
-
-static void devmap_null_create(ipc_callid_t iid, ipc_call_t *icall)
-{
-	fibril_mutex_lock(&null_devices_mutex);
-	
-	unsigned int i;
-	bool fnd = false;
-	
-	for (i = 0; i < NULL_DEVICES; i++) {
-		if (null_devices[i] == NULL) {
-			fnd = true;
-			break;
-		}
-	}
-	
-	if (!fnd) {
-		fibril_mutex_unlock(&null_devices_mutex);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
-	char null[DEVMAP_NAME_MAXLEN];
-	snprintf(null, DEVMAP_NAME_MAXLEN, "%u", i);
-	
-	char *dev_name = str_dup(null);
-	if (dev_name == NULL) {
-		fibril_mutex_unlock(&null_devices_mutex);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
-	devmap_device_t *device =
-	    (devmap_device_t *) malloc(sizeof(devmap_device_t));
-	if (device == NULL) {
-		fibril_mutex_unlock(&null_devices_mutex);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
-	fibril_mutex_lock(&devices_list_mutex);
-	
-	devmap_namespace_t *namespace = devmap_namespace_create("null");
-	if (namespace == NULL) {
-		fibril_mutex_lock(&devices_list_mutex);
-		fibril_mutex_unlock(&null_devices_mutex);
-		async_answer_0(iid, ENOMEM);
-		return;
-	}
-	
-	link_initialize(&device->devices);
-	link_initialize(&device->driver_devices);
-	
-	/* Get unique device handle */
-	device->handle = devmap_create_handle();
-	device->driver = NULL;
-	
-	devmap_namespace_addref(namespace, device);
-	device->name = dev_name;
-	
-	/*
-	 * Insert device into list of all devices and into null devices array.
-	 * Insert device into a dummy list of null driver's devices so that it
-	 * can be safely removed later.
-	 */
-	list_append(&device->devices, &devices_list);
-	list_append(&device->driver_devices, &dummy_null_driver_devices);
-	null_devices[i] = device;
-	
-	fibril_mutex_unlock(&devices_list_mutex);
-	fibril_mutex_unlock(&null_devices_mutex);
-	
-	async_answer_1(iid, EOK, (sysarg_t) i);
-}
-
-static void devmap_null_destroy(ipc_callid_t iid, ipc_call_t *icall)
-{
-	sysarg_t i = IPC_GET_ARG1(*icall);
-	if (i >= NULL_DEVICES) {
-		async_answer_0(iid, ELIMIT);
-		return;
-	}
-	
-	fibril_mutex_lock(&null_devices_mutex);
-	
-	if (null_devices[i] == NULL) {
-		fibril_mutex_unlock(&null_devices_mutex);
-		async_answer_0(iid, ENOENT);
-		return;
-	}
-	
-	fibril_mutex_lock(&devices_list_mutex);
-	devmap_device_unregister_core(null_devices[i]);
-	fibril_mutex_unlock(&devices_list_mutex);
-	
-	null_devices[i] = NULL;
-	
-	fibril_mutex_unlock(&null_devices_mutex);
-	async_answer_0(iid, EOK);
-}
-
-/** Initialize device mapper.
- *
- *
- */
-static bool devmap_init(void)
-{
-	fibril_mutex_lock(&null_devices_mutex);
-	
-	unsigned int i;
-	for (i = 0; i < NULL_DEVICES; i++)
-		null_devices[i] = NULL;
-	
-	fibril_mutex_unlock(&null_devices_mutex);
-	
-	return true;
-}
-
-/** Handle connection with device driver.
- *
- */
-static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
-{
-	/* Accept connection */
-	async_answer_0(iid, EOK);
-	
-	devmap_driver_t *driver = devmap_driver_register();
-	if (driver == NULL)
-		return;
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			break;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case DEVMAP_DRIVER_UNREGISTER:
-			if (NULL == driver)
-				async_answer_0(callid, ENOENT);
-			else
-				async_answer_0(callid, EOK);
-			break;
-		case DEVMAP_DEVICE_REGISTER:
-			/* Register one instance of device */
-			devmap_device_register(callid, &call, driver);
-			break;
-		case DEVMAP_DEVICE_UNREGISTER:
-			/* Remove instance of device identified by handler */
-			devmap_device_unregister(callid, &call, driver);
-			break;
-		case DEVMAP_DEVICE_GET_HANDLE:
-			devmap_device_get_handle(callid, &call);
-			break;
-		case DEVMAP_NAMESPACE_GET_HANDLE:
-			devmap_namespace_get_handle(callid, &call);
-			break;
-		default:
-			async_answer_0(callid, ENOENT);
-		}
-	}
-	
-	if (driver != NULL) {
-		/*
-		 * Unregister the device driver and all its devices.
-		 */
-		devmap_driver_unregister(driver);
-		driver = NULL;
-	}
-}
-
-/** Handle connection with device client.
- *
- */
-static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
-{
-	/* Accept connection */
-	async_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		if (!IPC_GET_IMETHOD(call))
-			break;
-		
-		switch (IPC_GET_IMETHOD(call)) {
-		case DEVMAP_DEVICE_GET_HANDLE:
-			devmap_device_get_handle(callid, &call);
-			break;
-		case DEVMAP_NAMESPACE_GET_HANDLE:
-			devmap_namespace_get_handle(callid, &call);
-			break;
-		case DEVMAP_HANDLE_PROBE:
-			devmap_handle_probe(callid, &call);
-			break;
-		case DEVMAP_NULL_CREATE:
-			devmap_null_create(callid, &call);
-			break;
-		case DEVMAP_NULL_DESTROY:
-			devmap_null_destroy(callid, &call);
-			break;
-		case DEVMAP_GET_NAMESPACE_COUNT:
-			devmap_get_namespace_count(callid, &call);
-			break;
-		case DEVMAP_GET_DEVICE_COUNT:
-			devmap_get_device_count(callid, &call);
-			break;
-		case DEVMAP_GET_NAMESPACES:
-			devmap_get_namespaces(callid, &call);
-			break;
-		case DEVMAP_GET_DEVICES:
-			devmap_get_devices(callid, &call);
-			break;
-		default:
-			async_answer_0(callid, ENOENT);
-		}
-	}
-}
-
-/** Function for handling connections to devmap
- *
- */
-static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	/* Select interface */
-	switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
-	case DEVMAP_DRIVER:
-		devmap_connection_driver(iid, icall);
-		break;
-	case DEVMAP_CLIENT:
-		devmap_connection_client(iid, icall);
-		break;
-	case DEVMAP_CONNECT_TO_DEVICE:
-		/* Connect client to selected device */
-		devmap_forward(iid, icall);
-		break;
-	default:
-		/* No such interface */
-		async_answer_0(iid, ENOENT);
-	}
-}
-
-/**
- *
- */
-int main(int argc, char *argv[])
-{
-	printf("%s: HelenOS Device Mapper\n", NAME);
-	
-	if (!devmap_init()) {
-		printf("%s: Error while initializing service\n", NAME);
-		return -1;
-	}
-	
-	/* Set a handler of incomming connections */
-	async_set_client_connection(devmap_connection);
-	
-	/* Register device mapper at naming service */
-	if (service_register(SERVICE_DEVMAP) != EOK)
-		return -1;
-	
-	printf("%s: Accepting connections\n", NAME);
-	async_manager();
-	
-	/* Never reached */
-	return 0;
-}
-
-/**
- * @}
- */
Index: pace/srv/fs/devfs/Makefile
===================================================================
--- uspace/srv/fs/devfs/Makefile	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,40 +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 = ../../..
-LIBS = $(LIBFS_PREFIX)/libfs.a
-EXTRA_CFLAGS += -I$(LIBFS_PREFIX)
-BINARY = devfs
-STATIC_NEEDED = y
-
-SOURCES = \
-	devfs.c \
-	devfs_ops.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: pace/srv/fs/devfs/devfs.c
===================================================================
--- uspace/srv/fs/devfs/devfs.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,93 +1,0 @@
-/*
- * Copyright (c) 2009 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 fs
- * @{
- */
-
-/**
- * @file devfs.c
- * @brief Devices file system.
- *
- * Every device registered to device mapper is represented as a file in this
- * file system.
- */
-
-#include <stdio.h>
-#include <ipc/services.h>
-#include <ns.h>
-#include <async.h>
-#include <errno.h>
-#include <task.h>
-#include <libfs.h>
-#include "devfs.h"
-#include "devfs_ops.h"
-
-#define NAME  "devfs"
-
-static vfs_info_t devfs_vfs_info = {
-	.name = NAME,
-	.concurrent_read_write = false,
-	.write_retains_size = false,
-};
-
-int main(int argc, char *argv[])
-{
-	printf("%s: HelenOS Device Filesystem\n", NAME);
-	
-	if (!devfs_init()) {
-		printf("%s: failed to initialize devfs\n", NAME);
-		return -1;
-	}
-	
-	async_sess_t *vfs_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
-	    SERVICE_VFS, 0, 0);
-	if (!vfs_sess) {
-		printf("%s: Unable to connect to VFS\n", NAME);
-		return -1;
-	}
-	
-	int rc = fs_register(vfs_sess, &devfs_vfs_info, &devfs_ops,
-	    &devfs_libfs_ops);
-	if (rc != EOK) {
-		printf("%s: Failed to register file system (%d)\n", NAME, rc);
-		return rc;
-	}
-	
-	printf("%s: Accepting connections\n", NAME);
-	task_retval(0);
-	async_manager();
-	
-	/* Not reached */
-	return 0;
-}
-
-/**
- * @}
- */
-
Index: pace/srv/fs/devfs/devfs.h
===================================================================
--- uspace/srv/fs/devfs/devfs.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,45 +1,0 @@
-/*
- * Copyright (c) 2009 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 fs
- * @{
- */ 
-
-#ifndef DEVFS_DEVFS_H_
-#define DEVFS_DEVFS_H_
-
-#include <libfs.h>
-
-extern vfs_out_ops_t devfs_ops;
-extern libfs_ops_t devfs_libfs_ops;
-
-#endif
-
-/**
- * @}
- */
Index: pace/srv/fs/devfs/devfs_ops.c
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,778 +1,0 @@
-/*
- * Copyright (c) 2009 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 fs
- * @{
- */
-
-/**
- * @file devfs_ops.c
- * @brief Implementation of VFS operations for the devfs file system server.
- */
-
-#include <macros.h>
-#include <bool.h>
-#include <errno.h>
-#include <malloc.h>
-#include <str.h>
-#include <libfs.h>
-#include <fibril_synch.h>
-#include <adt/hash_table.h>
-#include <ipc/devmap.h>
-#include <sys/stat.h>
-#include <libfs.h>
-#include <assert.h>
-#include "devfs.h"
-#include "devfs_ops.h"
-
-typedef struct {
-	devmap_handle_type_t type;
-	devmap_handle_t handle;
-} devfs_node_t;
-
-/** Opened devices structure */
-typedef struct {
-	devmap_handle_t handle;
-	async_sess_t *sess;       /**< If NULL, the structure is incomplete. */
-	size_t refcount;
-	link_t link;
-	fibril_condvar_t cv;      /**< Broadcast when completed. */
-} device_t;
-
-/** Hash table of opened devices */
-static hash_table_t devices;
-
-/** Hash table mutex */
-static FIBRIL_MUTEX_INITIALIZE(devices_mutex);
-
-#define DEVICES_KEYS        1
-#define DEVICES_KEY_HANDLE  0
-#define DEVICES_BUCKETS     256
-
-/* Implementation of hash table interface for the nodes hash table. */
-static hash_index_t devices_hash(unsigned long key[])
-{
-	return key[DEVICES_KEY_HANDLE] % DEVICES_BUCKETS;
-}
-
-static int devices_compare(unsigned long key[], hash_count_t keys, link_t *item)
-{
-	device_t *dev = hash_table_get_instance(item, device_t, link);
-	return (dev->handle == (devmap_handle_t) key[DEVICES_KEY_HANDLE]);
-}
-
-static void devices_remove_callback(link_t *item)
-{
-	free(hash_table_get_instance(item, device_t, link));
-}
-
-static hash_table_operations_t devices_ops = {
-	.hash = devices_hash,
-	.compare = devices_compare,
-	.remove_callback = devices_remove_callback
-};
-
-static int devfs_node_get_internal(fs_node_t **rfn, devmap_handle_type_t type,
-    devmap_handle_t handle)
-{
-	devfs_node_t *node = (devfs_node_t *) malloc(sizeof(devfs_node_t));
-	if (node == NULL) {
-		*rfn = NULL;
-		return ENOMEM;
-	}
-	
-	*rfn = (fs_node_t *) malloc(sizeof(fs_node_t));
-	if (*rfn == NULL) {
-		free(node);
-		*rfn = NULL;
-		return ENOMEM;
-	}
-	
-	fs_node_initialize(*rfn);
-	node->type = type;
-	node->handle = handle;
-	
-	(*rfn)->data = node;
-	return EOK;
-}
-
-static int devfs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
-{
-	return devfs_node_get_internal(rfn, DEV_HANDLE_NONE, 0);
-}
-
-static int devfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
-{
-	devfs_node_t *node = (devfs_node_t *) pfn->data;
-	int ret;
-	
-	if (node->handle == 0) {
-		/* Root directory */
-		
-		dev_desc_t *devs;
-		size_t count = devmap_get_namespaces(&devs);
-		
-		if (count > 0) {
-			size_t pos;
-			for (pos = 0; pos < count; pos++) {
-				/* Ignore root namespace */
-				if (str_cmp(devs[pos].name, "") == 0)
-					continue;
-				
-				if (str_cmp(devs[pos].name, component) == 0) {
-					ret = devfs_node_get_internal(rfn, DEV_HANDLE_NAMESPACE, devs[pos].handle);
-					free(devs);
-					return ret;
-				}
-			}
-			
-			free(devs);
-		}
-		
-		/* Search root namespace */
-		devmap_handle_t namespace;
-		if (devmap_namespace_get_handle("", &namespace, 0) == EOK) {
-			count = devmap_get_devices(namespace, &devs);
-			
-			if (count > 0) {
-				size_t pos;
-				for (pos = 0; pos < count; pos++) {
-					if (str_cmp(devs[pos].name, component) == 0) {
-						ret = devfs_node_get_internal(rfn, DEV_HANDLE_DEVICE, devs[pos].handle);
-						free(devs);
-						return ret;
-					}
-				}
-				
-				free(devs);
-			}
-		}
-		
-		*rfn = NULL;
-		return EOK;
-	}
-	
-	if (node->type == DEV_HANDLE_NAMESPACE) {
-		/* Namespace directory */
-		
-		dev_desc_t *devs;
-		size_t count = devmap_get_devices(node->handle, &devs);
-		if (count > 0) {
-			size_t pos;
-			for (pos = 0; pos < count; pos++) {
-				if (str_cmp(devs[pos].name, component) == 0) {
-					ret = devfs_node_get_internal(rfn, DEV_HANDLE_DEVICE, devs[pos].handle);
-					free(devs);
-					return ret;
-				}
-			}
-			
-			free(devs);
-		}
-		
-		*rfn = NULL;
-		return EOK;
-	}
-	
-	*rfn = NULL;
-	return EOK;
-}
-
-static int devfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
-{
-	return devfs_node_get_internal(rfn, devmap_handle_probe(index), index);
-}
-
-static int devfs_node_open(fs_node_t *fn)
-{
-	devfs_node_t *node = (devfs_node_t *) fn->data;
-	
-	if (node->handle == 0) {
-		/* Root directory */
-		return EOK;
-	}
-	
-	devmap_handle_type_t type = devmap_handle_probe(node->handle);
-	
-	if (type == DEV_HANDLE_NAMESPACE) {
-		/* Namespace directory */
-		return EOK;
-	}
-	
-	if (type == DEV_HANDLE_DEVICE) {
-		/* Device node */
-		
-		unsigned long key[] = {
-			[DEVICES_KEY_HANDLE] = (unsigned long) node->handle
-		};
-		link_t *lnk;
-		
-		fibril_mutex_lock(&devices_mutex);
-restart:
-		lnk = hash_table_find(&devices, key);
-		if (lnk == NULL) {
-			device_t *dev = (device_t *) malloc(sizeof(device_t));
-			if (dev == NULL) {
-				fibril_mutex_unlock(&devices_mutex);
-				return ENOMEM;
-			}
-			
-			dev->handle = node->handle;
-			
-			/* Mark as incomplete */
-			dev->sess = NULL;
-			dev->refcount = 1;
-			fibril_condvar_initialize(&dev->cv);
-			
-			/*
-			 * Insert the incomplete device structure so that other
-			 * fibrils will not race with us when we drop the mutex
-			 * below.
-			 */
-			hash_table_insert(&devices, key, &dev->link);
-			
-			/*
-			 * Drop the mutex to allow recursive devfs requests.
-			 */
-			fibril_mutex_unlock(&devices_mutex);
-			
-			async_sess_t *sess = devmap_device_connect(EXCHANGE_SERIALIZE,
-			    node->handle, 0);
-			
-			fibril_mutex_lock(&devices_mutex);
-			
-			/*
-			 * Notify possible waiters about this device structure
-			 * being completed (or destroyed).
-			 */
-			fibril_condvar_broadcast(&dev->cv);
-			
-			if (!sess) {
-				/*
-				 * Connecting failed, need to remove the
-				 * entry and free the device structure.
-				 */
-				hash_table_remove(&devices, key, DEVICES_KEYS);
-				fibril_mutex_unlock(&devices_mutex);
-				
-				return ENOENT;
-			}
-			
-			/* Set the correct session. */
-			dev->sess = sess;
-		} else {
-			device_t *dev = hash_table_get_instance(lnk, device_t, link);
-			
-			if (!dev->sess) {
-				/*
-				 * Wait until the device structure is completed
-				 * and start from the beginning as the device
-				 * structure might have entirely disappeared
-				 * while we were not holding the mutex in
-				 * fibril_condvar_wait().
-				 */
-				fibril_condvar_wait(&dev->cv, &devices_mutex);
-				goto restart;
-			}
-
-			dev->refcount++;
-		}
-		
-		fibril_mutex_unlock(&devices_mutex);
-		
-		return EOK;
-	}
-	
-	return ENOENT;
-}
-
-static int devfs_node_put(fs_node_t *fn)
-{
-	free(fn->data);
-	free(fn);
-	return EOK;
-}
-
-static int devfs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int lflag)
-{
-	assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
-	
-	*rfn = NULL;
-	return ENOTSUP;
-}
-
-static int devfs_destroy_node(fs_node_t *fn)
-{
-	return ENOTSUP;
-}
-
-static int devfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
-{
-	return ENOTSUP;
-}
-
-static int devfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
-{
-	return ENOTSUP;
-}
-
-static int devfs_has_children(bool *has_children, fs_node_t *fn)
-{
-	devfs_node_t *node = (devfs_node_t *) fn->data;
-	
-	if (node->handle == 0) {
-		size_t count = devmap_count_namespaces();
-		if (count > 0) {
-			*has_children = true;
-			return EOK;
-		}
-		
-		/* Root namespace */
-		devmap_handle_t namespace;
-		if (devmap_namespace_get_handle("", &namespace, 0) == EOK) {
-			count = devmap_count_devices(namespace);
-			if (count > 0) {
-				*has_children = true;
-				return EOK;
-			}
-		}
-		
-		*has_children = false;
-		return EOK;
-	}
-	
-	if (node->type == DEV_HANDLE_NAMESPACE) {
-		size_t count = devmap_count_devices(node->handle);
-		if (count > 0) {
-			*has_children = true;
-			return EOK;
-		}
-		
-		*has_children = false;
-		return EOK;
-	}
-	
-	*has_children = false;
-	return EOK;
-}
-
-static fs_index_t devfs_index_get(fs_node_t *fn)
-{
-	devfs_node_t *node = (devfs_node_t *) fn->data;
-	return node->handle;
-}
-
-static aoff64_t devfs_size_get(fs_node_t *fn)
-{
-	return 0;
-}
-
-static unsigned int devfs_lnkcnt_get(fs_node_t *fn)
-{
-	devfs_node_t *node = (devfs_node_t *) fn->data;
-	
-	if (node->handle == 0)
-		return 0;
-	
-	return 1;
-}
-
-static bool devfs_is_directory(fs_node_t *fn)
-{
-	devfs_node_t *node = (devfs_node_t *) fn->data;
-	
-	return ((node->type == DEV_HANDLE_NONE) || (node->type == DEV_HANDLE_NAMESPACE));
-}
-
-static bool devfs_is_file(fs_node_t *fn)
-{
-	devfs_node_t *node = (devfs_node_t *) fn->data;
-	
-	return (node->type == DEV_HANDLE_DEVICE);
-}
-
-static devmap_handle_t devfs_device_get(fs_node_t *fn)
-{
-	devfs_node_t *node = (devfs_node_t *) fn->data;
-	
-	if (node->type == DEV_HANDLE_DEVICE)
-		return node->handle;
-	
-	return 0;
-}
-
-/** libfs operations */
-libfs_ops_t devfs_libfs_ops = {
-	.root_get = devfs_root_get,
-	.match = devfs_match,
-	.node_get = devfs_node_get,
-	.node_open = devfs_node_open,
-	.node_put = devfs_node_put,
-	.create = devfs_create_node,
-	.destroy = devfs_destroy_node,
-	.link = devfs_link_node,
-	.unlink = devfs_unlink_node,
-	.has_children = devfs_has_children,
-	.index_get = devfs_index_get,
-	.size_get = devfs_size_get,
-	.lnkcnt_get = devfs_lnkcnt_get,
-	.is_directory = devfs_is_directory,
-	.is_file = devfs_is_file,
-	.device_get = devfs_device_get
-};
-
-bool devfs_init(void)
-{
-	if (!hash_table_create(&devices, DEVICES_BUCKETS,
-	    DEVICES_KEYS, &devices_ops))
-		return false;
-	
-	return true;
-}
-
-static int devfs_mounted(devmap_handle_t devmap_handle, const char *opts,
-    fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
-{
-	*index = 0;
-	*size = 0;
-	*lnkcnt = 0;
-	return EOK;
-}
-
-static int devfs_unmounted(devmap_handle_t devmap_handle)
-{
-	return ENOTSUP;
-}
-
-static int
-devfs_read(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
-    size_t *rbytes)
-{
-	if (index == 0) {
-		ipc_callid_t callid;
-		size_t size;
-		if (!async_data_read_receive(&callid, &size)) {
-			async_answer_0(callid, EINVAL);
-			return EINVAL;
-		}
-		
-		dev_desc_t *desc;
-		size_t count = devmap_get_namespaces(&desc);
-		
-		/* Get rid of root namespace */
-		size_t i;
-		for (i = 0; i < count; i++) {
-			if (str_cmp(desc[i].name, "") == 0) {
-				if (pos >= i)
-					pos++;
-				
-				break;
-			}
-		}
-		
-		if (pos < count) {
-			async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
-			free(desc);
-			*rbytes = 1;
-			return EOK;
-		}
-		
-		free(desc);
-		pos -= count;
-		
-		/* Search root namespace */
-		devmap_handle_t namespace;
-		if (devmap_namespace_get_handle("", &namespace, 0) == EOK) {
-			count = devmap_get_devices(namespace, &desc);
-			
-			if (pos < count) {
-				async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
-				free(desc);
-				*rbytes = 1;
-				return EOK;
-			}
-			
-			free(desc);
-		}
-		
-		async_answer_0(callid, ENOENT);
-		return ENOENT;
-	}
-	
-	devmap_handle_type_t type = devmap_handle_probe(index);
-	
-	if (type == DEV_HANDLE_NAMESPACE) {
-		/* Namespace directory */
-		ipc_callid_t callid;
-		size_t size;
-		if (!async_data_read_receive(&callid, &size)) {
-			async_answer_0(callid, EINVAL);
-			return EINVAL;
-		}
-		
-		dev_desc_t *desc;
-		size_t count = devmap_get_devices(index, &desc);
-		
-		if (pos < count) {
-			async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
-			free(desc);
-			*rbytes = 1;
-			return EOK;
-		}
-		
-		free(desc);
-		async_answer_0(callid, ENOENT);
-		return ENOENT;
-	}
-	
-	if (type == DEV_HANDLE_DEVICE) {
-		/* Device node */
-		
-		unsigned long key[] = {
-			[DEVICES_KEY_HANDLE] = (unsigned long) index
-		};
-		
-		fibril_mutex_lock(&devices_mutex);
-		link_t *lnk = hash_table_find(&devices, key);
-		if (lnk == NULL) {
-			fibril_mutex_unlock(&devices_mutex);
-			return ENOENT;
-		}
-		
-		device_t *dev = hash_table_get_instance(lnk, device_t, link);
-		assert(dev->sess);
-		
-		ipc_callid_t callid;
-		if (!async_data_read_receive(&callid, NULL)) {
-			fibril_mutex_unlock(&devices_mutex);
-			async_answer_0(callid, EINVAL);
-			return EINVAL;
-		}
-		
-		/* Make a request at the driver */
-		async_exch_t *exch = async_exchange_begin(dev->sess);
-		
-		ipc_call_t answer;
-		aid_t msg = async_send_4(exch, VFS_OUT_READ, devmap_handle,
-		    index, LOWER32(pos), UPPER32(pos), &answer);
-		
-		/* Forward the IPC_M_DATA_READ request to the driver */
-		async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
-		
-		async_exchange_end(exch);
-		
-		fibril_mutex_unlock(&devices_mutex);
-		
-		/* Wait for reply from the driver. */
-		sysarg_t rc;
-		async_wait_for(msg, &rc);
-		
-		*rbytes = IPC_GET_ARG1(answer);
-		return rc;
-	}
-	
-	return ENOENT;
-}
-
-static int
-devfs_write(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
-    size_t *wbytes, aoff64_t *nsize)
-{
-	if (index == 0)
-		return ENOTSUP;
-	
-	devmap_handle_type_t type = devmap_handle_probe(index);
-	
-	if (type == DEV_HANDLE_NAMESPACE) {
-		/* Namespace directory */
-		return ENOTSUP;
-	}
-	
-	if (type == DEV_HANDLE_DEVICE) {
-		/* Device node */
-		unsigned long key[] = {
-			[DEVICES_KEY_HANDLE] = (unsigned long) index
-		};
-		
-		fibril_mutex_lock(&devices_mutex);
-		link_t *lnk = hash_table_find(&devices, key);
-		if (lnk == NULL) {
-			fibril_mutex_unlock(&devices_mutex);
-			return ENOENT;
-		}
-		
-		device_t *dev = hash_table_get_instance(lnk, device_t, link);
-		assert(dev->sess);
-		
-		ipc_callid_t callid;
-		if (!async_data_write_receive(&callid, NULL)) {
-			fibril_mutex_unlock(&devices_mutex);
-			async_answer_0(callid, EINVAL);
-			return EINVAL;
-		}
-		
-		/* Make a request at the driver */
-		async_exch_t *exch = async_exchange_begin(dev->sess);
-		
-		ipc_call_t answer;
-		aid_t msg = async_send_4(exch, VFS_OUT_WRITE, devmap_handle,
-		    index, LOWER32(pos), UPPER32(pos), &answer);
-		
-		/* Forward the IPC_M_DATA_WRITE request to the driver */
-		async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
-		
-		async_exchange_end(exch);
-		
-		fibril_mutex_unlock(&devices_mutex);
-		
-		/* Wait for reply from the driver. */
-		sysarg_t rc;
-		async_wait_for(msg, &rc);
-		
-		*wbytes = IPC_GET_ARG1(answer);
-		*nsize = 0;
-		return rc;
-	}
-	
-	return ENOENT;
-}
-
-static int
-devfs_truncate(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t size)
-{
-	return ENOTSUP;
-}
-
-static int devfs_close(devmap_handle_t devmap_handle, fs_index_t index)
-{
-	if (index == 0)
-		return EOK;
-	
-	devmap_handle_type_t type = devmap_handle_probe(index);
-	
-	if (type == DEV_HANDLE_NAMESPACE) {
-		/* Namespace directory */
-		return EOK;
-	}
-	
-	if (type == DEV_HANDLE_DEVICE) {
-		unsigned long key[] = {
-			[DEVICES_KEY_HANDLE] = (unsigned long) index
-		};
-		
-		fibril_mutex_lock(&devices_mutex);
-		link_t *lnk = hash_table_find(&devices, key);
-		if (lnk == NULL) {
-			fibril_mutex_unlock(&devices_mutex);
-			return ENOENT;
-		}
-		
-		device_t *dev = hash_table_get_instance(lnk, device_t, link);
-		assert(dev->sess);
-		dev->refcount--;
-		
-		if (dev->refcount == 0) {
-			async_hangup(dev->sess);
-			hash_table_remove(&devices, key, DEVICES_KEYS);
-		}
-		
-		fibril_mutex_unlock(&devices_mutex);
-		
-		return EOK;
-	}
-	
-	return ENOENT;
-}
-
-static int devfs_sync(devmap_handle_t devmap_handle, fs_index_t index)
-{
-	if (index == 0)
-		return EOK;
-	
-	devmap_handle_type_t type = devmap_handle_probe(index);
-	
-	if (type == DEV_HANDLE_NAMESPACE) {
-		/* Namespace directory */
-		return EOK;
-	}
-	
-	if (type == DEV_HANDLE_DEVICE) {
-		unsigned long key[] = {
-			[DEVICES_KEY_HANDLE] = (unsigned long) index
-		};
-		
-		fibril_mutex_lock(&devices_mutex);
-		link_t *lnk = hash_table_find(&devices, key);
-		if (lnk == NULL) {
-			fibril_mutex_unlock(&devices_mutex);
-			return ENOENT;
-		}
-		
-		device_t *dev = hash_table_get_instance(lnk, device_t, link);
-		assert(dev->sess);
-		
-		/* Make a request at the driver */
-		async_exch_t *exch = async_exchange_begin(dev->sess);
-		
-		ipc_call_t answer;
-		aid_t msg = async_send_2(exch, VFS_OUT_SYNC, devmap_handle,
-		    index, &answer);
-		
-		async_exchange_end(exch);
-		
-		fibril_mutex_unlock(&devices_mutex);
-		
-		/* Wait for reply from the driver */
-		sysarg_t rc;
-		async_wait_for(msg, &rc);
-		
-		return rc;
-	}
-	
-	return  ENOENT;
-}
-
-static int devfs_destroy(devmap_handle_t devmap_handle, fs_index_t index)
-{
-	return ENOTSUP;
-}
-
-vfs_out_ops_t devfs_ops = {
-	.mounted = devfs_mounted,
-	.unmounted = devfs_unmounted,
-	.read = devfs_read,
-	.write = devfs_write,
-	.truncate = devfs_truncate,
-	.close = devfs_close,
-	.destroy = devfs_destroy,
-	.sync = devfs_sync,
-};
-
-/**
- * @}
- */
Index: pace/srv/fs/devfs/devfs_ops.h
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ 	(revision )
@@ -1,44 +1,0 @@
-/*
- * Copyright (c) 2009 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 fs
- * @{
- */
-
-#ifndef DEVFS_DEVFS_OPS_H_
-#define DEVFS_DEVFS_OPS_H_
-
-#include <bool.h>
-
-extern bool devfs_init(void);
-
-#endif
-
-/**
- * @}
- */
Index: uspace/srv/fs/ext2fs/ext2fs_ops.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -42,5 +42,5 @@
 #include <libext2.h>
 #include <ipc/services.h>
-#include <ipc/devmap.h>
+#include <ipc/loc.h>
 #include <macros.h>
 #include <async.h>
@@ -69,5 +69,5 @@
 typedef struct ext2fs_instance {
 	link_t link;
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 	ext2_filesystem_t *filesystem;
 	unsigned int open_nodes_count;
@@ -85,5 +85,5 @@
  * Forward declarations of auxiliary functions
  */
-static int ext2fs_instance_get(devmap_handle_t, ext2fs_instance_t **);
+static int ext2fs_instance_get(service_id_t, ext2fs_instance_t **);
 static int ext2fs_read_directory(ipc_callid_t, aoff64_t, size_t,
     ext2fs_instance_t *, ext2_inode_ref_t *, size_t *);
@@ -97,10 +97,10 @@
  * Forward declarations of EXT2 libfs operations.
  */
-static int ext2fs_root_get(fs_node_t **, devmap_handle_t);
+static int ext2fs_root_get(fs_node_t **, service_id_t);
 static int ext2fs_match(fs_node_t **, fs_node_t *, const char *);
-static int ext2fs_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
+static int ext2fs_node_get(fs_node_t **, service_id_t, fs_index_t);
 static int ext2fs_node_open(fs_node_t *);
 static int ext2fs_node_put(fs_node_t *);
-static int ext2fs_create_node(fs_node_t **, devmap_handle_t, int);
+static int ext2fs_create_node(fs_node_t **, service_id_t, int);
 static int ext2fs_destroy_node(fs_node_t *);
 static int ext2fs_link(fs_node_t *, fs_node_t *, const char *);
@@ -112,5 +112,5 @@
 static bool ext2fs_is_directory(fs_node_t *);
 static bool ext2fs_is_file(fs_node_t *node);
-static devmap_handle_t ext2fs_device_get(fs_node_t *node);
+static service_id_t ext2fs_device_get(fs_node_t *node);
 
 /*
@@ -134,6 +134,6 @@
 	ext2fs_node_t *enode = hash_table_get_instance(item, ext2fs_node_t, link);
 	assert(keys > 0);
-	if (enode->instance->devmap_handle !=
-	    ((devmap_handle_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {
+	if (enode->instance->service_id !=
+	    ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {
 		return false;
 	}
@@ -180,9 +180,9 @@
 
 /**
- * Find an instance of filesystem for the given devmap_handle
- */
-int ext2fs_instance_get(devmap_handle_t devmap_handle, ext2fs_instance_t **inst)
-{
-	EXT2FS_DBG("(%" PRIun ", -)", devmap_handle);
+ * Find an instance of filesystem for the given service_id
+ */
+int ext2fs_instance_get(service_id_t service_id, ext2fs_instance_t **inst)
+{
+	EXT2FS_DBG("(%" PRIun ", -)", service_id);
 	ext2fs_instance_t *tmp;
 	
@@ -198,5 +198,5 @@
 		tmp = list_get_instance(link, ext2fs_instance_t, link);
 		
-		if (tmp->devmap_handle == devmap_handle) {
+		if (tmp->service_id == service_id) {
 			*inst = tmp;
 			fibril_mutex_unlock(&instance_list_mutex);
@@ -213,8 +213,8 @@
 
 
-int ext2fs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
-{
-	EXT2FS_DBG("(-, %" PRIun ")", devmap_handle);
-	return ext2fs_node_get(rfn, devmap_handle, EXT2_INODE_ROOT_INDEX);
+int ext2fs_root_get(fs_node_t **rfn, service_id_t service_id)
+{
+	EXT2FS_DBG("(-, %" PRIun ")", service_id);
+	return ext2fs_node_get(rfn, service_id, EXT2_INODE_ROOT_INDEX);
 }
 
@@ -289,12 +289,12 @@
 
 /** Instantiate a EXT2 in-core node. */
-int ext2fs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
-{
-	EXT2FS_DBG("(-,%" PRIun ",%u)", devmap_handle, index);
+int ext2fs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
+{
+	EXT2FS_DBG("(-,%" PRIun ",%u)", service_id, index);
 	
 	ext2fs_instance_t *inst = NULL;
 	int rc;
 	
-	rc = ext2fs_instance_get(devmap_handle, &inst);
+	rc = ext2fs_instance_get(service_id, &inst);
 	if (rc != EOK) {
 		return rc;
@@ -317,5 +317,5 @@
 	/* Check if the node is not already open */
 	unsigned long key[] = {
-		[OPEN_NODES_DEV_HANDLE_KEY] = inst->devmap_handle,
+		[OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id,
 		[OPEN_NODES_INODE_KEY] = index,
 	};
@@ -411,5 +411,5 @@
 
 	unsigned long key[] = {
-		[OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->devmap_handle,
+		[OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->service_id,
 		[OPEN_NODES_INODE_KEY] = enode->inode_ref->index,
 	};
@@ -429,5 +429,5 @@
 }
 
-int ext2fs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
+int ext2fs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
 {
 	EXT2FS_DBG("");
@@ -557,9 +557,9 @@
 }
 
-devmap_handle_t ext2fs_device_get(fs_node_t *fn)
+service_id_t ext2fs_device_get(fs_node_t *fn)
 {
 	EXT2FS_DBG("");
 	ext2fs_node_t *enode = EXT2FS_NODE(fn);
-	return enode->instance->devmap_handle;
+	return enode->instance->service_id;
 }
 
@@ -588,5 +588,5 @@
  */
 
-static int ext2fs_mounted(devmap_handle_t devmap_handle, const char *opts,
+static int ext2fs_mounted(service_id_t service_id, const char *opts,
    fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
 {
@@ -610,5 +610,5 @@
 	
 	/* Initialize the filesystem  */
-	rc = ext2_filesystem_init(fs, devmap_handle);
+	rc = ext2_filesystem_init(fs, service_id);
 	if (rc != EOK) {
 		free(fs);
@@ -637,5 +637,5 @@
 	/* Initialize instance */
 	link_initialize(&inst->link);
-	inst->devmap_handle = devmap_handle;
+	inst->service_id = service_id;
 	inst->filesystem = fs;
 	inst->open_nodes_count = 0;
@@ -666,5 +666,5 @@
 }
 
-static int ext2fs_unmounted(devmap_handle_t devmap_handle)
+static int ext2fs_unmounted(service_id_t service_id)
 {
 	EXT2FS_DBG("");
@@ -672,5 +672,5 @@
 	int rc;
 	
-	rc = ext2fs_instance_get(devmap_handle, &inst);
+	rc = ext2fs_instance_get(service_id, &inst);
 	
 	if (rc != EOK)
@@ -698,5 +698,5 @@
 
 static int
-ext2fs_read(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+ext2fs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
     size_t *rbytes)
 {
@@ -717,5 +717,5 @@
 	}
 	
-	rc = ext2fs_instance_get(devmap_handle, &inst);
+	rc = ext2fs_instance_get(service_id, &inst);
 	if (rc != EOK) {
 		async_answer_0(callid, rc);
@@ -907,5 +907,5 @@
 	
 	/* Usual case - we need to read a block from device */
-	rc = block_get(&block, inst->devmap_handle, fs_block, BLOCK_FLAGS_NONE);
+	rc = block_get(&block, inst->service_id, fs_block, BLOCK_FLAGS_NONE);
 	if (rc != EOK) {
 		async_answer_0(callid, rc);
@@ -925,5 +925,5 @@
 
 static int
-ext2fs_write(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+ext2fs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
     size_t *wbytes, aoff64_t *nsize)
 {
@@ -933,5 +933,5 @@
 
 static int
-ext2fs_truncate(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t size)
+ext2fs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
 {
 	EXT2FS_DBG("");
@@ -939,11 +939,11 @@
 }
 
-static int ext2fs_close(devmap_handle_t devmap_handle, fs_index_t index)
-{
-	EXT2FS_DBG("");
-	return EOK;
-}
-
-static int ext2fs_destroy(devmap_handle_t devmap_handle, fs_index_t index)
+static int ext2fs_close(service_id_t service_id, fs_index_t index)
+{
+	EXT2FS_DBG("");
+	return EOK;
+}
+
+static int ext2fs_destroy(service_id_t service_id, fs_index_t index)
 {
 	EXT2FS_DBG("");
@@ -951,5 +951,5 @@
 }
 
-static int ext2fs_sync(devmap_handle_t devmap_handle, fs_index_t index)
+static int ext2fs_sync(service_id_t service_id, fs_index_t index)
 {
 	EXT2FS_DBG("");
Index: uspace/srv/fs/fat/fat.h
===================================================================
--- uspace/srv/fs/fat/fat.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/fs/fat/fat.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -175,5 +175,5 @@
 
 	fibril_mutex_t	lock;
-	devmap_handle_t	devmap_handle;
+	service_id_t	service_id;
 	fs_index_t	index;
 	/**
@@ -227,7 +227,7 @@
 extern libfs_ops_t fat_libfs_ops;
 
-extern int fat_idx_get_new(fat_idx_t **, devmap_handle_t);
-extern fat_idx_t *fat_idx_get_by_pos(devmap_handle_t, fat_cluster_t, unsigned);
-extern fat_idx_t *fat_idx_get_by_index(devmap_handle_t, fs_index_t);
+extern int fat_idx_get_new(fat_idx_t **, service_id_t);
+extern fat_idx_t *fat_idx_get_by_pos(service_id_t, fat_cluster_t, unsigned);
+extern fat_idx_t *fat_idx_get_by_index(service_id_t, fs_index_t);
 extern void fat_idx_destroy(fat_idx_t *);
 extern void fat_idx_hashin(fat_idx_t *);
@@ -236,6 +236,6 @@
 extern int fat_idx_init(void);
 extern void fat_idx_fini(void);
-extern int fat_idx_init_by_devmap_handle(devmap_handle_t);
-extern void fat_idx_fini_by_devmap_handle(devmap_handle_t);
+extern int fat_idx_init_by_service_id(service_id_t);
+extern void fat_idx_fini_by_service_id(service_id_t);
 
 #endif
Index: uspace/srv/fs/fat/fat_fat.c
===================================================================
--- uspace/srv/fs/fat/fat_fat.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/fs/fat/fat_fat.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -71,5 +71,5 @@
  *
  * @param bs		Buffer holding the boot sector for the file.
- * @param devmap_handle	Device handle of the device with the file.
+ * @param service_id	Service ID of the device with the file.
  * @param firstc	First cluster to start the walk with.
  * @param lastc		If non-NULL, output argument hodling the last cluster
@@ -82,5 +82,5 @@
  */
 int 
-fat_cluster_walk(fat_bs_t *bs, devmap_handle_t devmap_handle, fat_cluster_t firstc,
+fat_cluster_walk(fat_bs_t *bs, service_id_t service_id, fat_cluster_t firstc,
     fat_cluster_t *lastc, uint16_t *numc, uint16_t max_clusters)
 {
@@ -109,5 +109,5 @@
 		fidx = clst % (BPS(bs) / sizeof(fat_cluster_t));
 		/* read FAT1 */
-		rc = block_get(&b, devmap_handle, RSCNT(bs) + fsec,
+		rc = block_get(&b, service_id, RSCNT(bs) + fsec,
 		    BLOCK_FLAGS_NONE);
 		if (rc != EOK)
@@ -160,5 +160,5 @@
 		 * when fortunately we have the last cluster number cached.
 		 */
-		return block_get(block, nodep->idx->devmap_handle,
+		return block_get(block, nodep->idx->service_id,
 		    CLBN2PBN(bs, nodep->lastc_cached_value, bn), flags);
 	}
@@ -174,5 +174,5 @@
 
 fall_through:
-	rc = _fat_block_get(block, bs, nodep->idx->devmap_handle, firstc,
+	rc = _fat_block_get(block, bs, nodep->idx->service_id, firstc,
 	    &currc, relbn, flags);
 	if (rc != EOK)
@@ -193,5 +193,5 @@
  * @param block		Pointer to a block pointer for storing result.
  * @param bs		Buffer holding the boot sector of the file system.
- * @param devmap_handle	Device handle of the file system.
+ * @param service_id	Service ID handle of the file system.
  * @param fcl		First cluster used by the file. Can be zero if the file
  *			is empty.
@@ -205,5 +205,5 @@
  */
 int
-_fat_block_get(block_t **block, fat_bs_t *bs, devmap_handle_t devmap_handle,
+_fat_block_get(block_t **block, fat_bs_t *bs, service_id_t service_id,
     fat_cluster_t fcl, fat_cluster_t *clp, aoff64_t bn, int flags)
 {
@@ -222,5 +222,5 @@
 		/* root directory special case */
 		assert(bn < RDS(bs));
-		rc = block_get(block, devmap_handle,
+		rc = block_get(block, service_id,
 		    RSCNT(bs) + FATCNT(bs) * SF(bs) + bn, flags);
 		return rc;
@@ -228,10 +228,10 @@
 
 	max_clusters = bn / SPC(bs);
-	rc = fat_cluster_walk(bs, devmap_handle, fcl, &c, &clusters, max_clusters);
+	rc = fat_cluster_walk(bs, service_id, fcl, &c, &clusters, max_clusters);
 	if (rc != EOK)
 		return rc;
 	assert(clusters == max_clusters);
 
-	rc = block_get(block, devmap_handle, CLBN2PBN(bs, c, bn), flags);
+	rc = block_get(block, service_id, CLBN2PBN(bs, c, bn), flags);
 
 	if (clp)
@@ -281,5 +281,5 @@
 	/* zero out the initial part of the new cluster chain */
 	for (o = boundary; o < pos; o += BPS(bs)) {
-		rc = _fat_block_get(&b, bs, nodep->idx->devmap_handle, mcl,
+		rc = _fat_block_get(&b, bs, nodep->idx->service_id, mcl,
 		    NULL, (o - boundary) / BPS(bs), BLOCK_FLAGS_NOREAD);
 		if (rc != EOK)
@@ -298,5 +298,5 @@
  *
  * @param bs		Buffer holding the boot sector for the file system.
- * @param devmap_handle	Device handle for the file system.
+ * @param service_id	Service ID for the file system.
  * @param clst		Cluster which to get.
  * @param value		Output argument holding the value of the cluster.
@@ -305,5 +305,5 @@
  */
 int
-fat_get_cluster(fat_bs_t *bs, devmap_handle_t devmap_handle, unsigned fatno,
+fat_get_cluster(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     fat_cluster_t clst, fat_cluster_t *value)
 {
@@ -312,5 +312,5 @@
 	int rc;
 
-	rc = block_get(&b, devmap_handle, RSCNT(bs) + SF(bs) * fatno +
+	rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
 	    (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
 	if (rc != EOK)
@@ -327,5 +327,5 @@
  *
  * @param bs		Buffer holding the boot sector for the file system.
- * @param devmap_handle	Device handle for the file system.
+ * @param service_id	Device service ID for the file system.
  * @param fatno		Number of the FAT instance where to make the change.
  * @param clst		Cluster which is to be set.
@@ -335,5 +335,5 @@
  */
 int
-fat_set_cluster(fat_bs_t *bs, devmap_handle_t devmap_handle, unsigned fatno,
+fat_set_cluster(fat_bs_t *bs, service_id_t service_id, unsigned fatno,
     fat_cluster_t clst, fat_cluster_t value)
 {
@@ -343,5 +343,5 @@
 
 	assert(fatno < FATCNT(bs));
-	rc = block_get(&b, devmap_handle, RSCNT(bs) + SF(bs) * fatno +
+	rc = block_get(&b, service_id, RSCNT(bs) + SF(bs) * fatno +
 	    (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
 	if (rc != EOK)
@@ -358,5 +358,5 @@
  *
  * @param bs		Buffer holding the boot sector of the file system.
- * @param devmap_handle	Device handle of the file system.
+ * @param service_id	Service ID of the file system.
  * @param lifo		Chain of allocated clusters.
  * @param nclsts	Number of clusters in the lifo chain.
@@ -364,5 +364,5 @@
  * @return		EOK on success or a negative error code.
  */
-int fat_alloc_shadow_clusters(fat_bs_t *bs, devmap_handle_t devmap_handle,
+int fat_alloc_shadow_clusters(fat_bs_t *bs, service_id_t service_id,
     fat_cluster_t *lifo, unsigned nclsts)
 {
@@ -373,5 +373,5 @@
 	for (fatno = FAT1 + 1; fatno < bs->fatcnt; fatno++) {
 		for (c = 0; c < nclsts; c++) {
-			rc = fat_set_cluster(bs, devmap_handle, fatno, lifo[c],
+			rc = fat_set_cluster(bs, service_id, fatno, lifo[c],
 			    c == 0 ? FAT_CLST_LAST1 : lifo[c - 1]);
 			if (rc != EOK)
@@ -391,5 +391,5 @@
  *
  * @param bs		Buffer holding the boot sector of the file system.
- * @param devmap_handle	Device handle of the file system.
+ * @param service_id	Device service ID of the file system.
  * @param nclsts	Number of clusters to allocate.
  * @param mcl		Output parameter where the first cluster in the chain
@@ -401,5 +401,5 @@
  */
 int
-fat_alloc_clusters(fat_bs_t *bs, devmap_handle_t devmap_handle, unsigned nclsts,
+fat_alloc_clusters(fat_bs_t *bs, service_id_t service_id, unsigned nclsts,
     fat_cluster_t *mcl, fat_cluster_t *lcl)
 {
@@ -419,5 +419,5 @@
 	fibril_mutex_lock(&fat_alloc_lock);
 	for (b = 0, cl = 0; b < SF(bs); b++) {
-		rc = block_get(&blk, devmap_handle, RSCNT(bs) + b,
+		rc = block_get(&blk, service_id, RSCNT(bs) + b,
 		    BLOCK_FLAGS_NONE);
 		if (rc != EOK)
@@ -458,5 +458,5 @@
 					/* update the shadow copies of FAT */
 					rc = fat_alloc_shadow_clusters(bs,
-					    devmap_handle, lifo, nclsts);
+					    service_id, lifo, nclsts);
 					if (rc != EOK)
 						goto error;
@@ -485,5 +485,5 @@
 	 */
 	while (found--) {
-		rc = fat_set_cluster(bs, devmap_handle, FAT1, lifo[found],
+		rc = fat_set_cluster(bs, service_id, FAT1, lifo[found],
 		    FAT_CLST_RES0);
 		if (rc != EOK) {
@@ -500,5 +500,5 @@
  *
  * @param bs		Buffer hodling the boot sector of the file system.
- * @param devmap_handle	Device handle of the file system.
+ * @param service_id	Device service ID of the file system.
  * @param firstc	First cluster in the chain which is to be freed.
  *
@@ -506,5 +506,5 @@
  */
 int
-fat_free_clusters(fat_bs_t *bs, devmap_handle_t devmap_handle, fat_cluster_t firstc)
+fat_free_clusters(fat_bs_t *bs, service_id_t service_id, fat_cluster_t firstc)
 {
 	unsigned fatno;
@@ -515,9 +515,9 @@
 	while (firstc < FAT_CLST_LAST1) {
 		assert(firstc >= FAT_CLST_FIRST && firstc < FAT_CLST_BAD);
-		rc = fat_get_cluster(bs, devmap_handle, FAT1, firstc, &nextc);
+		rc = fat_get_cluster(bs, service_id, FAT1, firstc, &nextc);
 		if (rc != EOK)
 			return rc;
 		for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
-			rc = fat_set_cluster(bs, devmap_handle, fatno, firstc,
+			rc = fat_set_cluster(bs, service_id, fatno, firstc,
 			    FAT_CLST_RES0);
 			if (rc != EOK)
@@ -544,5 +544,5 @@
     fat_cluster_t lcl)
 {
-	devmap_handle_t devmap_handle = nodep->idx->devmap_handle;
+	service_id_t service_id = nodep->idx->service_id;
 	fat_cluster_t lastc;
 	uint8_t fatno;
@@ -558,5 +558,5 @@
 			nodep->lastc_cached_valid = false;
 		} else {
-			rc = fat_cluster_walk(bs, devmap_handle, nodep->firstc,
+			rc = fat_cluster_walk(bs, service_id, nodep->firstc,
 			    &lastc, NULL, (uint16_t) -1);
 			if (rc != EOK)
@@ -565,5 +565,5 @@
 
 		for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
-			rc = fat_set_cluster(bs, nodep->idx->devmap_handle, fatno,
+			rc = fat_set_cluster(bs, nodep->idx->service_id, fatno,
 			    lastc, mcl);
 			if (rc != EOK)
@@ -591,5 +591,5 @@
 {
 	int rc;
-	devmap_handle_t devmap_handle = nodep->idx->devmap_handle;
+	service_id_t service_id = nodep->idx->service_id;
 
 	/*
@@ -602,5 +602,5 @@
 	if (lcl == FAT_CLST_RES0) {
 		/* The node will have zero size and no clusters allocated. */
-		rc = fat_free_clusters(bs, devmap_handle, nodep->firstc);
+		rc = fat_free_clusters(bs, service_id, nodep->firstc);
 		if (rc != EOK)
 			return rc;
@@ -611,5 +611,5 @@
 		unsigned fatno;
 
-		rc = fat_get_cluster(bs, devmap_handle, FAT1, lcl, &nextc);
+		rc = fat_get_cluster(bs, service_id, FAT1, lcl, &nextc);
 		if (rc != EOK)
 			return rc;
@@ -617,5 +617,5 @@
 		/* Terminate the cluster chain in all copies of FAT. */
 		for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
-			rc = fat_set_cluster(bs, devmap_handle, fatno, lcl,
+			rc = fat_set_cluster(bs, service_id, fatno, lcl,
 			    FAT_CLST_LAST1);
 			if (rc != EOK)
@@ -624,5 +624,5 @@
 
 		/* Free all following clusters. */
-		rc = fat_free_clusters(bs, devmap_handle, nextc);
+		rc = fat_free_clusters(bs, service_id, nextc);
 		if (rc != EOK)
 			return rc;
@@ -639,5 +639,5 @@
 
 int
-fat_zero_cluster(struct fat_bs *bs, devmap_handle_t devmap_handle, fat_cluster_t c)
+fat_zero_cluster(struct fat_bs *bs, service_id_t service_id, fat_cluster_t c)
 {
 	int i;
@@ -646,5 +646,5 @@
 
 	for (i = 0; i < SPC(bs); i++) {
-		rc = _fat_block_get(&b, bs, devmap_handle, c, NULL, i,
+		rc = _fat_block_get(&b, bs, service_id, c, NULL, i,
 		    BLOCK_FLAGS_NOREAD);
 		if (rc != EOK)
@@ -666,5 +666,5 @@
  * does not contain a fat file system.
  */
-int fat_sanity_check(fat_bs_t *bs, devmap_handle_t devmap_handle)
+int fat_sanity_check(fat_bs_t *bs, service_id_t service_id)
 {
 	fat_cluster_t e0, e1;
@@ -707,9 +707,9 @@
 
 	for (fat_no = 0; fat_no < bs->fatcnt; fat_no++) {
-		rc = fat_get_cluster(bs, devmap_handle, fat_no, 0, &e0);
+		rc = fat_get_cluster(bs, service_id, fat_no, 0, &e0);
 		if (rc != EOK)
 			return EIO;
 
-		rc = fat_get_cluster(bs, devmap_handle, fat_no, 1, &e1);
+		rc = fat_get_cluster(bs, service_id, fat_no, 1, &e1);
 		if (rc != EOK)
 			return EIO;
Index: uspace/srv/fs/fat/fat_fat.h
===================================================================
--- uspace/srv/fs/fat/fat_fat.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/fs/fat/fat_fat.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -61,10 +61,10 @@
 #define fat_clusters_get(numc, bs, dh, fc) \
     fat_cluster_walk((bs), (dh), (fc), NULL, (numc), (uint16_t) -1)
-extern int fat_cluster_walk(struct fat_bs *, devmap_handle_t, fat_cluster_t,
+extern int fat_cluster_walk(struct fat_bs *, service_id_t, fat_cluster_t,
     fat_cluster_t *, uint16_t *, uint16_t);
 
 extern int fat_block_get(block_t **, struct fat_bs *, struct fat_node *,
     aoff64_t, int);
-extern int _fat_block_get(block_t **, struct fat_bs *, devmap_handle_t,
+extern int _fat_block_get(block_t **, struct fat_bs *, service_id_t,
     fat_cluster_t, fat_cluster_t *, aoff64_t, int);
 
@@ -73,17 +73,17 @@
 extern int fat_chop_clusters(struct fat_bs *, struct fat_node *,
     fat_cluster_t);
-extern int fat_alloc_clusters(struct fat_bs *, devmap_handle_t, unsigned,
+extern int fat_alloc_clusters(struct fat_bs *, service_id_t, unsigned,
     fat_cluster_t *, fat_cluster_t *);
-extern int fat_free_clusters(struct fat_bs *, devmap_handle_t, fat_cluster_t);
-extern int fat_alloc_shadow_clusters(struct fat_bs *, devmap_handle_t,
+extern int fat_free_clusters(struct fat_bs *, service_id_t, fat_cluster_t);
+extern int fat_alloc_shadow_clusters(struct fat_bs *, service_id_t,
     fat_cluster_t *, unsigned);
-extern int fat_get_cluster(struct fat_bs *, devmap_handle_t, unsigned,
+extern int fat_get_cluster(struct fat_bs *, service_id_t, unsigned,
     fat_cluster_t, fat_cluster_t *);
-extern int fat_set_cluster(struct fat_bs *, devmap_handle_t, unsigned,
+extern int fat_set_cluster(struct fat_bs *, service_id_t, unsigned,
     fat_cluster_t, fat_cluster_t);
 extern int fat_fill_gap(struct fat_bs *, struct fat_node *, fat_cluster_t,
     aoff64_t);
-extern int fat_zero_cluster(struct fat_bs *, devmap_handle_t, fat_cluster_t);
-extern int fat_sanity_check(struct fat_bs *, devmap_handle_t);
+extern int fat_zero_cluster(struct fat_bs *, service_id_t, fat_cluster_t);
+extern int fat_sanity_check(struct fat_bs *, service_id_t);
 
 #endif
Index: uspace/srv/fs/fat/fat_idx.c
===================================================================
--- uspace/srv/fs/fat/fat_idx.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/fs/fat/fat_idx.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -59,5 +59,5 @@
 typedef struct {
 	link_t		link;
-	devmap_handle_t devmap_handle;
+	service_id_t	service_id;
 
 	/** Next unassigned index. */
@@ -76,8 +76,8 @@
 static LIST_INITIALIZE(unused_list);
 
-static void unused_initialize(unused_t *u, devmap_handle_t devmap_handle)
+static void unused_initialize(unused_t *u, service_id_t service_id)
 {
 	link_initialize(&u->link);
-	u->devmap_handle = devmap_handle;
+	u->service_id = service_id;
 	u->next = 0;
 	u->remaining = ((uint64_t)((fs_index_t)-1)) + 1;
@@ -85,5 +85,5 @@
 }
 
-static unused_t *unused_find(devmap_handle_t devmap_handle, bool lock)
+static unused_t *unused_find(service_id_t service_id, bool lock)
 {
 	unused_t *u;
@@ -94,5 +94,5 @@
 	list_foreach(unused_list, l) {
 		u = list_get_instance(l, unused_t, link);
-		if (u->devmap_handle == devmap_handle) 
+		if (u->service_id == service_id) 
 			return u;
 	}
@@ -108,5 +108,5 @@
 /**
  * Global hash table of all used fat_idx_t structures.
- * The index structures are hashed by the devmap_handle, parent node's first
+ * The index structures are hashed by the service_id, parent node's first
  * cluster and index within the parent directory.
  */ 
@@ -122,5 +122,5 @@
 static hash_index_t pos_hash(unsigned long key[])
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t)key[UPH_DH_KEY];
+	service_id_t service_id = (service_id_t)key[UPH_DH_KEY];
 	fat_cluster_t pfc = (fat_cluster_t)key[UPH_PFC_KEY];
 	unsigned pdi = (unsigned)key[UPH_PDI_KEY];
@@ -142,5 +142,5 @@
 	h |= (pdi & ((1 << (UPH_BUCKETS_LOG / 4)) - 1)) <<
 	    (UPH_BUCKETS_LOG / 2); 
-	h |= (devmap_handle & ((1 << (UPH_BUCKETS_LOG / 4)) - 1)) <<
+	h |= (service_id & ((1 << (UPH_BUCKETS_LOG / 4)) - 1)) <<
 	    (3 * (UPH_BUCKETS_LOG / 4));
 
@@ -150,5 +150,5 @@
 static int pos_compare(unsigned long key[], hash_count_t keys, link_t *item)
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t)key[UPH_DH_KEY];
+	service_id_t service_id = (service_id_t)key[UPH_DH_KEY];
 	fat_cluster_t pfc;
 	unsigned pdi;
@@ -157,9 +157,9 @@
 	switch (keys) {
 	case 1:
-		return (devmap_handle == fidx->devmap_handle);
+		return (service_id == fidx->service_id);
 	case 3:
 		pfc = (fat_cluster_t) key[UPH_PFC_KEY];
 		pdi = (unsigned) key[UPH_PDI_KEY];
-		return (devmap_handle == fidx->devmap_handle) && (pfc == fidx->pfc) &&
+		return (service_id == fidx->service_id) && (pfc == fidx->pfc) &&
 		    (pdi == fidx->pdi);
 	default:
@@ -183,5 +183,5 @@
 /**
  * Global hash table of all used fat_idx_t structures.
- * The index structures are hashed by the devmap_handle and index.
+ * The index structures are hashed by the service_id and index.
  */
 static hash_table_t ui_hash;
@@ -195,10 +195,10 @@
 static hash_index_t idx_hash(unsigned long key[])
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t)key[UIH_DH_KEY];
+	service_id_t service_id = (service_id_t)key[UIH_DH_KEY];
 	fs_index_t index = (fs_index_t)key[UIH_INDEX_KEY];
 
 	hash_index_t h;
 
-	h = devmap_handle & ((1 << (UIH_BUCKETS_LOG / 2)) - 1);
+	h = service_id & ((1 << (UIH_BUCKETS_LOG / 2)) - 1);
 	h |= (index & ((1 << (UIH_BUCKETS_LOG / 2)) - 1)) <<
 	    (UIH_BUCKETS_LOG / 2);
@@ -209,5 +209,5 @@
 static int idx_compare(unsigned long key[], hash_count_t keys, link_t *item)
 {
-	devmap_handle_t devmap_handle = (devmap_handle_t)key[UIH_DH_KEY];
+	service_id_t service_id = (service_id_t)key[UIH_DH_KEY];
 	fs_index_t index;
 	fat_idx_t *fidx = list_get_instance(item, fat_idx_t, uih_link);
@@ -215,8 +215,8 @@
 	switch (keys) {
 	case 1:
-		return (devmap_handle == fidx->devmap_handle);
+		return (service_id == fidx->service_id);
 	case 2:
 		index = (fs_index_t) key[UIH_INDEX_KEY];
-		return (devmap_handle == fidx->devmap_handle) &&
+		return (service_id == fidx->service_id) &&
 		    (index == fidx->index);
 	default:
@@ -241,10 +241,10 @@
 
 /** Allocate a VFS index which is not currently in use. */
-static bool fat_index_alloc(devmap_handle_t devmap_handle, fs_index_t *index)
+static bool fat_index_alloc(service_id_t service_id, fs_index_t *index)
 {
 	unused_t *u;
 	
 	assert(index);
-	u = unused_find(devmap_handle, true);
+	u = unused_find(service_id, true);
 	if (!u)
 		return false;	
@@ -303,9 +303,9 @@
 
 /** Free a VFS index, which is no longer in use. */
-static void fat_index_free(devmap_handle_t devmap_handle, fs_index_t index)
+static void fat_index_free(service_id_t service_id, fs_index_t index)
 {
 	unused_t *u;
 
-	u = unused_find(devmap_handle, true);
+	u = unused_find(service_id, true);
 	assert(u);
 
@@ -365,5 +365,5 @@
 }
 
-static int fat_idx_create(fat_idx_t **fidxp, devmap_handle_t devmap_handle)
+static int fat_idx_create(fat_idx_t **fidxp, service_id_t service_id)
 {
 	fat_idx_t *fidx;
@@ -372,5 +372,5 @@
 	if (!fidx) 
 		return ENOMEM;
-	if (!fat_index_alloc(devmap_handle, &fidx->index)) {
+	if (!fat_index_alloc(service_id, &fidx->index)) {
 		free(fidx);
 		return ENOSPC;
@@ -380,5 +380,5 @@
 	link_initialize(&fidx->uih_link);
 	fibril_mutex_initialize(&fidx->lock);
-	fidx->devmap_handle = devmap_handle;
+	fidx->service_id = service_id;
 	fidx->pfc = FAT_CLST_RES0;	/* no parent yet */
 	fidx->pdi = 0;
@@ -389,5 +389,5 @@
 }
 
-int fat_idx_get_new(fat_idx_t **fidxp, devmap_handle_t devmap_handle)
+int fat_idx_get_new(fat_idx_t **fidxp, service_id_t service_id)
 {
 	fat_idx_t *fidx;
@@ -395,5 +395,5 @@
 
 	fibril_mutex_lock(&used_lock);
-	rc = fat_idx_create(&fidx, devmap_handle);
+	rc = fat_idx_create(&fidx, service_id);
 	if (rc != EOK) {
 		fibril_mutex_unlock(&used_lock);
@@ -402,5 +402,5 @@
 		
 	unsigned long ikey[] = {
-		[UIH_DH_KEY] = devmap_handle,
+		[UIH_DH_KEY] = service_id,
 		[UIH_INDEX_KEY] = fidx->index,
 	};
@@ -415,10 +415,10 @@
 
 fat_idx_t *
-fat_idx_get_by_pos(devmap_handle_t devmap_handle, fat_cluster_t pfc, unsigned pdi)
+fat_idx_get_by_pos(service_id_t service_id, fat_cluster_t pfc, unsigned pdi)
 {
 	fat_idx_t *fidx;
 	link_t *l;
 	unsigned long pkey[] = {
-		[UPH_DH_KEY] = devmap_handle,
+		[UPH_DH_KEY] = service_id,
 		[UPH_PFC_KEY] = pfc,
 		[UPH_PDI_KEY] = pdi,
@@ -432,5 +432,5 @@
 		int rc;
 
-		rc = fat_idx_create(&fidx, devmap_handle);
+		rc = fat_idx_create(&fidx, service_id);
 		if (rc != EOK) {
 			fibril_mutex_unlock(&used_lock);
@@ -439,5 +439,5 @@
 		
 		unsigned long ikey[] = {
-			[UIH_DH_KEY] = devmap_handle,
+			[UIH_DH_KEY] = service_id,
 			[UIH_INDEX_KEY] = fidx->index,
 		};
@@ -458,5 +458,5 @@
 {
 	unsigned long pkey[] = {
-		[UPH_DH_KEY] = idx->devmap_handle,
+		[UPH_DH_KEY] = idx->service_id,
 		[UPH_PFC_KEY] = idx->pfc,
 		[UPH_PDI_KEY] = idx->pdi,
@@ -471,5 +471,5 @@
 {
 	unsigned long pkey[] = {
-		[UPH_DH_KEY] = idx->devmap_handle,
+		[UPH_DH_KEY] = idx->service_id,
 		[UPH_PFC_KEY] = idx->pfc,
 		[UPH_PDI_KEY] = idx->pdi,
@@ -482,10 +482,10 @@
 
 fat_idx_t *
-fat_idx_get_by_index(devmap_handle_t devmap_handle, fs_index_t index)
+fat_idx_get_by_index(service_id_t service_id, fs_index_t index)
 {
 	fat_idx_t *fidx = NULL;
 	link_t *l;
 	unsigned long ikey[] = {
-		[UIH_DH_KEY] = devmap_handle,
+		[UIH_DH_KEY] = service_id,
 		[UIH_INDEX_KEY] = index,
 	};
@@ -509,8 +509,8 @@
 {
 	unsigned long ikey[] = {
-		[UIH_DH_KEY] = idx->devmap_handle,
+		[UIH_DH_KEY] = idx->service_id,
 		[UIH_INDEX_KEY] = idx->index,
 	};
-	devmap_handle_t devmap_handle = idx->devmap_handle;
+	service_id_t service_id = idx->service_id;
 	fs_index_t index = idx->index;
 
@@ -526,5 +526,5 @@
 	fibril_mutex_unlock(&used_lock);
 	/* Release the VFS index. */
-	fat_index_free(devmap_handle, index);
+	fat_index_free(service_id, index);
 	/* The index structure itself is freed in idx_remove_callback(). */
 }
@@ -548,5 +548,5 @@
 }
 
-int fat_idx_init_by_devmap_handle(devmap_handle_t devmap_handle)
+int fat_idx_init_by_service_id(service_id_t service_id)
 {
 	unused_t *u;
@@ -556,7 +556,7 @@
 	if (!u)
 		return ENOMEM;
-	unused_initialize(u, devmap_handle);
+	unused_initialize(u, service_id);
 	fibril_mutex_lock(&unused_lock);
-	if (!unused_find(devmap_handle, false)) {
+	if (!unused_find(service_id, false)) {
 		list_append(&u->link, &unused_list);
 	} else {
@@ -568,11 +568,11 @@
 }
 
-void fat_idx_fini_by_devmap_handle(devmap_handle_t devmap_handle)
+void fat_idx_fini_by_service_id(service_id_t service_id)
 {
 	unsigned long ikey[] = {
-		[UIH_DH_KEY] = devmap_handle
+		[UIH_DH_KEY] = service_id
 	};
 	unsigned long pkey[] = {
-		[UPH_DH_KEY] = devmap_handle
+		[UPH_DH_KEY] = service_id
 	};
 
@@ -590,5 +590,5 @@
 	 * Free the unused and freed structures for this instance.
 	 */
-	unused_t *u = unused_find(devmap_handle, true);
+	unused_t *u = unused_find(service_id, true);
 	assert(u);
 	list_remove(&u->link);
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -43,5 +43,5 @@
 #include <libblock.h>
 #include <ipc/services.h>
-#include <ipc/devmap.h>
+#include <ipc/loc.h>
 #include <macros.h>
 #include <async.h>
@@ -72,10 +72,10 @@
  * Forward declarations of FAT libfs operations.
  */
-static int fat_root_get(fs_node_t **, devmap_handle_t);
+static int fat_root_get(fs_node_t **, service_id_t);
 static int fat_match(fs_node_t **, fs_node_t *, const char *);
-static int fat_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
+static int fat_node_get(fs_node_t **, service_id_t, fs_index_t);
 static int fat_node_open(fs_node_t *);
 static int fat_node_put(fs_node_t *);
-static int fat_create_node(fs_node_t **, devmap_handle_t, int);
+static int fat_create_node(fs_node_t **, service_id_t, int);
 static int fat_destroy_node(fs_node_t *);
 static int fat_link(fs_node_t *, fs_node_t *, const char *);
@@ -87,5 +87,5 @@
 static bool fat_is_directory(fs_node_t *);
 static bool fat_is_file(fs_node_t *node);
-static devmap_handle_t fat_device_get(fs_node_t *node);
+static service_id_t fat_device_get(fs_node_t *node);
 
 /*
@@ -119,8 +119,8 @@
 	assert(node->dirty);
 
-	bs = block_bb_get(node->idx->devmap_handle);
+	bs = block_bb_get(node->idx->service_id);
 	
 	/* Read the block that contains the dentry of interest. */
-	rc = _fat_block_get(&b, bs, node->idx->devmap_handle, node->idx->pfc,
+	rc = _fat_block_get(&b, bs, node->idx->service_id, node->idx->pfc,
 	    NULL, (node->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
 	    BLOCK_FLAGS_NONE);
@@ -144,5 +144,5 @@
 }
 
-static int fat_node_fini_by_devmap_handle(devmap_handle_t devmap_handle)
+static int fat_node_fini_by_service_id(service_id_t service_id)
 {
 	fat_node_t *nodep;
@@ -168,5 +168,5 @@
 			goto restart;
 		}
-		if (nodep->idx->devmap_handle != devmap_handle) {
+		if (nodep->idx->service_id != service_id) {
 			fibril_mutex_unlock(&nodep->idx->lock);
 			fibril_mutex_unlock(&nodep->lock);
@@ -298,8 +298,8 @@
 		return rc;
 
-	bs = block_bb_get(idxp->devmap_handle);
+	bs = block_bb_get(idxp->service_id);
 
 	/* Read the block that contains the dentry of interest. */
-	rc = _fat_block_get(&b, bs, idxp->devmap_handle, idxp->pfc, NULL,
+	rc = _fat_block_get(&b, bs, idxp->service_id, idxp->pfc, NULL,
 	    (idxp->pdi * sizeof(fat_dentry_t)) / BPS(bs), BLOCK_FLAGS_NONE);
 	if (rc != EOK) {
@@ -322,5 +322,5 @@
 		 */
 		uint16_t clusters;
-		rc = fat_clusters_get(&clusters, bs, idxp->devmap_handle,
+		rc = fat_clusters_get(&clusters, bs, idxp->service_id,
 		    uint16_t_le2host(d->firstc));
 		if (rc != EOK) {
@@ -356,7 +356,7 @@
  */
 
-int fat_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
-{
-	return fat_node_get(rfn, devmap_handle, 0);
+int fat_root_get(fs_node_t **rfn, service_id_t service_id)
+{
+	return fat_node_get(rfn, service_id, 0);
 }
 
@@ -369,13 +369,13 @@
 	unsigned blocks;
 	fat_dentry_t *d;
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 	block_t *b;
 	int rc;
 
 	fibril_mutex_lock(&parentp->idx->lock);
-	devmap_handle = parentp->idx->devmap_handle;
+	service_id = parentp->idx->service_id;
 	fibril_mutex_unlock(&parentp->idx->lock);
 
-	bs = block_bb_get(devmap_handle);
+	bs = block_bb_get(service_id);
 	blocks = parentp->size / BPS(bs);
 	for (i = 0; i < blocks; i++) {
@@ -402,5 +402,5 @@
 				/* hit */
 				fat_node_t *nodep;
-				fat_idx_t *idx = fat_idx_get_by_pos(devmap_handle,
+				fat_idx_t *idx = fat_idx_get_by_pos(service_id,
 				    parentp->firstc, i * DPS(bs) + j);
 				if (!idx) {
@@ -435,5 +435,5 @@
 
 /** Instantiate a FAT in-core node. */
-int fat_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
+int fat_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
 {
 	fat_node_t *nodep;
@@ -441,5 +441,5 @@
 	int rc;
 
-	idxp = fat_idx_get_by_index(devmap_handle, index);
+	idxp = fat_idx_get_by_index(service_id, index);
 	if (!idxp) {
 		*rfn = NULL;
@@ -492,5 +492,5 @@
 }
 
-int fat_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
+int fat_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
 {
 	fat_idx_t *idxp;
@@ -500,14 +500,14 @@
 	int rc;
 
-	bs = block_bb_get(devmap_handle);
+	bs = block_bb_get(service_id);
 	if (flags & L_DIRECTORY) {
 		/* allocate a cluster */
-		rc = fat_alloc_clusters(bs, devmap_handle, 1, &mcl, &lcl);
+		rc = fat_alloc_clusters(bs, service_id, 1, &mcl, &lcl);
 		if (rc != EOK)
 			return rc;
 		/* populate the new cluster with unused dentries */
-		rc = fat_zero_cluster(bs, devmap_handle, mcl);
+		rc = fat_zero_cluster(bs, service_id, mcl);
 		if (rc != EOK) {
-			(void) fat_free_clusters(bs, devmap_handle, mcl);
+			(void) fat_free_clusters(bs, service_id, mcl);
 			return rc;
 		}
@@ -516,10 +516,10 @@
 	rc = fat_node_get_new(&nodep);
 	if (rc != EOK) {
-		(void) fat_free_clusters(bs, devmap_handle, mcl);
-		return rc;
-	}
-	rc = fat_idx_get_new(&idxp, devmap_handle);
+		(void) fat_free_clusters(bs, service_id, mcl);
+		return rc;
+	}
+	rc = fat_idx_get_new(&idxp, service_id);
 	if (rc != EOK) {
-		(void) fat_free_clusters(bs, devmap_handle, mcl);	
+		(void) fat_free_clusters(bs, service_id, mcl);	
 		(void) fat_node_put(FS_NODE(nodep));
 		return rc;
@@ -570,9 +570,9 @@
 	assert(!has_children);
 
-	bs = block_bb_get(nodep->idx->devmap_handle);
+	bs = block_bb_get(nodep->idx->service_id);
 	if (nodep->firstc != FAT_CLST_RES0) {
 		assert(nodep->size);
 		/* Free all clusters allocated to the node. */
-		rc = fat_free_clusters(bs, nodep->idx->devmap_handle,
+		rc = fat_free_clusters(bs, nodep->idx->service_id,
 		    nodep->firstc);
 	}
@@ -620,5 +620,5 @@
 	
 	fibril_mutex_lock(&parentp->idx->lock);
-	bs = block_bb_get(parentp->idx->devmap_handle);
+	bs = block_bb_get(parentp->idx->service_id);
 
 	blocks = parentp->size / BPS(bs);
@@ -659,12 +659,12 @@
 		return ENOSPC;
 	}
-	rc = fat_alloc_clusters(bs, parentp->idx->devmap_handle, 1, &mcl, &lcl);
+	rc = fat_alloc_clusters(bs, parentp->idx->service_id, 1, &mcl, &lcl);
 	if (rc != EOK) {
 		fibril_mutex_unlock(&parentp->idx->lock);
 		return rc;
 	}
-	rc = fat_zero_cluster(bs, parentp->idx->devmap_handle, mcl);
+	rc = fat_zero_cluster(bs, parentp->idx->service_id, mcl);
 	if (rc != EOK) {
-		(void) fat_free_clusters(bs, parentp->idx->devmap_handle, mcl);
+		(void) fat_free_clusters(bs, parentp->idx->service_id, mcl);
 		fibril_mutex_unlock(&parentp->idx->lock);
 		return rc;
@@ -672,5 +672,5 @@
 	rc = fat_append_clusters(bs, parentp, mcl, lcl);
 	if (rc != EOK) {
-		(void) fat_free_clusters(bs, parentp->idx->devmap_handle, mcl);
+		(void) fat_free_clusters(bs, parentp->idx->service_id, mcl);
 		fibril_mutex_unlock(&parentp->idx->lock);
 		return rc;
@@ -789,7 +789,7 @@
 	assert(childp->lnkcnt == 1);
 	fibril_mutex_lock(&childp->idx->lock);
-	bs = block_bb_get(childp->idx->devmap_handle);
-
-	rc = _fat_block_get(&b, bs, childp->idx->devmap_handle, childp->idx->pfc,
+	bs = block_bb_get(childp->idx->service_id);
+
+	rc = _fat_block_get(&b, bs, childp->idx->service_id, childp->idx->pfc,
 	    NULL, (childp->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
 	    BLOCK_FLAGS_NONE);
@@ -841,5 +841,5 @@
 	
 	fibril_mutex_lock(&nodep->idx->lock);
-	bs = block_bb_get(nodep->idx->devmap_handle);
+	bs = block_bb_get(nodep->idx->service_id);
 
 	blocks = nodep->size / BPS(bs);
@@ -910,5 +910,5 @@
 }
 
-devmap_handle_t fat_device_get(fs_node_t *node)
+service_id_t fat_device_get(fs_node_t *node)
 {
 	return 0;
@@ -940,5 +940,5 @@
 
 static int
-fat_mounted(devmap_handle_t devmap_handle, const char *opts, fs_index_t *index,
+fat_mounted(service_id_t service_id, const char *opts, fs_index_t *index,
     aoff64_t *size, unsigned *linkcnt)
 {
@@ -954,42 +954,42 @@
 
 	/* initialize libblock */
-	rc = block_init(EXCHANGE_SERIALIZE, devmap_handle, BS_SIZE);
+	rc = block_init(EXCHANGE_SERIALIZE, service_id, BS_SIZE);
 	if (rc != EOK)
 		return rc;
 
 	/* prepare the boot block */
-	rc = block_bb_read(devmap_handle, BS_BLOCK);
+	rc = block_bb_read(service_id, BS_BLOCK);
 	if (rc != EOK) {
-		block_fini(devmap_handle);
+		block_fini(service_id);
 		return rc;
 	}
 
 	/* get the buffer with the boot sector */
-	bs = block_bb_get(devmap_handle);
+	bs = block_bb_get(service_id);
 	
 	if (BPS(bs) != BS_SIZE) {
-		block_fini(devmap_handle);
+		block_fini(service_id);
 		return ENOTSUP;
 	}
 
 	/* Initialize the block cache */
-	rc = block_cache_init(devmap_handle, BPS(bs), 0 /* XXX */, cmode);
+	rc = block_cache_init(service_id, BPS(bs), 0 /* XXX */, cmode);
 	if (rc != EOK) {
-		block_fini(devmap_handle);
+		block_fini(service_id);
 		return rc;
 	}
 
 	/* Do some simple sanity checks on the file system. */
-	rc = fat_sanity_check(bs, devmap_handle);
+	rc = fat_sanity_check(bs, service_id);
 	if (rc != EOK) {
-		(void) block_cache_fini(devmap_handle);
-		block_fini(devmap_handle);
-		return rc;
-	}
-
-	rc = fat_idx_init_by_devmap_handle(devmap_handle);
+		(void) block_cache_fini(service_id);
+		block_fini(service_id);
+		return rc;
+	}
+
+	rc = fat_idx_init_by_service_id(service_id);
 	if (rc != EOK) {
-		(void) block_cache_fini(devmap_handle);
-		block_fini(devmap_handle);
+		(void) block_cache_fini(service_id);
+		block_fini(service_id);
 		return rc;
 	}
@@ -998,7 +998,7 @@
 	fs_node_t *rfn = (fs_node_t *)malloc(sizeof(fs_node_t));
 	if (!rfn) {
-		(void) block_cache_fini(devmap_handle);
-		block_fini(devmap_handle);
-		fat_idx_fini_by_devmap_handle(devmap_handle);
+		(void) block_cache_fini(service_id);
+		block_fini(service_id);
+		fat_idx_fini_by_service_id(service_id);
 		return ENOMEM;
 	}
@@ -1007,18 +1007,18 @@
 	if (!rootp) {
 		free(rfn);
-		(void) block_cache_fini(devmap_handle);
-		block_fini(devmap_handle);
-		fat_idx_fini_by_devmap_handle(devmap_handle);
+		(void) block_cache_fini(service_id);
+		block_fini(service_id);
+		fat_idx_fini_by_service_id(service_id);
 		return ENOMEM;
 	}
 	fat_node_initialize(rootp);
 
-	fat_idx_t *ridxp = fat_idx_get_by_pos(devmap_handle, FAT_CLST_ROOTPAR, 0);
+	fat_idx_t *ridxp = fat_idx_get_by_pos(service_id, FAT_CLST_ROOTPAR, 0);
 	if (!ridxp) {
 		free(rfn);
 		free(rootp);
-		(void) block_cache_fini(devmap_handle);
-		block_fini(devmap_handle);
-		fat_idx_fini_by_devmap_handle(devmap_handle);
+		(void) block_cache_fini(service_id);
+		block_fini(service_id);
+		fat_idx_fini_by_service_id(service_id);
 		return ENOMEM;
 	}
@@ -1045,5 +1045,5 @@
 }
 
-static int fat_unmounted(devmap_handle_t devmap_handle)
+static int fat_unmounted(service_id_t service_id)
 {
 	fs_node_t *fn;
@@ -1051,5 +1051,5 @@
 	int rc;
 
-	rc = fat_root_get(&fn, devmap_handle);
+	rc = fat_root_get(&fn, service_id);
 	if (rc != EOK)
 		return rc;
@@ -1076,8 +1076,8 @@
 	 * stop using libblock for this instance.
 	 */
-	(void) fat_node_fini_by_devmap_handle(devmap_handle);
-	fat_idx_fini_by_devmap_handle(devmap_handle);
-	(void) block_cache_fini(devmap_handle);
-	block_fini(devmap_handle);
+	(void) fat_node_fini_by_service_id(service_id);
+	fat_idx_fini_by_service_id(service_id);
+	(void) block_cache_fini(service_id);
+	block_fini(service_id);
 
 	return EOK;
@@ -1085,5 +1085,5 @@
 
 static int
-fat_read(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+fat_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
     size_t *rbytes)
 {
@@ -1095,5 +1095,5 @@
 	int rc;
 
-	rc = fat_node_get(&fn, devmap_handle, index);
+	rc = fat_node_get(&fn, service_id, index);
 	if (rc != EOK)
 		return rc;
@@ -1110,5 +1110,5 @@
 	}
 
-	bs = block_bb_get(devmap_handle);
+	bs = block_bb_get(service_id);
 
 	if (nodep->type == FAT_FILE) {
@@ -1213,5 +1213,5 @@
 
 static int
-fat_write(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+fat_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
     size_t *wbytes, aoff64_t *nsize)
 {
@@ -1225,5 +1225,5 @@
 	int rc;
 	
-	rc = fat_node_get(&fn, devmap_handle, index);
+	rc = fat_node_get(&fn, service_id, index);
 	if (rc != EOK)
 		return rc;
@@ -1240,5 +1240,5 @@
 	}
 
-	bs = block_bb_get(devmap_handle);
+	bs = block_bb_get(service_id);
 
 	/*
@@ -1299,5 +1299,5 @@
 		nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs);
 		/* create an independent chain of nclsts clusters in all FATs */
-		rc = fat_alloc_clusters(bs, devmap_handle, nclsts, &mcl, &lcl);
+		rc = fat_alloc_clusters(bs, service_id, nclsts, &mcl, &lcl);
 		if (rc != EOK) {
 			/* could not allocate a chain of nclsts clusters */
@@ -1309,13 +1309,13 @@
 		rc = fat_fill_gap(bs, nodep, mcl, pos);
 		if (rc != EOK) {
-			(void) fat_free_clusters(bs, devmap_handle, mcl);
+			(void) fat_free_clusters(bs, service_id, mcl);
 			(void) fat_node_put(fn);
 			async_answer_0(callid, rc);
 			return rc;
 		}
-		rc = _fat_block_get(&b, bs, devmap_handle, lcl, NULL,
+		rc = _fat_block_get(&b, bs, service_id, lcl, NULL,
 		    (pos / BPS(bs)) % SPC(bs), flags);
 		if (rc != EOK) {
-			(void) fat_free_clusters(bs, devmap_handle, mcl);
+			(void) fat_free_clusters(bs, service_id, mcl);
 			(void) fat_node_put(fn);
 			async_answer_0(callid, rc);
@@ -1327,5 +1327,5 @@
 		rc = block_put(b);
 		if (rc != EOK) {
-			(void) fat_free_clusters(bs, devmap_handle, mcl);
+			(void) fat_free_clusters(bs, service_id, mcl);
 			(void) fat_node_put(fn);
 			return rc;
@@ -1337,5 +1337,5 @@
 		rc = fat_append_clusters(bs, nodep, mcl, lcl);
 		if (rc != EOK) {
-			(void) fat_free_clusters(bs, devmap_handle, mcl);
+			(void) fat_free_clusters(bs, service_id, mcl);
 			(void) fat_node_put(fn);
 			return rc;
@@ -1350,5 +1350,5 @@
 
 static int
-fat_truncate(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t size)
+fat_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
 {
 	fs_node_t *fn;
@@ -1357,5 +1357,5 @@
 	int rc;
 
-	rc = fat_node_get(&fn, devmap_handle, index);
+	rc = fat_node_get(&fn, service_id, index);
 	if (rc != EOK)
 		return rc;
@@ -1364,5 +1364,5 @@
 	nodep = FAT_NODE(fn);
 
-	bs = block_bb_get(devmap_handle);
+	bs = block_bb_get(service_id);
 
 	if (nodep->size == size) {
@@ -1391,5 +1391,5 @@
 		} else {
 			fat_cluster_t lastc;
-			rc = fat_cluster_walk(bs, devmap_handle, nodep->firstc,
+			rc = fat_cluster_walk(bs, service_id, nodep->firstc,
 			    &lastc, NULL, (size - 1) / BPC(bs));
 			if (rc != EOK)
@@ -1408,10 +1408,10 @@
 }
 
-static int fat_close(devmap_handle_t devmap_handle, fs_index_t index)
+static int fat_close(service_id_t service_id, fs_index_t index)
 {
 	return EOK;
 }
 
-static int fat_destroy(devmap_handle_t devmap_handle, fs_index_t index)
+static int fat_destroy(service_id_t service_id, fs_index_t index)
 {
 	fs_node_t *fn;
@@ -1419,5 +1419,5 @@
 	int rc;
 
-	rc = fat_node_get(&fn, devmap_handle, index);
+	rc = fat_node_get(&fn, service_id, index);
 	if (rc != EOK)
 		return rc;
@@ -1436,8 +1436,8 @@
 }
 
-static int fat_sync(devmap_handle_t devmap_handle, fs_index_t index)
+static int fat_sync(service_id_t service_id, fs_index_t index)
 {
 	fs_node_t *fn;
-	int rc = fat_node_get(&fn, devmap_handle, index);
+	int rc = fat_node_get(&fn, service_id, index);
 	if (rc != EOK)
 		return rc;
Index: uspace/srv/fs/locfs/Makefile
===================================================================
--- uspace/srv/fs/locfs/Makefile	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/srv/fs/locfs/Makefile	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,40 @@
+#
+# 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 = ../../..
+LIBS = $(LIBFS_PREFIX)/libfs.a
+EXTRA_CFLAGS += -I$(LIBFS_PREFIX)
+BINARY = locfs
+STATIC_NEEDED = y
+
+SOURCES = \
+	locfs.c \
+	locfs_ops.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/fs/locfs/locfs.c
===================================================================
--- uspace/srv/fs/locfs/locfs.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/srv/fs/locfs/locfs.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009 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 fs
+ * @{
+ */
+
+/**
+ * @file locfs.c
+ * @brief Location-service file system.
+ *
+ * Every service registered with location service is represented as a file in this
+ * file system.
+ */
+
+#include <stdio.h>
+#include <ipc/services.h>
+#include <ns.h>
+#include <async.h>
+#include <errno.h>
+#include <task.h>
+#include <libfs.h>
+#include "locfs.h"
+#include "locfs_ops.h"
+
+#define NAME  "locfs"
+
+static vfs_info_t locfs_vfs_info = {
+	.name = NAME,
+	.concurrent_read_write = false,
+	.write_retains_size = false,
+};
+
+int main(int argc, char *argv[])
+{
+	printf("%s: HelenOS Device Filesystem\n", NAME);
+	
+	if (!locfs_init()) {
+		printf("%s: failed to initialize locfs\n", NAME);
+		return -1;
+	}
+	
+	async_sess_t *vfs_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
+	    SERVICE_VFS, 0, 0);
+	if (!vfs_sess) {
+		printf("%s: Unable to connect to VFS\n", NAME);
+		return -1;
+	}
+	
+	int rc = fs_register(vfs_sess, &locfs_vfs_info, &locfs_ops,
+	    &locfs_libfs_ops);
+	if (rc != EOK) {
+		printf("%s: Failed to register file system (%d)\n", NAME, rc);
+		return rc;
+	}
+	
+	printf("%s: Accepting connections\n", NAME);
+	task_retval(0);
+	async_manager();
+	
+	/* Not reached */
+	return 0;
+}
+
+/**
+ * @}
+ */
+
Index: uspace/srv/fs/locfs/locfs.h
===================================================================
--- uspace/srv/fs/locfs/locfs.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/srv/fs/locfs/locfs.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2009 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 fs
+ * @{
+ */ 
+
+#ifndef LOCFS_LOCFS_H_
+#define LOCFS_LOCFS_H_
+
+#include <libfs.h>
+
+extern vfs_out_ops_t locfs_ops;
+extern libfs_ops_t locfs_libfs_ops;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/locfs/locfs_ops.c
===================================================================
--- uspace/srv/fs/locfs/locfs_ops.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/srv/fs/locfs/locfs_ops.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) 2009 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 fs
+ * @{
+ */
+
+/**
+ * @file locfs_ops.c
+ * @brief Implementation of VFS operations for the locfs file system server.
+ */
+
+#include <macros.h>
+#include <bool.h>
+#include <errno.h>
+#include <malloc.h>
+#include <str.h>
+#include <libfs.h>
+#include <fibril_synch.h>
+#include <adt/hash_table.h>
+#include <ipc/loc.h>
+#include <sys/stat.h>
+#include <libfs.h>
+#include <assert.h>
+#include "locfs.h"
+#include "locfs_ops.h"
+
+typedef struct {
+	loc_object_type_t type;
+	service_id_t service_id;
+} locfs_node_t;
+
+/** Opened services structure */
+typedef struct {
+	service_id_t service_id;
+	async_sess_t *sess;       /**< If NULL, the structure is incomplete. */
+	size_t refcount;
+	link_t link;
+	fibril_condvar_t cv;      /**< Broadcast when completed. */
+} service_t;
+
+/** Hash table of opened services */
+static hash_table_t services;
+
+/** Hash table mutex */
+static FIBRIL_MUTEX_INITIALIZE(services_mutex);
+
+#define SERVICES_KEYS        1
+#define SERVICES_KEY_HANDLE  0
+#define SERVICES_BUCKETS     256
+
+/* Implementation of hash table interface for the nodes hash table. */
+static hash_index_t services_hash(unsigned long key[])
+{
+	return key[SERVICES_KEY_HANDLE] % SERVICES_BUCKETS;
+}
+
+static int services_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	service_t *dev = hash_table_get_instance(item, service_t, link);
+	return (dev->service_id == (service_id_t) key[SERVICES_KEY_HANDLE]);
+}
+
+static void services_remove_callback(link_t *item)
+{
+	free(hash_table_get_instance(item, service_t, link));
+}
+
+static hash_table_operations_t services_ops = {
+	.hash = services_hash,
+	.compare = services_compare,
+	.remove_callback = services_remove_callback
+};
+
+static int locfs_node_get_internal(fs_node_t **rfn, loc_object_type_t type,
+    service_id_t service_id)
+{
+	locfs_node_t *node = (locfs_node_t *) malloc(sizeof(locfs_node_t));
+	if (node == NULL) {
+		*rfn = NULL;
+		return ENOMEM;
+	}
+	
+	*rfn = (fs_node_t *) malloc(sizeof(fs_node_t));
+	if (*rfn == NULL) {
+		free(node);
+		*rfn = NULL;
+		return ENOMEM;
+	}
+	
+	fs_node_initialize(*rfn);
+	node->type = type;
+	node->service_id = service_id;
+	
+	(*rfn)->data = node;
+	return EOK;
+}
+
+static int locfs_root_get(fs_node_t **rfn, service_id_t service_id)
+{
+	return locfs_node_get_internal(rfn, LOC_OBJECT_NONE, 0);
+}
+
+static int locfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+{
+	locfs_node_t *node = (locfs_node_t *) pfn->data;
+	int ret;
+	
+	if (node->service_id == 0) {
+		/* Root directory */
+		
+		loc_sdesc_t *nspaces;
+		size_t count = loc_get_namespaces(&nspaces);
+		
+		if (count > 0) {
+			size_t pos;
+			for (pos = 0; pos < count; pos++) {
+				/* Ignore root namespace */
+				if (str_cmp(nspaces[pos].name, "") == 0)
+					continue;
+				
+				if (str_cmp(nspaces[pos].name, component) == 0) {
+					ret = locfs_node_get_internal(rfn, LOC_OBJECT_NAMESPACE, nspaces[pos].id);
+					free(nspaces);
+					return ret;
+				}
+			}
+			
+			free(nspaces);
+		}
+		
+		/* Search root namespace */
+		service_id_t namespace;
+		loc_sdesc_t *svcs;
+		if (loc_namespace_get_id("", &namespace, 0) == EOK) {
+			count = loc_get_services(namespace, &svcs);
+			
+			if (count > 0) {
+				size_t pos;
+				for (pos = 0; pos < count; pos++) {
+					if (str_cmp(svcs[pos].name, component) == 0) {
+						ret = locfs_node_get_internal(rfn, LOC_OBJECT_SERVICE, svcs[pos].id);
+						free(svcs);
+						return ret;
+					}
+				}
+				
+				free(svcs);
+			}
+		}
+		
+		*rfn = NULL;
+		return EOK;
+	}
+	
+	if (node->type == LOC_OBJECT_NAMESPACE) {
+		/* Namespace directory */
+		
+		loc_sdesc_t *svcs;
+		size_t count = loc_get_services(node->service_id, &svcs);
+		if (count > 0) {
+			size_t pos;
+			for (pos = 0; pos < count; pos++) {
+				if (str_cmp(svcs[pos].name, component) == 0) {
+					ret = locfs_node_get_internal(rfn, LOC_OBJECT_SERVICE, svcs[pos].id);
+					free(svcs);
+					return ret;
+				}
+			}
+			
+			free(svcs);
+		}
+		
+		*rfn = NULL;
+		return EOK;
+	}
+	
+	*rfn = NULL;
+	return EOK;
+}
+
+static int locfs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
+{
+	return locfs_node_get_internal(rfn, loc_id_probe(index), index);
+}
+
+static int locfs_node_open(fs_node_t *fn)
+{
+	locfs_node_t *node = (locfs_node_t *) fn->data;
+	
+	if (node->service_id == 0) {
+		/* Root directory */
+		return EOK;
+	}
+	
+	loc_object_type_t type = loc_id_probe(node->service_id);
+	
+	if (type == LOC_OBJECT_NAMESPACE) {
+		/* Namespace directory */
+		return EOK;
+	}
+	
+	if (type == LOC_OBJECT_SERVICE) {
+		/* Device node */
+		
+		unsigned long key[] = {
+			[SERVICES_KEY_HANDLE] = (unsigned long) node->service_id
+		};
+		link_t *lnk;
+		
+		fibril_mutex_lock(&services_mutex);
+restart:
+		lnk = hash_table_find(&services, key);
+		if (lnk == NULL) {
+			service_t *dev = (service_t *) malloc(sizeof(service_t));
+			if (dev == NULL) {
+				fibril_mutex_unlock(&services_mutex);
+				return ENOMEM;
+			}
+			
+			dev->service_id = node->service_id;
+			
+			/* Mark as incomplete */
+			dev->sess = NULL;
+			dev->refcount = 1;
+			fibril_condvar_initialize(&dev->cv);
+			
+			/*
+			 * Insert the incomplete device structure so that other
+			 * fibrils will not race with us when we drop the mutex
+			 * below.
+			 */
+			hash_table_insert(&services, key, &dev->link);
+			
+			/*
+			 * Drop the mutex to allow recursive locfs requests.
+			 */
+			fibril_mutex_unlock(&services_mutex);
+			
+			async_sess_t *sess = loc_service_connect(
+			    EXCHANGE_SERIALIZE, node->service_id, 0);
+			
+			fibril_mutex_lock(&services_mutex);
+			
+			/*
+			 * Notify possible waiters about this device structure
+			 * being completed (or destroyed).
+			 */
+			fibril_condvar_broadcast(&dev->cv);
+			
+			if (!sess) {
+				/*
+				 * Connecting failed, need to remove the
+				 * entry and free the device structure.
+				 */
+				hash_table_remove(&services, key, SERVICES_KEYS);
+				fibril_mutex_unlock(&services_mutex);
+				
+				return ENOENT;
+			}
+			
+			/* Set the correct session. */
+			dev->sess = sess;
+		} else {
+			service_t *dev = hash_table_get_instance(lnk, service_t, link);
+			
+			if (!dev->sess) {
+				/*
+				 * Wait until the device structure is completed
+				 * and start from the beginning as the device
+				 * structure might have entirely disappeared
+				 * while we were not holding the mutex in
+				 * fibril_condvar_wait().
+				 */
+				fibril_condvar_wait(&dev->cv, &services_mutex);
+				goto restart;
+			}
+
+			dev->refcount++;
+		}
+		
+		fibril_mutex_unlock(&services_mutex);
+		
+		return EOK;
+	}
+	
+	return ENOENT;
+}
+
+static int locfs_node_put(fs_node_t *fn)
+{
+	free(fn->data);
+	free(fn);
+	return EOK;
+}
+
+static int locfs_create_node(fs_node_t **rfn, service_id_t service_id, int lflag)
+{
+	assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
+	
+	*rfn = NULL;
+	return ENOTSUP;
+}
+
+static int locfs_destroy_node(fs_node_t *fn)
+{
+	return ENOTSUP;
+}
+
+static int locfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	return ENOTSUP;
+}
+
+static int locfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	return ENOTSUP;
+}
+
+static int locfs_has_children(bool *has_children, fs_node_t *fn)
+{
+	locfs_node_t *node = (locfs_node_t *) fn->data;
+	
+	if (node->service_id == 0) {
+		size_t count = loc_count_namespaces();
+		if (count > 0) {
+			*has_children = true;
+			return EOK;
+		}
+		
+		/* Root namespace */
+		service_id_t namespace;
+		if (loc_namespace_get_id("", &namespace, 0) == EOK) {
+			count = loc_count_services(namespace);
+			if (count > 0) {
+				*has_children = true;
+				return EOK;
+			}
+		}
+		
+		*has_children = false;
+		return EOK;
+	}
+	
+	if (node->type == LOC_OBJECT_NAMESPACE) {
+		size_t count = loc_count_services(node->service_id);
+		if (count > 0) {
+			*has_children = true;
+			return EOK;
+		}
+		
+		*has_children = false;
+		return EOK;
+	}
+	
+	*has_children = false;
+	return EOK;
+}
+
+static fs_index_t locfs_index_get(fs_node_t *fn)
+{
+	locfs_node_t *node = (locfs_node_t *) fn->data;
+	return node->service_id;
+}
+
+static aoff64_t locfs_size_get(fs_node_t *fn)
+{
+	return 0;
+}
+
+static unsigned int locfs_lnkcnt_get(fs_node_t *fn)
+{
+	locfs_node_t *node = (locfs_node_t *) fn->data;
+	
+	if (node->service_id == 0)
+		return 0;
+	
+	return 1;
+}
+
+static bool locfs_is_directory(fs_node_t *fn)
+{
+	locfs_node_t *node = (locfs_node_t *) fn->data;
+	
+	return ((node->type == LOC_OBJECT_NONE) || (node->type == LOC_OBJECT_NAMESPACE));
+}
+
+static bool locfs_is_file(fs_node_t *fn)
+{
+	locfs_node_t *node = (locfs_node_t *) fn->data;
+	
+	return (node->type == LOC_OBJECT_SERVICE);
+}
+
+static service_id_t locfs_device_get(fs_node_t *fn)
+{
+	locfs_node_t *node = (locfs_node_t *) fn->data;
+	
+	if (node->type == LOC_OBJECT_SERVICE)
+		return node->service_id;
+	
+	return 0;
+}
+
+/** libfs operations */
+libfs_ops_t locfs_libfs_ops = {
+	.root_get = locfs_root_get,
+	.match = locfs_match,
+	.node_get = locfs_node_get,
+	.node_open = locfs_node_open,
+	.node_put = locfs_node_put,
+	.create = locfs_create_node,
+	.destroy = locfs_destroy_node,
+	.link = locfs_link_node,
+	.unlink = locfs_unlink_node,
+	.has_children = locfs_has_children,
+	.index_get = locfs_index_get,
+	.size_get = locfs_size_get,
+	.lnkcnt_get = locfs_lnkcnt_get,
+	.is_directory = locfs_is_directory,
+	.is_file = locfs_is_file,
+	.device_get = locfs_device_get
+};
+
+bool locfs_init(void)
+{
+	if (!hash_table_create(&services, SERVICES_BUCKETS,
+	    SERVICES_KEYS, &services_ops))
+		return false;
+	
+	return true;
+}
+
+static int locfs_mounted(service_id_t service_id, const char *opts,
+    fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
+{
+	*index = 0;
+	*size = 0;
+	*lnkcnt = 0;
+	return EOK;
+}
+
+static int locfs_unmounted(service_id_t service_id)
+{
+	return ENOTSUP;
+}
+
+static int
+locfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
+    size_t *rbytes)
+{
+	if (index == 0) {
+		ipc_callid_t callid;
+		size_t size;
+		if (!async_data_read_receive(&callid, &size)) {
+			async_answer_0(callid, EINVAL);
+			return EINVAL;
+		}
+		
+		loc_sdesc_t *desc;
+		size_t count = loc_get_namespaces(&desc);
+		
+		/* Get rid of root namespace */
+		size_t i;
+		for (i = 0; i < count; i++) {
+			if (str_cmp(desc[i].name, "") == 0) {
+				if (pos >= i)
+					pos++;
+				
+				break;
+			}
+		}
+		
+		if (pos < count) {
+			async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
+			free(desc);
+			*rbytes = 1;
+			return EOK;
+		}
+		
+		free(desc);
+		pos -= count;
+		
+		/* Search root namespace */
+		service_id_t namespace;
+		if (loc_namespace_get_id("", &namespace, 0) == EOK) {
+			count = loc_get_services(namespace, &desc);
+			
+			if (pos < count) {
+				async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
+				free(desc);
+				*rbytes = 1;
+				return EOK;
+			}
+			
+			free(desc);
+		}
+		
+		async_answer_0(callid, ENOENT);
+		return ENOENT;
+	}
+	
+	loc_object_type_t type = loc_id_probe(index);
+	
+	if (type == LOC_OBJECT_NAMESPACE) {
+		/* Namespace directory */
+		ipc_callid_t callid;
+		size_t size;
+		if (!async_data_read_receive(&callid, &size)) {
+			async_answer_0(callid, EINVAL);
+			return EINVAL;
+		}
+		
+		loc_sdesc_t *desc;
+		size_t count = loc_get_services(index, &desc);
+		
+		if (pos < count) {
+			async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
+			free(desc);
+			*rbytes = 1;
+			return EOK;
+		}
+		
+		free(desc);
+		async_answer_0(callid, ENOENT);
+		return ENOENT;
+	}
+	
+	if (type == LOC_OBJECT_SERVICE) {
+		/* Device node */
+		
+		unsigned long key[] = {
+			[SERVICES_KEY_HANDLE] = (unsigned long) index
+		};
+		
+		fibril_mutex_lock(&services_mutex);
+		link_t *lnk = hash_table_find(&services, key);
+		if (lnk == NULL) {
+			fibril_mutex_unlock(&services_mutex);
+			return ENOENT;
+		}
+		
+		service_t *dev = hash_table_get_instance(lnk, service_t, link);
+		assert(dev->sess);
+		
+		ipc_callid_t callid;
+		if (!async_data_read_receive(&callid, NULL)) {
+			fibril_mutex_unlock(&services_mutex);
+			async_answer_0(callid, EINVAL);
+			return EINVAL;
+		}
+		
+		/* Make a request at the driver */
+		async_exch_t *exch = async_exchange_begin(dev->sess);
+		
+		ipc_call_t answer;
+		aid_t msg = async_send_4(exch, VFS_OUT_READ, service_id,
+		    index, LOWER32(pos), UPPER32(pos), &answer);
+		
+		/* Forward the IPC_M_DATA_READ request to the driver */
+		async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+		
+		async_exchange_end(exch);
+		
+		fibril_mutex_unlock(&services_mutex);
+		
+		/* Wait for reply from the driver. */
+		sysarg_t rc;
+		async_wait_for(msg, &rc);
+		
+		*rbytes = IPC_GET_ARG1(answer);
+		return rc;
+	}
+	
+	return ENOENT;
+}
+
+static int
+locfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
+    size_t *wbytes, aoff64_t *nsize)
+{
+	if (index == 0)
+		return ENOTSUP;
+	
+	loc_object_type_t type = loc_id_probe(index);
+	
+	if (type == LOC_OBJECT_NAMESPACE) {
+		/* Namespace directory */
+		return ENOTSUP;
+	}
+	
+	if (type == LOC_OBJECT_SERVICE) {
+		/* Device node */
+		unsigned long key[] = {
+			[SERVICES_KEY_HANDLE] = (unsigned long) index
+		};
+		
+		fibril_mutex_lock(&services_mutex);
+		link_t *lnk = hash_table_find(&services, key);
+		if (lnk == NULL) {
+			fibril_mutex_unlock(&services_mutex);
+			return ENOENT;
+		}
+		
+		service_t *dev = hash_table_get_instance(lnk, service_t, link);
+		assert(dev->sess);
+		
+		ipc_callid_t callid;
+		if (!async_data_write_receive(&callid, NULL)) {
+			fibril_mutex_unlock(&services_mutex);
+			async_answer_0(callid, EINVAL);
+			return EINVAL;
+		}
+		
+		/* Make a request at the driver */
+		async_exch_t *exch = async_exchange_begin(dev->sess);
+		
+		ipc_call_t answer;
+		aid_t msg = async_send_4(exch, VFS_OUT_WRITE, service_id,
+		    index, LOWER32(pos), UPPER32(pos), &answer);
+		
+		/* Forward the IPC_M_DATA_WRITE request to the driver */
+		async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
+		
+		async_exchange_end(exch);
+		
+		fibril_mutex_unlock(&services_mutex);
+		
+		/* Wait for reply from the driver. */
+		sysarg_t rc;
+		async_wait_for(msg, &rc);
+		
+		*wbytes = IPC_GET_ARG1(answer);
+		*nsize = 0;
+		return rc;
+	}
+	
+	return ENOENT;
+}
+
+static int
+locfs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
+{
+	return ENOTSUP;
+}
+
+static int locfs_close(service_id_t service_id, fs_index_t index)
+{
+	if (index == 0)
+		return EOK;
+	
+	loc_object_type_t type = loc_id_probe(index);
+	
+	if (type == LOC_OBJECT_NAMESPACE) {
+		/* Namespace directory */
+		return EOK;
+	}
+	
+	if (type == LOC_OBJECT_SERVICE) {
+		unsigned long key[] = {
+			[SERVICES_KEY_HANDLE] = (unsigned long) index
+		};
+		
+		fibril_mutex_lock(&services_mutex);
+		link_t *lnk = hash_table_find(&services, key);
+		if (lnk == NULL) {
+			fibril_mutex_unlock(&services_mutex);
+			return ENOENT;
+		}
+		
+		service_t *dev = hash_table_get_instance(lnk, service_t, link);
+		assert(dev->sess);
+		dev->refcount--;
+		
+		if (dev->refcount == 0) {
+			async_hangup(dev->sess);
+			hash_table_remove(&services, key, SERVICES_KEYS);
+		}
+		
+		fibril_mutex_unlock(&services_mutex);
+		
+		return EOK;
+	}
+	
+	return ENOENT;
+}
+
+static int locfs_sync(service_id_t service_id, fs_index_t index)
+{
+	if (index == 0)
+		return EOK;
+	
+	loc_object_type_t type = loc_id_probe(index);
+	
+	if (type == LOC_OBJECT_NAMESPACE) {
+		/* Namespace directory */
+		return EOK;
+	}
+	
+	if (type == LOC_OBJECT_SERVICE) {
+		unsigned long key[] = {
+			[SERVICES_KEY_HANDLE] = (unsigned long) index
+		};
+		
+		fibril_mutex_lock(&services_mutex);
+		link_t *lnk = hash_table_find(&services, key);
+		if (lnk == NULL) {
+			fibril_mutex_unlock(&services_mutex);
+			return ENOENT;
+		}
+		
+		service_t *dev = hash_table_get_instance(lnk, service_t, link);
+		assert(dev->sess);
+		
+		/* Make a request at the driver */
+		async_exch_t *exch = async_exchange_begin(dev->sess);
+		
+		ipc_call_t answer;
+		aid_t msg = async_send_2(exch, VFS_OUT_SYNC, service_id,
+		    index, &answer);
+		
+		async_exchange_end(exch);
+		
+		fibril_mutex_unlock(&services_mutex);
+		
+		/* Wait for reply from the driver */
+		sysarg_t rc;
+		async_wait_for(msg, &rc);
+		
+		return rc;
+	}
+	
+	return  ENOENT;
+}
+
+static int locfs_destroy(service_id_t service_id, fs_index_t index)
+{
+	return ENOTSUP;
+}
+
+vfs_out_ops_t locfs_ops = {
+	.mounted = locfs_mounted,
+	.unmounted = locfs_unmounted,
+	.read = locfs_read,
+	.write = locfs_write,
+	.truncate = locfs_truncate,
+	.close = locfs_close,
+	.destroy = locfs_destroy,
+	.sync = locfs_sync,
+};
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/locfs/locfs_ops.h
===================================================================
--- uspace/srv/fs/locfs/locfs_ops.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/srv/fs/locfs/locfs_ops.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2009 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 fs
+ * @{
+ */
+
+#ifndef LOCFS_LOCFS_OPS_H_
+#define LOCFS_LOCFS_OPS_H_
+
+#include <bool.h>
+
+extern bool locfs_init(void);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/tmpfs/tmpfs.h
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/fs/tmpfs/tmpfs.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -61,5 +61,5 @@
 	fs_node_t *bp;		/**< Back pointer to the FS node. */
 	fs_index_t index;	/**< TMPFS node index. */
-	devmap_handle_t devmap_handle;/**< Device handle. */
+	service_id_t service_id;/**< Service ID of block device. */
 	link_t nh_link;		/**< Nodes hash table link. */
 	tmpfs_dentry_type_t type;
@@ -74,5 +74,5 @@
 
 extern bool tmpfs_init(void);
-extern bool tmpfs_restore(devmap_handle_t);
+extern bool tmpfs_restore(service_id_t);
 
 #endif
Index: uspace/srv/fs/tmpfs/tmpfs_dump.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -55,5 +55,5 @@
 
 static bool
-tmpfs_restore_recursion(devmap_handle_t dev, size_t *bufpos, size_t *buflen,
+tmpfs_restore_recursion(service_id_t dsid, size_t *bufpos, size_t *buflen,
     aoff64_t *pos, fs_node_t *pfn)
 {
@@ -68,5 +68,5 @@
 		uint32_t size;
 		
-		if (block_seqread(dev, bufpos, buflen, pos, &entry,
+		if (block_seqread(dsid, bufpos, buflen, pos, &entry,
 		    sizeof(entry)) != EOK)
 			return false;
@@ -82,5 +82,5 @@
 				return false;
 			
-			rc = ops->create(&fn, dev, L_FILE);
+			rc = ops->create(&fn, dsid, L_FILE);
 			if (rc != EOK || fn == NULL) {
 				free(fname);
@@ -88,5 +88,5 @@
 			}
 			
-			if (block_seqread(dev, bufpos, buflen, pos, fname,
+			if (block_seqread(dsid, bufpos, buflen, pos, fname,
 			    entry.len) != EOK) {
 				(void) ops->destroy(fn);
@@ -104,5 +104,5 @@
 			free(fname);
 			
-			if (block_seqread(dev, bufpos, buflen, pos, &size,
+			if (block_seqread(dsid, bufpos, buflen, pos, &size,
 			    sizeof(size)) != EOK)
 				return false;
@@ -116,5 +116,5 @@
 			
 			nodep->size = size;
-			if (block_seqread(dev, bufpos, buflen, pos, nodep->data,
+			if (block_seqread(dsid, bufpos, buflen, pos, nodep->data,
 			    size) != EOK)
 				return false;
@@ -126,5 +126,5 @@
 				return false;
 			
-			rc = ops->create(&fn, dev, L_DIRECTORY);
+			rc = ops->create(&fn, dsid, L_DIRECTORY);
 			if (rc != EOK || fn == NULL) {
 				free(fname);
@@ -132,5 +132,5 @@
 			}
 			
-			if (block_seqread(dev, bufpos, buflen, pos, fname,
+			if (block_seqread(dsid, bufpos, buflen, pos, fname,
 			    entry.len) != EOK) {
 				(void) ops->destroy(fn);
@@ -148,5 +148,5 @@
 			free(fname);
 			
-			if (!tmpfs_restore_recursion(dev, bufpos, buflen, pos,
+			if (!tmpfs_restore_recursion(dsid, bufpos, buflen, pos,
 			    fn))
 				return false;
@@ -161,5 +161,5 @@
 }
 
-bool tmpfs_restore(devmap_handle_t dev)
+bool tmpfs_restore(service_id_t dsid)
 {
 	libfs_ops_t *ops = &tmpfs_libfs_ops;
@@ -167,5 +167,5 @@
 	int rc;
 
-	rc = block_init(EXCHANGE_SERIALIZE, dev, TMPFS_COMM_SIZE);
+	rc = block_init(EXCHANGE_SERIALIZE, dsid, TMPFS_COMM_SIZE);
 	if (rc != EOK)
 		return false; 
@@ -176,5 +176,5 @@
 	
 	char tag[6];
-	if (block_seqread(dev, &bufpos, &buflen, &pos, tag, 5) != EOK)
+	if (block_seqread(dsid, &bufpos, &buflen, &pos, tag, 5) != EOK)
 		goto error;
 	
@@ -183,16 +183,16 @@
 		goto error;
 	
-	rc = ops->root_get(&fn, dev);
+	rc = ops->root_get(&fn, dsid);
 	if (rc != EOK)
 		goto error;
 
-	if (!tmpfs_restore_recursion(dev, &bufpos, &buflen, &pos, fn))
-		goto error;
-		
-	block_fini(dev);
+	if (!tmpfs_restore_recursion(dsid, &bufpos, &buflen, &pos, fn))
+		goto error;
+		
+	block_fini(dsid);
 	return true;
 	
 error:
-	block_fini(dev);
+	block_fini(dsid);
 	return false;
 }
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -69,8 +69,8 @@
 /* Forward declarations of static functions. */
 static int tmpfs_match(fs_node_t **, fs_node_t *, const char *);
-static int tmpfs_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
+static int tmpfs_node_get(fs_node_t **, service_id_t, fs_index_t);
 static int tmpfs_node_open(fs_node_t *);
 static int tmpfs_node_put(fs_node_t *);
-static int tmpfs_create_node(fs_node_t **, devmap_handle_t, int);
+static int tmpfs_create_node(fs_node_t **, service_id_t, int);
 static int tmpfs_destroy_node(fs_node_t *);
 static int tmpfs_link_node(fs_node_t *, fs_node_t *, const char *);
@@ -78,7 +78,7 @@
 
 /* Implementation of helper functions. */
-static int tmpfs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
-{
-	return tmpfs_node_get(rfn, devmap_handle, TMPFS_SOME_ROOT); 
+static int tmpfs_root_get(fs_node_t **rfn, service_id_t service_id)
+{
+	return tmpfs_node_get(rfn, service_id, TMPFS_SOME_ROOT); 
 }
 
@@ -114,5 +114,5 @@
 }
 
-static devmap_handle_t tmpfs_device_get(fs_node_t *fn)
+static service_id_t tmpfs_device_get(fs_node_t *fn)
 {
 	return 0;
@@ -158,7 +158,7 @@
 	switch (keys) {
 	case 1:
-		return (nodep->devmap_handle == key[NODES_KEY_DEV]);
+		return (nodep->service_id == key[NODES_KEY_DEV]);
 	case 2:	
-		return ((nodep->devmap_handle == key[NODES_KEY_DEV]) &&
+		return ((nodep->service_id == key[NODES_KEY_DEV]) &&
 		    (nodep->index == key[NODES_KEY_INDEX]));
 	default:
@@ -202,5 +202,5 @@
 	nodep->bp = NULL;
 	nodep->index = 0;
-	nodep->devmap_handle = 0;
+	nodep->service_id = 0;
 	nodep->type = TMPFS_NONE;
 	nodep->lnkcnt = 0;
@@ -226,10 +226,10 @@
 }
 
-static bool tmpfs_instance_init(devmap_handle_t devmap_handle)
+static bool tmpfs_instance_init(service_id_t service_id)
 {
 	fs_node_t *rfn;
 	int rc;
 	
-	rc = tmpfs_create_node(&rfn, devmap_handle, L_DIRECTORY);
+	rc = tmpfs_create_node(&rfn, service_id, L_DIRECTORY);
 	if (rc != EOK || !rfn)
 		return false;
@@ -238,8 +238,8 @@
 }
 
-static void tmpfs_instance_done(devmap_handle_t devmap_handle)
-{
-	unsigned long key[] = {
-		[NODES_KEY_DEV] = devmap_handle
+static void tmpfs_instance_done(service_id_t service_id)
+{
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = service_id
 	};
 	/*
@@ -270,8 +270,8 @@
 }
 
-int tmpfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
-{
-	unsigned long key[] = {
-		[NODES_KEY_DEV] = devmap_handle,
+int tmpfs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
+{
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = service_id,
 		[NODES_KEY_INDEX] = index
 	};
@@ -299,5 +299,5 @@
 }
 
-int tmpfs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int lflag)
+int tmpfs_create_node(fs_node_t **rfn, service_id_t service_id, int lflag)
 {
 	fs_node_t *rootfn;
@@ -318,5 +318,5 @@
 	nodep->bp->data = nodep;	/* link the FS and TMPFS nodes */
 
-	rc = tmpfs_root_get(&rootfn, devmap_handle);
+	rc = tmpfs_root_get(&rootfn, service_id);
 	assert(rc == EOK);
 	if (!rootfn)
@@ -324,5 +324,5 @@
 	else
 		nodep->index = tmpfs_next_index++;
-	nodep->devmap_handle = devmap_handle;
+	nodep->service_id = service_id;
 	if (lflag & L_DIRECTORY) 
 		nodep->type = TMPFS_DIRECTORY;
@@ -332,5 +332,5 @@
 	/* Insert the new node into the nodes hash table. */
 	unsigned long key[] = {
-		[NODES_KEY_DEV] = nodep->devmap_handle,
+		[NODES_KEY_DEV] = nodep->service_id,
 		[NODES_KEY_INDEX] = nodep->index
 	};
@@ -348,5 +348,5 @@
 
 	unsigned long key[] = {
-		[NODES_KEY_DEV] = nodep->devmap_handle,
+		[NODES_KEY_DEV] = nodep->service_id,
 		[NODES_KEY_INDEX] = nodep->index
 	};
@@ -432,5 +432,5 @@
 
 static int
-tmpfs_mounted(devmap_handle_t devmap_handle, const char *opts,
+tmpfs_mounted(service_id_t service_id, const char *opts,
     fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
 {
@@ -439,5 +439,5 @@
 	
 	/* Check if this device is not already mounted. */
-	rc = tmpfs_root_get(&rootfn, devmap_handle);
+	rc = tmpfs_root_get(&rootfn, service_id);
 	if ((rc == EOK) && (rootfn)) {
 		(void) tmpfs_node_put(rootfn);
@@ -446,12 +446,12 @@
 
 	/* Initialize TMPFS instance. */
-	if (!tmpfs_instance_init(devmap_handle))
+	if (!tmpfs_instance_init(service_id))
 		return ENOMEM;
 
-	rc = tmpfs_root_get(&rootfn, devmap_handle);
+	rc = tmpfs_root_get(&rootfn, service_id);
 	assert(rc == EOK);
 	tmpfs_node_t *rootp = TMPFS_NODE(rootfn);
 	if (str_cmp(opts, "restore") == 0) {
-		if (!tmpfs_restore(devmap_handle))
+		if (!tmpfs_restore(service_id))
 			return ELIMIT;
 	}
@@ -464,11 +464,11 @@
 }
 
-static int tmpfs_unmounted(devmap_handle_t devmap_handle)
-{
-	tmpfs_instance_done(devmap_handle);
-	return EOK;
-}
-
-static int tmpfs_read(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+static int tmpfs_unmounted(service_id_t service_id)
+{
+	tmpfs_instance_done(service_id);
+	return EOK;
+}
+
+static int tmpfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
     size_t *rbytes)
 {
@@ -478,5 +478,5 @@
 	link_t *hlp;
 	unsigned long key[] = {
-		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_DEV] = service_id,
 		[NODES_KEY_INDEX] = index
 	};
@@ -532,5 +532,5 @@
 
 static int
-tmpfs_write(devmap_handle_t devmap_handle, fs_index_t index, aoff64_t pos,
+tmpfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
     size_t *wbytes, aoff64_t *nsize)
 {
@@ -540,5 +540,5 @@
 	link_t *hlp;
 	unsigned long key[] = {
-		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_DEV] = service_id,
 		[NODES_KEY_INDEX] = index
 	};
@@ -594,5 +594,5 @@
 }
 
-static int tmpfs_truncate(devmap_handle_t devmap_handle, fs_index_t index,
+static int tmpfs_truncate(service_id_t service_id, fs_index_t index,
     aoff64_t size)
 {
@@ -601,5 +601,5 @@
 	 */
 	unsigned long key[] = {
-		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_DEV] = service_id,
 		[NODES_KEY_INDEX] = index
 	};
@@ -629,14 +629,14 @@
 }
 
-static int tmpfs_close(devmap_handle_t devmap_handle, fs_index_t index)
-{
-	return EOK;
-}
-
-static int tmpfs_destroy(devmap_handle_t devmap_handle, fs_index_t index)
+static int tmpfs_close(service_id_t service_id, fs_index_t index)
+{
+	return EOK;
+}
+
+static int tmpfs_destroy(service_id_t service_id, fs_index_t index)
 {
 	link_t *hlp;
 	unsigned long key[] = {
-		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_DEV] = service_id,
 		[NODES_KEY_INDEX] = index
 	};
@@ -649,5 +649,5 @@
 }
 
-static int tmpfs_sync(devmap_handle_t devmap_handle, fs_index_t index)
+static int tmpfs_sync(service_id_t service_id, fs_index_t index)
 {
 	/*
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/console/console.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -53,5 +53,5 @@
 #include <sysinfo.h>
 #include <event.h>
-#include <devmap.h>
+#include <loc.h>
 #include <fcntl.h>
 #include <vfs/vfs.h>
@@ -81,5 +81,5 @@
 	size_t index;             /**< Console index */
 	size_t refcount;          /**< Connection reference count */
-	devmap_handle_t devmap_handle;  /**< Device handle */
+	service_id_t service_id;  /**< Service ID */
 	keybuffer_t keybuffer;    /**< Buffer for incoming keys. */
 	screenbuffer_t scr;       /**< Screenbuffer for saving screen
@@ -582,5 +582,5 @@
 			continue;
 		
-		if (consoles[i].devmap_handle == (devmap_handle_t) IPC_GET_ARG1(*icall)) {
+		if (consoles[i].service_id == (service_id_t) IPC_GET_ARG1(*icall)) {
 			cons = &consoles[i];
 			break;
@@ -721,13 +721,13 @@
 }
 
-static async_sess_t *connect_input(const char *dev_path)
+static async_sess_t *connect_input(const char *svc_path)
 {
 	async_sess_t *sess;
 	async_exch_t *exch;
-	devmap_handle_t handle;
-	
-	int rc = devmap_device_get_handle(dev_path, &handle, 0);
+	service_id_t service_id;
+	
+	int rc = loc_service_get_id(svc_path, &service_id, 0);
 	if (rc == EOK) {
-		sess = devmap_device_connect(EXCHANGE_ATOMIC, handle, 0);
+		sess = loc_service_connect(EXCHANGE_ATOMIC, service_id, 0);
 		if (sess == NULL) {
 			printf("%s: Failed to connect to input server\n", NAME);
@@ -773,8 +773,8 @@
 	}
 	
-	/* Register driver */
-	int rc = devmap_driver_register(NAME, client_connection);
+	/* Register server */
+	int rc = loc_server_register(NAME, client_connection);
 	if (rc < 0) {
-		printf("%s: Unable to register driver (%d)\n", NAME, rc);
+		printf("%s: Unable to register server (%d)\n", NAME, rc);
 		return false;
 	}
@@ -820,9 +820,9 @@
 			consoles[i].refcount = 0;
 			
-			char vc[DEVMAP_NAME_MAXLEN + 1];
-			snprintf(vc, DEVMAP_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
+			char vc[LOC_NAME_MAXLEN + 1];
+			snprintf(vc, LOC_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
 			
-			if (devmap_device_register(vc, &consoles[i].devmap_handle) != EOK) {
-				printf("%s: Unable to register device %s\n", NAME, vc);
+			if (loc_service_register(vc, &consoles[i].service_id) != EOK) {
+				printf("%s: Unable to register service %s\n", NAME, vc);
 				return false;
 			}
Index: uspace/srv/hid/input/ctl/kbdev.c
===================================================================
--- uspace/srv/hid/input/ctl/kbdev.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/input/ctl/kbdev.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -48,7 +48,8 @@
 #include <kbd_ctl.h>
 #include <kbd_port.h>
+#include <loc.h>
 #include <stdlib.h>
 #include <vfs/vfs_sess.h>
-
+#include <sys/typefmt.h>
 
 static int kbdev_ctl_init(kbd_dev_t *);
@@ -70,7 +71,4 @@
 	/** Session with kbdev device */
 	async_sess_t *sess;
-
-	/** File descriptor of open kbdev device */
-	int fd;
 } kbdev_t;
 
@@ -84,5 +82,4 @@
 
 	kbdev->kbd_dev = kdev;
-	kbdev->fd = -1;
 
 	return kbdev;
@@ -93,6 +90,4 @@
 	if (kbdev->sess != NULL)
 		async_hangup(kbdev->sess);
-	if (kbdev->fd >= 0)
-		close(kbdev->fd);
 	free(kbdev);
 }
@@ -100,22 +95,13 @@
 static int kbdev_ctl_init(kbd_dev_t *kdev)
 {
-	const char *pathname;
 	async_sess_t *sess;
 	async_exch_t *exch;
 	kbdev_t *kbdev;
-	int fd;
 	int rc;
 
-	pathname = kdev->dev_path;
-
-	fd = open(pathname, O_RDWR);
-	if (fd < 0) {
-		return -1;
-	}
-
-	sess = fd_session(EXCHANGE_SERIALIZE, fd);
+	sess = loc_service_connect(EXCHANGE_SERIALIZE, kdev->svc_id, 0);
 	if (sess == NULL) {
-		printf("%s: Failed starting session with '%s'\n", NAME, pathname);
-		close(fd);
+		printf("%s: Failed starting session with '%s.'\n", NAME,
+		    kdev->svc_name);
 		return -1;
 	}
@@ -124,14 +110,14 @@
 	if (kbdev == NULL) {
 		printf("%s: Failed allocating device structure for '%s'.\n",
-		    NAME, pathname);
+		    NAME, kdev->svc_name);
 		return -1;
 	}
 
-	kbdev->fd = fd;
 	kbdev->sess = sess;
 
 	exch = async_exchange_begin(sess);
 	if (exch == NULL) {
-		printf("%s: Failed starting exchange with '%s'.\n", NAME, pathname);
+		printf("%s: Failed starting exchange with '%s'.\n", NAME,
+		    kdev->svc_name);
 		kbdev_destroy(kbdev);
 		return -1;
@@ -141,5 +127,5 @@
 	if (rc != EOK) {
 		printf("%s: Failed creating callback connection from '%s'.\n",
-		    NAME, pathname);
+		    NAME, kdev->svc_name);
 		async_exchange_end(exch);
 		kbdev_destroy(kbdev);
Index: uspace/srv/hid/input/generic/input.c
===================================================================
--- uspace/srv/hid/input/generic/input.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/input/generic/input.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -38,4 +38,5 @@
 
 #include <adt/list.h>
+#include <bool.h>
 #include <ipc/services.h>
 #include <ipc/input.h>
@@ -53,5 +54,5 @@
 #include <io/console.h>
 #include <io/keycode.h>
-#include <devmap.h>
+#include <loc.h>
 #include <input.h>
 #include <kbd.h>
@@ -64,7 +65,4 @@
 // FIXME: remove this header
 #include <abi/ipc/methods.h>
-
-/* In microseconds */
-#define DISCOVERY_POLL_INTERVAL  (10 * 1000 * 1000)
 
 #define NUM_LAYOUTS  3
@@ -275,5 +273,5 @@
 	kdev->port_ops = port;
 	kdev->ctl_ops = ctl;
-	kdev->dev_path = NULL;
+	kdev->svc_id = 0;
 	
 	/* Initialize port driver. */
@@ -303,5 +301,5 @@
 	mdev->port_ops = port;
 	mdev->proto_ops = proto;
-	mdev->dev_path = NULL;
+	mdev->svc_id = 0;
 	
 	/* Initialize port driver. */
@@ -324,8 +322,8 @@
 /** Add new kbdev device.
  *
- * @param dev_path Filesystem path to the device (/dev/class/...)
+ * @param service_id	Service ID of the keyboard device
  *
  */
-static int kbd_add_kbdev(const char *dev_path)
+static int kbd_add_kbdev(service_id_t service_id, kbd_dev_t **kdevp)
 {
 	kbd_dev_t *kdev = kbd_dev_new();
@@ -333,8 +331,14 @@
 		return -1;
 	
-	kdev->dev_path = dev_path;
+	kdev->svc_id = service_id;
 	kdev->port_ops = NULL;
 	kdev->ctl_ops = &kbdev_ctl;
 	
+	int rc = loc_service_get_name(service_id, &kdev->svc_name);
+	if (rc != EOK) {
+		kdev->svc_name = NULL;
+		goto fail;
+	}
+	
 	/* Initialize controller driver. */
 	if ((*kdev->ctl_ops->init)(kdev) != 0) {
@@ -343,7 +347,10 @@
 	
 	list_append(&kdev->kbd_devs, &kbd_devs);
+	*kdevp = kdev;
 	return EOK;
 	
 fail:
+	if (kdev->svc_name != NULL)
+		free(kdev->svc_name);
 	free(kdev);
 	return -1;
@@ -352,8 +359,8 @@
 /** Add new mousedev device.
  *
- * @param dev_path Filesystem path to the device (/dev/class/...)
+ * @param service_id	Service ID of the mouse device
  *
  */
-static int mouse_add_mousedev(const char *dev_path)
+static int mouse_add_mousedev(service_id_t service_id, mouse_dev_t **mdevp)
 {
 	mouse_dev_t *mdev = mouse_dev_new();
@@ -361,8 +368,14 @@
 		return -1;
 	
-	mdev->dev_path = dev_path;
+	mdev->svc_id = service_id;
 	mdev->port_ops = NULL;
 	mdev->proto_ops = &mousedev_proto;
 	
+	int rc = loc_service_get_name(service_id, &mdev->svc_name);
+	if (rc != EOK) {
+		mdev->svc_name = NULL;
+		goto fail;
+	}
+	
 	/* Initialize controller driver. */
 	if ((*mdev->proto_ops->init)(mdev) != 0) {
@@ -371,4 +384,5 @@
 	
 	list_append(&mdev->mouse_devs, &mouse_devs);
+	*mdevp = mdev;
 	return EOK;
 	
@@ -480,70 +494,143 @@
 }
 
-/** Periodically check for new input devices.
- *
- * Looks under /dev/class/keyboard and /dev/class/mouse.
- *
- * @param arg Ignored
- *
- */
-static int dev_discovery_fibril(void *arg)
-{
-	char *dev_path;
-	size_t kbd_id = 1;
-	size_t mouse_id = 1;
+static int dev_check_new_kbdevs(void)
+{
+	category_id_t keyboard_cat;
+	service_id_t *svcs;
+	size_t count, i;
+	bool already_known;
 	int rc;
 	
-	while (true) {
-		async_usleep(DISCOVERY_POLL_INTERVAL);
-		
-		/*
-		 * Check for new keyboard device
-		 */
-		rc = asprintf(&dev_path, "/dev/class/keyboard\\%zu", kbd_id);
-		if (rc < 0)
-			continue;
-		
-		if (kbd_add_kbdev(dev_path) == EOK) {
-			printf("%s: Connected keyboard device '%s'\n",
-			    NAME, dev_path);
-			
-			/* XXX Handle device removal */
-			++kbd_id;
+	rc = loc_category_get_id("keyboard", &keyboard_cat, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		printf("%s: Failed resolving category 'keyboard'.\n", NAME);
+		return ENOENT;
+	}
+	
+	/*
+	 * Check for new keyboard devices
+	 */
+	rc = loc_category_get_svcs(keyboard_cat, &svcs, &count);
+	if (rc != EOK) {
+		printf("%s: Failed getting list of keyboard devices.\n",
+		    NAME);
+		return EIO;
+	}
+
+	for (i = 0; i < count; i++) {
+		already_known = false;
+		
+		/* Determine whether we already know this device. */
+		list_foreach(kbd_devs, kdev_link) {
+			kbd_dev_t *kdev = list_get_instance(kdev_link,
+			    kbd_dev_t, kbd_devs);
+			if (kdev->svc_id == svcs[i]) {
+				already_known = true;
+				break;
+			}
 		}
 		
-		free(dev_path);
-		
-		/*
-		 * Check for new mouse device
-		 */
-		rc = asprintf(&dev_path, "/dev/class/mouse\\%zu", mouse_id);
-		if (rc < 0)
-			continue;
-		
-		if (mouse_add_mousedev(dev_path) == EOK) {
-			printf("%s: Connected mouse device '%s'\n",
-			    NAME, dev_path);
-			
-			/* XXX Handle device removal */
-			++mouse_id;
+		if (!already_known) {
+			kbd_dev_t *kdev;
+			if (kbd_add_kbdev(svcs[i], &kdev) == EOK) {
+				printf("%s: Connected keyboard device '%s'\n",
+				    NAME, kdev->svc_name);
+			}
 		}
-		
-		free(dev_path);
-	}
+	}
+	
+	free(svcs);
+	
+	/* XXX Handle device removal */
 	
 	return EOK;
 }
 
-/** Start a fibril for discovering new devices. */
-static void input_start_dev_discovery(void)
-{
-	fid_t fid = fibril_create(dev_discovery_fibril, NULL);
-	if (!fid) {
-		printf("%s: Failed to create device discovery fibril.\n",
+static int dev_check_new_mousedevs(void)
+{
+	category_id_t mouse_cat;
+	service_id_t *svcs;
+	size_t count, i;
+	bool already_known;
+	int rc;
+	
+	rc = loc_category_get_id("mouse", &mouse_cat, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		printf("%s: Failed resolving category 'mouse'.\n", NAME);
+		return ENOENT;
+	}
+	
+	/*
+	 * Check for new mouse devices
+	 */
+	rc = loc_category_get_svcs(mouse_cat, &svcs, &count);
+	if (rc != EOK) {
+		printf("%s: Failed getting list of mouse devices.\n",
 		    NAME);
-		return;
-	}
-	
-	fibril_add_ready(fid);
+		return EIO;
+	}
+	
+	for (i = 0; i < count; i++) {
+		already_known = false;
+		
+		/* Determine whether we already know this device. */
+		list_foreach(mouse_devs, mdev_link) {
+			mouse_dev_t *mdev = list_get_instance(mdev_link,
+			    mouse_dev_t, mouse_devs);
+			if (mdev->svc_id == svcs[i]) {
+				already_known = true;
+				break;
+			}
+		}
+		
+		if (!already_known) {
+			mouse_dev_t *mdev;
+			if (mouse_add_mousedev(svcs[i], &mdev) == EOK) {
+				printf("%s: Connected mouse device '%s'\n",
+				    NAME, mdev->svc_name);
+			}
+		}
+	}
+	
+	free(svcs);
+	
+	/* XXX Handle device removal */
+	
+	return EOK;
+}
+
+static int dev_check_new(void)
+{
+	int rc;
+	
+	rc = dev_check_new_kbdevs();
+	if (rc != EOK)
+		return rc;
+	
+	rc = dev_check_new_mousedevs();
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
+}
+
+static void cat_change_cb(void)
+{
+	dev_check_new();
+}
+
+/** Start listening for new devices. */
+static int input_start_dev_discovery(void)
+{
+	int rc;
+
+	rc = loc_register_cat_change_cb(cat_change_cb);
+	if (rc != EOK) {
+		printf("%s: Failed registering callback for device discovery. "
+		    "(%d)\n", NAME, rc);
+		return rc;
+	}
+
+	return dev_check_new();
 }
 
@@ -572,16 +659,16 @@
 	
 	/* Register driver */
-	int rc = devmap_driver_register(NAME, client_connection);
+	int rc = loc_server_register(NAME, client_connection);
 	if (rc < 0) {
-		printf("%s: Unable to register driver (%d)\n", NAME, rc);
+		printf("%s: Unable to register server (%d)\n", NAME, rc);
 		return -1;
 	}
 	
-	char kbd[DEVMAP_NAME_MAXLEN + 1];
-	snprintf(kbd, DEVMAP_NAME_MAXLEN, "%s/%s", NAMESPACE, NAME);
-	
-	devmap_handle_t devmap_handle;
-	if (devmap_device_register(kbd, &devmap_handle) != EOK) {
-		printf("%s: Unable to register device %s\n", NAME, kbd);
+	char kbd[LOC_NAME_MAXLEN + 1];
+	snprintf(kbd, LOC_NAME_MAXLEN, "%s/%s", NAMESPACE, NAME);
+	
+	service_id_t service_id;
+	if (loc_service_register(kbd, &service_id) != EOK) {
+		printf("%s: Unable to register service %s\n", NAME, kbd);
 		return -1;
 	}
Index: uspace/srv/hid/input/include/kbd.h
===================================================================
--- uspace/srv/hid/input/include/kbd.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/input/include/kbd.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -40,4 +40,5 @@
 
 #include <adt/list.h>
+#include <ipc/loc.h>
 
 struct kbd_port_ops;
@@ -49,6 +50,9 @@
 	link_t kbd_devs;
 
-	/** Path to the device (only for kbdev devices) */
-	const char *dev_path;
+	/** Service ID (only for kbdev devices) */
+	service_id_t svc_id;
+
+	/** Device service name (only for kbdev devices) */
+	char *svc_name;
 
 	/** Port ops */
Index: uspace/srv/hid/input/include/mouse.h
===================================================================
--- uspace/srv/hid/input/include/mouse.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/input/include/mouse.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -39,4 +39,5 @@
 
 #include <adt/list.h>
+#include <ipc/loc.h>
 
 struct mouse_port_ops;
@@ -47,6 +48,9 @@
 	link_t mouse_devs;
 	
-	/** Path to the device (only for mouseev devices) */
-	const char *dev_path;
+	/** Service ID (only for mousedev devices) */
+	service_id_t svc_id;
+	
+	/** Device service name (only for mousedev devices) */
+	char *svc_name;
 	
 	/** Port ops */
Index: uspace/srv/hid/input/port/adb.c
===================================================================
--- uspace/srv/hid/input/port/adb.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/input/port/adb.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -43,5 +43,5 @@
 #include <fcntl.h>
 #include <errno.h>
-#include <devmap.h>
+#include <loc.h>
 
 static void kbd_port_events(ipc_callid_t iid, ipc_call_t *icall, void *arg);
@@ -66,5 +66,5 @@
 {
 	const char *dev = "adb/kbd";
-	devmap_handle_t handle;
+	service_id_t service_id;
 	async_exch_t *exch;
 	int rc;
@@ -72,9 +72,9 @@
 	kbd_dev = kdev;
 	
-	rc = devmap_device_get_handle(dev, &handle, 0);
+	rc = loc_service_get_id(dev, &service_id, 0);
 	if (rc != EOK)
 		return rc;
 	
-	dev_sess = devmap_device_connect(EXCHANGE_ATOMIC, handle, 0);
+	dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id, 0);
 	if (dev_sess == NULL) {
 		printf("%s: Failed to connect to device\n", NAME);
Index: uspace/srv/hid/input/port/adb_mouse.c
===================================================================
--- uspace/srv/hid/input/port/adb_mouse.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/input/port/adb_mouse.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -41,5 +41,5 @@
 #include <mouse.h>
 #include <errno.h>
-#include <devmap.h>
+#include <loc.h>
 #include <stdio.h>
 
@@ -79,10 +79,10 @@
 	mouse_dev = mdev;
 	
-	devmap_handle_t handle;
-	int rc = devmap_device_get_handle(dev, &handle, 0);
+	service_id_t service_id;
+	int rc = loc_service_get_id(dev, &service_id, 0);
 	if (rc != EOK)
 		return rc;
 	
-	dev_sess = devmap_device_connect(EXCHANGE_ATOMIC, handle, 0);
+	dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id, 0);
 	if (dev_sess == NULL) {
 		printf("%s: Failed to connect to device\n", NAME);
Index: uspace/srv/hid/input/port/chardev.c
===================================================================
--- uspace/srv/hid/input/port/chardev.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/input/port/chardev.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -40,5 +40,5 @@
 #include <kbd_port.h>
 #include <kbd.h>
-#include <devmap.h>
+#include <loc.h>
 #include <errno.h>
 #include <stdio.h>
@@ -71,5 +71,5 @@
 static int chardev_port_init(kbd_dev_t *kdev)
 {
-	devmap_handle_t handle;
+	service_id_t service_id;
 	async_exch_t *exch;
 	unsigned int i;
@@ -79,5 +79,5 @@
 	
 	for (i = 0; i < num_devs; i++) {
-		rc = devmap_device_get_handle(in_devs[i], &handle, 0);
+		rc = loc_service_get_id(in_devs[i], &service_id, 0);
 		if (rc == EOK)
 			break;
@@ -89,5 +89,5 @@
 	}
 	
-	dev_sess = devmap_device_connect(EXCHANGE_ATOMIC, handle,
+	dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id,
 	    IPC_FLAG_BLOCKING);
 	if (dev_sess == NULL) {
Index: uspace/srv/hid/input/port/chardev_mouse.c
===================================================================
--- uspace/srv/hid/input/port/chardev_mouse.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/input/port/chardev_mouse.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -39,5 +39,5 @@
 #include <async.h>
 #include <errno.h>
-#include <devmap.h>
+#include <loc.h>
 #include <input.h>
 #include <mouse_port.h>
@@ -82,5 +82,5 @@
 static int chardev_port_init(mouse_dev_t *mdev)
 {
-	devmap_handle_t handle;
+	service_id_t service_id;
 	unsigned int i;
 	int rc;
@@ -89,5 +89,5 @@
 	
 	for (i = 0; i < num_devs; i++) {
-		rc = devmap_device_get_handle(in_devs[i], &handle, 0);
+		rc = loc_service_get_id(in_devs[i], &service_id, 0);
 		if (rc == EOK)
 			break;
@@ -99,5 +99,5 @@
 	}
 	
-	dev_sess = devmap_device_connect(EXCHANGE_ATOMIC, handle,
+	dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id,
 	    IPC_FLAG_BLOCKING);
 	if (dev_sess == NULL) {
Index: uspace/srv/hid/input/proto/mousedev.c
===================================================================
--- uspace/srv/hid/input/proto/mousedev.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/input/proto/mousedev.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -44,7 +44,9 @@
 #include <ipc/mouseev.h>
 #include <input.h>
+#include <loc.h>
 #include <mouse.h>
 #include <mouse_port.h>
 #include <mouse_proto.h>
+#include <sys/typefmt.h>
 
 /** Mousedev softstate */
@@ -55,7 +57,4 @@
 	/** Session to mouse device */
 	async_sess_t *sess;
-	
-	/** File descriptor of open mousedev device */
-	int fd;
 } mousedev_t;
 
@@ -67,5 +66,4 @@
 	
 	mousedev->mouse_dev = mdev;
-	mousedev->fd = -1;
 	
 	return mousedev;
@@ -76,7 +74,4 @@
 	if (mousedev->sess != NULL)
 		async_hangup(mousedev->sess);
-	
-	if (mousedev->fd >= 0)
-		close(mousedev->fd);
 	
 	free(mousedev);
@@ -122,14 +117,9 @@
 static int mousedev_proto_init(mouse_dev_t *mdev)
 {
-	const char *pathname = mdev->dev_path;
-	
-	int fd = open(pathname, O_RDWR);
-	if (fd < 0)
-		return -1;
-	
-	async_sess_t *sess = fd_session(EXCHANGE_SERIALIZE, fd);
+	async_sess_t *sess = loc_service_connect(EXCHANGE_SERIALIZE,
+	    mdev->svc_id, 0);
 	if (sess == NULL) {
-		printf("%s: Failed starting session with '%s'\n", NAME, pathname);
-		close(fd);
+		printf("%s: Failed starting session with '%s'\n", NAME,
+		    mdev->svc_name);
 		return -1;
 	}
@@ -138,14 +128,14 @@
 	if (mousedev == NULL) {
 		printf("%s: Failed allocating device structure for '%s'.\n",
-		    NAME, pathname);
+		    NAME, mdev->svc_name);
 		return -1;
 	}
 	
-	mousedev->fd = fd;
 	mousedev->sess = sess;
 	
 	async_exch_t *exch = async_exchange_begin(sess);
 	if (exch == NULL) {
-		printf("%s: Failed starting exchange with '%s'.\n", NAME, pathname);
+		printf("%s: Failed starting exchange with '%s'.\n", NAME,
+		    mdev->svc_name);
 		mousedev_destroy(mousedev);
 		return -1;
@@ -157,5 +147,5 @@
 	if (rc != EOK) {
 		printf("%s: Failed creating callback connection from '%s'.\n",
-		    NAME, pathname);
+		    NAME, mdev->svc_name);
 		mousedev_destroy(mousedev);
 		return -1;
Index: uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c
===================================================================
--- uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -39,5 +39,5 @@
 #include <ddi.h>
 #include <libarch/ddi.h>
-#include <devmap.h>
+#include <loc.h>
 #include <io/console.h>
 #include <vfs/vfs.h>
@@ -90,5 +90,5 @@
 	printf(NAME ": S3C24xx touchscreen driver\n");
 
-	rc = devmap_driver_register(NAME, s3c24xx_ts_connection);
+	rc = loc_server_register(NAME, s3c24xx_ts_connection);
 	if (rc < 0) {
 		printf(NAME ": Unable to register driver.\n");
@@ -103,5 +103,5 @@
 		return -1;
 
-	rc = devmap_device_register(NAMESPACE "/mouse", &ts->devmap_handle);
+	rc = loc_service_register(NAMESPACE "/mouse", &ts->service_id);
 	if (rc != EOK) {
 		printf(NAME ": Unable to register device %s.\n",
Index: uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.h
===================================================================
--- uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hid/s3c24xx_ts/s3c24xx_ts.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -124,6 +124,6 @@
 	int client_phone;
 
-	/** Device handle */
-	devmap_handle_t devmap_handle;
+	/** Service ID */
+	service_id_t service_id;
 
 	/** Device/driver state */
Index: uspace/srv/hw/bus/cuda_adb/cuda_adb.c
===================================================================
--- uspace/srv/hw/bus/cuda_adb/cuda_adb.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hw/bus/cuda_adb/cuda_adb.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -43,5 +43,5 @@
 #include <ddi.h>
 #include <libarch/ddi.h>
-#include <devmap.h>
+#include <loc.h>
 #include <sysinfo.h>
 #include <errno.h>
@@ -147,5 +147,5 @@
 int main(int argc, char *argv[])
 {
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 	int rc;
 	int i;
@@ -155,29 +155,29 @@
 	for (i = 0; i < ADB_MAX_ADDR; ++i) {
 		adb_dev[i].client_phone = -1;
-		adb_dev[i].devmap_handle = 0;
-	}
-
-	rc = devmap_driver_register(NAME, cuda_connection);
+		adb_dev[i].service_id = 0;
+	}
+
+	rc = loc_server_register(NAME, cuda_connection);
 	if (rc < 0) {
-		printf(NAME ": Unable to register driver.\n");
+		printf(NAME ": Unable to register server.\n");
 		return rc;
 	}
 
-	rc = devmap_device_register("adb/kbd", &devmap_handle);
+	rc = loc_service_register("adb/kbd", &service_id);
 	if (rc != EOK) {
-		printf(NAME ": Unable to register device %s.\n", "adb/kdb");
+		printf(NAME ": Unable to register service %s.\n", "adb/kdb");
 		return rc;
 	}
 
-	adb_dev[2].devmap_handle = devmap_handle;
-	adb_dev[8].devmap_handle = devmap_handle;
-
-	rc = devmap_device_register("adb/mouse", &devmap_handle);
+	adb_dev[2].service_id = service_id;
+	adb_dev[8].service_id = service_id;
+
+	rc = loc_service_register("adb/mouse", &service_id);
 	if (rc != EOK) {
-		printf(NAME ": Unable to register device %s.\n", "adb/mouse");
+		printf(NAME ": Unable to register servise %s.\n", "adb/mouse");
 		return rc;
 	}
 
-	adb_dev[9].devmap_handle = devmap_handle;
+	adb_dev[9].service_id = service_id;
 
 	if (cuda_init() < 0) {
@@ -198,15 +198,15 @@
 	ipc_call_t call;
 	sysarg_t method;
-	devmap_handle_t dh;
+	service_id_t dsid;
 	int retval;
 	int dev_addr, i;
 
 	/* Get the device handle. */
-	dh = IPC_GET_ARG1(*icall);
+	dsid = IPC_GET_ARG1(*icall);
 
 	/* Determine which disk device is the client connecting to. */
 	dev_addr = -1;
 	for (i = 0; i < ADB_MAX_ADDR; i++) {
-		if (adb_dev[i].devmap_handle == dh)
+		if (adb_dev[i].service_id == dsid)
 			dev_addr = i;
 	}
@@ -242,5 +242,5 @@
 			 */
 			for (i = 0; i < ADB_MAX_ADDR; ++i) {
-				if (adb_dev[i].devmap_handle == dh) {
+				if (adb_dev[i].service_id == dsid) {
 					adb_dev[i].client_phone = IPC_GET_ARG5(call);
 				}
Index: uspace/srv/hw/bus/cuda_adb/cuda_adb.h
===================================================================
--- uspace/srv/hw/bus/cuda_adb/cuda_adb.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hw/bus/cuda_adb/cuda_adb.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -38,5 +38,5 @@
 
 #include <sys/types.h>
-#include <ipc/devmap.h>
+#include <ipc/loc.h>
 #include <fibril_synch.h>
 
@@ -104,5 +104,5 @@
 
 typedef struct {
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 	int client_phone;
 } adb_dev_t;
Index: uspace/srv/hw/char/i8042/i8042.c
===================================================================
--- uspace/srv/hw/char/i8042/i8042.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hw/char/i8042/i8042.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -39,5 +39,5 @@
 #include <ddi.h>
 #include <libarch/ddi.h>
-#include <devmap.h>
+#include <loc.h>
 #include <async.h>
 #include <async_obsolete.h>
@@ -135,7 +135,7 @@
 	printf(NAME ": i8042 PS/2 port driver\n");
 
-	rc = devmap_driver_register(NAME, i8042_connection);
+	rc = loc_server_register(NAME, i8042_connection);
 	if (rc < 0) {
-		printf(NAME ": Unable to register driver.\n");
+		printf(NAME ": Unable to register server.\n");
 		return rc;
 	}
@@ -148,5 +148,5 @@
 
 		snprintf(name, 16, "%s/ps2%c", NAMESPACE, dchar[i]);
-		rc = devmap_device_register(name, &i8042_port[i].devmap_handle);
+		rc = loc_service_register(name, &i8042_port[i].service_id);
 		if (rc != EOK) {
 			printf(NAME ": Unable to register device %s.\n", name);
@@ -221,5 +221,5 @@
 	ipc_call_t call;
 	sysarg_t method;
-	devmap_handle_t dh;
+	service_id_t dsid;
 	int retval;
 	int dev_id, i;
@@ -228,10 +228,10 @@
 
 	/* Get the device handle. */
-	dh = IPC_GET_ARG1(*icall);
+	dsid = IPC_GET_ARG1(*icall);
 
 	/* Determine which disk device is the client connecting to. */
 	dev_id = -1;
 	for (i = 0; i < MAX_DEVS; i++) {
-		if (i8042_port[i].devmap_handle == dh)
+		if (i8042_port[i].service_id == dsid)
 			dev_id = i;
 	}
Index: uspace/srv/hw/char/i8042/i8042.h
===================================================================
--- uspace/srv/hw/char/i8042/i8042.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hw/char/i8042/i8042.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -52,5 +52,5 @@
 /** Softstate structure, one for each serial port (primary and aux). */
 typedef struct {
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 	int client_phone;
 } i8042_port_t;
Index: uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c
===================================================================
--- uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -39,5 +39,5 @@
 #include <ddi.h>
 #include <libarch/ddi.h>
-#include <devmap.h>
+#include <loc.h>
 #include <ipc/char.h>
 #include <async.h>
@@ -83,7 +83,7 @@
 	printf(NAME ": S3C24xx on-chip UART driver\n");
 
-	rc = devmap_driver_register(NAME, s3c24xx_uart_connection);
+	rc = loc_server_register(NAME, s3c24xx_uart_connection);
 	if (rc < 0) {
-		printf(NAME ": Unable to register driver.\n");
+		printf(NAME ": Unable to register server.\n");
 		return -1;
 	}
@@ -96,5 +96,5 @@
 		return -1;
 
-	rc = devmap_device_register(NAMESPACE "/" NAME, &uart->devmap_handle);
+	rc = loc_service_register(NAMESPACE "/" NAME, &uart->service_id);
 	if (rc != EOK) {
 		printf(NAME ": Unable to register device %s.\n",
Index: uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.h
===================================================================
--- uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -87,6 +87,6 @@
 	int client_phone;
 
-	/** Device handle */
-	devmap_handle_t devmap_handle;
+	/** Service ID */
+	service_id_t service_id;
 } s3c24xx_uart_t;
 
Index: uspace/srv/hw/irc/i8259/i8259.c
===================================================================
--- uspace/srv/hw/irc/i8259/i8259.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hw/irc/i8259/i8259.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -50,5 +50,5 @@
 #include <async.h>
 #include <stdio.h>
-#include <ipc/devmap.h>
+#include <ipc/loc.h>
 
 #define NAME  "i8259"
Index: uspace/srv/hw/irc/obio/obio.c
===================================================================
--- uspace/srv/hw/irc/obio/obio.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/hw/irc/obio/obio.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -55,5 +55,5 @@
 #include <async.h>
 #include <stdio.h>
-#include <ipc/devmap.h>
+#include <ipc/loc.h>
 
 #define NAME "obio"
Index: uspace/srv/loc/Makefile
===================================================================
--- uspace/srv/loc/Makefile	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/srv/loc/Makefile	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,38 @@
+#
+# 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 = ../..
+BINARY = loc
+STATIC_NEEDED = y
+
+SOURCES = \
+	category.c \
+	loc.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/loc/category.c
===================================================================
--- uspace/srv/loc/category.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/srv/loc/category.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup loc
+ * @{
+ */
+/** @file Categories for location service.
+ */
+
+#include <adt/list.h>
+#include <errno.h>
+#include <fibril_synch.h>
+#include <stdlib.h>
+#include <str.h>
+
+#include "category.h"
+#include "loc.h"
+
+/** Initialize category directory. */
+void categ_dir_init(categ_dir_t *cdir)
+{
+	fibril_mutex_initialize(&cdir->mutex);
+	list_initialize(&cdir->categories);
+}
+
+/** Add new category to directory. */
+void categ_dir_add_cat(categ_dir_t *cdir, category_t *cat)
+{
+	list_append(&cat->cat_list, &cdir->categories);
+}
+
+/** Get list of categories. */
+int categ_dir_get_categories(categ_dir_t *cdir, category_id_t *id_buf,
+    size_t buf_size, size_t *act_size)
+{
+	size_t act_cnt;
+	size_t buf_cnt;
+
+	assert(fibril_mutex_is_locked(&cdir->mutex));
+
+	buf_cnt = buf_size / sizeof(category_id_t);
+
+	act_cnt = list_count(&cdir->categories);
+	*act_size = act_cnt * sizeof(category_id_t);
+
+	if (buf_size % sizeof(category_id_t) != 0)
+		return EINVAL;
+
+	size_t pos = 0;
+	list_foreach(cdir->categories, item) {
+		category_t *cat =
+		    list_get_instance(item, category_t, cat_list);
+
+		if (pos < buf_cnt)
+			id_buf[pos] = cat->id;
+		pos++;
+	}
+
+	return EOK;
+}
+
+
+/** Initialize category structure. */
+static void category_init(category_t *cat, const char *name)
+{
+	fibril_mutex_initialize(&cat->mutex);
+	cat->name = str_dup(name);
+	cat->id = loc_create_id();
+	link_initialize(&cat->cat_list);
+	list_initialize(&cat->svc_memb);
+}
+
+/** Allocate new category. */
+category_t *category_new(const char *name)
+{
+	category_t *cat;
+
+	cat = malloc(sizeof(category_t));
+	if (cat == NULL)
+		return NULL;
+
+	category_init(cat, name);
+	return cat;
+}
+
+/** Add service to category. */
+int category_add_service(category_t *cat, loc_service_t *svc)
+{
+	assert(fibril_mutex_is_locked(&cat->mutex));
+	assert(fibril_mutex_is_locked(&services_list_mutex));
+
+	/* Verify that category does not contain this service yet. */
+	list_foreach(cat->svc_memb, item) {
+		svc_categ_t *memb = list_get_instance(item, svc_categ_t,
+		    cat_link);
+		if (memb->svc == svc) {
+			return EEXIST;
+		}
+	}
+
+	svc_categ_t *nmemb = malloc(sizeof(svc_categ_t));
+	if (nmemb == NULL)
+		return ENOMEM;
+
+	nmemb->svc = svc;
+	nmemb->cat = cat;
+
+	list_append(&nmemb->cat_link, &cat->svc_memb);
+	list_append(&nmemb->svc_link, &svc->cat_memb);
+
+	return EOK;
+}
+
+/** Remove service from category. */
+void category_remove_service(svc_categ_t *memb)
+{
+	assert(fibril_mutex_is_locked(&memb->cat->mutex));
+	assert(fibril_mutex_is_locked(&services_list_mutex));
+
+	list_remove(&memb->cat_link);
+	list_remove(&memb->svc_link);
+
+	free(memb);
+}
+
+/** Get category by ID. */
+category_t *category_get(categ_dir_t *cdir, catid_t catid)
+{
+	assert(fibril_mutex_is_locked(&cdir->mutex));
+
+	list_foreach(cdir->categories, item) {
+		category_t *cat = list_get_instance(item, category_t,
+		    cat_list);
+		if (cat->id == catid)
+			return cat;
+	}
+
+	return NULL;
+}
+
+/** Find category by name. */
+category_t *category_find_by_name(categ_dir_t *cdir, const char *name)
+{
+	assert(fibril_mutex_is_locked(&cdir->mutex));
+
+	list_foreach(cdir->categories, item) {
+		category_t *cat = list_get_instance(item, category_t,
+		    cat_list);
+		if (str_cmp(cat->name, name) == 0)
+			return cat;
+	}
+
+	return NULL;
+}
+
+/** Get list of services in category. */
+int category_get_services(category_t *cat, service_id_t *id_buf,
+    size_t buf_size, size_t *act_size)
+{
+	size_t act_cnt;
+	size_t buf_cnt;
+
+	assert(fibril_mutex_is_locked(&cat->mutex));
+
+	buf_cnt = buf_size / sizeof(service_id_t);
+
+	act_cnt = list_count(&cat->svc_memb);
+	*act_size = act_cnt * sizeof(service_id_t);
+
+	if (buf_size % sizeof(service_id_t) != 0)
+		return EINVAL;
+
+	size_t pos = 0;
+	list_foreach(cat->svc_memb, item) {
+		svc_categ_t *memb =
+		    list_get_instance(item, svc_categ_t, cat_link);
+
+		if (pos < buf_cnt)
+			id_buf[pos] = memb->svc->id;
+		pos++;
+	}
+
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/loc/category.h
===================================================================
--- uspace/srv/loc/category.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/srv/loc/category.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup loc
+ * @{
+ */
+/** @file Categories for location service.
+ */
+
+#ifndef CATEGORY_H_
+#define CATEGORY_H_
+
+#include <adt/list.h>
+#include "loc.h"
+
+typedef sysarg_t catid_t;
+
+/** Service category */
+typedef struct {
+	/** Protects this structure, list of services */
+	fibril_mutex_t mutex;
+
+	/** Identifier */
+	catid_t id;
+
+	/** Category name */
+	const char *name;
+
+	/** Link to list of categories (categ_dir_t.categories) */
+	link_t cat_list;
+
+	/** List of service memberships in this category (svc_categ_t) */
+	list_t svc_memb;
+} category_t;
+
+/** Service directory ogranized by categories (yellow pages) */
+typedef struct {
+	/** Protects this structure, list of categories */
+	fibril_mutex_t mutex;
+	/** List of all categories (category_t) */
+	list_t categories;
+} categ_dir_t;
+
+/** Service in category membership. */
+typedef struct {
+	/** Link to category_t.svc_memb list */
+	link_t cat_link;
+	/** Link to loc_service_t.cat_memb list */
+	link_t svc_link;
+	
+	/** Category */
+	category_t *cat;
+	/** Service */
+	loc_service_t *svc;
+} svc_categ_t;
+
+extern void categ_dir_init(categ_dir_t *);
+extern void categ_dir_add_cat(categ_dir_t *, category_t *);
+extern int categ_dir_get_categories(categ_dir_t *, service_id_t *, size_t,
+    size_t *);
+extern category_t *category_new(const char *);
+extern int category_add_service(category_t *, loc_service_t *);
+extern void category_remove_service(svc_categ_t *);
+extern category_t *category_get(categ_dir_t *, catid_t);
+extern category_t *category_find_by_name(categ_dir_t *, const char *);
+extern int category_get_services(category_t *, service_id_t *, size_t,
+    size_t *);
+
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/loc/loc.c
===================================================================
--- uspace/srv/loc/loc.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/srv/loc/loc.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,1457 @@
+/*
+ * Copyright (c) 2007 Josef Cejka
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @defgroup loc Location Service.
+ * @brief HelenOS location service.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <ipc/services.h>
+#include <ns.h>
+#include <async.h>
+#include <stdio.h>
+#include <errno.h>
+#include <bool.h>
+#include <fibril_synch.h>
+#include <macros.h>
+#include <stdlib.h>
+#include <str.h>
+#include <ipc/loc.h>
+#include <assert.h>
+
+#include "category.h"
+#include "loc.h"
+
+#define NAME          "loc"
+#define NULL_SERVICES  256
+
+LIST_INITIALIZE(services_list);
+LIST_INITIALIZE(namespaces_list);
+LIST_INITIALIZE(servers_list);
+
+/* Locking order:
+ *  servers_list_mutex
+ *  services_list_mutex
+ *  (loc_server_t *)->services_mutex
+ *  create_id_mutex
+ **/
+
+FIBRIL_MUTEX_INITIALIZE(services_list_mutex);
+static FIBRIL_CONDVAR_INITIALIZE(services_list_cv);
+static FIBRIL_MUTEX_INITIALIZE(servers_list_mutex);
+static FIBRIL_MUTEX_INITIALIZE(create_id_mutex);
+static FIBRIL_MUTEX_INITIALIZE(null_services_mutex);
+
+static service_id_t last_id = 0;
+static loc_service_t *null_services[NULL_SERVICES];
+
+/*
+ * Dummy list for null services. This is necessary so that null services can
+ * be used just as any other services, e.g. in loc_service_unregister_core().
+ */
+static LIST_INITIALIZE(dummy_null_services);
+
+/** Service directory ogranized by categories (yellow pages) */
+static categ_dir_t cdir;
+
+static FIBRIL_MUTEX_INITIALIZE(callback_sess_mutex);
+static async_sess_t *callback_sess = NULL;
+
+service_id_t loc_create_id(void)
+{
+	/* TODO: allow reusing old ids after their unregistration
+	 * and implement some version of LRU algorithm, avoid overflow
+	 */
+	
+	fibril_mutex_lock(&create_id_mutex);
+	last_id++;
+	fibril_mutex_unlock(&create_id_mutex);
+	
+	return last_id;
+}
+
+/** Convert fully qualified service name to namespace and service name.
+ *
+ * A fully qualified service name can be either a plain service name
+ * (then the namespace is considered to be an empty string) or consist
+ * of two components separated by a slash. No more than one slash
+ * is allowed.
+ *
+ */
+static bool loc_fqsn_split(const char *fqsn, char **ns_name, char **name)
+{
+	size_t cnt = 0;
+	size_t slash_offset = 0;
+	size_t slash_after = 0;
+	
+	size_t offset = 0;
+	size_t offset_prev = 0;
+	wchar_t c;
+	
+	while ((c = str_decode(fqsn, &offset, STR_NO_LIMIT)) != 0) {
+		if (c == '/') {
+			cnt++;
+			slash_offset = offset_prev;
+			slash_after = offset;
+		}
+		offset_prev = offset;
+	}
+	
+	/* More than one slash */
+	if (cnt > 1)
+		return false;
+	
+	/* No slash -> namespace is empty */
+	if (cnt == 0) {
+		*ns_name = str_dup("");
+		if (*ns_name == NULL)
+			return false;
+		
+		*name = str_dup(fqsn);
+		if (*name == NULL) {
+			free(*ns_name);
+			return false;
+		}
+		
+		if (str_cmp(*name, "") == 0) {
+			free(*name);
+			free(*ns_name);
+			return false;
+		}
+		
+		return true;
+	}
+	
+	/* Exactly one slash */
+	*ns_name = str_ndup(fqsn, slash_offset);
+	if (*ns_name == NULL)
+		return false;
+	
+	*name = str_dup(fqsn + slash_after);
+	if (*name == NULL) {
+		free(*ns_name);
+		return false;
+	}
+	
+	if (str_cmp(*name, "") == 0) {
+		free(*name);
+		free(*ns_name);
+		return false;
+	}
+	
+	return true;
+}
+
+/** Find namespace with given name. */
+static loc_namespace_t *loc_namespace_find_name(const char *name)
+{
+	assert(fibril_mutex_is_locked(&services_list_mutex));
+	
+	list_foreach(namespaces_list, item) {
+		loc_namespace_t *namespace =
+		    list_get_instance(item, loc_namespace_t, namespaces);
+		if (str_cmp(namespace->name, name) == 0)
+			return namespace;
+	}
+	
+	return NULL;
+}
+
+/** Find namespace with given ID.
+ *
+ * @todo: use hash table
+ *
+ */
+static loc_namespace_t *loc_namespace_find_id(service_id_t id)
+{
+	assert(fibril_mutex_is_locked(&services_list_mutex));
+	
+	list_foreach(namespaces_list, item) {
+		loc_namespace_t *namespace =
+		    list_get_instance(item, loc_namespace_t, namespaces);
+		if (namespace->id == id)
+			return namespace;
+	}
+	
+	return NULL;
+}
+
+/** Find service with given name. */
+static loc_service_t *loc_service_find_name(const char *ns_name,
+    const char *name)
+{
+	assert(fibril_mutex_is_locked(&services_list_mutex));
+	
+	list_foreach(services_list, item) {
+		loc_service_t *service =
+		    list_get_instance(item, loc_service_t, services);
+		if ((str_cmp(service->namespace->name, ns_name) == 0)
+		    && (str_cmp(service->name, name) == 0))
+			return service;
+	}
+	
+	return NULL;
+}
+
+/** Find service with given ID.
+ *
+ * @todo: use hash table
+ *
+ */
+static loc_service_t *loc_service_find_id(service_id_t id)
+{
+	assert(fibril_mutex_is_locked(&services_list_mutex));
+	
+	list_foreach(services_list, item) {
+		loc_service_t *service =
+		    list_get_instance(item, loc_service_t, services);
+		if (service->id == id)
+			return service;
+	}
+	
+	return NULL;
+}
+
+/** Create a namespace (if not already present). */
+static loc_namespace_t *loc_namespace_create(const char *ns_name)
+{
+	loc_namespace_t *namespace;
+	
+	assert(fibril_mutex_is_locked(&services_list_mutex));
+	
+	namespace = loc_namespace_find_name(ns_name);
+	if (namespace != NULL)
+		return namespace;
+	
+	namespace = (loc_namespace_t *) malloc(sizeof(loc_namespace_t));
+	if (namespace == NULL)
+		return NULL;
+	
+	namespace->name = str_dup(ns_name);
+	if (namespace->name == NULL) {
+		free(namespace);
+		return NULL;
+	}
+	
+	namespace->id = loc_create_id();
+	namespace->refcnt = 0;
+	
+	/*
+	 * Insert new namespace into list of registered namespaces
+	 */
+	list_append(&(namespace->namespaces), &namespaces_list);
+	
+	return namespace;
+}
+
+/** Destroy a namespace (if it is no longer needed). */
+static void loc_namespace_destroy(loc_namespace_t *namespace)
+{
+	assert(fibril_mutex_is_locked(&services_list_mutex));
+
+	if (namespace->refcnt == 0) {
+		list_remove(&(namespace->namespaces));
+		
+		free(namespace->name);
+		free(namespace);
+	}
+}
+
+/** Increase namespace reference count by including service. */
+static void loc_namespace_addref(loc_namespace_t *namespace,
+    loc_service_t *service)
+{
+	assert(fibril_mutex_is_locked(&services_list_mutex));
+
+	service->namespace = namespace;
+	namespace->refcnt++;
+}
+
+/** Decrease namespace reference count. */
+static void loc_namespace_delref(loc_namespace_t *namespace)
+{
+	assert(fibril_mutex_is_locked(&services_list_mutex));
+
+	namespace->refcnt--;
+	loc_namespace_destroy(namespace);
+}
+
+/** Unregister service and free it. */
+static void loc_service_unregister_core(loc_service_t *service)
+{
+	assert(fibril_mutex_is_locked(&services_list_mutex));
+	assert(fibril_mutex_is_locked(&cdir.mutex));
+	
+	loc_namespace_delref(service->namespace);
+	list_remove(&(service->services));
+	list_remove(&(service->server_services));
+	
+	/* Remove service from all categories. */
+	while (!list_empty(&service->cat_memb)) {
+		link_t *link = list_first(&service->cat_memb);
+		svc_categ_t *memb = list_get_instance(link, svc_categ_t,
+		    svc_link);
+		fibril_mutex_lock(&memb->cat->mutex);
+		category_remove_service(memb);
+		fibril_mutex_unlock(&memb->cat->mutex);
+	}
+	
+	free(service->name);
+	free(service);
+}
+
+/**
+ * Read info about new server and add it into linked list of registered
+ * servers.
+ */
+static loc_server_t *loc_server_register(void)
+{
+	ipc_call_t icall;
+	ipc_callid_t iid = async_get_call(&icall);
+	
+	if (IPC_GET_IMETHOD(icall) != LOC_SERVER_REGISTER) {
+		async_answer_0(iid, EREFUSED);
+		return NULL;
+	}
+	
+	loc_server_t *server =
+	    (loc_server_t *) malloc(sizeof(loc_server_t));
+	if (server == NULL) {
+		async_answer_0(iid, ENOMEM);
+		return NULL;
+	}
+	
+	/*
+	 * Get server name
+	 */
+	int rc = async_data_write_accept((void **) &server->name, true, 0,
+	    LOC_NAME_MAXLEN, 0, NULL);
+	if (rc != EOK) {
+		free(server);
+		async_answer_0(iid, rc);
+		return NULL;
+	}
+	
+	/*
+	 * Create connection to the server
+	 */
+	server->sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (!server->sess) {
+		free(server->name);
+		free(server);
+		async_answer_0(iid, ENOTSUP);
+		return NULL;
+	}
+	
+	/*
+	 * Initialize mutex for list of services
+	 * supplied by this server
+	 */
+	fibril_mutex_initialize(&server->services_mutex);
+	
+	/*
+	 * Initialize list of supplied services
+	 */
+	list_initialize(&server->services);
+
+	link_initialize(&server->servers);
+	
+	fibril_mutex_lock(&servers_list_mutex);
+	
+	/* TODO:
+	 * Check that no server with name equal to
+	 * server->name is registered
+	 */
+	
+	/*
+	 * Insert new server into list of registered servers
+	 */
+	list_append(&(server->servers), &servers_list);
+	fibril_mutex_unlock(&servers_list_mutex);
+	
+	async_answer_0(iid, EOK);
+	
+	return server;
+}
+
+/**
+ * Unregister server, unregister all its services and free server
+ * structure.
+ *
+ */
+static int loc_server_unregister(loc_server_t *server)
+{
+	if (server == NULL)
+		return EEXISTS;
+	
+	fibril_mutex_lock(&servers_list_mutex);
+	
+	if (server->sess)
+		async_hangup(server->sess);
+	
+	/* Remove it from list of servers */
+	list_remove(&(server->servers));
+	
+	/* Unregister all its services */
+	fibril_mutex_lock(&services_list_mutex);
+	fibril_mutex_lock(&server->services_mutex);
+	fibril_mutex_lock(&cdir.mutex);
+	
+	while (!list_empty(&server->services)) {
+		loc_service_t *service = list_get_instance(
+		    list_first(&server->services), loc_service_t,
+		    server_services);
+		loc_service_unregister_core(service);
+	}
+	
+	fibril_mutex_unlock(&cdir.mutex);
+	fibril_mutex_unlock(&server->services_mutex);
+	fibril_mutex_unlock(&services_list_mutex);
+	fibril_mutex_unlock(&servers_list_mutex);
+	
+	/* Free name and server */
+	if (server->name != NULL)
+		free(server->name);
+	
+	free(server);
+	
+	return EOK;
+}
+
+/** Register service
+ *
+ */
+static void loc_service_register(ipc_callid_t iid, ipc_call_t *icall,
+    loc_server_t *server)
+{
+	if (server == NULL) {
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+	
+	/* Create new service entry */
+	loc_service_t *service =
+	    (loc_service_t *) malloc(sizeof(loc_service_t));
+	if (service == NULL) {
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	/* Set the interface, if any. */
+	service->forward_interface = IPC_GET_ARG1(*icall);
+
+	/* Get fqsn */
+	char *fqsn;
+	int rc = async_data_write_accept((void **) &fqsn, true, 0,
+	    LOC_NAME_MAXLEN, 0, NULL);
+	if (rc != EOK) {
+		free(service);
+		async_answer_0(iid, rc);
+		return;
+	}
+	
+	char *ns_name;
+	if (!loc_fqsn_split(fqsn, &ns_name, &service->name)) {
+		free(fqsn);
+		free(service);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	free(fqsn);
+	
+	fibril_mutex_lock(&services_list_mutex);
+	
+	loc_namespace_t *namespace = loc_namespace_create(ns_name);
+	free(ns_name);
+	if (namespace == NULL) {
+		fibril_mutex_unlock(&services_list_mutex);
+		free(service->name);
+		free(service);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	link_initialize(&service->services);
+	link_initialize(&service->server_services);
+	list_initialize(&service->cat_memb);
+	
+	/* Check that service is not already registered */
+	if (loc_service_find_name(namespace->name, service->name) != NULL) {
+		printf("%s: Service '%s/%s' already registered\n", NAME,
+		    namespace->name, service->name);
+		loc_namespace_destroy(namespace);
+		fibril_mutex_unlock(&services_list_mutex);
+		free(service->name);
+		free(service);
+		async_answer_0(iid, EEXISTS);
+		return;
+	}
+	
+	/* Get unique service ID */
+	service->id = loc_create_id();
+
+	loc_namespace_addref(namespace, service);
+	service->server = server;
+	
+	/* Insert service into list of all services  */
+	list_append(&service->services, &services_list);
+	
+	/* Insert service into list of services supplied by one server */
+	fibril_mutex_lock(&service->server->services_mutex);
+	
+	list_append(&service->server_services, &service->server->services);
+	
+	fibril_mutex_unlock(&service->server->services_mutex);
+	fibril_condvar_broadcast(&services_list_cv);
+	fibril_mutex_unlock(&services_list_mutex);
+	
+	async_answer_1(iid, EOK, service->id);
+}
+
+/**
+ *
+ */
+static void loc_service_unregister(ipc_callid_t iid, ipc_call_t *icall, 
+    loc_server_t *server)
+{
+	loc_service_t *svc;
+	
+	fibril_mutex_lock(&services_list_mutex);
+	svc = loc_service_find_id(IPC_GET_ARG1(*icall));
+	if (svc == NULL) {
+		fibril_mutex_unlock(&services_list_mutex);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+	
+	fibril_mutex_lock(&cdir.mutex);
+	loc_service_unregister_core(svc);
+	fibril_mutex_unlock(&cdir.mutex);
+	fibril_mutex_unlock(&services_list_mutex);
+	async_answer_0(iid, EOK);
+}
+
+static void loc_category_get_name(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	size_t size;
+	size_t act_size;
+	category_t *cat;
+	
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+	
+	fibril_mutex_lock(&cdir.mutex);
+	
+	cat = category_get(&cdir, IPC_GET_ARG1(*icall));
+	if (cat == NULL) {
+		fibril_mutex_unlock(&cdir.mutex);
+		async_answer_0(callid, ENOENT);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+	
+	act_size = str_size(cat->name);
+	if (act_size > size) {
+		fibril_mutex_unlock(&cdir.mutex);
+		async_answer_0(callid, EOVERFLOW);
+		async_answer_0(iid, EOVERFLOW);
+		return;
+	}
+	
+	sysarg_t retval = async_data_read_finalize(callid, cat->name,
+	    min(size, act_size));
+	
+	fibril_mutex_unlock(&cdir.mutex);
+	
+	async_answer_0(iid, retval);
+}
+
+static void loc_service_get_name(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	size_t size;
+	size_t act_size;
+	loc_service_t *svc;
+	
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+	
+	fibril_mutex_lock(&services_list_mutex);
+	
+	svc = loc_service_find_id(IPC_GET_ARG1(*icall));
+	if (svc == NULL) {
+		fibril_mutex_unlock(&services_list_mutex);
+		async_answer_0(callid, ENOENT);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+	
+	act_size = str_size(svc->name);
+	if (act_size > size) {
+		fibril_mutex_unlock(&services_list_mutex);
+		async_answer_0(callid, EOVERFLOW);
+		async_answer_0(iid, EOVERFLOW);
+		return;
+	}
+	
+	sysarg_t retval = async_data_read_finalize(callid, svc->name,
+	    min(size, act_size));
+	
+	fibril_mutex_unlock(&services_list_mutex);
+	
+	async_answer_0(iid, retval);
+}
+
+/** Connect client to the service.
+ *
+ * Find server supplying requested service and forward
+ * the message to it.
+ *
+ */
+static void loc_forward(ipc_callid_t callid, ipc_call_t *call)
+{
+	fibril_mutex_lock(&services_list_mutex);
+	
+	/*
+	 * Get ID from request
+	 */
+	service_id_t id = IPC_GET_ARG2(*call);
+	loc_service_t *svc = loc_service_find_id(id);
+	
+	if ((svc == NULL) || (svc->server == NULL) || (!svc->server->sess)) {
+		fibril_mutex_unlock(&services_list_mutex);
+		async_answer_0(callid, ENOENT);
+		return;
+	}
+	
+	async_exch_t *exch = async_exchange_begin(svc->server->sess);
+	
+	if (svc->forward_interface == 0)
+		async_forward_fast(callid, exch, svc->id, 0, 0, IPC_FF_NONE);
+	else
+		async_forward_fast(callid, exch, svc->forward_interface,
+		    svc->id, 0, IPC_FF_NONE);
+	
+	async_exchange_end(exch);
+	
+	fibril_mutex_unlock(&services_list_mutex);
+}
+
+/** Find ID for service identified by name.
+ *
+ * In answer will be send EOK and service ID in arg1 or a error
+ * code from errno.h.
+ *
+ */
+static void loc_service_get_id(ipc_callid_t iid, ipc_call_t *icall)
+{
+	char *fqsn;
+	
+	/* Get fqsn */
+	int rc = async_data_write_accept((void **) &fqsn, true, 0,
+	    LOC_NAME_MAXLEN, 0, NULL);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+	
+	char *ns_name;
+	char *name;
+	if (!loc_fqsn_split(fqsn, &ns_name, &name)) {
+		free(fqsn);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	free(fqsn);
+	
+	fibril_mutex_lock(&services_list_mutex);
+	const loc_service_t *svc;
+	
+recheck:
+	
+	/*
+	 * Find service name in the list of known services.
+	 */
+	svc = loc_service_find_name(ns_name, name);
+	
+	/*
+	 * Device was not found.
+	 */
+	if (svc == NULL) {
+		if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
+			/* Blocking lookup */
+			fibril_condvar_wait(&services_list_cv,
+			    &services_list_mutex);
+			goto recheck;
+		}
+		
+		async_answer_0(iid, ENOENT);
+		free(ns_name);
+		free(name);
+		fibril_mutex_unlock(&services_list_mutex);
+		return;
+	}
+	
+	async_answer_1(iid, EOK, svc->id);
+	
+	fibril_mutex_unlock(&services_list_mutex);
+	free(ns_name);
+	free(name);
+}
+
+/** Find ID for namespace identified by name.
+ *
+ * In answer will be send EOK and service ID in arg1 or a error
+ * code from errno.h.
+ *
+ */
+static void loc_namespace_get_id(ipc_callid_t iid, ipc_call_t *icall)
+{
+	char *name;
+	
+	/* Get service name */
+	int rc = async_data_write_accept((void **) &name, true, 0,
+	    LOC_NAME_MAXLEN, 0, NULL);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+	
+	fibril_mutex_lock(&services_list_mutex);
+	const loc_namespace_t *namespace;
+	
+recheck:
+	
+	/*
+	 * Find namespace name in the list of known namespaces.
+	 */
+	namespace = loc_namespace_find_name(name);
+	
+	/*
+	 * Namespace was not found.
+	 */
+	if (namespace == NULL) {
+		if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
+			/* Blocking lookup */
+			fibril_condvar_wait(&services_list_cv,
+			    &services_list_mutex);
+			goto recheck;
+		}
+		
+		async_answer_0(iid, ENOENT);
+		free(name);
+		fibril_mutex_unlock(&services_list_mutex);
+		return;
+	}
+	
+	async_answer_1(iid, EOK, namespace->id);
+	
+	fibril_mutex_unlock(&services_list_mutex);
+	free(name);
+}
+
+/** Find ID for category specified by name.
+ *
+ * On success, answer will contain EOK int retval and service ID in arg1.
+ * On failure, error code will be sent in retval.
+ *
+ */
+static void loc_callback_create(ipc_callid_t iid, ipc_call_t *icall)
+{
+	async_sess_t *cb_sess = async_callback_receive(EXCHANGE_SERIALIZE);
+	if (cb_sess == NULL) {
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	fibril_mutex_lock(&callback_sess_mutex);
+	if (callback_sess != NULL) {
+		fibril_mutex_unlock(&callback_sess_mutex);
+		async_answer_0(iid, EEXIST);
+		return;
+	}
+	
+	callback_sess = cb_sess;
+	fibril_mutex_unlock(&callback_sess_mutex);
+	
+	async_answer_0(iid, EOK);
+}
+
+void loc_category_change_event(void)
+{
+	fibril_mutex_lock(&callback_sess_mutex);
+
+	if (callback_sess != NULL) {
+		async_exch_t *exch = async_exchange_begin(callback_sess);
+		async_msg_0(exch, LOC_EVENT_CAT_CHANGE);
+		async_exchange_end(exch);
+	}
+
+	fibril_mutex_unlock(&callback_sess_mutex);
+}
+
+/** Find ID for category specified by name.
+ *
+ * On success, answer will contain EOK int retval and service ID in arg1.
+ * On failure, error code will be sent in retval.
+ *
+ */
+static void loc_category_get_id(ipc_callid_t iid, ipc_call_t *icall)
+{
+	char *name;
+	category_t *cat;
+	
+	/* Get service name */
+	int rc = async_data_write_accept((void **) &name, true, 0,
+	    LOC_NAME_MAXLEN, 0, NULL);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+	
+	fibril_mutex_lock(&cdir.mutex);
+
+	cat = category_find_by_name(&cdir, name);
+	if (cat == NULL) {
+		/* Category not found */
+		async_answer_0(iid, ENOENT);
+		goto cleanup;
+	}
+	
+	async_answer_1(iid, EOK, cat->id);
+cleanup:
+	fibril_mutex_unlock(&cdir.mutex);
+	free(name);
+}
+
+static void loc_id_probe(ipc_callid_t iid, ipc_call_t *icall)
+{
+	fibril_mutex_lock(&services_list_mutex);
+	
+	loc_namespace_t *namespace =
+	    loc_namespace_find_id(IPC_GET_ARG1(*icall));
+	if (namespace == NULL) {
+		loc_service_t *svc =
+		    loc_service_find_id(IPC_GET_ARG1(*icall));
+		if (svc == NULL)
+			async_answer_1(iid, EOK, LOC_OBJECT_NONE);
+		else
+			async_answer_1(iid, EOK, LOC_OBJECT_SERVICE);
+	} else
+		async_answer_1(iid, EOK, LOC_OBJECT_NAMESPACE);
+	
+	fibril_mutex_unlock(&services_list_mutex);
+}
+
+static void loc_get_namespace_count(ipc_callid_t iid, ipc_call_t *icall)
+{
+	fibril_mutex_lock(&services_list_mutex);
+	async_answer_1(iid, EOK, list_count(&namespaces_list));
+	fibril_mutex_unlock(&services_list_mutex);
+}
+
+static void loc_get_service_count(ipc_callid_t iid, ipc_call_t *icall)
+{
+	fibril_mutex_lock(&services_list_mutex);
+	
+	loc_namespace_t *namespace =
+	    loc_namespace_find_id(IPC_GET_ARG1(*icall));
+	if (namespace == NULL)
+		async_answer_0(iid, EEXISTS);
+	else
+		async_answer_1(iid, EOK, namespace->refcnt);
+	
+	fibril_mutex_unlock(&services_list_mutex);
+}
+
+static void loc_get_categories(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	size_t size;
+	size_t act_size;
+	int rc;
+	
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+	
+	category_id_t *id_buf = (category_id_t *) malloc(size);
+	if (id_buf == NULL) {
+		fibril_mutex_unlock(&cdir.mutex);
+		async_answer_0(callid, ENOMEM);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	fibril_mutex_lock(&cdir.mutex);
+	
+	rc = categ_dir_get_categories(&cdir, id_buf, size, &act_size);
+	if (rc != EOK) {
+		fibril_mutex_unlock(&cdir.mutex);
+		async_answer_0(callid, rc);
+		async_answer_0(iid, rc);
+		return;
+	}
+	
+	fibril_mutex_unlock(&cdir.mutex);
+	
+	sysarg_t retval = async_data_read_finalize(callid, id_buf, size);
+	free(id_buf);
+	
+	async_answer_1(iid, retval, act_size);
+}
+
+static void loc_get_namespaces(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+	
+	if ((size % sizeof(loc_sdesc_t)) != 0) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	fibril_mutex_lock(&services_list_mutex);
+	
+	size_t count = size / sizeof(loc_sdesc_t);
+	if (count != list_count(&namespaces_list)) {
+		fibril_mutex_unlock(&services_list_mutex);
+		async_answer_0(callid, EOVERFLOW);
+		async_answer_0(iid, EOVERFLOW);
+		return;
+	}
+	
+	loc_sdesc_t *desc = (loc_sdesc_t *) malloc(size);
+	if (desc == NULL) {
+		fibril_mutex_unlock(&services_list_mutex);
+		async_answer_0(callid, ENOMEM);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	size_t pos = 0;
+	list_foreach(namespaces_list, item) {
+		loc_namespace_t *namespace =
+		    list_get_instance(item, loc_namespace_t, namespaces);
+		
+		desc[pos].id = namespace->id;
+		str_cpy(desc[pos].name, LOC_NAME_MAXLEN, namespace->name);
+		pos++;
+	}
+	
+	sysarg_t retval = async_data_read_finalize(callid, desc, size);
+	
+	free(desc);
+	fibril_mutex_unlock(&services_list_mutex);
+	
+	async_answer_0(iid, retval);
+}
+
+static void loc_get_services(ipc_callid_t iid, ipc_call_t *icall)
+{
+	/* FIXME: Use faster algorithm which can make better use
+	   of namespaces */
+	
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+	
+	if ((size % sizeof(loc_sdesc_t)) != 0) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	fibril_mutex_lock(&services_list_mutex);
+	
+	loc_namespace_t *namespace =
+	    loc_namespace_find_id(IPC_GET_ARG1(*icall));
+	if (namespace == NULL) {
+		fibril_mutex_unlock(&services_list_mutex);
+		async_answer_0(callid, ENOENT);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+	
+	size_t count = size / sizeof(loc_sdesc_t);
+	if (count != namespace->refcnt) {
+		fibril_mutex_unlock(&services_list_mutex);
+		async_answer_0(callid, EOVERFLOW);
+		async_answer_0(iid, EOVERFLOW);
+		return;
+	}
+	
+	loc_sdesc_t *desc = (loc_sdesc_t *) malloc(size);
+	if (desc == NULL) {
+		fibril_mutex_unlock(&services_list_mutex);
+		async_answer_0(callid, ENOMEM);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+	
+	size_t pos = 0;
+	list_foreach(services_list, item) {
+		loc_service_t *service =
+		    list_get_instance(item, loc_service_t, services);
+		
+		if (service->namespace == namespace) {
+			desc[pos].id = service->id;
+			str_cpy(desc[pos].name, LOC_NAME_MAXLEN, service->name);
+			pos++;
+		}
+	}
+	
+	sysarg_t retval = async_data_read_finalize(callid, desc, size);
+	
+	free(desc);
+	fibril_mutex_unlock(&services_list_mutex);
+	
+	async_answer_0(iid, retval);
+}
+
+static void loc_category_get_svcs(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	size_t size;
+	size_t act_size;
+	int rc;
+	
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+	
+	fibril_mutex_lock(&cdir.mutex);
+	
+	category_t *cat = category_get(&cdir, IPC_GET_ARG1(*icall));
+	if (cat == NULL) {
+		fibril_mutex_unlock(&cdir.mutex);
+		async_answer_0(callid, ENOENT);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+	
+	category_id_t *id_buf = (category_id_t *) malloc(size);
+	if (id_buf == NULL) {
+		fibril_mutex_unlock(&cdir.mutex);
+		async_answer_0(callid, ENOMEM);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	fibril_mutex_lock(&cat->mutex);
+	
+	rc = category_get_services(cat, id_buf, size, &act_size);
+	if (rc != EOK) {
+		fibril_mutex_unlock(&cat->mutex);
+		fibril_mutex_unlock(&cdir.mutex);
+		async_answer_0(callid, rc);
+		async_answer_0(iid, rc);
+		return;
+	}
+	
+	fibril_mutex_unlock(&cat->mutex);
+	fibril_mutex_unlock(&cdir.mutex);
+	
+	sysarg_t retval = async_data_read_finalize(callid, id_buf, size);
+	free(id_buf);
+	
+	async_answer_1(iid, retval, act_size);
+}
+
+
+static void loc_null_create(ipc_callid_t iid, ipc_call_t *icall)
+{
+	fibril_mutex_lock(&null_services_mutex);
+	
+	unsigned int i;
+	bool fnd = false;
+	
+	for (i = 0; i < NULL_SERVICES; i++) {
+		if (null_services[i] == NULL) {
+			fnd = true;
+			break;
+		}
+	}
+	
+	if (!fnd) {
+		fibril_mutex_unlock(&null_services_mutex);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	char null[LOC_NAME_MAXLEN];
+	snprintf(null, LOC_NAME_MAXLEN, "%u", i);
+	
+	char *dev_name = str_dup(null);
+	if (dev_name == NULL) {
+		fibril_mutex_unlock(&null_services_mutex);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	loc_service_t *service =
+	    (loc_service_t *) malloc(sizeof(loc_service_t));
+	if (service == NULL) {
+		fibril_mutex_unlock(&null_services_mutex);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	fibril_mutex_lock(&services_list_mutex);
+	
+	loc_namespace_t *namespace = loc_namespace_create("null");
+	if (namespace == NULL) {
+		fibril_mutex_lock(&services_list_mutex);
+		fibril_mutex_unlock(&null_services_mutex);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	link_initialize(&service->services);
+	link_initialize(&service->server_services);
+	
+	/* Get unique service ID */
+	service->id = loc_create_id();
+	service->server = NULL;
+	
+	loc_namespace_addref(namespace, service);
+	service->name = dev_name;
+	
+	/*
+	 * Insert service into list of all services and into null services array.
+	 * Insert service into a dummy list of null server's services so that it
+	 * can be safely removed later.
+	 */
+	list_append(&service->services, &services_list);
+	list_append(&service->server_services, &dummy_null_services);
+	null_services[i] = service;
+	
+	fibril_mutex_unlock(&services_list_mutex);
+	fibril_mutex_unlock(&null_services_mutex);
+	
+	async_answer_1(iid, EOK, (sysarg_t) i);
+}
+
+static void loc_null_destroy(ipc_callid_t iid, ipc_call_t *icall)
+{
+	sysarg_t i = IPC_GET_ARG1(*icall);
+	if (i >= NULL_SERVICES) {
+		async_answer_0(iid, ELIMIT);
+		return;
+	}
+	
+	fibril_mutex_lock(&null_services_mutex);
+	
+	if (null_services[i] == NULL) {
+		fibril_mutex_unlock(&null_services_mutex);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+	
+	fibril_mutex_lock(&services_list_mutex);
+	fibril_mutex_lock(&cdir.mutex);
+	loc_service_unregister_core(null_services[i]);
+	fibril_mutex_unlock(&cdir.mutex);
+	fibril_mutex_unlock(&services_list_mutex);
+	
+	null_services[i] = NULL;
+	
+	fibril_mutex_unlock(&null_services_mutex);
+	async_answer_0(iid, EOK);
+}
+
+static void loc_service_add_to_cat(ipc_callid_t iid, ipc_call_t *icall)
+{
+	category_t *cat;
+	loc_service_t *svc;
+	catid_t cat_id;
+	service_id_t svc_id;
+	sysarg_t retval;
+	
+	svc_id = IPC_GET_ARG1(*icall);
+	cat_id = IPC_GET_ARG2(*icall);
+	
+	fibril_mutex_lock(&services_list_mutex);
+	fibril_mutex_lock(&cdir.mutex);
+	
+	cat = category_get(&cdir, cat_id);
+	svc = loc_service_find_id(svc_id);
+	
+	fibril_mutex_lock(&cat->mutex);
+	retval = category_add_service(cat, svc);
+
+	fibril_mutex_unlock(&cat->mutex);
+	fibril_mutex_unlock(&cdir.mutex);
+	fibril_mutex_unlock(&services_list_mutex);
+
+	async_answer_0(iid, retval);
+
+	loc_category_change_event();
+}
+
+
+/** Initialize location service.
+ *
+ *
+ */
+static bool loc_init(void)
+{
+	unsigned int i;
+	category_t *cat;
+
+	for (i = 0; i < NULL_SERVICES; i++)
+		null_services[i] = NULL;
+	
+	categ_dir_init(&cdir);
+
+	cat = category_new("bd");
+	categ_dir_add_cat(&cdir, cat);
+
+	cat = category_new("keyboard");
+	categ_dir_add_cat(&cdir, cat);
+
+	cat = category_new("mouse");
+	categ_dir_add_cat(&cdir, cat);
+
+	cat = category_new("serial");
+	categ_dir_add_cat(&cdir, cat);
+
+	cat = category_new("usbhc");
+	categ_dir_add_cat(&cdir, cat);
+
+	cat = category_new("virtual");
+	categ_dir_add_cat(&cdir, cat);
+
+	return true;
+}
+
+/** Handle connection on supplier port.
+ *
+ */
+static void loc_connection_supplier(ipc_callid_t iid, ipc_call_t *icall)
+{
+	/* Accept connection */
+	async_answer_0(iid, EOK);
+	
+	loc_server_t *server = loc_server_register();
+	if (server == NULL)
+		return;
+	
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
+		switch (IPC_GET_IMETHOD(call)) {
+		case LOC_SERVER_UNREGISTER:
+			if (server == NULL)
+				async_answer_0(callid, ENOENT);
+			else
+				async_answer_0(callid, EOK);
+			break;
+		case LOC_SERVICE_ADD_TO_CAT:
+			/* Add service to category */
+			loc_service_add_to_cat(callid, &call);
+			break;
+		case LOC_SERVICE_REGISTER:
+			/* Register one service */
+			loc_service_register(callid, &call, server);
+			break;
+		case LOC_SERVICE_UNREGISTER:
+			/* Remove one service */
+			loc_service_unregister(callid, &call, server);
+			break;
+		case LOC_SERVICE_GET_ID:
+			loc_service_get_id(callid, &call);
+			break;
+		case LOC_NAMESPACE_GET_ID:
+			loc_namespace_get_id(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOENT);
+		}
+	}
+	
+	if (server != NULL) {
+		/*
+		 * Unregister the server and all its services.
+		 */
+		loc_server_unregister(server);
+		server = NULL;
+	}
+}
+
+/** Handle connection on consumer port.
+ *
+ */
+static void loc_connection_consumer(ipc_callid_t iid, ipc_call_t *icall)
+{
+	/* Accept connection */
+	async_answer_0(iid, EOK);
+	
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		
+		if (!IPC_GET_IMETHOD(call))
+			break;
+		
+		switch (IPC_GET_IMETHOD(call)) {
+		case LOC_SERVICE_GET_ID:
+			loc_service_get_id(callid, &call);
+			break;
+		case LOC_SERVICE_GET_NAME:
+			loc_service_get_name(callid, &call);
+			break;
+		case LOC_NAMESPACE_GET_ID:
+			loc_namespace_get_id(callid, &call);
+			break;
+		case LOC_CALLBACK_CREATE:
+			loc_callback_create(callid, &call);
+			break;
+		case LOC_CATEGORY_GET_ID:
+			loc_category_get_id(callid, &call);
+			break;
+		case LOC_CATEGORY_GET_NAME:
+			loc_category_get_name(callid, &call);
+			break;
+		case LOC_CATEGORY_GET_SVCS:
+			loc_category_get_svcs(callid, &call);
+			break;
+		case LOC_ID_PROBE:
+			loc_id_probe(callid, &call);
+			break;
+		case LOC_NULL_CREATE:
+			loc_null_create(callid, &call);
+			break;
+		case LOC_NULL_DESTROY:
+			loc_null_destroy(callid, &call);
+			break;
+		case LOC_GET_NAMESPACE_COUNT:
+			loc_get_namespace_count(callid, &call);
+			break;
+		case LOC_GET_SERVICE_COUNT:
+			loc_get_service_count(callid, &call);
+			break;
+		case LOC_GET_CATEGORIES:
+			loc_get_categories(callid, &call);
+			break;
+		case LOC_GET_NAMESPACES:
+			loc_get_namespaces(callid, &call);
+			break;
+		case LOC_GET_SERVICES:
+			loc_get_services(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOENT);
+		}
+	}
+}
+
+/** Function for handling connections to location service
+ *
+ */
+static void loc_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	/* Select interface */
+	switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
+	case LOC_PORT_SUPPLIER:
+		loc_connection_supplier(iid, icall);
+		break;
+	case LOC_PORT_CONSUMER:
+		loc_connection_consumer(iid, icall);
+		break;
+	case LOC_CONNECT_TO_SERVICE:
+		/* Connect client to selected service */
+		loc_forward(iid, icall);
+		break;
+	default:
+		/* No such interface */
+		async_answer_0(iid, ENOENT);
+	}
+}
+
+/**
+ *
+ */
+int main(int argc, char *argv[])
+{
+	printf("%s: HelenOS Location Service\n", NAME);
+	
+	if (!loc_init()) {
+		printf("%s: Error while initializing service\n", NAME);
+		return -1;
+	}
+	
+	/* Set a handler of incomming connections */
+	async_set_client_connection(loc_connection);
+	
+	/* Register location service at naming service */
+	if (service_register(SERVICE_LOC) != EOK)
+		return -1;
+	
+	printf("%s: Accepting connections\n", NAME);
+	async_manager();
+	
+	/* Never reached */
+	return 0;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/loc/loc.h
===================================================================
--- uspace/srv/loc/loc.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
+++ uspace/srv/loc/loc.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup loc
+ * @{
+ */
+/** @file HelenOS location service.
+ */
+
+#ifndef LOC_H_
+#define LOC_H_
+
+#include <ipc/loc.h>
+#include <async.h>
+#include <fibril_synch.h>
+#include <sys/types.h>
+
+/** Representation of server (supplier).
+ *
+ * Each server supplies a set of services.
+ *
+ */
+typedef struct {
+	/** Link to servers_list */
+	link_t servers;
+	
+	/** List of services supplied by this server */
+	list_t services;
+	
+	/** Session asociated with this server */
+	async_sess_t *sess;
+	
+	/** Server name */
+	char *name;
+	
+	/** Fibril mutex for list of services owned by this server */
+	fibril_mutex_t services_mutex;
+} loc_server_t;
+
+/** Info about registered namespaces
+ *
+ */
+typedef struct {
+	/** Link to namespaces_list */
+	link_t namespaces;
+	
+	/** Unique namespace identifier */
+	service_id_t id;
+	
+	/** Namespace name */
+	char *name;
+	
+	/** Reference count */
+	size_t refcnt;
+} loc_namespace_t;
+
+/** Info about registered service
+ *
+ */
+typedef struct {
+	/** Link to global list of services (services_list) */
+	link_t services;
+	/** Link to server list of services (loc_server_t.services) */
+	link_t server_services;
+	/** Link to list of services in category (category_t.services) */
+	link_t cat_services;
+	/** List of category memberships (svc_categ_t) */
+	list_t cat_memb;
+	/** Unique service identifier */
+	service_id_t id;
+	/** Service namespace */
+	loc_namespace_t *namespace;
+	/** Service name */
+	char *name;
+	/** Supplier of this service */
+	loc_server_t *server;
+	/** Use this interface when forwarding to server. */
+	sysarg_t forward_interface;
+} loc_service_t;
+
+extern fibril_mutex_t services_list_mutex;
+
+extern service_id_t loc_create_id(void);
+extern void loc_category_change_event(void);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/vfs/vfs.h	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -38,5 +38,5 @@
 #include <fibril_synch.h>
 #include <sys/types.h>
-#include <devmap.h>
+#include <loc.h>
 #include <bool.h>
 #include <ipc/vfs.h>
@@ -61,5 +61,5 @@
 #define VFS_PAIR \
 	fs_handle_t fs_handle; \
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 
 /**
@@ -67,5 +67,5 @@
  * doesn't contain any state. For a stateful structure, see vfs_node_t.
  *
- * @note	fs_handle, devmap_handle and index are meant to be returned in one
+ * @note	fs_handle, service_id and index are meant to be returned in one
  *		IPC reply.
  */
@@ -180,5 +180,5 @@
 extern void vfs_node_put(vfs_node_t *);
 extern void vfs_node_forget(vfs_node_t *);
-extern unsigned vfs_nodes_refcount_sum_get(fs_handle_t, devmap_handle_t);
+extern unsigned vfs_nodes_refcount_sum_get(fs_handle_t, service_id_t);
 
 
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/vfs/vfs_file.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -137,5 +137,5 @@
 	
 	ipc_call_t answer;
-	aid_t msg = async_send_2(exch, VFS_OUT_CLOSE, file->node->devmap_handle,
+	aid_t msg = async_send_2(exch, VFS_OUT_CLOSE, file->node->service_id,
 	    file->node->index, &answer);
 	
Index: uspace/srv/vfs/vfs_lookup.c
===================================================================
--- uspace/srv/vfs/vfs_lookup.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/vfs/vfs_lookup.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -162,5 +162,5 @@
 	aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) first,
 	    (sysarg_t) (first + len - 1) % PLB_SIZE,
-	    (sysarg_t) root->devmap_handle, (sysarg_t) lflag, (sysarg_t) index,
+	    (sysarg_t) root->service_id, (sysarg_t) lflag, (sysarg_t) index,
 	    &answer);
 	
@@ -185,5 +185,5 @@
 	
 	result->triplet.fs_handle = (fs_handle_t) rc;
-	result->triplet.devmap_handle = (devmap_handle_t) IPC_GET_ARG1(answer);
+	result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
 	result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
 	result->size =
Index: uspace/srv/vfs/vfs_node.c
===================================================================
--- uspace/srv/vfs/vfs_node.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/vfs/vfs_node.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -116,5 +116,5 @@
 		unsigned long key[] = {
 			[KEY_FS_HANDLE] = node->fs_handle,
-			[KEY_DEV_HANDLE] = node->devmap_handle,
+			[KEY_DEV_HANDLE] = node->service_id,
 			[KEY_INDEX] = node->index
 		};
@@ -138,5 +138,5 @@
 		async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
 		sysarg_t rc = async_req_2_0(exch, VFS_OUT_DESTROY,
-		    (sysarg_t) node->devmap_handle, (sysarg_t)node->index);
+		    (sysarg_t) node->service_id, (sysarg_t)node->index);
 		
 		assert(rc == EOK);
@@ -160,5 +160,5 @@
 	unsigned long key[] = {
 		[KEY_FS_HANDLE] = node->fs_handle,
-		[KEY_DEV_HANDLE] = node->devmap_handle,
+		[KEY_DEV_HANDLE] = node->service_id,
 		[KEY_INDEX] = node->index
 	};
@@ -184,5 +184,5 @@
 	unsigned long key[] = {
 		[KEY_FS_HANDLE] = result->triplet.fs_handle,
-		[KEY_DEV_HANDLE] = result->triplet.devmap_handle,
+		[KEY_DEV_HANDLE] = result->triplet.service_id,
 		[KEY_INDEX] = result->triplet.index
 	};
@@ -200,5 +200,5 @@
 		memset(node, 0, sizeof(vfs_node_t));
 		node->fs_handle = result->triplet.fs_handle;
-		node->devmap_handle = result->triplet.devmap_handle;
+		node->service_id = result->triplet.service_id;
 		node->index = result->triplet.index;
 		node->size = result->size;
@@ -252,5 +252,5 @@
 	vfs_node_t *node = hash_table_get_instance(item, vfs_node_t, nh_link);
 	return (node->fs_handle == (fs_handle_t) key[KEY_FS_HANDLE]) &&
-	    (node->devmap_handle == key[KEY_DEV_HANDLE]) &&
+	    (node->service_id == key[KEY_DEV_HANDLE]) &&
 	    (node->index == key[KEY_INDEX]);
 }
@@ -264,5 +264,5 @@
 	unsigned refcnt;
 	fs_handle_t fs_handle;
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 };
 
@@ -273,15 +273,15 @@
 
 	if ((node->fs_handle == rd->fs_handle) &&
-	    (node->devmap_handle == rd->devmap_handle))
+	    (node->service_id == rd->service_id))
 		rd->refcnt += node->refcnt;
 }
 
 unsigned
-vfs_nodes_refcount_sum_get(fs_handle_t fs_handle, devmap_handle_t devmap_handle)
+vfs_nodes_refcount_sum_get(fs_handle_t fs_handle, service_id_t service_id)
 {
 	struct refcnt_data rd = {
 		.refcnt = 0,
 		.fs_handle = fs_handle,
-		.devmap_handle = devmap_handle
+		.service_id = service_id
 	};
 
@@ -305,5 +305,5 @@
 	ipc_call_t answer;
 	aid_t req = async_send_2(exch, VFS_OUT_OPEN_NODE,
-	    (sysarg_t) node->devmap_handle, (sysarg_t) node->index, &answer);
+	    (sysarg_t) node->service_id, (sysarg_t) node->index, &answer);
 	
 	vfs_exchange_release(exch);
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/vfs/vfs_ops.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -54,5 +54,5 @@
 
 /* Forward declarations of static functions. */
-static int vfs_truncate_internal(fs_handle_t, devmap_handle_t, fs_index_t,
+static int vfs_truncate_internal(fs_handle_t, service_id_t, fs_index_t,
     aoff64_t);
 
@@ -65,8 +65,8 @@
 vfs_pair_t rootfs = {
 	.fs_handle = 0,
-	.devmap_handle = 0
+	.service_id = 0
 };
 
-static void vfs_mount_internal(ipc_callid_t rid, devmap_handle_t devmap_handle,
+static void vfs_mount_internal(ipc_callid_t rid, service_id_t service_id,
     fs_handle_t fs_handle, char *mp, char *opts)
 {
@@ -125,5 +125,5 @@
 			exch = vfs_exchange_grab(fs_handle);
 			msg = async_send_1(exch, VFS_OUT_MOUNTED,
-			    (sysarg_t) devmap_handle, &answer);
+			    (sysarg_t) service_id, &answer);
 			/* Send the mount options */
 			rc = async_data_write_start(exch, (void *)opts,
@@ -150,5 +150,5 @@
 			
 			mr_res.triplet.fs_handle = fs_handle;
-			mr_res.triplet.devmap_handle = devmap_handle;
+			mr_res.triplet.service_id = service_id;
 			mr_res.triplet.index = rindex;
 			mr_res.size = rsize;
@@ -157,5 +157,5 @@
 			
 			rootfs.fs_handle = fs_handle;
-			rootfs.devmap_handle = devmap_handle;
+			rootfs.service_id = service_id;
 			
 			/* Add reference to the mounted root. */
@@ -178,6 +178,6 @@
 	
 	/*
-	 * At this point, we have all necessary pieces: file system and device
-	 * handles, and we know the mount point VFS node.
+	 * At this point, we have all necessary pieces: file system handle
+	 * and service ID, and we know the mount point VFS node.
 	 */
 	
@@ -187,8 +187,8 @@
 	exch = vfs_exchange_grab(mp_res.triplet.fs_handle);
 	msg = async_send_4(exch, VFS_OUT_MOUNT,
-	    (sysarg_t) mp_res.triplet.devmap_handle,
+	    (sysarg_t) mp_res.triplet.service_id,
 	    (sysarg_t) mp_res.triplet.index,
 	    (sysarg_t) fs_handle,
-	    (sysarg_t) devmap_handle, &answer);
+	    (sysarg_t) service_id, &answer);
 	
 	/* Send connection */
@@ -234,5 +234,5 @@
 		
 		mr_res.triplet.fs_handle = fs_handle;
-		mr_res.triplet.devmap_handle = devmap_handle;
+		mr_res.triplet.service_id = service_id;
 		mr_res.triplet.index = rindex;
 		mr_res.size = rsize;
@@ -255,5 +255,5 @@
 void vfs_mount(ipc_callid_t rid, ipc_call_t *request)
 {
-	devmap_handle_t devmap_handle;
+	service_id_t service_id;
 
 	/*
@@ -262,5 +262,5 @@
 	 * in the request.
 	 */
-	devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	service_id = (service_id_t) IPC_GET_ARG1(*request);
 	
 	/*
@@ -350,5 +350,5 @@
 	
 	/* Do the mount */
-	vfs_mount_internal(rid, devmap_handle, fs_handle, mp, opts);
+	vfs_mount_internal(rid, service_id, fs_handle, mp, opts);
 	free(mp);
 	free(fs_name);
@@ -409,5 +409,5 @@
 	 */
 	if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,
-	    mr_node->devmap_handle) != 2) {
+	    mr_node->service_id) != 2) {
 		fibril_rwlock_write_unlock(&namespace_rwlock);
 		vfs_node_put(mr_node);
@@ -430,5 +430,5 @@
 		exch = vfs_exchange_grab(mr_node->fs_handle);
 		rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
-		    mr_node->devmap_handle);
+		    mr_node->service_id);
 		vfs_exchange_release(exch);
 		
@@ -441,5 +441,5 @@
 		
 		rootfs.fs_handle = 0;
-		rootfs.devmap_handle = 0;
+		rootfs.service_id = 0;
 	} else {
 		
@@ -470,5 +470,5 @@
 		exch = vfs_exchange_grab(mp_node->fs_handle);
 		rc = async_req_2_0(exch, VFS_OUT_UNMOUNT,
-		    mp_node->devmap_handle, mp_node->index);
+		    mp_node->service_id, mp_node->index);
 		vfs_exchange_release(exch);
 		
@@ -575,5 +575,5 @@
 		if (node->size) {
 			rc = vfs_truncate_internal(node->fs_handle,
-			    node->devmap_handle, node->index, 0);
+			    node->service_id, node->index, 0);
 			if (rc) {
 				fibril_rwlock_write_unlock(&node->contents_rwlock);
@@ -639,5 +639,5 @@
 	aid_t msg;
 	ipc_call_t answer;
-	msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->devmap_handle,
+	msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
 	    file->node->index, &answer);
 	
@@ -724,5 +724,5 @@
 	if (read) {
 		rc = async_data_read_forward_4_1(fs_exch, VFS_OUT_READ,
-		    file->node->devmap_handle, file->node->index,
+		    file->node->service_id, file->node->index,
 		    LOWER32(file->pos), UPPER32(file->pos), &answer);
 	} else {
@@ -731,5 +731,5 @@
 		
 		rc = async_data_write_forward_4_1(fs_exch, VFS_OUT_WRITE,
-		    file->node->devmap_handle, file->node->index,
+		    file->node->service_id, file->node->index,
 		    LOWER32(file->pos), UPPER32(file->pos), &answer);
 	}
@@ -862,10 +862,10 @@
 }
 
-int vfs_truncate_internal(fs_handle_t fs_handle, devmap_handle_t devmap_handle,
+int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
     fs_index_t index, aoff64_t size)
 {
 	async_exch_t *exch = vfs_exchange_grab(fs_handle);
 	sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE,
-	    (sysarg_t) devmap_handle, (sysarg_t) index, LOWER32(size),
+	    (sysarg_t) service_id, (sysarg_t) index, LOWER32(size),
 	    UPPER32(size));
 	vfs_exchange_release(exch);
@@ -890,5 +890,5 @@
 	fibril_rwlock_write_lock(&file->node->contents_rwlock);
 	rc = vfs_truncate_internal(file->node->fs_handle,
-	    file->node->devmap_handle, file->node->index, size);
+	    file->node->service_id, file->node->index, size);
 	if (rc == EOK)
 		file->node->size = size;
@@ -924,5 +924,5 @@
 	
 	aid_t msg;
-	msg = async_send_3(exch, VFS_OUT_STAT, file->node->devmap_handle,
+	msg = async_send_3(exch, VFS_OUT_STAT, file->node->service_id,
 	    file->node->index, true, NULL);
 	async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
@@ -977,5 +977,5 @@
 	
 	aid_t msg;
-	msg = async_send_3(exch, VFS_OUT_STAT, node->devmap_handle,
+	msg = async_send_3(exch, VFS_OUT_STAT, node->service_id,
 	    node->index, false, NULL);
 	async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
@@ -1154,5 +1154,5 @@
 	/* Check whether linking to the same file system instance. */
 	if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
-	    (old_node->devmap_handle != new_par_lr.triplet.devmap_handle)) {
+	    (old_node->service_id != new_par_lr.triplet.service_id)) {
 		fibril_rwlock_write_unlock(&namespace_rwlock);
 		vfs_node_put(old_node);
Index: uspace/srv/vfs/vfs_register.c
===================================================================
--- uspace/srv/vfs/vfs_register.c	(revision d894fbdb1cbc656ff7db4a33f03a2d331d2b4837)
+++ uspace/srv/vfs/vfs_register.c	(revision 42a619b240617c4f0e4dd04ddf2366f3c5a0709a)
@@ -306,5 +306,5 @@
 	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) {
 			handle = fs->fs_handle;
 			break;
