Index: uspace/drv/usbhid/main.c
===================================================================
--- uspace/drv/usbhid/main.c	(revision 5f7c846793c87adf089e5a8bd77a9a0a684a3757)
+++ uspace/drv/usbhid/main.c	(revision 2471aaf0c3d2f0d812e7b4f6d5a4984f620452cc)
@@ -42,4 +42,5 @@
 
 #include <usb/devdrv.h>
+#include <usb/devpoll.h>
 
 #include "usbhid.h"
Index: uspace/drv/usbhub/usbhub.c
===================================================================
--- uspace/drv/usbhub/usbhub.c	(revision 5f7c846793c87adf089e5a8bd77a9a0a684a3757)
+++ uspace/drv/usbhub/usbhub.c	(revision 2471aaf0c3d2f0d812e7b4f6d5a4984f620452cc)
@@ -45,4 +45,5 @@
 #include <usb/request.h>
 #include <usb/classes/hub.h>
+#include <usb/devpoll.h>
 #include <stdio.h>
 
Index: uspace/drv/usbkbd/main.c
===================================================================
--- uspace/drv/usbkbd/main.c	(revision 5f7c846793c87adf089e5a8bd77a9a0a684a3757)
+++ uspace/drv/usbkbd/main.c	(revision 2471aaf0c3d2f0d812e7b4f6d5a4984f620452cc)
@@ -42,4 +42,5 @@
 
 #include <usb/devdrv.h>
+#include <usb/devpoll.h>
 
 #include "kbddev.h"
Index: uspace/drv/usbmouse/main.c
===================================================================
--- uspace/drv/usbmouse/main.c	(revision 5f7c846793c87adf089e5a8bd77a9a0a684a3757)
+++ uspace/drv/usbmouse/main.c	(revision 2471aaf0c3d2f0d812e7b4f6d5a4984f620452cc)
@@ -36,4 +36,5 @@
 #include "mouse.h"
 #include <usb/debug.h>
+#include <usb/devpoll.h>
 #include <errno.h>
 #include <str_error.h>
Index: uspace/lib/usb/include/usb/devdrv.h
===================================================================
--- uspace/lib/usb/include/usb/devdrv.h	(revision 5f7c846793c87adf089e5a8bd77a9a0a684a3757)
+++ uspace/lib/usb/include/usb/devdrv.h	(revision 2471aaf0c3d2f0d812e7b4f6d5a4984f620452cc)
@@ -162,11 +162,4 @@
     usb_endpoint_description_t **);
 
