Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ boot/Makefile.common	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -150,5 +150,4 @@
 	$(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: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/Makefile	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -44,5 +44,4 @@
 	app/killall \
 	app/klog \
-	app/locinfo \
 	app/lsusb \
 	app/mkfat \
Index: uspace/app/lsusb/main.c
===================================================================
--- uspace/app/lsusb/main.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/app/lsusb/main.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -50,12 +50,15 @@
 
 #define MAX_USB_ADDRESS USB11_ADDRESS_MAX
+#define MAX_FAILED_ATTEMPTS 10
 #define MAX_PATH_LENGTH 1024
 
-static void print_found_hc(service_id_t sid, const char *path)
+static void print_found_hc(size_t class_index, const char *path)
 {
-	printf("Bus %" PRIun ": %s\n", sid, path);
+	// printf(NAME ": host controller %zu is `%s'.\n", class_index, path);
+	printf("Bus %02zu: %s\n", class_index, 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);
 }
@@ -92,29 +95,13 @@
 int main(int argc, char *argv[])
 {
-	category_id_t usbhc_cat;
-	service_id_t *svcs;
-	size_t count;
-	size_t i;
-	int rc;
+	size_t class_index = 0;
+	size_t failed_attempts = 0;
 
-	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++) {
+	while (failed_attempts < MAX_FAILED_ATTEMPTS) {
+		class_index++;
 		devman_handle_t hc_handle = 0;
-		int rc = usb_ddf_get_hc_handle_by_sid(svcs[i], &hc_handle);
+		int rc = usb_ddf_get_hc_handle_by_class(class_index, &hc_handle);
 		if (rc != EOK) {
-			printf(NAME ": Error resolving handle of HC with SID %"
-			    PRIun ", skipping.\n", svcs[i]);
+			failed_attempts++;
 			continue;
 		}
@@ -122,13 +109,9 @@
 		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(svcs[i], path);
+		print_found_hc(class_index, path);
 		print_hc_devices(hc_handle);
 	}
-
-	free(svcs);
 
 	return 0;
Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/app/tester/Makefile	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -56,4 +56,6 @@
 	mm/malloc3.c \
 	mm/mapping1.c \
+	devs/devman1.c \
+	devs/devman2.c \
 	hw/misc/virtchar1.c \
 	hw/serial/serial1.c \
Index: uspace/app/tester/devs/devman1.c
===================================================================
--- uspace/app/tester/devs/devman1.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
+++ uspace/app/tester/devs/devman1.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -0,0 +1,89 @@
+/*
+ * 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: uspace/app/tester/devs/devman1.def
===================================================================
--- uspace/app/tester/devs/devman1.def	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
+++ uspace/app/tester/devs/devman1.def	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -0,0 +1,6 @@
+{
+	"devman1",
+	"devman test",
+	&test_devman1,
+	false
+},
Index: uspace/app/tester/devs/devman2.c
===================================================================
--- uspace/app/tester/devs/devman2.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
+++ uspace/app/tester/devs/devman2.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -0,0 +1,94 @@
+/*
+ * 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, "/loc/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: uspace/app/tester/devs/devman2.def
===================================================================
--- uspace/app/tester/devs/devman2.def	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
+++ uspace/app/tester/devs/devman2.def	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -0,0 +1,6 @@
+{
+	"devman2",
+	"devman test",
+	&test_devman2,
+	false
+},
Index: uspace/app/tester/hw/misc/virtchar1.c
===================================================================
--- uspace/app/tester/hw/misc/virtchar1.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/app/tester/hw/misc/virtchar1.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -49,4 +49,5 @@
 
 #define DEVICE_PATH_NORMAL "/loc/devices/\\virt\\null\\a"
+#define DEVICE_PATH_CLASSES "/loc/class/virt-null\\1"
 #define BUFFER_SIZE 64
 
@@ -104,4 +105,9 @@
 	}
 
+	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 f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/app/tester/tester.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -68,4 +68,6 @@
 #include "hw/misc/virtchar1.def"
 #include "libext2/libext2_1.def"
+#include "devs/devman1.def"
+#include "devs/devman2.def"
 	{NULL, NULL, NULL, false}
 };
Index: uspace/drv/bus/usb/ehci/main.c
===================================================================
--- uspace/drv/bus/usb/ehci/main.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/bus/usb/ehci/main.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -101,5 +101,5 @@
 	    "Failed to bind EHCI function: %s.\n",
 	    str_error(ret));
-	ret = ddf_fun_add_to_category(hc_fun, USB_HC_CATEGORY);
+	ret = ddf_fun_add_to_class(hc_fun, USB_HC_DDF_CLASS_NAME);
 	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 f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/bus/usb/ohci/ohci.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -244,5 +244,5 @@
 	    "Failed to bind OHCI device function: %s.\n", str_error(ret));
 
-	ret = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
+	ret = ddf_fun_add_to_class(instance->hc_fun, USB_HC_DDF_CLASS_NAME);
 	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 f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/bus/usb/uhci/uhci.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -267,5 +267,5 @@
 	    str_error(ret));
 
-	ret = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
+	ret = ddf_fun_add_to_class(instance->hc_fun, USB_HC_DDF_CLASS_NAME);
 	CHECK_RET_FINI_RETURN(ret,
 	    "Failed to add UHCI to HC class: %s.\n", str_error(ret));
Index: uspace/drv/bus/usb/usbhid/kbd/kbddev.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/kbddev.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/bus/usb/usbhid/kbd/kbddev.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -102,5 +102,5 @@
 
 const char *HID_KBD_FUN_NAME = "keyboard";
-const char *HID_KBD_CATEGORY_NAME = "keyboard";
+const char *HID_KBD_CLASS_NAME = "keyboard";
 
 static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev);
@@ -551,10 +551,10 @@
 	    HID_KBD_FUN_NAME, fun->handle);
 	
-	usb_log_debug("Adding DDF function to category %s...\n", 
+	usb_log_debug("Adding DDF function to class %s...\n", 
 	    HID_KBD_CLASS_NAME);
-	rc = ddf_fun_add_to_category(fun, HID_KBD_CATEGORY_NAME);
+	rc = ddf_fun_add_to_class(fun, HID_KBD_CLASS_NAME);
 	if (rc != EOK) {
 		usb_log_error(
-		    "Could not add DDF function to category %s: %s.\n",
+		    "Could not add DDF function to class %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 f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -74,6 +74,6 @@
 const char *HID_MOUSE_FUN_NAME = "mouse";
 const char *HID_MOUSE_WHEEL_FUN_NAME = "mouse-wheel";
-const char *HID_MOUSE_CATEGORY = "mouse";
-const char *HID_MOUSE_WHEEL_CATEGORY = "keyboard";
+const char *HID_MOUSE_CLASS_NAME = "mouse";
+const char *HID_MOUSE_WHEEL_CLASS_NAME = "keyboard";
 
 /** Default idle rate for mouses. */
@@ -345,11 +345,11 @@
 	}
 	
-	usb_log_debug("Adding DDF function to category %s...\n", 
-	    HID_MOUSE_CATEGORY);
-	rc = ddf_fun_add_to_category(fun, HID_MOUSE_CATEGORY);
+	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);
 	if (rc != EOK) {
 		usb_log_error(
-		    "Could not add DDF function to category %s: %s.\n",
-		    HID_MOUSE_CATEGORY, str_error(rc));
+		    "Could not add DDF function to class %s: %s.\n",
+		    HID_MOUSE_CLASS_NAME, str_error(rc));
 		ddf_fun_destroy(fun);
 		return rc;
