Index: uspace/lib/usb/include/usb/devpoll.h
===================================================================
--- uspace/lib/usb/include/usb/devpoll.h	(revision 5e07e2b5094b0de129558ce45621318cec5853d6)
+++ uspace/lib/usb/include/usb/devpoll.h	(revision 8989f48f9bfa498b808c36381eebab4f7955d89d)
@@ -37,4 +37,47 @@
 
 #include <usb/devdrv.h>
+#include <time.h>
+
+typedef struct {
+	/** Maximum number of consecutive errors before polling termination. */
+	size_t max_failures;
+	/** Delay between poll requests in milliseconds.
+	 * Set to negative value to use value from endpoint descriptor.
+	 */
+	int delay;
+	/** Whether to automatically try to clear the HALT feature after
+	 * the endpoint stalls.
+	 */
+	bool auto_clear_halt;
+	/** Callback when data arrives.
+	 *
+	 * @param dev Device that was polled.
+	 * @param data Data buffer (in USB endianness).
+	 * @param data_size Size of the @p data buffer in bytes.
+	 * @param arg Custom argument.
+	 * @return Whether to continue in polling.
+	 */
+	bool (*on_data)(usb_device_t *dev, uint8_t *data, size_t data_size,
+	    void *arg);
+	/** Callback when polling is terminated.
+	 *
+	 * @param dev Device where the polling was terminated.
+	 * @param due_to_errors Whether polling stopped due to several failures.
+	 * @param arg Custom argument.
+	 */
+	void (*on_polling_end)(usb_device_t *dev, bool due_to_errors,
+	    void *arg);
+	/** Callback when error occurs.
+	 *
+	 * @param dev Device where error occurred.
+	 * @param err_code Error code (as returned from usb_pipe_read).
+	 * @param arg Custom argument.
+	 * @return Whether to continue in polling.
+	 */
+	bool (*on_error)(usb_device_t *dev, int err_code, void *arg);
+} usb_device_auto_polling_t;
+
+int usb_device_auto_polling(usb_device_t *, size_t, usb_device_auto_polling_t *,
+    size_t, void *);
 
 typedef bool (*usb_polling_callback_t)(usb_device_t *,
Index: uspace/lib/usb/src/devpoll.c
===================================================================
--- uspace/lib/usb/src/devpoll.c	(revision 5e07e2b5094b0de129558ce45621318cec5853d6)
+++ uspace/lib/usb/src/devpoll.c	(revision 8989f48f9bfa498b808c36381eebab4f7955d89d)
@@ -45,12 +45,18 @@
 /** Data needed for polling. */
 typedef struct {
+	size_t max_failures;
+	useconds_t delay;
+	bool auto_clear_halt;
+	bool (*on_data)(usb_device_t *, uint8_t *, size_t, void *);
+	void (*on_polling_end)(usb_device_t *, bool, void *);
+	bool (*on_error)(usb_device_t *, int, void *);
+
 	usb_device_t *dev;
 	size_t pipe_index;
-	usb_polling_callback_t callback;
-	usb_polling_terminted_callback_t terminated_callback;
 	size_t request_size;
 	uint8_t *buffer;
 	void *custom_arg;
 } polling_data_t;
+
 
 /** Polling fibril.
@@ -74,5 +80,5 @@
 
 	size_t failed_attempts = 0;
-	while (failed_attempts < MAX_FAILED_ATTEMPTS) {
+	while (failed_attempts <= polling_data->max_failures) {
 		int rc;
 
@@ -81,13 +87,25 @@
 		    polling_data->request_size, &actual_size);
 
-		
-//		if (rc == ESTALL) {
-//			usb_log_debug("Seding clear feature...\n");
-//			usb_request_clear_feature(pipe, USB_REQUEST_TYPE_STANDARD,
-//			  USB_REQUEST_RECIPIENT_ENDPOINT, 0, pipe->endpoint_no);
-//			continue;
-//		}
+		/* If the pipe stalled, we can try to reset the stall. */
+		if ((rc == ESTALL) && (polling_data->auto_clear_halt)) {
+			/*
+			 * We ignore error here as this is usually a futile
+			 * attempt anyway.
+			 */
+			usb_request_clear_endpoint_halt(
+			    &polling_data->dev->ctrl_pipe,
+			    pipe->endpoint_no);
+		}
 
 		if (rc != EOK) {
+			if (polling_data->on_error != NULL) {
+				bool cont = polling_data->on_error(
+				    polling_data->dev, rc,
+				    polling_data->custom_arg);
+				if (!cont) {
+					failed_attempts
+					    = polling_data->max_failures;
+				}
+			}
 			failed_attempts++;
 			continue;
@@ -95,5 +113,5 @@
 
 		/* We have the data, execute the callback now. */
-		bool carry_on = polling_data->callback(polling_data->dev,
+		bool carry_on = polling_data->on_data(polling_data->dev,
 		    polling_data->buffer, actual_size,
 		    polling_data->custom_arg);
@@ -106,4 +124,7 @@
 		/* Reset as something might be only a temporary problem. */
 		failed_attempts = 0;
+
+		/* Take a rest before next request. */
+		async_usleep(polling_data->delay);
 	}
 
@@ -114,6 +135,6 @@
 	}
 
-	if (polling_data->terminated_callback != NULL) {
-		polling_data->terminated_callback(polling_data->dev,
+	if (polling_data->on_polling_end != NULL) {
+		polling_data->on_polling_end(polling_data->dev,
 		    failed_attempts > 0, polling_data->custom_arg);
 	}
@@ -159,4 +180,60 @@
 	}
 
+	usb_device_auto_polling_t *auto_polling
+	    = malloc(sizeof(usb_device_auto_polling_t));
+	if (auto_polling == NULL) {
+		return ENOMEM;
+	}
+
+	auto_polling->auto_clear_halt = true;
+	auto_polling->delay = 0;
+	auto_polling->max_failures = MAX_FAILED_ATTEMPTS;
+	auto_polling->on_data = callback;
+	auto_polling->on_polling_end = terminated_callback;
+	auto_polling->on_error = NULL;
+
+	int rc = usb_device_auto_polling(dev, pipe_index, auto_polling,
+	   request_size, arg);
+
+	free(auto_polling);
+
+	return rc;
+}
+
+/** Start automatic device polling over interrupt in pipe.
+ *
+ * The polling settings is copied thus it is okay to destroy the structure
+ * after this function returns.
+ *
+ * @warning There is no guarantee when the request to the device
+ * will be sent for the first time (it is possible that this
+ * first request would be executed prior to return from this function).
+ *
+ * @param dev Device to be periodically polled.
+ * @param pipe_index Index of the endpoint pipe used for polling.
+ * @param polling Polling settings.
+ * @param request_size How many bytes to ask for in each request.
+ * @param arg Custom argument (passed as is to the callbacks).
+ * @return Error code.
+ * @retval EOK New fibril polling the device was already started.
+ */
+int usb_device_auto_polling(usb_device_t *dev, size_t pipe_index,
+    usb_device_auto_polling_t *polling,
+    size_t request_size, void *arg)
+{
+	if (dev == NULL) {
+		return EBADMEM;
+	}
+	if (pipe_index >= dev->pipes_count) {
+		return EINVAL;
+	}
+	if ((dev->pipes[pipe_index].pipe->transfer_type != USB_TRANSFER_INTERRUPT)
+	    || (dev->pipes[pipe_index].pipe->direction != USB_DIRECTION_IN)) {
+		return EINVAL;
+	}
+	if ((polling == NULL) || (polling->on_data == NULL)) {
+		return EBADMEM;
+	}
+
 	polling_data_t *polling_data = malloc(sizeof(polling_data_t));
 	if (polling_data == NULL) {
@@ -164,16 +241,27 @@
 	}
 
-	/* Allocate now to prevent immediate failure in the polling fibril. */
-	polling_data->buffer = malloc(request_size);
+	/* Fill-in the data. */
+	polling_data->buffer = malloc(sizeof(request_size));
 	if (polling_data->buffer == NULL) {
 		free(polling_data);
 		return ENOMEM;
 	}
+	polling_data->request_size = request_size;
 	polling_data->dev = dev;
 	polling_data->pipe_index = pipe_index;
-	polling_data->callback = callback;
-	polling_data->terminated_callback = terminated_callback;
-	polling_data->request_size = request_size;
 	polling_data->custom_arg = arg;
+
+	polling_data->max_failures = polling->max_failures;
+	if (polling->delay >= 0) {
+		polling_data->delay = (useconds_t) polling->delay;
+	} else {
+		polling_data->delay = (useconds_t) dev->pipes[pipe_index]
+		    .descriptor->poll_interval;
+	}
+	polling_data->auto_clear_halt = polling->auto_clear_halt;
+
+	polling_data->on_data = polling->on_data;
+	polling_data->on_polling_end = polling->on_polling_end;
+	polling_data->on_error = polling->on_error;
 
 	fid_t fibril = fibril_create(polling_fibril, polling_data);
@@ -181,10 +269,9 @@
 		free(polling_data->buffer);
 		free(polling_data);
-		/* FIXME: better error code. */
 		return ENOMEM;
 	}
 	fibril_add_ready(fibril);
 
-	/* The allocated buffer etc. will be freed by the fibril. */
+	/* Fibril launched. That fibril will free the allocated data. */
 
 	return EOK;