-typedef bool (*usb_polling_callback_t)(usb_device_t *,
-    uint8_t *, size_t, void *);
-typedef void (*usb_polling_terminted_callback_t)(usb_device_t *, bool, void *);
-
-int usb_device_auto_poll(usb_device_t *, size_t,
-    usb_polling_callback_t, size_t, usb_polling_terminted_callback_t, void *);
-
 int usb_device_retrieve_descriptors(usb_pipe_t *, usb_device_descriptors_t *);
 int usb_device_create_pipes(ddf_dev_t *, usb_device_connection_t *,
Index: uspace/lib/usb/include/usb/devpoll.h
===================================================================
--- uspace/lib/usb/include/usb/devpoll.h	(revision 2471aaf0c3d2f0d812e7b4f6d5a4984f620452cc)
+++ uspace/lib/usb/include/usb/devpoll.h	(revision 2471aaf0c3d2f0d812e7b4f6d5a4984f620452cc)
@@ -0,0 +1,99 @@
+/*
+ * 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 libusb
+ * @{
+ */
+/** @file
+ * USB device polling functions.
+ */
+#ifndef LIBUSB_DEVPOLL_H_
+#define LIBUSB_DEVPOLL_H_
+
+#include <usb/devdrv.h>
+#include <time.h>
+
+typedef struct {
+	/** Level of debugging messages from auto polling.
+	 * 0 - nothing
+	 * 1 - inform about errors and polling start/end
+	 * 2 - also dump every retrieved buffer
+	 */
+	int debug;
+	/** 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 *,
+    uint8_t *, size_t, void *);
+typedef void (*usb_polling_terminted_callback_t)(usb_device_t *, bool, void *);
+
+int usb_device_auto_poll(usb_device_t *, size_t,
+    usb_polling_callback_t, size_t, usb_polling_terminted_callback_t, void *);
+
+#endif
+/**
+ * @}
+ */
Index: uspace/lib/usb/include/usb/pipes.h
===================================================================
--- uspace/lib/usb/include/usb/pipes.h	(revision 5f7c846793c87adf089e5a8bd77a9a0a684a3757)
+++ uspace/lib/usb/include/usb/pipes.h	(revision 2471aaf0c3d2f0d812e7b4f6d5a4984f620452cc)
@@ -99,4 +99,9 @@
 	/** Number of active transfers over the pipe. */
 	int refcount;
+
+	/** Whether to automatically reset halt on the endpoint.
+	 * Valid only for control endpoint zero.
+	 */
+	bool auto_reset_halt;
 } usb_pipe_t;
 
Index: uspace/lib/usb/src/devpoll.c
===================================================================
--- uspace/lib/usb/src/devpoll.c	(revision 5f7c846793c87adf089e5a8bd77a9a0a684a3757)
+++ uspace/lib/usb/src/devpoll.c	(revision 2471aaf0c3d2f0d812e7b4f6d5a4984f620452cc)
@@ -33,7 +33,8 @@
  * USB device driver framework - automatic interrupt polling.
  */
-#include <usb/devdrv.h>
+#include <usb/devpoll.h>
 #include <usb/request.h>
 #include <usb/debug.h>
+#include <usb/classes/classes.h>
 #include <errno.h>
 #include <str_error.h>
@@ -45,8 +46,14 @@
 /** Data needed for polling. */
 typedef struct {
+	int debug;
+	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;
@@ -54,4 +61,5 @@
 } polling_data_t;
 
+
 /** Polling fibril.
  *
@@ -67,12 +75,20 @@
 	    = polling_data->dev->pipes[polling_data->pipe_index].pipe;
 	
-	usb_log_debug("Pipe interface number: %d, protocol: %d, subclass: %d, max packet size: %d\n", 
-	    polling_data->dev->pipes[polling_data->pipe_index].interface_no,
-	    polling_data->dev->pipes[polling_data->pipe_index].description->interface_protocol,
-	    polling_data->dev->pipes[polling_data->pipe_index].description->interface_subclass,
-	    pipe->max_packet_size);
+	if (polling_data->debug > 0) {
+		usb_endpoint_mapping_t *mapping
+		    = &polling_data->dev->pipes[polling_data->pipe_index];
+		usb_log_debug("Poll0x%x: started polling of `%s' - " \
+		    "interface %d (%s,%d,%d), %zuB/%zu.\n",
+		    polling_data,
+		    polling_data->dev->ddf_dev->name,
+		    (int) mapping->interface->interface_number,
+		    usb_str_class(mapping->interface->interface_class),
+		    (int) mapping->interface->interface_subclass,
+		    (int) mapping->interface->interface_protocol,
+		    polling_data->request_size, pipe->max_packet_size);
+	}
 
 	size_t failed_attempts = 0;
-	while (failed_attempts < MAX_FAILED_ATTEMPTS) {
+	while (failed_attempts <= polling_data->max_failures) {
 		int rc;
 
@@ -81,13 +97,40 @@
 		    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 (polling_data->debug > 1) {
+			if (rc == EOK) {
+				usb_log_debug(
+				    "Poll0x%x: received: '%s' (%zuB).\n",
+				    polling_data,
+				    usb_debug_str_buffer(polling_data->buffer,
+				        actual_size, 16),
+				    actual_size);
+			} else {
+				usb_log_debug(
+				    "Poll0x%x: polling failed: %s.\n",
+				    polling_data, str_error(rc));
+			}
+		}
+
+		/* 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 +138,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,15 +149,26 @@
 		/* Reset as something might be only a temporary problem. */
 		failed_attempts = 0;
-	}
-
-	if (failed_attempts > 0) {
-		usb_log_error(
-		    "Polling of device `%s' terminated: recurring failures.\n",
-		    polling_data->dev->ddf_dev->name);
-	}
-
-	if (polling_data->terminated_callback != NULL) {
-		polling_data->terminated_callback(polling_data->dev,
+
+		/* Take a rest before next request. */
+		async_usleep(polling_data->delay);
+	}
+
+	if (polling_data->on_polling_end != NULL) {
+		polling_data->on_polling_end(polling_data->dev,
 		    failed_attempts > 0, polling_data->custom_arg);
+	}
+
+	if (polling_data->debug > 0) {
+		if (failed_attempts > 0) {
+			usb_log_error(
+			    "Polling of device `%s' terminated: %s.\n",
+			    polling_data->dev->ddf_dev->name,
+			    "recurring failures");
+		} else {
+			usb_log_debug(
+			    "Polling of device `%s' terminated by user.\n",
+			    polling_data->dev->ddf_dev->name
+			);
+		}
 	}
 
@@ -159,4 +213,61 @@
 	}
 
