Index: uspace/app/tmon/Makefile
===================================================================
--- uspace/app/tmon/Makefile	(revision a8723748f11aced50ec8c8b3ca56ba447f743ba0)
+++ uspace/app/tmon/Makefile	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
@@ -30,5 +30,5 @@
 BINARY = tmon
 
-LIBS = usbdiag
+LIBS = drv usbdiag
 
 SOURCES = \
Index: uspace/app/tmon/main.c
===================================================================
--- uspace/app/tmon/main.c	(revision a8723748f11aced50ec8c8b3ca56ba447f743ba0)
+++ uspace/app/tmon/main.c	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
@@ -36,5 +36,9 @@
 
 #include <stdio.h>
+#include <loc.h>
 #include <usb/diag/diag.h>
+#include <usb/diag/iface.h>
+#include <devman.h>
+#include <errno.h>
 
 #define NAME "tmon"
@@ -43,4 +47,40 @@
 {
 	printf(NAME ": hello USB transfers!\n\n");
+}
+
+static void print_list_item(service_id_t svc)
+{
+	int rc;
+	devman_handle_t diag_handle = 0;
+
+	if ((rc = devman_fun_sid_to_handle(svc, &diag_handle))) {
+		printf(NAME ": Error resolving handle of device with SID %ld, skipping.\n", svc);
+		return;
+	}
+}
+
+static int print_list()
+{
+	category_id_t diag_cat;
+	service_id_t *svcs;
+	size_t count;
+	int rc;
+
+	if ((rc = loc_category_get_id(USB_DIAG_CATEGORY, &diag_cat, 0))) {
+		printf(NAME ": Error resolving category '%s'", USB_DIAG_CATEGORY);
+		return 1;
+	}
+
+	if ((rc = loc_category_get_svcs(diag_cat, &svcs, &count))) {
+		printf(NAME ": Error getting list of host controllers.\n");
+		return 1;
+	}
+
+	for (unsigned i = 0; i < count; ++i) {
+		print_list_item(svcs[i]);
+	}
+
+	free(svcs);
+	return 0;
 }
 
@@ -52,13 +92,5 @@
 	}
 
-	int out;
-	const int rc = usb_diag_test(0, &out);
-	if (rc) {
-		printf("Error: %d\n", rc);
-	} else {
-		printf("The number is %d.\n", out);
-	}
-
-	return 0;
+	return print_list();
 }
 
Index: uspace/drv/bus/usb/usbdiag/device.c
===================================================================
--- uspace/drv/bus/usb/usbdiag/device.c	(revision a8723748f11aced50ec8c8b3ca56ba447f743ba0)
+++ uspace/drv/bus/usb/usbdiag/device.c	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
@@ -36,4 +36,5 @@
 #include <errno.h>
 #include <usb/debug.h>
+#include <usb/diag/iface.h>
 
 #include "device.h"
@@ -41,8 +42,35 @@
 #define NAME "usbdiag"
 
+static void connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	// usb_diag_fun_t *fun = (usb_diag_fun_t *) ddf_fun_data_get((ddf_fun_t *) arg);
+
+	// FIXME: handle connection
+}
+
+static int some_test(ddf_fun_t *fun, int x, int *y)
+{
+	*y = x + 42;
+	return EOK;
+}
+
+static usb_diag_iface_t diag_interface = {
+	.test = some_test,
+};
+
+static ddf_dev_ops_t diag_ops = {
+	.interfaces[USBDIAG_DEV_IFACE] = &diag_interface
+};
+
 static int device_init(usb_diag_dev_t *dev)
 {
-	// TODO: allocate data structures, set up stuffs
+	ddf_fun_t *fun = usb_device_ddf_fun_create(dev->usb_dev, fun_exposed, "tmon");
+	if (!fun)
+		return ENOMEM;
 
+	ddf_fun_set_conn_handler(fun, connection);
+	ddf_fun_set_ops(fun, &diag_ops);
+
+	dev->fun = fun;
 	return EOK;
 }
