Index: uspace/drv/bus/usb/xhci/endpoint.c
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.c	(revision bb784ae40ffd2eb0cda12cf5cc8254d941590b46)
+++ uspace/drv/bus/usb/xhci/endpoint.c	(revision dbf32b10e7146a1f953c4eda94c63b8ac246f0ba)
@@ -81,13 +81,18 @@
 }
 
-uint8_t xhci_endpoint_ctx_offset(xhci_endpoint_t *ep)
-{
-	/* 0 is slot ctx, 1 is EP0, then it's EP1 out, in, EP2 out, in, etc. */
-
-	uint8_t off = 2 * (ep->base.target.endpoint);
-	if (ep->base.direction == USB_DIRECTION_IN || ep->base.target.endpoint == 0)
-		++off;
-
-	return off;
+/** Return an index to the endpoint array. The indices are assigned as follows:
+ * 0	EP0 BOTH
+ * 1	EP1 OUT
+ * 2	EP1 IN
+ *
+ * For control endpoints >0, the IN endpoint index is used.
+ * 
+ * The index returned must be usually offset by a number of contexts preceding
+ * the endpoint contexts themselves.
+ */
+uint8_t xhci_endpoint_index(xhci_endpoint_t *ep)
+{
+	return  (2 * ep->base.target.endpoint)
+	    - (ep->base.direction == USB_DIRECTION_OUT);
 }
 
@@ -211,6 +216,6 @@
 		XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, 0);
 
-		const uint8_t ep_offset = xhci_endpoint_ctx_offset(ep);
-		XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, ep_offset);
+		const uint8_t ep_idx = xhci_endpoint_index(ep);
+		XHCI_INPUT_CTRL_CTX_ADD_SET(ictx->ctrl_ctx, ep_idx + 1); /* Preceded by slot ctx */
 
 		ep_ring = malloc(sizeof(xhci_trb_ring_t));
@@ -227,17 +232,17 @@
 		switch (ep->base.transfer_type) {
 		case USB_TRANSFER_CONTROL:
-			setup_control_ep_ctx(ep, &ictx->endpoint_ctx[ep_offset - 1], ep_ring);
+			setup_control_ep_ctx(ep, &ictx->endpoint_ctx[ep_idx], ep_ring);
 			break;
 
 		case USB_TRANSFER_BULK:
-			setup_bulk_ep_ctx(ep, &ictx->endpoint_ctx[ep_offset - 1], ep_ring, &ss_desc);
+			setup_bulk_ep_ctx(ep, &ictx->endpoint_ctx[ep_idx], ep_ring, &ss_desc);
 			break;
 
 		case USB_TRANSFER_ISOCHRONOUS:
-			setup_isoch_ep_ctx(ep, &ictx->endpoint_ctx[ep_offset - 1], ep_ring, &ss_desc);
+			setup_isoch_ep_ctx(ep, &ictx->endpoint_ctx[ep_idx], ep_ring, &ss_desc);
 			break;
 
 		case USB_TRANSFER_INTERRUPT:
-			setup_interrupt_ep_ctx(ep, &ictx->endpoint_ctx[ep_offset - 1], ep_ring, &ss_desc);
+			setup_interrupt_ep_ctx(ep, &ictx->endpoint_ctx[ep_idx], ep_ring, &ss_desc);
 			break;
 
Index: uspace/drv/bus/usb/xhci/endpoint.h
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.h	(revision bb784ae40ffd2eb0cda12cf5cc8254d941590b46)
+++ uspace/drv/bus/usb/xhci/endpoint.h	(revision dbf32b10e7146a1f953c4eda94c63b8ac246f0ba)
@@ -97,5 +97,5 @@
 void xhci_device_fini(xhci_device_t *);
 
-uint8_t xhci_endpoint_ctx_offset(xhci_endpoint_t *);
+uint8_t xhci_endpoint_index(xhci_endpoint_t *);
 
 int xhci_device_add_endpoint(xhci_device_t *, xhci_endpoint_t *);
Index: uspace/drv/bus/usb/xhci/hc.c
===================================================================
--- uspace/drv/bus/usb/xhci/hc.c	(revision bb784ae40ffd2eb0cda12cf5cc8254d941590b46)
+++ uspace/drv/bus/usb/xhci/hc.c	(revision dbf32b10e7146a1f953c4eda94c63b8ac246f0ba)
@@ -634,4 +634,5 @@
 	uint32_t v = host2xhci(32, target & BIT_RRANGE(uint32_t, 7));
 	pio_write_32(&hc->db_arry[doorbell], v);
+	usb_log_debug("Ringing doorbell %d, target = %d", doorbell, target);
 	return EOK;
 }