+	usb_device_auto_polling_t *auto_polling
+	    = malloc(sizeof(usb_device_auto_polling_t));
+	if (auto_polling == NULL) {
+		return ENOMEM;
+	}
+
+	auto_polling->debug = 1;
+	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 +275,28 @@
 	}
 
-	/* 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->debug = polling->debug;
+	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 +304,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;
Index: uspace/lib/usb/src/pipesinit.c
===================================================================
--- uspace/lib/usb/src/pipesinit.c	(revision 5f7c846793c87adf089e5a8bd77a9a0a684a3757)
+++ uspace/lib/usb/src/pipesinit.c	(revision 2471aaf0c3d2f0d812e7b4f6d5a4984f620452cc)
@@ -365,4 +365,5 @@
 	pipe->direction = direction;
 	pipe->refcount = 0;
+	pipe->auto_reset_halt = false;
 
 	return EOK;
@@ -385,4 +386,6 @@
 	    0, USB_TRANSFER_CONTROL, CTRL_PIPE_MIN_PACKET_SIZE,
 	    USB_DIRECTION_BOTH);
+
+	pipe->auto_reset_halt = true;
 
 	return rc;
Index: uspace/lib/usb/src/pipesio.c
===================================================================
--- uspace/lib/usb/src/pipesio.c	(revision 5f7c846793c87adf089e5a8bd77a9a0a684a3757)
+++ uspace/lib/usb/src/pipesio.c	(revision 2471aaf0c3d2f0d812e7b4f6d5a4984f620452cc)
@@ -49,4 +49,5 @@
 #include <assert.h>
 #include <usbhc_iface.h>
+#include <usb/request.h>
 #include "pipepriv.h"
 
@@ -307,4 +308,23 @@
 }
 
+/** Try to clear endpoint halt of default control pipe.
+ *
+ * @param pipe Pipe for control endpoint zero.
+ */
+static void clear_self_endpoint_halt(usb_pipe_t *pipe)
+{
+	assert(pipe != NULL);
+
+	if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) {
+		return;
+	}
+
+
+	/* Prevent indefinite recursion. */
+	pipe->auto_reset_halt = false;
+	usb_request_clear_endpoint_halt(pipe, 0);
+	pipe->auto_reset_halt = true;
+}
+
 
 /** Request a control read transfer, no checking of input parameters.
@@ -436,4 +456,8 @@
 	    setup_buffer, setup_buffer_size,
 	    data_buffer, data_buffer_size, &act_size);
+
+	if (rc == ESTALL) {
+		clear_self_endpoint_halt(pipe);
+	}
 
 	pipe_drop_ref(pipe);
@@ -563,4 +587,8 @@
 	    setup_buffer, setup_buffer_size, data_buffer, data_buffer_size);
 
+	if (rc == ESTALL) {
+		clear_self_endpoint_halt(pipe);
+	}
+
 	pipe_drop_ref(pipe);
 
