Index: uspace/lib/usbdev/include/usb/dev/poll.h
===================================================================
--- uspace/lib/usbdev/include/usb/dev/poll.h	(revision 71f211f6909eb71f441da24a2ff90c3ecefd18fd)
+++ uspace/lib/usbdev/include/usb/dev/poll.h	(revision 8a0c52aeaaac4a9b56e38889ad9b3f7105544319)
@@ -102,6 +102,8 @@
 } usb_device_polling_config_t;
 
-extern int usb_device_poll(usb_device_t *, usb_endpoint_mapping_t *,
+int usb_device_poll(usb_device_t *, usb_endpoint_mapping_t *,
     const usb_device_polling_config_t *, size_t, usb_device_polling_t **);
+
+int usb_device_poll_join(usb_device_polling_t *);
 
 #endif
Index: uspace/lib/usbdev/src/devpoll.c
===================================================================
--- uspace/lib/usbdev/src/devpoll.c	(revision 71f211f6909eb71f441da24a2ff90c3ecefd18fd)
+++ uspace/lib/usbdev/src/devpoll.c	(revision 8a0c52aeaaac4a9b56e38889ad9b3f7105544319)
@@ -47,4 +47,5 @@
 #include <errno.h>
 #include <fibril.h>
+#include <fibril_synch.h>
 #include <stdbool.h>
 #include <stdlib.h>
@@ -62,5 +63,5 @@
 
 	/** Device enpoint mapping to use for polling. */
-	usb_endpoint_mapping_t *polling_mapping;
+	usb_endpoint_mapping_t *ep_mapping;
 
 	/** Size of the recieved data. */
@@ -69,5 +70,23 @@
 	/** Data buffer. */
 	uint8_t *buffer;
+
+	/** True if polling is currently in operation. */
+	volatile bool running;
+
+	/** True if polling should terminate as soon as possible. */
+	volatile bool joining;
+
+	/** Synchronization primitives for joining polling end. */
+	fibril_mutex_t guard;
+	fibril_condvar_t cv;
 };
+
+
+static void polling_fini(usb_device_polling_t *polling)
+{
+	/* Free the allocated memory. */
+	free(polling->buffer);
+	free(polling);
+}
 
 
@@ -80,14 +99,15 @@
 {
 	assert(arg);
-	const usb_device_polling_t *data = arg;
+	usb_device_polling_t *data = arg;
+	data->running = true;
 
 	/* Helper to reduce typing. */
 	const usb_device_polling_config_t *params = &data->config;
 
-	usb_pipe_t *pipe = &data->polling_mapping->pipe;
+	usb_pipe_t *pipe = &data->ep_mapping->pipe;
 
 	if (params->debug > 0) {
 		const usb_endpoint_mapping_t *mapping =
-		    data->polling_mapping;
+		    data->ep_mapping;
 		usb_log_debug("Poll (%p): started polling of `%s' - " \
 		    "interface %d (%s,%d,%d), %zuB/%zu.\n",
@@ -136,5 +156,5 @@
 			const bool cont = (params->on_error == NULL) ? true :
 			    params->on_error(data->dev, rc, params->arg);
-			if (!cont) {
+			if (!cont || data->joining) {
 				/* This is user requested abort, erases failures. */
 				failed_attempts = 0;
@@ -184,7 +204,14 @@
 	}
 
-	/* Free the allocated memory. */
-	free(data->buffer);
-	free(data);
+	data->running = false;
+
+	if (data->joining) {
+		/* Notify joiners, if any. */
+		fibril_mutex_lock(&data->guard);
+		fibril_condvar_signal(&data->cv);
+		fibril_mutex_unlock(&data->guard);
+	} else {
+		polling_fini(data);
+	}
 
 	return EOK;
@@ -235,5 +262,8 @@
 	instance->request_size = req_size;
 	instance->dev = dev;
-	instance->polling_mapping = epm;
+	instance->ep_mapping = epm;
+	instance->joining = false;
+	fibril_mutex_initialize(&instance->guard);
+	fibril_condvar_initialize(&instance->cv);
 
 	/* Copy provided settings. */
@@ -265,4 +295,30 @@
 }
 
+int usb_device_poll_join(usb_device_polling_t *polling)
+{
+	int rc;
+	if (!polling)
+		return EBADMEM;
+
+	/* Set the flag */
+	polling->joining = true;
+
+	/* Unregister the pipe. */
+	if ((rc = usb_device_unmap_ep(polling->ep_mapping))) {
+		return rc;
+	}
+
+	/* Wait for the fibril to terminate. */
+	fibril_mutex_lock(&polling->guard);
+	while (polling->running)
+		fibril_condvar_wait(&polling->cv, &polling->guard);
+	fibril_mutex_unlock(&polling->guard);
+
+	/* Free the instance. */
+	polling_fini(polling);
+
+	return EOK;
+}
+
 /**
  * @}