@@ -383,11 +383,11 @@
 	}
 	
-	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);
+	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);
 	if (rc != EOK) {
 		usb_log_error(
-		    "Could not add DDF function to category %s: %s.\n",
-		    HID_MOUSE_WHEEL_CATEGORY, str_error(rc));
+		    "Could not add DDF function to class %s: %s.\n",
+		    HID_MOUSE_WHEEL_CLASS_NAME, 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 f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/bus/usb/usbhid/mouse/mousedev.h	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -59,5 +59,5 @@
 
 const char *HID_MOUSE_FUN_NAME;
-const char *HID_MOUSE_CATEGORY;
+const char *HID_MOUSE_CLASS_NAME;
 
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/bus/usb/usbhid/multimedia/multimedia.c
===================================================================
--- uspace/drv/bus/usb/usbhid/multimedia/multimedia.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/bus/usb/usbhid/multimedia/multimedia.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -205,11 +205,11 @@
 	}
 	
-	usb_log_debug("%s function created (handle: %" PRIun ").\n",
+	usb_log_debug("%s function created (jandle: %" PRIun ").\n",
 	    NAME, fun->handle);
 	
-	rc = ddf_fun_add_to_category(fun, "keyboard");
+	rc = ddf_fun_add_to_class(fun, "keyboard");
 	if (rc != EOK) {
 		usb_log_error(
-		    "Could not add DDF function to category 'keyboard': %s.\n",
+		    "Could not add DDF function to class '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 f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/bus/usb/usbhub/usbhub.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -131,5 +131,5 @@
 	opResult = ddf_fun_bind(hub_fun);
 	assert(opResult == EOK);
-	opResult = ddf_fun_add_to_category(hub_fun, "hub");
+	opResult = ddf_fun_add_to_class(hub_fun, "hub");
 	assert(opResult == EOK);
 
Index: uspace/drv/bus/usb/usbmouse/init.c
===================================================================
--- uspace/drv/bus/usb/usbmouse/init.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/bus/usb/usbmouse/init.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -116,5 +116,5 @@
 	
 	/* Add the function to mouse class. */
-	rc = ddf_fun_add_to_category(mouse->mouse_fun, "mouse");
+	rc = ddf_fun_add_to_class(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 f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/bus/usb/vhc/main.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -104,5 +104,5 @@
 	}
 
-	rc = ddf_fun_add_to_category(hc, USB_HC_CATEGORY);
+	rc = ddf_fun_add_to_class(hc, USB_HC_DDF_CLASS_NAME);
 	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 f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/char/ns8250/ns8250.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -781,5 +781,5 @@
 	ns->fun = fun;
 	
-	ddf_fun_add_to_category(fun, "serial");
+	ddf_fun_add_to_class(fun, "serial");
 	
 	ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
Index: uspace/drv/test/test1/test1.c
===================================================================
--- uspace/drv/test/test1/test1.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/test/test1/test1.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -143,9 +143,9 @@
 	}
 
-	ddf_fun_add_to_category(fun_a, "virtual");
+	ddf_fun_add_to_class(fun_a, "virtual");
 
 	if (str_cmp(dev->name, "null") == 0) {
 		fun_a->ops = &char_device_ops;
-		ddf_fun_add_to_category(fun_a, "virt-null");
+		ddf_fun_add_to_class(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 f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/test/test2/test2.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -123,5 +123,5 @@
 	}
 
-	ddf_fun_add_to_category(fun_a, "virtual");
+	ddf_fun_add_to_class(fun_a, "virtual");
 
 	return EOK;
Index: uspace/drv/test/test3/test3.c
===================================================================
--- uspace/drv/test/test3/test3.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/drv/test/test3/test3.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -50,5 +50,5 @@
 };
 
-static int register_fun_and_add_to_category(ddf_dev_t *parent,
+static int register_fun_and_add_to_class(ddf_dev_t *parent,
      const char *base_name, size_t index, const char *class_name)
 {
@@ -77,5 +77,5 @@
 	}
 	
-	ddf_fun_add_to_category(fun, class_name);
+	ddf_fun_add_to_class(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_category(dev,
+		rc = register_fun_and_add_to_class(dev,
 		    "test3_", i, "test3");
 		if (rc != EOK) {
Index: uspace/lib/c/generic/devman.c
===================================================================
--- uspace/lib/c/generic/devman.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/c/generic/devman.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -271,14 +271,14 @@
 }
 
-int devman_add_device_to_category(devman_handle_t devman_handle,
-    const char *cat_name)
+int devman_add_device_to_class(devman_handle_t devman_handle,
+    const char *class_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_CATEGORY,
+	aid_t req = async_send_1(exch, DEVMAN_ADD_DEVICE_TO_CLASS,
 	    devman_handle, &answer);
-	sysarg_t retval = async_data_write_start(exch, cat_name,
-	    str_size(cat_name));
+	sysarg_t retval = async_data_write_start(exch, class_name,
+	    str_size(class_name));
 	
 	devman_exchange_end(exch);
@@ -333,5 +333,5 @@
 		exch = devman_exchange_begin(DEVMAN_CLIENT);
 		if (exch == NULL)
-			return ENOMEM;
+			return errno;
 	}
 	
@@ -364,9 +364,59 @@
 }
 
+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 ENOMEM;
+		return errno;
 	
 	ipc_call_t answer;
@@ -413,17 +463,4 @@
 }
 
-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: uspace/lib/c/generic/loc.c
===================================================================
--- uspace/lib/c/generic/loc.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/c/generic/loc.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -45,7 +45,4 @@
 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;
@@ -54,40 +51,4 @@
 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)
@@ -99,38 +60,4 @@
 	
 	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;
 }
 
@@ -364,15 +291,14 @@
 }
 