Index: uspace/drv/bus/usb/xhci/transfers.c
===================================================================
--- uspace/drv/bus/usb/xhci/transfers.c	(revision bb784ae40ffd2eb0cda12cf5cc8254d941590b46)
+++ uspace/drv/bus/usb/xhci/transfers.c	(revision dbf32b10e7146a1f953c4eda94c63b8ac246f0ba)
@@ -43,62 +43,44 @@
 #include "trb_ring.h"
 
-static inline uint8_t get_transfer_type(xhci_trb_t* trb, uint8_t bmRequestType, uint16_t wLength)
+typedef enum {
+    STAGE_OUT,
+    STAGE_IN,
+} stage_dir_flag_t;
+
+#define REQUEST_TYPE_DTD (0x80)
+#define REQUEST_TYPE_IS_DEVICE_TO_HOST(rq) ((rq) & REQUEST_TYPE_DTD)
+
+
+/** Get direction flag of data stage.
+ *  See Table 7 of xHCI specification.
+ */
+static inline stage_dir_flag_t get_status_direction_flag(xhci_trb_t* trb,
+	uint8_t bmRequestType, uint16_t wLength)
 {
 	/* See Table 7 of xHCI specification */
-	if (bmRequestType & 0x80) {
-		/* Device-to-host transfer */
-		if (wLength) {
-			/* IN data stage */
-			return 3;
-		}
-		else {
-			/* No data stage */
-			return 0;
-		}
-	}
-	else {
-		/* Host-to-device transfer */
-		if (wLength) {
-			/* OUT data stage */
-			return 2;
-		}
-		else {
-			/* No data stage */
-			return 0;
-		}
-	}
-}
-
-static inline uint8_t get_data_direction(xhci_trb_t* trb, uint8_t bmRequestType, uint16_t wLength)
-{
+	return REQUEST_TYPE_IS_DEVICE_TO_HOST(bmRequestType) && (wLength > 0)
+		? STAGE_OUT
+		: STAGE_IN;
+}
+
+typedef enum {
+    DATA_STAGE_NO = 0,
+    DATA_STAGE_OUT = 2,
+    DATA_STAGE_IN = 3,
+} data_stage_type_t;
+
+/** Get transfer type flag.
+ *  See Table 8 of xHCI specification.
+ */
+static inline data_stage_type_t get_transfer_type(xhci_trb_t* trb, uint8_t
+	bmRequestType, uint16_t wLength)
+{
+	if (wLength == 0)
+		return DATA_STAGE_NO;
+
 	/* See Table 7 of xHCI specification */
-	if (bmRequestType & 0x80) {
-		/* Device-to-host transfer */
-		return 1;
-	}
-	else {
-		/* Host-to-device transfer */
-		return 0;
-	}
-}
-
-static inline uint8_t get_status_direction(xhci_trb_t* trb, uint8_t bmRequestType, uint16_t wLength)
-{
-	/* See Table 7 of xHCI specification */
-	if (bmRequestType & 0x80) {
-		/* Device-to-host transfer */
-		if (wLength) {
-			/* Out direction */
-			return 0;
-		}
-		else {
-			/* In direction */
-			return 1;
-		}
-	}
-	else {
-		/* Host-to-device transfer, always IN direction */
-		return 1;
-	}
+	return REQUEST_TYPE_IS_DEVICE_TO_HOST(bmRequestType)
+		? DATA_STAGE_IN
+		: DATA_STAGE_NO;
 }
 
@@ -107,18 +89,7 @@
 	usb_request_type_t request_type = SETUP_REQUEST_TYPE_GET_TYPE(setup->request_type);
 
-	if (request_type == USB_REQUEST_TYPE_STANDARD) {
-		usb_stddevreq_t request = setup->request;
-
-		switch (request) {
-		case USB_DEVREQ_SET_CONFIGURATION:
-		case USB_DEVREQ_SET_INTERFACE:
-			return true;
-
-		default:
-			return false;
-		}
-	}
-
-	return false;
+	return request_type == USB_REQUEST_TYPE_STANDARD &&
+		(setup->request == USB_DEVREQ_SET_CONFIGURATION
+		|| setup->request == USB_DEVREQ_SET_INTERFACE);
 }
 
@@ -190,5 +161,5 @@
 
 	xhci_trb_t trb_setup;
-	memset(&trb_setup, 0, sizeof(xhci_trb_t));
+	xhci_trb_clean(&trb_setup);
 
 	TRB_CTRL_SET_SETUP_WVALUE(trb_setup, setup->value);
