Index: uspace/drv/uhci-hcd/batch.c
===================================================================
--- uspace/drv/uhci-hcd/batch.c	(revision 7ac73a4b0be58a18822a76290c8e2578cbc50448)
+++ uspace/drv/uhci-hcd/batch.c	(revision 00db345ac0b5fb5841cf7eaac2d0a1eba5487690)
@@ -47,6 +47,7 @@
 static int batch_schedule(batch_t *instance);
 
-static void batch_control(
-    batch_t *instance, int data_stage, int status_stage);
+static void batch_control(batch_t *instance,
+    usb_packet_id data_stage, usb_packet_id status_stage);
+static void batch_data(batch_t *instance, usb_packet_id pid);
 static void batch_call_in(batch_t *instance);
 static void batch_call_out(batch_t *instance);
@@ -83,5 +84,5 @@
 	}
 
-	instance->tds = malloc32(sizeof(transfer_descriptor_t) * instance->packets);
+	instance->tds = malloc32(sizeof(td_t) * instance->packets);
 	if (instance->tds == NULL) {
 		usb_log_error("Failed to allocate transfer descriptors.\n");
@@ -90,5 +91,5 @@
 		return NULL;
 	}
-	bzero(instance->tds, sizeof(transfer_descriptor_t) * instance->packets);
+	bzero(instance->tds, sizeof(td_t) * instance->packets);
 
 	const size_t transport_size = max_packet_size * instance->packets;
@@ -151,18 +152,22 @@
 	size_t i = 0;
 	for (;i < instance->packets; ++i) {
-		if (transfer_descriptor_is_active(&instance->tds[i])) {
+		if (td_is_active(&instance->tds[i])) {
 			return false;
 		}
-		instance->error = transfer_descriptor_status(&instance->tds[i]);
+
+		instance->error = td_status(&instance->tds[i]);
 		if (instance->error != EOK) {
+			usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
+			    instance, i, instance->tds[i].status);
 			if (i > 0)
-				instance->transfered_size -= instance->setup_size;
-			usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
-			  instance, i, instance->tds[i].status);
+				goto substract_ret;
 			return true;
 		}
-		instance->transfered_size +=
-		    transfer_descriptor_actual_size(&instance->tds[i]);
-	}
+
+		instance->transfered_size += td_act_size(&instance->tds[i]);
+		if (td_is_short(&instance->tds[i]))
+			goto substract_ret;
+	}
+substract_ret:
 	instance->transfered_size -= instance->setup_size;
 	return true;