-/** Get object name.
- *
- * Provided ID of an object, return its name.
- *
- * @param method	IPC method
- * @param id		Object ID
+/** 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
  */
-static int loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
+int loc_service_get_name(service_id_t svc_id, char **name)
 {
 	async_exch_t *exch;
@@ -386,5 +312,5 @@
 	
 	ipc_call_t answer;
-	aid_t req = async_send_1(exch, method, id, &answer);
+	aid_t req = async_send_1(exch, LOC_SERVICE_GET_NAME, svc_id, &answer);
 	aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
 	    &dreply);
@@ -415,31 +341,4 @@
 }
 
-/** 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,
@@ -850,11 +749,2 @@
 	    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/include/devman.h
===================================================================
--- uspace/lib/c/include/devman.h	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/c/include/devman.h	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -38,5 +38,4 @@
 
 #include <ipc/devman.h>
-#include <ipc/loc.h>
 #include <async.h>
 #include <bool.h>
@@ -57,8 +56,9 @@
 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_category(devman_handle_t, const char *);
-extern int devman_fun_sid_to_handle(service_id_t, devman_handle_t *);
+extern int devman_add_device_to_class(devman_handle_t, const char *);
 
 #endif
Index: uspace/lib/c/include/ipc/devman.h
===================================================================
--- uspace/lib/c/include/ipc/devman.h	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/c/include/ipc/devman.h	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -138,5 +138,5 @@
 	DEVMAN_ADD_FUNCTION,
 	DEVMAN_ADD_MATCH_ID,
-	DEVMAN_ADD_DEVICE_TO_CATEGORY
+	DEVMAN_ADD_DEVICE_TO_CLASS
 
 } driver_to_devman_t;
@@ -149,6 +149,6 @@
 typedef enum {
 	DEVMAN_DEVICE_GET_HANDLE = IPC_FIRST_USER_METHOD,
-	DEVMAN_DEVICE_GET_DEVICE_PATH,
-	DEVMAN_FUN_SID_TO_HANDLE
+	DEVMAN_DEVICE_GET_HANDLE_BY_CLASS,
+	DEVMAN_DEVICE_GET_DEVICE_PATH
 } client_to_devman_t;
 
Index: uspace/lib/c/include/ipc/loc.h
===================================================================
--- uspace/lib/c/include/ipc/loc.h	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/c/include/ipc/loc.h	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -57,7 +57,5 @@
 	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,
@@ -70,8 +68,4 @@
 	LOC_GET_SERVICES
 } loc_request_t;
-
-typedef enum {
-	LOC_EVENT_CAT_CHANGE = IPC_FIRST_USER_METHOD
-} loc_event_t;
 
 /** Ports provided by location service.
Index: uspace/lib/c/include/loc.h
===================================================================
--- uspace/lib/c/include/loc.h	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/c/include/loc.h	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -40,6 +40,4 @@
 #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);
@@ -75,5 +73,4 @@
 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);
 
 
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/drv/generic/driver.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -635,14 +635,14 @@
 }
 
-/** Add exposed function to category.
+/** Add exposed function to class.
  *
  * Must only be called when the function is bound.
  */
