Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision cce8a8318e65105693f8390140c8d7327f39cac6)
+++ uspace/srv/devman/main.c	(revision 12f9f0d0827e1f7c54cf26d56ffabf49e22936f7)
@@ -682,4 +682,6 @@
 	
 	if (fun == NULL || fun->dev->drv == NULL) {
+		log_msg(LVL_WARN, "devman_connection_loc(): function "
+		    "not found.\n");
 		async_answer_0(iid, ENOENT);
 		return;
@@ -687,9 +689,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);
Index: uspace/srv/hid/input/generic/input.c
===================================================================
--- uspace/srv/hid/input/generic/input.c	(revision cce8a8318e65105693f8390140c8d7327f39cac6)
+++ uspace/srv/hid/input/generic/input.c	(revision 12f9f0d0827e1f7c54cf26d56ffabf49e22936f7)
@@ -66,7 +66,4 @@
 #include <abi/ipc/methods.h>
 
-/* In microseconds */
-#define DISCOVERY_POLL_INTERVAL  (10 * 1000 * 1000)
-
 #define NUM_LAYOUTS  3
 
@@ -497,14 +494,7 @@
 }
 
-/** 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;
+static int dev_check_new_kbdevs(void)
+{
+	category_id_t keyboard_cat;
 	service_id_t *svcs;
 	size_t count, i;
@@ -518,4 +508,49 @@
 	}
 	
+	/*
+	 * 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);
+			}
+		}
+	}
+	
+	/* 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) {
@@ -524,90 +559,74 @@
 	}
 	
-	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);
-				}
+	/*
+	 * 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;
 			}
 		}
 		
-		/* 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);
-				}
+		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 */
-	}
+	}
+	
+	/* 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",
-		    NAME);
-		return;
-	}
-	
-	fibril_add_ready(fid);
+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();
 }
 
Index: uspace/srv/loc/loc.c
===================================================================
--- uspace/srv/loc/loc.c	(revision cce8a8318e65105693f8390140c8d7327f39cac6)
+++ uspace/srv/loc/loc.c	(revision 12f9f0d0827e1f7c54cf26d56ffabf49e22936f7)
@@ -84,4 +84,7 @@
 /** 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)
@@ -728,4 +731,44 @@
  *
  */
+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)
 {
@@ -1129,4 +1172,6 @@
 
 	async_answer_0(iid, retval);
+
+	loc_category_change_event();
 }
 
@@ -1243,4 +1288,7 @@
 		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:
Index: uspace/srv/loc/loc.h
===================================================================
--- uspace/srv/loc/loc.h	(revision cce8a8318e65105693f8390140c8d7327f39cac6)
+++ uspace/srv/loc/loc.h	(revision 12f9f0d0827e1f7c54cf26d56ffabf49e22936f7)
@@ -102,4 +102,5 @@
 
 extern service_id_t loc_create_id(void);
+extern void loc_category_change_event(void);
 
 #endif