@@ -50,5 +78,5 @@
 static void device_fini(usb_diag_dev_t *dev)
 {
-	// TODO: tear down data structures
+	ddf_fun_destroy(dev->fun);
 }
 
Index: uspace/drv/bus/usb/usbdiag/device.h
===================================================================
--- uspace/drv/bus/usb/usbdiag/device.h	(revision a8723748f11aced50ec8c8b3ca56ba447f743ba0)
+++ uspace/drv/bus/usb/usbdiag/device.h	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
@@ -40,8 +40,9 @@
 
 /**
- * USB debug device.
+ * USB diagnostic device.
  */
 typedef struct usb_diag_dev {
 	usb_device_t *usb_dev;
+	ddf_fun_t *fun;
 } usb_diag_dev_t;
 
Index: uspace/drv/bus/usb/usbdiag/main.c
===================================================================
--- uspace/drv/bus/usb/usbdiag/main.c	(revision a8723748f11aced50ec8c8b3ca56ba447f743ba0)
+++ uspace/drv/bus/usb/usbdiag/main.c	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
@@ -38,4 +38,5 @@
 #include <usb/dev/driver.h>
 #include <usb/diag/diag.h>
+#include <str_error.h>
 
 #include "usbdiag.h"
@@ -44,29 +45,39 @@
 #define NAME "usbdiag"
 
-static void usb_diag_test_impl(ipc_callid_t rid, ipc_call_t *request)
-{
-	int x = IPC_GET_ARG1(*request);
-	int ret = 4200 + x;
-	async_answer_0(rid, ret);
-}
-
 static int device_add(usb_device_t *dev)
 {
+	int rc;
 	usb_log_info("Adding device '%s'", usb_device_get_name(dev));
 
-	int err;
+	usb_diag_dev_t *diag_dev;
+	if ((rc = usb_diag_dev_create(dev, &diag_dev))) {
+		usb_log_error("Failed create device: %s.\n", str_error(rc));
+		goto err;
+	}
 
-	usb_diag_dev_t *diag_dev;
-	if ((err = usb_diag_dev_create(dev, &diag_dev)))
-		return err;
+	if ((rc = ddf_fun_bind(diag_dev->fun))) {
+		usb_log_error("Failed to bind DDF function: %s.\n", str_error(rc));
+		goto err_create;
+	}
 
-	/* TODO: Register device in some list. */
-	/* TODO: Register device DDF function. */
+	if ((rc = ddf_fun_add_to_category(diag_dev->fun, USB_DIAG_CATEGORY))) {
+		usb_log_error("Failed add DDF to category '"
+		    USB_DIAG_CATEGORY "': %s.\n", str_error(rc));
+		goto err_bind;
+	}
 
 	return EOK;
+
+err_bind:
+	ddf_fun_unbind(diag_dev->fun);
+err_create:
+	usb_diag_dev_destroy(diag_dev);
+err:
+	return rc;
 }
 
 static int device_remove(usb_device_t *dev)
 {
+	int rc;
 	usb_log_info("Removing device '%s'", usb_device_get_name(dev));
 
@@ -74,10 +85,16 @@
 
 	/* TODO: Make sure nothing is going on with the device. */
-	/* TODO: Unregister device DDF function. */
-	/* TODO: Remove device from list */
+
+	if ((rc = ddf_fun_unbind(diag_dev->fun))) {
+		usb_log_error("Failed to unbind DDF function: %s\n", str_error(rc));
+		goto err;
+	}
 
 	usb_diag_dev_destroy(diag_dev);
 
 	return EOK;
+
+err:
+	return rc;
 }
 
@@ -107,41 +124,4 @@
 }
 