-int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name)
+int ddf_fun_add_to_class(ddf_fun_t *fun, const char *class_name)
 {
 	assert(fun->bound == true);
 	assert(fun->ftype == fun_exposed);
 	
-	return devman_add_device_to_category(fun->handle, cat_name);
+	return devman_add_device_to_class(fun->handle, class_name);
 }
 
Index: uspace/lib/drv/include/ddf/driver.h
===================================================================
--- uspace/lib/drv/include/ddf/driver.h	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/drv/include/ddf/driver.h	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -151,5 +151,5 @@
 extern int ddf_fun_add_match_id(ddf_fun_t *, const char *, int);
 
-extern int ddf_fun_add_to_category(ddf_fun_t *, const char *);
+extern int ddf_fun_add_to_class(ddf_fun_t *, const char *);
 
 #endif
Index: uspace/lib/usb/include/usb/hc.h
===================================================================
--- uspace/lib/usb/include/usb/hc.h	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/usb/include/usb/hc.h	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -38,5 +38,4 @@
 #include <sys/types.h>
 #include <ipc/devman.h>
-#include <ipc/loc.h>
 #include <ddf/driver.h>
 #include <bool.h>
@@ -69,5 +68,5 @@
     devman_handle_t *);
 
-int usb_ddf_get_hc_handle_by_sid(service_id_t, devman_handle_t *);
+int usb_ddf_get_hc_handle_by_class(size_t, devman_handle_t *);
 
 
Index: uspace/lib/usb/include/usb/usb.h
===================================================================
--- uspace/lib/usb/include/usb/usb.h	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/usb/include/usb/usb.h	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -174,6 +174,6 @@
 } usb_packet_id;
 
-/** Category for USB host controllers. */
-#define USB_HC_CATEGORY "usbhc"
+/** Class name for USB host controllers. */
+#define USB_HC_DDF_CLASS_NAME "usbhc"
 
 #endif
Index: uspace/lib/usb/src/hc.c
===================================================================
--- uspace/lib/usb/src/hc.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/usb/src/hc.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -201,19 +201,32 @@
 /** Get host controller handle by its class index.
  *
- * @param sid Service ID of the HC function.
+ * @param class_index Class index for the host controller.
  * @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_sid(service_id_t sid, devman_handle_t *hc_handle)
-{
-	devman_handle_t handle;
+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 rc;
-	
-	rc = devman_fun_sid_to_handle(sid, &handle);
-	if (hc_handle != NULL)
-		*hc_handle = handle;
-	
-	return 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;
 }
 
Index: uspace/lib/usb/src/resolve.c
===================================================================
--- uspace/lib/usb/src/resolve.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/lib/usb/src/resolve.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -46,10 +46,10 @@
     devman_handle_t *out_hc_handle, usb_address_t *out_device_address)
 {
-	uint64_t sid;
+	size_t class_index;
 	size_t address;
 	int rc;
 	char *ptr;
 
-	rc = str_uint64(path, &ptr, 10, false, &sid);
+	rc = str_size_t(path, &ptr, 10, false, &class_index);
 	if (rc != EOK) {
 		return false;
@@ -64,5 +64,5 @@
 		return false;
 	}
-	rc = usb_ddf_get_hc_handle_by_sid(sid, out_hc_handle);
+	rc = usb_ddf_get_hc_handle_by_class(class_index, out_hc_handle);
 	if (rc != EOK) {
 		return false;
Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/srv/devman/devman.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -73,4 +73,14 @@
 }
 
+static int loc_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, loc_link);
+	assert(class_info != NULL);
+
+	return (class_info->service_id == (service_id_t) key[0]);
+}
+
 static void devices_remove_callback(link_t *item)
 {
@@ -92,4 +102,10 @@
 	.hash = devices_hash,
 	.compare = loc_functions_compare,
+	.remove_callback = devices_remove_callback
+};
+
+static hash_table_operations_t loc_devices_class_ops = {
+	.hash = devices_hash,
+	.compare = loc_devices_class_compare,
 	.remove_callback = devices_remove_callback
 };
@@ -934,4 +950,5 @@
 		link_initialize(&res->dev_functions);
 		list_initialize(&res->match_ids.ids);
+		list_initialize(&res->classes);
 		link_initialize(&res->devman_fun);
 		link_initialize(&res->loc_fun);
@@ -1176,4 +1193,34 @@
 }
 
+/** 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.
  *
@@ -1188,4 +1235,187 @@
 	return find_fun_node_in_device(pfun->child, name);
 }
+
+/* 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->loc_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->loc_functions, DEVICE_BUCKETS, 1,
+	    &loc_devices_class_ops);
+}
+
 
 /* loc devices */
@@ -1206,4 +1436,35 @@
 }
 
