Index: uspace/drv/bus/usb/uhci/hc.c
===================================================================
--- uspace/drv/bus/usb/uhci/hc.c	(revision a312d8f527427930eb111c09105cfcf076485261)
+++ uspace/drv/bus/usb/uhci/hc.c	(revision 17873ac7d4019500d5125f0b78948a7b91d478ec)
@@ -177,5 +177,5 @@
 			uhci_transfer_batch_t *batch =
 			    uhci_transfer_batch_from_link(current);
-			uhci_transfer_batch_finish(batch);
+			usb_transfer_batch_finish(&batch->base);
 		}
 	}
Index: uspace/drv/bus/usb/uhci/transfer_list.c
===================================================================
--- uspace/drv/bus/usb/uhci/transfer_list.c	(revision a312d8f527427930eb111c09105cfcf076485261)
+++ uspace/drv/bus/usb/uhci/transfer_list.c	(revision 17873ac7d4019500d5125f0b78948a7b91d478ec)
@@ -115,4 +115,12 @@
 	assert(instance);
 	assert(uhci_batch);
+
+	endpoint_t *ep = uhci_batch->base.ep;
+
+	/* First, wait until the endpoint is free to use */
+	fibril_mutex_lock(&ep->guard);
+	endpoint_activate_locked(ep, &uhci_batch->base);
+	fibril_mutex_unlock(&ep->guard);
+
 	usb_log_debug2("Batch %p adding to queue %s.\n",
 	    uhci_batch, instance->name);
@@ -189,5 +197,5 @@
 		    uhci_transfer_batch_from_link(current);
 		transfer_list_remove_batch(instance, batch);
-		uhci_transfer_batch_abort(batch);
+		endpoint_abort(batch->base.ep);
 	}
 	fibril_mutex_unlock(&instance->guard);
Index: uspace/drv/bus/usb/uhci/uhci_batch.c
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_batch.c	(revision a312d8f527427930eb111c09105cfcf076485261)
+++ uspace/drv/bus/usb/uhci/uhci_batch.c	(revision 17873ac7d4019500d5125f0b78948a7b91d478ec)
@@ -64,13 +64,4 @@
 }
 
-void uhci_transfer_batch_finish(uhci_transfer_batch_t *batch)
-{
-	if (batch->base.dir == USB_DIRECTION_IN) {
-		assert(batch->base.transfered_size <= batch->base.buffer_size);
-		memcpy(batch->base.buffer, uhci_transfer_batch_data_buffer(batch), batch->base.transfered_size);
-	}
-	usb_transfer_batch_finish(&batch->base);
-}
-
 /** Allocate memory and initialize internal data structure.
  *
@@ -113,5 +104,5 @@
 	}
 
-	const size_t setup_size = (uhci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)
+	const size_t setup_size = (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL)
 		? USB_SETUP_PACKET_SIZE
 		: 0;
@@ -165,10 +156,11 @@
 {
 	assert(uhci_batch);
+	usb_transfer_batch_t *batch = &uhci_batch->base;
 
 	usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT
 	    " checking %zu transfer(s) for completion.\n",
-	    uhci_batch, USB_TRANSFER_BATCH_ARGS(uhci_batch->base),
+	    uhci_batch, USB_TRANSFER_BATCH_ARGS(*batch),
 	    uhci_batch->td_count);
-	uhci_batch->base.transfered_size = 0;
+	batch->transfered_size = 0;
 
 	for (size_t i = 0;i < uhci_batch->td_count; ++i) {
@@ -177,7 +169,7 @@
 		}
 
-		uhci_batch->base.error = td_status(&uhci_batch->tds[i]);
-		if (uhci_batch->base.error != EOK) {
-			assert(uhci_batch->base.ep != NULL);
+		batch->error = td_status(&uhci_batch->tds[i]);
+		if (batch->error != EOK) {
+			assert(batch->ep != NULL);
 
 			usb_log_debug("Batch %p found error TD(%zu->%p):%"
@@ -186,5 +178,5 @@
 			td_print_status(&uhci_batch->tds[i]);
 
-			endpoint_toggle_set(uhci_batch->base.ep,
+			endpoint_toggle_set(batch->ep,
 			    td_toggle(&uhci_batch->tds[i]));
 			if (i > 0)
@@ -193,5 +185,5 @@
 		}
 
-		uhci_batch->base.transfered_size
+		batch->transfered_size
 		    += td_act_size(&uhci_batch->tds[i]);
 		if (td_is_short(&uhci_batch->tds[i]))
@@ -199,6 +191,19 @@
 	}
 substract_ret:
-	if (uhci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)
-		uhci_batch->base.transfered_size -= USB_SETUP_PACKET_SIZE;
+	if (batch->ep->transfer_type == USB_TRANSFER_CONTROL)
+		batch->transfered_size -= USB_SETUP_PACKET_SIZE;
+
+	fibril_mutex_lock(&batch->ep->guard);
+	usb_transfer_batch_reset_toggle(batch);
+	endpoint_deactivate_locked(batch->ep);
+	fibril_mutex_unlock(&batch->ep->guard);
+
+	if (batch->dir == USB_DIRECTION_IN) {
+		assert(batch->transfered_size <= batch->buffer_size);
+		memcpy(batch->buffer,
+		    uhci_transfer_batch_data_buffer(uhci_batch),
+		    batch->transfered_size);
+	}
+
 	return true;
 }
Index: uspace/drv/bus/usb/uhci/uhci_batch.h
===================================================================
--- uspace/drv/bus/usb/uhci/uhci_batch.h	(revision a312d8f527427930eb111c09105cfcf076485261)
+++ uspace/drv/bus/usb/uhci/uhci_batch.h	(revision 17873ac7d4019500d5125f0b78948a7b91d478ec)
@@ -98,17 +98,4 @@
 }
 
-/** Aborts the batch.
- * Sets error to EINTR and size off transferd data to 0, before finishing the
- * batch.
- * @param uhci_batch Batch to abort.
- */
-static inline void uhci_transfer_batch_abort(uhci_transfer_batch_t *uhci_batch)
-{
-	assert(uhci_batch);
-	uhci_batch->base.error = EINTR;
-	uhci_batch->base.transfered_size = 0;
-	usb_transfer_batch_finish(&uhci_batch->base);
-}
-
 /** Linked list conversion wrapper.
  * @param l Linked list link.
Index: uspace/drv/bus/usb/xhci/bus.c
===================================================================
--- uspace/drv/bus/usb/xhci/bus.c	(revision a312d8f527427930eb111c09105cfcf076485261)
+++ uspace/drv/bus/usb/xhci/bus.c	(revision 17873ac7d4019500d5125f0b78948a7b91d478ec)
@@ -198,13 +198,8 @@
 	for (size_t i = 0; i < ARRAY_SIZE(xhci_dev->endpoints); ++i) {
 		xhci_endpoint_t *ep = xhci_dev->endpoints[i];
-		if (!ep || !ep->base.active)
+		if (!ep)
 			continue;
 
-		/* FIXME: This is racy. */
-		if ((err = xhci_transfer_abort(&ep->active_transfer))) {
-			usb_log_warning("Failed to abort active transfer to "
-			    " endpoint " XHCI_EP_FMT ": %s", XHCI_EP_ARGS(*ep),
-			    str_error(err));
-		}
+		endpoint_abort(&ep->base);
 	}
 
@@ -454,5 +449,5 @@
 }
 
-static int reset_toggle(bus_t *bus_base, usb_target_t target, bool all)
+static int reset_toggle(bus_t *bus_base, usb_target_t target, toggle_reset_mode_t mode)
 {
 	// TODO: Implement me!
Index: uspace/drv/bus/usb/xhci/endpoint.h
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.h	(revision a312d8f527427930eb111c09105cfcf076485261)
+++ uspace/drv/bus/usb/xhci/endpoint.h	(revision 17873ac7d4019500d5125f0b78948a7b91d478ec)
@@ -68,9 +68,4 @@
 	/** Main transfer ring (unused if streams are enabled) */
 	xhci_trb_ring_t ring;
-
-	/** There shall be only one transfer active on an endpoint. The
-	 * synchronization is performed using the active flag in base
-	 * endpoint_t */
-	xhci_transfer_t active_transfer;
 
 	/** Primary stream context array (or NULL if endpoint doesn't use streams). */
Index: uspace/drv/bus/usb/xhci/transfers.c
===================================================================
--- uspace/drv/bus/usb/xhci/transfers.c	(revision a312d8f527427930eb111c09105cfcf076485261)
+++ uspace/drv/bus/usb/xhci/transfers.c	(revision 17873ac7d4019500d5125f0b78948a7b91d478ec)
@@ -101,16 +101,9 @@
 xhci_transfer_t* xhci_transfer_create(endpoint_t* ep)
 {
-	xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
-	xhci_transfer_t *transfer = &xhci_ep->active_transfer;
-
-	/* Do not access the transfer yet, it may be still in use. */
+	xhci_transfer_t *transfer = calloc(1, sizeof(xhci_transfer_t));
+	if (!transfer)
+		return NULL;
 
 	usb_transfer_batch_init(&transfer->batch, ep);
-	assert(ep->active);
-
-	/* Clean just our data. */
-	memset(((void *) transfer) + sizeof(usb_transfer_batch_t), 0,
-	    sizeof(xhci_transfer_t) - sizeof(usb_transfer_batch_t));
-
 	return transfer;
 }
@@ -246,13 +239,4 @@
 	usb_log_error("Isochronous transfers are not yet implemented!");
 	return ENOTSUP;
-}
-
-int xhci_transfer_abort(xhci_transfer_t *transfer)
-{
-	usb_transfer_batch_t *batch = &transfer->batch;
-	batch->error = EAGAIN;
-	batch->transfered_size = 0;
-	usb_transfer_batch_finish(batch);
-	return EOK;
 }
 