-static void connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
-{
-	bool cont = true;
-
-	async_answer_0(iid, EOK);
-
-	while (cont) {
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-
-		if (!IPC_GET_IMETHOD(call))
-			break;
-
-		switch (IPC_GET_IMETHOD(call)) {
-		case USB_DIAG_IN_TEST:
-			usb_diag_test_impl(callid, &call);
-			break;
-		default:
-			async_answer_0(callid, ENOTSUP);
-			break;
-		}
-	}
-}
-
-static int server_fibril(void *arg)
-{
-	// async_set_client_data_constructor(NULL);
-	// async_set_client_data_destructor(NULL);
-	async_set_fallback_port_handler(connection, NULL);
-	// async_event_task_subscribe();
-	// service_register();
-	async_manager();
-
-	/* Never reached. */
-	return EOK;
-}
-
 /** USB diagnostic driver ops. */
 static const usb_driver_ops_t diag_driver_ops = {
@@ -166,10 +146,4 @@
 	log_init(NAME);
 
-	/* Start usbdiag service. */
-	fid_t srv = fibril_create(server_fibril, NULL);
-	if (!srv)
-		return ENOMEM;
-	fibril_add_ready(srv);
-
 	return usb_driver_main(&diag_driver);
 }
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision a8723748f11aced50ec8c8b3ca56ba447f743ba0)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
@@ -44,11 +44,11 @@
 	/** Audio device pcm buffer interface */
 	AUDIO_PCM_BUFFER_IFACE,
-	
+
 	/** Network interface controller interface */
 	NIC_DEV_IFACE,
-		
+
 	/** IEEE 802.11 interface controller interface */
 	IEEE80211_DEV_IFACE,
-	
+
 	/** Interface provided by any PCI device. */
 	PCI_DEV_IFACE,
@@ -56,4 +56,6 @@
 	/** Interface provided by any USB device. */
 	USB_DEV_IFACE,
+	/** Interface provided by USB diagnostic devices. */
+	USBDIAG_DEV_IFACE,
 	/** Interface provided by USB host controller to USB device. */
 	USBHC_DEV_IFACE,
Index: uspace/lib/usbdiag/Makefile
===================================================================
--- uspace/lib/usbdiag/Makefile	(revision a8723748f11aced50ec8c8b3ca56ba447f743ba0)
+++ uspace/lib/usbdiag/Makefile	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
@@ -32,5 +32,5 @@
 
 SOURCES = \
-	src/test.c
+	src/remote_usbdiag.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/usbdiag/include/usb/diag/diag.h
===================================================================
--- uspace/lib/usbdiag/include/usb/diag/diag.h	(revision a8723748f11aced50ec8c8b3ca56ba447f743ba0)
+++ uspace/lib/usbdiag/include/usb/diag/diag.h	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
@@ -36,12 +36,5 @@
 #define LIBUSBDIAG_DIAG_H_
 
-#include <ipc/common.h>
-
-typedef enum {
-  USB_DIAG_IN_TEST = IPC_FIRST_USER_METHOD,
-} usb_diag_in_request_t;
-
-/** Just a dummy symbol to make compiler happy. TODO: remove it */
-int usb_diag_test(int, int*);
+#define USB_DIAG_CATEGORY "usbdiag"
 
 #endif
