Index: uspace/drv/uhci-hcd/batch.c
===================================================================
--- uspace/drv/uhci-hcd/batch.c	(revision f5246b6cca9ab3e2acd462138c8db1515769796d)
+++ uspace/drv/uhci-hcd/batch.c	(revision 0e06a149861dfcac692875af11dfb8e7e9944ca5)
@@ -49,4 +49,5 @@
 static void batch_control(
     batch_t *instance, int data_stage, int status_stage);
+static void batch_data(batch_t *instance, int pid);
 static void batch_call_in(batch_t *instance);
 static void batch_call_out(batch_t *instance);
@@ -192,52 +193,71 @@
 {
 	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, int 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);
+		const size_t packet_size =
+		    (instance->max_packet_size > remain_size) ?
+		    remain_size : instance->max_packet_size;
+
+		transfer_descriptor_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;
 }
 /*----------------------------------------------------------------------------*/
Index: uspace/drv/uhci-hcd/batch.h
===================================================================
--- uspace/drv/uhci-hcd/batch.h	(revision f5246b6cca9ab3e2acd462138c8db1515769796d)
+++ uspace/drv/uhci-hcd/batch.h	(revision 0e06a149861dfcac692875af11dfb8e7e9944ca5)
@@ -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 f5246b6cca9ab3e2acd462138c8db1515769796d)
+++ uspace/drv/uhci-hcd/iface.c	(revision 0e06a149861dfcac692875af11dfb8e7e9944ca5)
@@ -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,