@@ -277,13 +261,21 @@
 	}
 
-	xhci_transfer_t *transfer = &ep->active_transfer;
-
-	/** FIXME: This is racy. Do we care? */
+	/* FIXME: This is racy. Do we care? */
 	ep->ring.dequeue = addr;
 
-	usb_transfer_batch_t *batch = &transfer->batch;
+	fibril_mutex_lock(&ep->base.guard);
+	usb_transfer_batch_t *batch = ep->base.active_batch;
+	if (!batch) {
+		fibril_mutex_unlock(&ep->base.guard);
+		return ENOENT;
+	}
 
 	batch->error = (TRB_COMPLETION_CODE(*trb) == XHCI_TRBC_SUCCESS) ? EOK : ENAK;
 	batch->transfered_size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb);
+	usb_transfer_batch_reset_toggle(batch);
+	endpoint_deactivate_locked(&ep->base);
+	fibril_mutex_unlock(&ep->base.guard);
+
+	xhci_transfer_t *transfer = xhci_transfer_from_batch(batch);
 
 	if (batch->dir == USB_DIRECTION_IN) {
@@ -309,13 +301,12 @@
 {
 	assert(hc);
+	endpoint_t *ep = batch->ep;
 
 	xhci_transfer_t *transfer = xhci_transfer_from_batch(batch);
-	xhci_endpoint_t *xhci_ep = xhci_endpoint_get(batch->ep);
-	assert(xhci_ep);
-
+	xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
 	xhci_device_t *xhci_dev = xhci_ep_to_dev(xhci_ep);
 
 	/* Offline devices don't schedule transfers other than on EP0. */
-	if (!xhci_dev->online && xhci_ep->base.endpoint) {
+	if (!xhci_dev->online && ep->endpoint > 0) {
 		return EAGAIN;
 	}
@@ -334,6 +325,7 @@
 	if (batch->buffer_size > 0) {
 		transfer->hc_buffer = malloc32(batch->buffer_size);
-	}
-
+		if (!transfer->hc_buffer)
+			return ENOMEM;
+	}
 
 	if (batch->dir != USB_DIRECTION_IN) {
@@ -342,7 +334,17 @@
 	}
 
+	fibril_mutex_lock(&ep->guard);
+	endpoint_activate_locked(ep, batch);
 	const int err = transfer_handlers[batch->ep->transfer_type](hc, transfer);
-	if (err)
+
+	if (err) {
+		endpoint_deactivate_locked(ep);
+		fibril_mutex_unlock(&ep->guard);
 		return err;
+	}
+
+	/* After the critical section, the transfer can already be finished or aborted. */
+	transfer = NULL; batch = NULL;
+	fibril_mutex_unlock(&ep->guard);
 
 	const uint8_t slot_id = xhci_dev->slot_id;
Index: uspace/drv/bus/usb/xhci/transfers.h
===================================================================
--- uspace/drv/bus/usb/xhci/transfers.h	(revision a312d8f527427930eb111c09105cfcf076485261)
+++ uspace/drv/bus/usb/xhci/transfers.h	(revision 17873ac7d4019500d5125f0b78948a7b91d478ec)
@@ -58,5 +58,4 @@
 xhci_transfer_t* xhci_transfer_create(endpoint_t *);
 int xhci_transfer_schedule(xhci_hc_t *, usb_transfer_batch_t *);
-int xhci_transfer_abort(xhci_transfer_t *);
 int xhci_handle_transfer_event(xhci_hc_t *, xhci_trb_t *);
 void xhci_transfer_destroy(xhci_transfer_t *);