@@ -192,56 +197,75 @@
 {
 	assert(instance);
-
+	batch_data(instance, USB_PID_IN);
+	instance->next_step = batch_call_in_and_dispose;
+	usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
+	batch_schedule(instance);
+}
+/*----------------------------------------------------------------------------*/
+void batch_interrupt_out(batch_t *instance)
+{
+	assert(instance);
+	memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
+	batch_data(instance, USB_PID_OUT);
+	instance->next_step = batch_call_out_and_dispose;
+	usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
+	batch_schedule(instance);
+}
+/*----------------------------------------------------------------------------*/
+void batch_bulk_in(batch_t *instance)
+{
+	assert(instance);
+	batch_data(instance, USB_PID_IN);
+	instance->next_step = batch_call_in_and_dispose;
+	usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
+	batch_schedule(instance);
+}
+/*----------------------------------------------------------------------------*/
+void batch_bulk_out(batch_t *instance)
+{
+	assert(instance);
+	memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
+	batch_data(instance, USB_PID_OUT);
+	instance->next_step = batch_call_out_and_dispose;
+	usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
+	batch_schedule(instance);
+}
+/*----------------------------------------------------------------------------*/
+static void batch_data(batch_t *instance, usb_packet_id pid)
+{
+	assert(instance);
 	const bool low_speed = instance->speed == USB_SPEED_LOW;
 	int toggle = 1;
-	size_t i = 0;
-	for (;i < instance->packets; ++i) {
+
+	size_t packet = 0;
+	size_t remain_size = instance->buffer_size;
+	while (remain_size > 0) {
 		char *data =
-		    instance->transport_buffer + (i  * instance->max_packet_size);
-		transfer_descriptor_t *next = (i + 1) < instance->packets ?
-		    &instance->tds[i + 1] : NULL;
+		    instance->transport_buffer + instance->buffer_size
+		    - remain_size;
+
 		toggle = 1 - toggle;
 
-		transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
-		    instance->max_packet_size, toggle, false, low_speed,
-		    instance->target, USB_PID_IN, data, next);
-	}
-
-	instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
-
-	instance->next_step = batch_call_in_and_dispose;
-	usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
-	batch_schedule(instance);
-}
-/*----------------------------------------------------------------------------*/
-void batch_interrupt_out(batch_t *instance)
-{
-	assert(instance);
-	memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
-
-	const bool low_speed = instance->speed == USB_SPEED_LOW;
-	int toggle = 1;
-	size_t i = 0;
-	for (;i < instance->packets; ++i) {
-		char *data =
-		    instance->transport_buffer + (i  * instance->max_packet_size);
-		transfer_descriptor_t *next = (i + 1) < instance->packets ?
-		    &instance->tds[i + 1] : NULL;
-		toggle = 1 - toggle;
-
-		transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
-		    instance->max_packet_size, toggle++, false, low_speed,
-		    instance->target, USB_PID_OUT, data, next);
-	}
-
-	instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
-
-	instance->next_step = batch_call_out_and_dispose;
-	usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
-	batch_schedule(instance);
-}
-/*----------------------------------------------------------------------------*/
-static void batch_control(
-    batch_t *instance, int data_stage, int status_stage)
+		const size_t packet_size =
+		    (instance->max_packet_size > remain_size) ?
+		    remain_size : instance->max_packet_size;
+
+		td_init(&instance->tds[packet],
+		    DEFAULT_ERROR_COUNT, packet_size, toggle, false, low_speed,
+		    instance->target, pid, data,
+		    &instance->tds[packet + 1]);
+
+		++packet;
+		assert(packet <= instance->packets);
+		assert(packet_size <= remain_size);
+		remain_size -= packet_size;
+	}
+
+	instance->tds[packet - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
+	instance->tds[packet - 1].next = 0 | LINK_POINTER_TERMINATE_FLAG;
+}
+/*----------------------------------------------------------------------------*/
+static void batch_control(batch_t *instance,
+   usb_packet_id data_stage, usb_packet_id status_stage)
 {
 	assert(instance);
@@ -250,5 +274,5 @@
 	int toggle = 0;
 	/* setup stage */
-	transfer_descriptor_init(instance->tds, DEFAULT_ERROR_COUNT,
+	td_init(instance->tds, DEFAULT_ERROR_COUNT,
 	    instance->setup_size, toggle, false, low_speed, instance->target,
 	    USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]);
@@ -268,5 +292,5 @@
 		    remain_size : instance->max_packet_size;
 
-		transfer_descriptor_init(&instance->tds[packet],
+		td_init(&instance->tds[packet],
 		    DEFAULT_ERROR_COUNT, packet_size, toggle, false, low_speed,
 		    instance->target, data_stage, data,
@@ -281,5 +305,5 @@
 	/* status stage */
 	assert(packet == instance->packets - 1);
-	transfer_descriptor_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,
+	td_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,
 	    0, 1, false, low_speed, instance->target, status_stage, NULL, NULL);
 
Index: uspace/drv/uhci-hcd/batch.h
===================================================================
--- uspace/drv/uhci-hcd/batch.h	(revision 7ac73a4b0be58a18822a76290c8e2578cbc50448)
+++ uspace/drv/uhci-hcd/batch.h	(revision 00db345ac0b5fb5841cf7eaac2d0a1eba5487690)
@@ -65,5 +65,5 @@
 	ddf_fun_t *fun;
 	queue_head_t *qh;
-	transfer_descriptor_t *tds;
+	td_t *tds;
 	void (*next_step)(struct batch*);
 } batch_t;
@@ -86,14 +86,7 @@
 void batch_interrupt_out(batch_t *instance);
 
-/* DEPRECATED FUNCTIONS NEEDED BY THE OLD API */
-void batch_control_setup_old(batch_t *instance);
+void batch_bulk_in(batch_t *instance);
 
-void batch_control_write_data_old(batch_t *instance);
-
-void batch_control_read_data_old(batch_t *instance);
-
-void batch_control_write_status_old(batch_t *instance);
-
-void batch_control_read_status_old(batch_t *instance);
+void batch_bulk_out(batch_t *instance);
 #endif
 /**
Index: uspace/drv/uhci-hcd/iface.c
===================================================================
--- uspace/drv/uhci-hcd/iface.c	(revision 7ac73a4b0be58a18822a76290c8e2578cbc50448)
+++ uspace/drv/uhci-hcd/iface.c	(revision 00db345ac0b5fb5841cf7eaac2d0a1eba5487690)
@@ -140,4 +140,43 @@
 }
 /*----------------------------------------------------------------------------*/
+static int bulk_out(ddf_fun_t *fun, usb_target_t target,
+    size_t max_packet_size, void *data, size_t size,
+    usbhc_iface_transfer_out_callback_t callback, void *arg)
+{
+	assert(fun);
+	uhci_t *hc = fun_to_uhci(fun);
+	assert(hc);
+	usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
+
+	usb_log_debug("Bulk OUT %d:%d %zu(%zu).\n",
+	    target.address, target.endpoint, size, max_packet_size);
+
+	batch_t *batch = batch_get(fun, target, USB_TRANSFER_BULK,
+	    max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg);
+	if (!batch)
+		return ENOMEM;
+	batch_bulk_out(batch);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
+static int bulk_in(ddf_fun_t *fun, usb_target_t target,
+    size_t max_packet_size, void *data, size_t size,
+    usbhc_iface_transfer_in_callback_t callback, void *arg)
+{
+	assert(fun);
+	uhci_t *hc = fun_to_uhci(fun);
+	assert(hc);
+	usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
+	usb_log_debug("Bulk IN %d:%d %zu(%zu).\n",
+	    target.address, target.endpoint, size, max_packet_size);
+
+	batch_t *batch = batch_get(fun, target, USB_TRANSFER_BULK,
+	    max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg);
+	if (!batch)
+		return ENOMEM;
+	batch_bulk_in(batch);
+	return EOK;
+}
+/*----------------------------------------------------------------------------*/
 static int control_write(ddf_fun_t *fun, usb_target_t target,
     size_t max_packet_size,
@@ -181,6 +220,4 @@
 	return EOK;
 }
-
-
 /*----------------------------------------------------------------------------*/
 usbhc_iface_t uhci_iface = {
@@ -194,4 +231,7 @@
 	.interrupt_in = interrupt_in,
 
+	.bulk_in = bulk_in,
+	.bulk_out = bulk_out,
+
 	.control_read = control_read,
 	.control_write = control_write,
Index: uspace/drv/uhci-hcd/uhci.c
===================================================================
--- uspace/drv/uhci-hcd/uhci.c	(revision 7ac73a4b0be58a18822a76290c8e2578cbc50448)
+++ uspace/drv/uhci-hcd/uhci.c	(revision 00db345ac0b5fb5841cf7eaac2d0a1eba5487690)
@@ -336,5 +336,5 @@
 		uhci_interrupt(instance, status);
 		pio_write_16(&instance->registers->usbsts, 0x1f);
-		async_usleep(UHCI_CLEANER_TIMEOUT * 5);
+		async_usleep(UHCI_CLEANER_TIMEOUT);
 	}
 	return EOK;
Index: uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c
===================================================================
--- uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c	(revision 7ac73a4b0be58a18822a76290c8e2578cbc50448)
+++ uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c	(revision 00db345ac0b5fb5841cf7eaac2d0a1eba5487690)
@@ -38,9 +38,10 @@
 #include "utils/malloc32.h"
 
-void transfer_descriptor_init(transfer_descriptor_t *instance,
-    int error_count, size_t size, bool toggle, bool isochronous, bool low_speed,
-    usb_target_t target, int pid, void *buffer, transfer_descriptor_t *next)
+void td_init(td_t *instance, int err_count, size_t size, bool toggle, bool iso,
+    bool low_speed, usb_target_t target, usb_packet_id pid, void *buffer, td_t *next)
 {
 	assert(instance);
+	assert(size < 1024);
+	assert((pid == USB_PID_SETUP) || (pid == USB_PID_IN) || (pid == USB_PID_OUT));
 
 	instance->next = 0
@@ -49,15 +50,19 @@
 
 	instance->status = 0
-	  | ((error_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS)
-		| (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0)
-	  | TD_STATUS_ERROR_ACTIVE;
+	    | ((err_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS)
+	    | (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0)
+	    | (iso ? TD_STATUS_ISOCHRONOUS_FLAG : 0)
+	    | TD_STATUS_ERROR_ACTIVE;
 
-	assert(size < 1024);
+	if (pid == USB_PID_IN && !iso) {
+		instance->status |= TD_STATUS_SPD_FLAG;
+	}
+
 	instance->device = 0
-		| (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS)
-		| (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0)
-		| ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS)
-		| ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS)
-		| ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS);
+	    | (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS)
+	    | (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0)
+	    | ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS)
+	    | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS)
+	    | ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS);
 
 	instance->buffer_ptr = 0;
@@ -68,9 +73,9 @@
 
 	usb_log_debug2("Created TD: %X:%X:%X:%X(%p).\n",
-		instance->next, instance->status, instance->device,
-	  instance->buffer_ptr, buffer);
+	    instance->next, instance->status, instance->device,
+	    instance->buffer_ptr, buffer);
 }
 /*----------------------------------------------------------------------------*/
-int transfer_descriptor_status(transfer_descriptor_t *instance)
+int td_status(td_t *instance)
 {
 	assert(instance);
Index: uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h
===================================================================
--- uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h	(revision 7ac73a4b0be58a18822a76290c8e2578cbc50448)
+++ uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h	(revision 00db345ac0b5fb5841cf7eaac2d0a1eba5487690)
@@ -88,23 +88,32 @@
 	 * we don't use it anyway
 	 */
-} __attribute__((packed)) transfer_descriptor_t;
+} __attribute__((packed)) td_t;
 
 
-void transfer_descriptor_init(transfer_descriptor_t *instance,
-    int error_count, size_t size, bool toggle, bool isochronous, bool low_speed,
-    usb_target_t target, int pid, void *buffer, transfer_descriptor_t * next);
+void td_init(td_t *instance, int error_count, size_t size, bool toggle, bool iso,
+    bool low_speed, usb_target_t target, usb_packet_id pid, void *buffer,
+    td_t *next);
 
-int transfer_descriptor_status(transfer_descriptor_t *instance);
+int td_status(td_t *instance);
 
-static inline size_t transfer_descriptor_actual_size(
-    transfer_descriptor_t *instance)
+static inline size_t td_act_size(td_t *instance)
 {
 	assert(instance);
 	return
-	    ((instance->status >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK;
+	    ((instance->status >> TD_STATUS_ACTLEN_POS) + 1)
+	    & TD_STATUS_ACTLEN_MASK;
 }
 
-static inline bool transfer_descriptor_is_active(
-    transfer_descriptor_t *instance)
+static inline bool td_is_short(td_t *instance)
+{
+	const size_t act_size = td_act_size(instance);
+	const size_t max_size =
+	    ((instance->device >> TD_DEVICE_MAXLEN_POS) + 1)
+	    & TD_DEVICE_MAXLEN_MASK;
+	return
+	    (instance->status | TD_STATUS_SPD_FLAG) && act_size < max_size;
+}
+
+static inline bool td_is_active(td_t *instance)
 {
 	assert(instance);
Index: uspace/drv/usbhub/usbhub.c
===================================================================
--- uspace/drv/usbhub/usbhub.c	(revision 7ac73a4b0be58a18822a76290c8e2578cbc50448)
+++ uspace/drv/usbhub/usbhub.c	(revision 00db345ac0b5fb5841cf7eaac2d0a1eba5487690)
@@ -233,4 +233,7 @@
 	dprintf(USB_LOG_LEVEL_DEBUG, "starting control transaction");
 	usb_endpoint_pipe_start_session(&result->endpoints.control);
+	opResult = usb_request_set_configuration(&result->endpoints.control, 1);
+	assert(opResult == EOK);
+
 	opResult = usb_request_get_descriptor(&result->endpoints.control,
 			USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
@@ -243,5 +246,6 @@
 		dprintf(USB_LOG_LEVEL_ERROR, "failed when receiving hub descriptor, badcode = %d",opResult);
 		free(serialized_descriptor);
-		return result;
+		free(result);
+		return NULL;
 	}
 	dprintf(USB_LOG_LEVEL_DEBUG2, "deserializing descriptor");
@@ -249,6 +253,6 @@
 	if(descriptor==NULL){
 		dprintf(USB_LOG_LEVEL_WARNING, "could not deserialize descriptor ");
-		result->port_count = 1;///\TODO this code is only for debug!!!
-		return result;
+		free(result);
+		return NULL;
 	}
 
@@ -286,4 +290,7 @@
 
 	usb_hub_info_t * hub_info = usb_create_hub_info(dev);
+	if(!hub_info){
+		return EINTR;
+	}
 
 	int opResult;
@@ -294,5 +301,5 @@
 	opResult = usb_hub_process_configuration_descriptors(hub_info);
 	if(opResult != EOK){
-		dprintf(USB_LOG_LEVEL_ERROR,"could not get condiguration descriptors, %d",
+		dprintf(USB_LOG_LEVEL_ERROR,"could not get configuration descriptors, %d",
 				opResult);
 		return opResult;
Index: uspace/drv/usbmouse/main.c
===================================================================
--- uspace/drv/usbmouse/main.c	(revision 7ac73a4b0be58a18822a76290c8e2578cbc50448)
+++ uspace/drv/usbmouse/main.c	(revision 00db345ac0b5fb5841cf7eaac2d0a1eba5487690)
@@ -74,5 +74,5 @@
 int main(int argc, char *argv[])
 {
-	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
+	usb_log_enable(USB_LOG_LEVEL_DEBUG2, NAME);
 
 	return ddf_driver_main(&mouse_driver);
Index: uspace/drv/usbmouse/mouse.c
===================================================================
--- uspace/drv/usbmouse/mouse.c	(revision 7ac73a4b0be58a18822a76290c8e2578cbc50448)
+++ uspace/drv/usbmouse/mouse.c	(revision 00db345ac0b5fb5841cf7eaac2d0a1eba5487690)
@@ -37,4 +37,5 @@
 #include <usb/debug.h>
 #include <errno.h>
+#include <str_error.h>
 #include <ipc/mouse.h>
 
@@ -64,12 +65,35 @@
 
 		size_t actual_size;
+		int rc;
 
-		/* FIXME: check for errors. */
-		usb_endpoint_pipe_start_session(&mouse->poll_pipe);
+		/*
+		 * Error checking note:
+		 * - failure when starting a session is considered
+		 *   temporary (e.g. out of phones, next try might succeed)
+		 * - failure of transfer considered fatal (probably the
+		 *   device was unplugged)
+		 * - session closing not checked (shall not fail anyway)
+		 */
 
-		usb_endpoint_pipe_read(&mouse->poll_pipe,
+		rc = usb_endpoint_pipe_start_session(&mouse->poll_pipe);
+		if (rc != EOK) {
+			usb_log_warning("Failed to start session, will try again: %s.\n",
+			    str_error(rc));
+			continue;
+		}
+
+		rc = usb_endpoint_pipe_read(&mouse->poll_pipe,
 		    buffer, buffer_size, &actual_size);
 
 		usb_endpoint_pipe_end_session(&mouse->poll_pipe);
+
+		if (rc != EOK) {
+			usb_log_error("Failed reading mouse input: %s.\n",
+			    str_error(rc));
+			break;
+		}
+
+		usb_log_debug2("got buffer: %s.\n",
+		    usb_debug_str_buffer(buffer, buffer_size, 0));
 
 		uint8_t butt = buffer[0];
@@ -115,4 +139,14 @@
 	}
 
+	/*
+	 * Device was probably unplugged.
+	 * Hang-up the phone to the console.
+	 * FIXME: release allocated memory.
+	 */
+	async_hangup(mouse->console_phone);
+	mouse->console_phone = -1;
+
+	usb_log_error("Mouse polling fibril terminated.\n");
+
 	return EOK;
 }