+fun_node_t *find_loc_class_function(class_list_t *classes,
+    service_id_t service_id)
+{
+	fun_node_t *fun = NULL;
+	dev_class_info_t *cli;
+	link_t *link;
+	unsigned long key = (unsigned long)service_id;
+	
+	fibril_rwlock_read_lock(&classes->rwlock);
+	link = hash_table_find(&classes->loc_functions, &key);
+	if (link != NULL) {
+		cli = hash_table_get_instance(link, dev_class_info_t,
+		    loc_link);
+		fun = cli->fun;
+	}
+	fibril_rwlock_read_unlock(&classes->rwlock);
+	
+	return fun;
+}
+
+void class_add_loc_function(class_list_t *class_list, dev_class_info_t *cli)
+{
+	unsigned long key = (unsigned long) cli->service_id;
+	
+	fibril_rwlock_write_lock(&class_list->rwlock);
+	hash_table_insert(&class_list->loc_functions, &key, &cli->loc_link);
+	fibril_rwlock_write_unlock(&class_list->rwlock);
+
+	assert(find_loc_class_function(class_list, cli->service_id) != NULL);
+}
+
 void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
 {
Index: uspace/srv/devman/devman.h
===================================================================
--- uspace/srv/devman/devman.h	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/srv/devman/devman.h	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -53,4 +53,5 @@
 #define DEVICE_BUCKETS 256
 
+#define LOC_CLASS_NAMESPACE "class"
 #define LOC_DEVICE_NAMESPACE "devices"
 #define LOC_SEPARATOR '\\'
@@ -169,4 +170,6 @@
 	match_id_list_t match_ids;
 	
+	/** List of device classes to which this device function belongs. */
+	list_t classes;
 	/** Service ID if the device function is registered with loc. */
 	service_id_t service_id;
@@ -210,4 +213,82 @@
 	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;
+	/** Service ID in the class namespace. */
+	service_id_t service_id;
+	
+	/**
+	 * Link to hash table of services registered with location service using
+	 * their class names.
+	 */
+	link_t loc_link;
+} dev_class_info_t;
+
+/** The list of device classes. */
+typedef struct class_list {
+	/** List of classes. */
+	list_t classes;
+	
+	/**
+	 * Hash table of services registered with location service using their
+	 * class name, indexed by service IDs.
+	 */
+	hash_table_t loc_functions;
+	
+	/** Fibril mutex for list of classes. */
+	fibril_rwlock_t rwlock;
+} class_list_t;
 
 /* Match ids and scores */
@@ -258,4 +339,5 @@
 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 */
@@ -266,4 +348,20 @@
 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 *);
+
 /* Loc services */
 
@@ -271,5 +369,7 @@
 
 extern fun_node_t *find_loc_tree_function(dev_tree_t *, service_id_t);
-
+extern fun_node_t *find_loc_class_function(class_list_t *, service_id_t);
+
+extern void class_add_loc_function(class_list_t *, dev_class_info_t *);
 extern void tree_add_loc_function(dev_tree_t *, fun_node_t *);
 
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/srv/devman/main.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -64,4 +64,5 @@
 static driver_list_t drivers_list;
 static dev_tree_t device_tree;
+static class_list_t class_list;
 
 /** Register running driver. */
@@ -332,5 +333,31 @@
 }
 
-static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
+static void loc_register_class_dev(dev_class_info_t *cli)
+{
+	/* Create loc path and name for the service. */
+	char *loc_pathname = NULL;
+
+	asprintf(&loc_pathname, "%s/%s%c%s", LOC_CLASS_NAMESPACE,
+	    cli->dev_class->name, LOC_SEPARATOR, cli->dev_name);
+	if (loc_pathname == NULL)
+		return;
+	
+	/*
+	 * Register the device with location service and remember its
+	 * service ID.
+	 */
+	loc_service_register_with_iface(loc_pathname,
+	    &cli->service_id, DEVMAN_CONNECT_FROM_LOC);
+	
+	/*
+	 * Add device to the hash map of class devices registered with
+	 * location service.
+	 */
+	class_add_loc_function(&class_list, cli);
+	
+	free(loc_pathname);
+}
+
+static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call)
 {
 	devman_handle_t handle = IPC_GET_ARG1(*call);
@@ -338,7 +365,7 @@
 	int rc;
 	
-	/* Get category name. */
-	char *cat_name;
-	rc = async_data_write_accept((void **) &cat_name, true,
+	/* Get class name. */
+	char *class_name;
+	rc = async_data_write_accept((void **) &class_name, true,
 	    0, 0, 0, 0);
 	if (rc != EOK) {
@@ -353,14 +380,20 @@
 	}
 	
-	rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
+	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 with location service. */
+	loc_register_class_dev(class_info);
+	
+	rc = loc_category_get_id(class_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);
+		    "`%s'.", fun->pathname, class_name);
+	}
+	
+	log_msg(LVL_NOTE, "Function `%s' added to class `%s' as `%s'.",
+	    fun->pathname, class_name, class_info->dev_name);
 
 	async_answer_0(callid, EOK);