@@ -210,5 +181,5 @@
 	/* Data stage */
 	xhci_trb_t trb_data;
-	memset(&trb_data, 0, sizeof(xhci_trb_t));
+	xhci_trb_clean(&trb_data);
 
 	if (setup->length > 0) {
@@ -226,5 +197,6 @@
 		TRB_CTRL_SET_TRB_TYPE(trb_data, XHCI_TRB_TYPE_DATA_STAGE);
 
-		transfer->direction = get_data_direction(&trb_setup, setup->request_type, setup->length);
+		transfer->direction = REQUEST_TYPE_IS_DEVICE_TO_HOST(setup->request_type) 
+					? STAGE_IN : STAGE_OUT;
 		TRB_CTRL_SET_DIR(trb_data, transfer->direction);
 	}
@@ -232,5 +204,5 @@
 	/* Status stage */
 	xhci_trb_t trb_status;
-	memset(&trb_status, 0, sizeof(xhci_trb_t));
+	xhci_trb_clean(&trb_status);
 
 	// FIXME: Evaluate next TRB? 4.12.3
@@ -241,5 +213,5 @@
 
 	TRB_CTRL_SET_TRB_TYPE(trb_status, XHCI_TRB_TYPE_STATUS_STAGE);
-	TRB_CTRL_SET_DIR(trb_status, get_status_direction(&trb_setup, setup->request_type, setup->length));
+	TRB_CTRL_SET_DIR(trb_status, get_status_direction_flag(&trb_setup, setup->request_type, setup->length));
 
 	uintptr_t dummy = 0;
@@ -251,9 +223,4 @@
 
 	list_append(&transfer->link, &hc->transfers);
-
-	/* For control transfers, the target is always 1. */
-	// FIXME: ignoring return code
-	const uint8_t target = xhci_endpoint_ctx_offset(xhci_ep);
-	hc_ring_doorbell(hc, slot_id, target);
 
 	// Issue a Configure Endpoint command, if needed.
@@ -264,5 +231,6 @@
 	}
 
-	return EOK;
+	const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbels start at 1 */
+	return hc_ring_doorbell(hc, slot_id, target);
 }
 
@@ -284,5 +252,5 @@
 
 	xhci_trb_t trb;
-	memset(&trb, 0, sizeof(xhci_trb_t));
+	xhci_trb_clean(&trb);
 	trb.parameter = addr_to_phys(transfer->hc_buffer);
 
@@ -301,7 +269,6 @@
 
 	// TODO: target = endpoint | stream_id << 16
-	const uint8_t target = xhci_endpoint_ctx_offset(xhci_ep);
-	hc_ring_doorbell(hc, slot_id, target);
-	return EOK;
+	const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */
+	return hc_ring_doorbell(hc, slot_id, target);
 }
 
@@ -323,5 +290,5 @@
 
 	xhci_trb_t trb;
-	memset(&trb, 0, sizeof(xhci_trb_t));
+	xhci_trb_clean(&trb);
 	trb.parameter = addr_to_phys(transfer->hc_buffer);
 
@@ -339,6 +306,5 @@
 	list_append(&transfer->link, &hc->transfers);
 
-	const uint8_t target = xhci_endpoint_ctx_offset(xhci_ep);
-	usb_log_debug("Ringing doorbell for slot_id = %d, target = %d", slot_id, target);
+	const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */
 	return hc_ring_doorbell(hc, slot_id, target);
 }
@@ -367,19 +333,7 @@
 	usb_transfer_batch_t *batch = transfer->batch;
 
-	batch->error = (TRB_COMPLETION_CODE(*trb) == XHCI_TRBC_SUCCESS) ? EOK : ENAK;
-	batch->transfered_size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb);
-	if (transfer->direction) {
-		memcpy(batch->buffer, transfer->hc_buffer, batch->buffer_size);
-
-		/* Device-to-host, IN */
-		if (batch->callback_in)
-			batch->callback_in(batch->error, batch->transfered_size, batch->arg);
-	}
-	else {
-		/* Host-to-device, OUT */
-		if (batch->callback_out)
-			batch->callback_out(batch->error, batch->arg);
-	}
-
+	const int err = (TRB_COMPLETION_CODE(*trb) == XHCI_TRBC_SUCCESS) ? EOK : ENAK;
+	const size_t size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb);
+	usb_transfer_batch_finish_error(batch, transfer->hc_buffer, size, err);
 	xhci_transfer_fini(transfer);
 	return EOK;