Index: uspace/lib/usbdiag/include/usb/diag/iface.h
===================================================================
--- uspace/lib/usbdiag/include/usb/diag/iface.h	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
+++ uspace/lib/usbdiag/include/usb/diag/iface.h	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017 Petr Manek
+ * 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 libusbdiag
+ * @{
+ */
+/** @file
+ * @brief USB diagnostic device communication interface.
+ */
+#ifndef LIBUSBDIAG_IFACE_H_
+#define LIBUSBDIAG_IFACE_H_
+
+#include <async.h>
+#include <ddf/driver.h>
+
+async_sess_t *usb_diag_connect(devman_handle_t);
+void usb_diag_disconnect(async_sess_t*);
+int usb_diag_test(async_exch_t*, int, int*);
+
+/** USB diagnostic device communication interface. */
+typedef struct {
+	int (*test)(ddf_fun_t*, int, int*);
+} usb_diag_iface_t;
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usbdiag/src/remote_usbdiag.c
===================================================================
--- uspace/lib/usbdiag/src/remote_usbdiag.c	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
+++ uspace/lib/usbdiag/src/remote_usbdiag.c	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2017 Petr Manek
+ * 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 libusbdiag
+ * @{
+ */
+/** @file
+ * USB diagnostic device remote interface.
+ */
+
+#include <async.h>
+#include <assert.h>
+#include <macros.h>
+#include <errno.h>
+#include <devman.h>
+
+#include <usb/diag/iface.h>
+#include "ddf/driver.h"
+
+typedef enum {
+	IPC_M_USB_DIAG_TEST,
+} usb_iface_funcs_t;
+
+async_sess_t *usb_diag_connect(devman_handle_t handle)
+{
+	return devman_device_connect(handle, IPC_FLAG_BLOCKING);
+}
+
+void usb_diag_disconnect(async_sess_t *sess)
+{
+	if (sess)
+		async_hangup(sess);
+}
+
+int usb_diag_test(async_exch_t *exch, int x, int *y)
+{
+	if (!exch)
+		return EBADMEM;
+
+	sysarg_t y_;
+	const int ret = async_req_2_1(exch, DEV_IFACE_ID(USBDIAG_DEV_IFACE), IPC_M_USB_DIAG_TEST, x, &y_);
+
+	if (y)
+		*y = (int) y_;
+
+	return ret;
+}
+
+static void remote_usb_diag_test(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
+
+/** Remote USB diagnostic interface operations. */
+static const remote_iface_func_ptr_t remote_usb_diag_iface_ops [] = {
+	[IPC_M_USB_DIAG_TEST] = remote_usb_diag_test,
+};
+
+/** Remote USB diagnostic interface structure. */
+const remote_iface_t remote_usb_diag_iface = {
+	.method_count = ARRAY_SIZE(remote_usb_diag_iface_ops),
+	.methods = remote_usb_diag_iface_ops,
+};
+
+void remote_usb_diag_test(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
+{
+	const usb_diag_iface_t *diag_iface = (usb_diag_iface_t *) iface;
+
+	if (diag_iface->test == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+
+	int x = DEV_IPC_GET_ARG1(*call);
+	int y;
+	const int ret = diag_iface->test(fun, x, &y);
+	if (ret != EOK) {
+		async_answer_0(callid, ret);
+	} else {
+		async_answer_1(callid, EOK, y);
+	}
+}
+
+/**
+ * @}
+ */
Index: pace/lib/usbdiag/src/test.c
===================================================================
--- uspace/lib/usbdiag/src/test.c	(revision a8723748f11aced50ec8c8b3ca56ba447f743ba0)
+++ 	(revision )
@@ -1,55 +1,0 @@
-/*
- * Copyright (c) 2017 Petr Manek
- * 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 libusbdiag
- * @{
- */
-/** @file
- * Testing stuff
- */
-
-#include <async.h>
-#include <usb/diag/diag.h>
-
-int usb_diag_test(int x, int *out)
-{
-	sysarg_t _out;
-	async_sess_t *session = NULL;
-	async_exch_t *exch = async_exchange_begin(session);
-	const int rc = async_req_1_1(exch, USB_DIAG_IN_TEST, x, &_out);
-	async_exchange_end(exch);
-
-	if (out)
-		*out = (int) _out;
-
-	return rc;
-}
-
-/**
- * @}
- */
Index: uspace/srv/locsrv/locsrv.c
===================================================================
--- uspace/srv/locsrv/locsrv.c	(revision a8723748f11aced50ec8c8b3ca56ba447f743ba0)
+++ uspace/srv/locsrv/locsrv.c	(revision 64d138bec5d6824306e69dd9350f6058fb4a56a0)
@@ -1353,4 +1353,7 @@
 	categ_dir_add_cat(&cdir, cat);
 
+	cat = category_new("usbdiag");
+	categ_dir_add_cat(&cdir, cat);
+
 	cat = category_new("usbhc");
 	categ_dir_add_cat(&cdir, cat);