@@ -416,6 +449,6 @@
 			devman_add_function(callid, &call);
 			break;
-		case DEVMAN_ADD_DEVICE_TO_CATEGORY:
-			devman_add_function_to_cat(callid, &call);
+		case DEVMAN_ADD_DEVICE_TO_CLASS:
+			devman_add_function_to_class(callid, &call);
 			break;
 		default:
@@ -450,4 +483,38 @@
 }
 
+/** 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) {
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+
+	async_answer_1(iid, EOK, fun->handle);
+}
+
 /** Find device path by its handle. */
 static void devman_get_device_path_by_handle(ipc_callid_t iid,
@@ -487,18 +554,4 @@
 }
 
-/** 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. */
@@ -519,9 +572,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:
@@ -625,8 +678,8 @@
 
 	fun = find_loc_tree_function(&device_tree, service_id);
+	if (fun == NULL)
+		fun = find_loc_class_function(&class_list, 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;
@@ -634,4 +687,9 @@
 	
 	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);
@@ -695,4 +753,6 @@
 	}
 
+	init_class_list(&class_list);
+	
 	/*
 	 * !!! devman_connection ... as the device manager is not a real loc
Index: uspace/srv/hid/input/generic/input.c
===================================================================
--- uspace/srv/hid/input/generic/input.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/srv/hid/input/generic/input.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -66,4 +66,7 @@
 #include <abi/ipc/methods.h>
 
+/* In microseconds */
+#define DISCOVERY_POLL_INTERVAL  (10 * 1000 * 1000)
+
 #define NUM_LAYOUTS  3
 
@@ -494,7 +497,14 @@
 }
 
-static int dev_check_new_kbdevs(void)
-{
-	category_id_t keyboard_cat;
+/** Periodically check for new input devices.
+ *
+ * Looks under /loc/class/keyboard and /loc/class/mouse.
+ *
+ * @param arg Ignored
+ *
+ */
+static int dev_discovery_fibril(void *arg)
+{
+	category_id_t keyboard_cat, mouse_cat;
 	service_id_t *svcs;
 	size_t count, i;
@@ -508,51 +518,4 @@
 	}
 	
-	/*
-	 * 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;
-			}
-		}
-		
-		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(svcs);
-	
-	/* XXX Handle device removal */
-	
-	return EOK;
-}
-
-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) {
@@ -561,76 +524,90 @@
 	}
 	
-	/*
-	 * 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 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;
+	while (true) {
+		async_usleep(DISCOVERY_POLL_INTERVAL);
+		
+		/*
+		 * 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);
+			continue;
+		}
+
+		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;
+				}
+			}
+
+			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);
+				}
 			}
 		}
 		
-		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);
+		/* XXX Handle device removal */
+		
+		/*
+		 * 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);
+			continue;
+		}
+
+		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 */
+		
+		/* 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();
+/** 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",
+		    NAME);
+		return;
+	}
+	
+	fibril_add_ready(fid);
 }
 
Index: uspace/srv/loc/loc.c
===================================================================
--- uspace/srv/loc/loc.c	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/srv/loc/loc.c	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -84,7 +84,4 @@
 /** 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)
@@ -536,43 +533,4 @@
 }
 
-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)
 {
@@ -613,4 +571,5 @@
 	async_answer_0(iid, retval);
 }
+
 
 /** Connect client to the service.
@@ -769,44 +728,4 @@
  *
  */
-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)
 {
@@ -1210,6 +1129,4 @@
 
 	async_answer_0(iid, retval);
-
-	loc_category_change_event();
 }
 
@@ -1239,7 +1156,4 @@
 
 	cat = category_new("serial");
-	categ_dir_add_cat(&cdir, cat);
-
-	cat = category_new("usbhc");
 	categ_dir_add_cat(&cdir, cat);
 
@@ -1330,12 +1244,6 @@
 			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:
Index: uspace/srv/loc/loc.h
===================================================================
--- uspace/srv/loc/loc.h	(revision f55b12b50bc3129ca8946bc5f823407db5214561)
+++ uspace/srv/loc/loc.h	(revision 3190e88f9acc9542b60dfabd34fed444e2548d21)
@@ -102,5 +102,4 @@
 
 extern service_id_t loc_create_id(void);
-extern void loc_category_change_event(void);
 
 #endif
