Index: uspace/drv/ohci/batch.c
===================================================================
--- uspace/drv/ohci/batch.c	(revision 7628050704273f2f93129546d6caf64dc4034f4f)
+++ uspace/drv/ohci/batch.c	(revision c6fe4699d267b97fcb861bf87324fb21c4072051)
@@ -51,4 +51,5 @@
 static void batch_control(usb_transfer_batch_t *instance,
     usb_direction_t data_dir, usb_direction_t status_dir);
+static void batch_data(usb_transfer_batch_t *instance);
 static void batch_call_in_and_dispose(usb_transfer_batch_t *instance);
 static void batch_call_out_and_dispose(usb_transfer_batch_t *instance);
@@ -183,5 +184,5 @@
 	assert(instance->direction == USB_DIRECTION_IN);
 	instance->next_step = batch_call_in_and_dispose;
-	/* TODO: implement */
+	batch_data(instance);
 	usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
 }
@@ -195,5 +196,5 @@
 	    instance->buffer_size);
 	instance->next_step = batch_call_out_and_dispose;
-	/* TODO: implement */
+	batch_data(instance);
 	usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
 }
@@ -204,5 +205,5 @@
 	instance->direction = USB_DIRECTION_IN;
 	instance->next_step = batch_call_in_and_dispose;
-	/* TODO: implement */
+	batch_data(instance);
 	usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
 }
@@ -213,5 +214,5 @@
 	instance->direction = USB_DIRECTION_IN;
 	instance->next_step = batch_call_in_and_dispose;
-	/* TODO: implement */
+	batch_data(instance);
 	usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
 }
@@ -274,4 +275,37 @@
 }
 /*----------------------------------------------------------------------------*/
+void batch_data(usb_transfer_batch_t *instance)
+{
+	assert(instance);
+	ohci_batch_t *data = instance->private_data;
+	assert(data);
+	ed_init(data->ed, instance->ep);
+	ed_add_tds(data->ed, &data->tds[0], &data->tds[data->td_count - 1]);
+	usb_log_debug("Created ED(%p): %x:%x:%x:%x.\n", data->ed,
+	    data->ed->status, data->ed->td_tail, data->ed->td_head,
+	    data->ed->next);
+
+	/* data stage */
+	size_t td_current = 1;
+	size_t remain_size = instance->buffer_size;
+	char *transfer_buffer = instance->transport_buffer;
+	while (remain_size > 0) {
+		size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER ?
+		    OHCI_TD_MAX_TRANSFER : remain_size;
+
+		td_init(&data->tds[td_current], instance->ep->direction,
+		    transfer_buffer, transfer_size, -1);
+		td_set_next(&data->tds[td_current], &data->tds[td_current + 1]);
+		usb_log_debug("Created DATA TD: %x:%x:%x:%x.\n",
+		    data->tds[td_current].status, data->tds[td_current].cbp,
+		    data->tds[td_current].next, data->tds[td_current].be);
+
+		transfer_buffer += transfer_size;
+		remain_size -= transfer_size;
+		assert(td_current < data->td_count);
+		++td_current;
+	}
+}
+/*----------------------------------------------------------------------------*/
 /** Helper function calls callback and correctly disposes of batch structure.
  *
Index: uspace/drv/ohci/hc.c
===================================================================
--- uspace/drv/ohci/hc.c	(revision 7628050704273f2f93129546d6caf64dc4034f4f)
+++ uspace/drv/ohci/hc.c	(revision c6fe4699d267b97fcb861bf87324fb21c4072051)
@@ -147,7 +147,18 @@
 		break;
 	case USB_TRANSFER_BULK:
+		instance->registers->control &= ~C_BLE;
+		transfer_list_add_batch(
+		    instance->transfers[batch->transfer_type], batch);
 		instance->registers->command_status |= CS_BLF;
 		usb_log_debug2("Set bulk transfer filled: %x.\n",
 			instance->registers->command_status);
+		instance->registers->control |= C_BLE;
+		break;
+	case USB_TRANSFER_INTERRUPT:
+	case USB_TRANSFER_ISOCHRONOUS:
+		instance->registers->control &= ~C_PLE;
+		transfer_list_add_batch(
+		    instance->transfers[batch->transfer_type], batch);
+		instance->registers->control |= C_PLE;
 		break;
 	default:
