Index: uspace/drv/bus/usb/xhci/device.c
===================================================================
--- uspace/drv/bus/usb/xhci/device.c	(revision abb5d08b8dadddf815ac338a1b5357b8df0b66e6)
+++ uspace/drv/bus/usb/xhci/device.c	(revision 51c1d500b4bb389b18317382df9d42881fe3471e)
@@ -52,4 +52,5 @@
 #include "bus.h"
 #include "endpoint.h"
+#include "hw_struct/context.h"
 
 #include "device.h"
@@ -86,8 +87,6 @@
 	dev->base.endpoints[0] = ep0_base;
 
-	xhci_endpoint_t *ep0 = xhci_endpoint_get(ep0_base);
-
 	/* Address device */
-	if ((err = hc_address_device(dev, ep0)))
+	if ((err = hc_address_device(dev)))
 		goto err_added;
 
@@ -127,8 +126,5 @@
 	ep0->base.max_transfer_size = max_packet_size * ep0->base.packets_per_uframe;
 
-	xhci_ep_ctx_t ep_ctx;
-	xhci_setup_endpoint_context(ep0, &ep_ctx);
-
-	if ((err = hc_update_endpoint(dev, 0, &ep_ctx)))
+	if ((err = hc_update_endpoint(ep0)))
 		return err;
 
@@ -306,4 +302,40 @@
 }
 
+/**
+ * Fill a slot context that is part of an Input Context with appropriate
+ * values.
+ *
+ * @param ctx Slot context, zeroed out.
+ */
+void xhci_setup_slot_context(xhci_device_t *dev, xhci_slot_ctx_t *ctx)
+{
+	/* Initialize slot_ctx according to section 4.3.3 point 3. */
+	XHCI_SLOT_ROOT_HUB_PORT_SET(*ctx, dev->rh_port);
+	XHCI_SLOT_ROUTE_STRING_SET(*ctx, dev->route_str);
+	XHCI_SLOT_SPEED_SET(*ctx, hc_speed_to_psiv(dev->base.speed));
+
+	/*
+	 * Note: This function is used even before this flag can be set, to
+	 *       issue the address device command. It is OK, because these
+	 *       flags are not required to be valid for that command.
+	 */
+	if (dev->is_hub) {
+		XHCI_SLOT_HUB_SET(*ctx, 1);
+		XHCI_SLOT_NUM_PORTS_SET(*ctx, dev->num_ports);
+		XHCI_SLOT_TT_THINK_TIME_SET(*ctx, dev->tt_think_time);
+		XHCI_SLOT_MTT_SET(*ctx, 0); // MTT not supported yet
+	}
+
+	/* Setup Transaction Translation. TODO: Test this with HS hub. */
+	if (dev->base.tt.dev != NULL) {
+		xhci_device_t *hub = xhci_device_get(dev->base.tt.dev);
+		XHCI_SLOT_TT_HUB_SLOT_ID_SET(*ctx, hub->slot_id);
+		XHCI_SLOT_TT_HUB_PORT_SET(*ctx, dev->base.tt.port);
+	}
+
+	// As we always allocate space for whole input context, we can set this to maximum
+	XHCI_SLOT_CTX_ENTRIES_SET(*ctx, 31);
+}
+
 
 /**
Index: uspace/drv/bus/usb/xhci/device.h
===================================================================
--- uspace/drv/bus/usb/xhci/device.h	(revision abb5d08b8dadddf815ac338a1b5357b8df0b66e6)
+++ uspace/drv/bus/usb/xhci/device.h	(revision 51c1d500b4bb389b18317382df9d42881fe3471e)
@@ -38,4 +38,6 @@
 #include <usb/host/dma_buffer.h>
 
+typedef struct xhci_slot_ctx xhci_slot_ctx_t;
+
 typedef struct xhci_device {
 	device_t base;		/**< Inheritance. Keep this first. */
@@ -71,4 +73,6 @@
 void xhci_device_gone(device_t *);
 
+void xhci_setup_slot_context(xhci_device_t *, xhci_slot_ctx_t *);
+
 static inline xhci_device_t * xhci_device_get(device_t *dev)
 {
Index: uspace/drv/bus/usb/xhci/endpoint.c
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.c	(revision abb5d08b8dadddf815ac338a1b5357b8df0b66e6)
+++ uspace/drv/bus/usb/xhci/endpoint.c	(revision 51c1d500b4bb389b18317382df9d42881fe3471e)
@@ -172,10 +172,6 @@
 	int err;
 	xhci_endpoint_t *ep = xhci_endpoint_get(ep_base);
-	xhci_device_t *dev = xhci_device_get(ep_base->device);
-
-	xhci_ep_ctx_t ep_ctx;
-	xhci_setup_endpoint_context(ep, &ep_ctx);
-
-	if ((err = hc_add_endpoint(dev, xhci_endpoint_index(ep), &ep_ctx)))
+
+	if ((err = hc_add_endpoint(ep)))
 		return err;
 
@@ -189,4 +185,5 @@
 {
 	xhci_device_t *dev = xhci_device_get(ep->device);
+	xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
 
 	usb_transfer_batch_t *batch = NULL;
@@ -194,5 +191,5 @@
 	if (ep->active_batch) {
 		if (dev->slot_id) {
-			const int err = hc_stop_endpoint(dev, xhci_endpoint_dci(xhci_endpoint_get(ep)));
+			const int err = hc_stop_endpoint(xhci_ep);
 			if (err) {
 				usb_log_warning("Failed to stop endpoint %u of device " XHCI_DEV_FMT ": %s",
@@ -235,5 +232,5 @@
 	if (dev->slot_id) {
 
-		if ((err = hc_drop_endpoint(dev, xhci_endpoint_index(ep)))) {
+		if ((err = hc_drop_endpoint(ep))) {
 			usb_log_error("Failed to drop endpoint " XHCI_EP_FMT ": %s", XHCI_EP_ARGS(*ep), str_error(err));
 		}
@@ -318,26 +315,16 @@
 }
 
-/** See section 4.5.1 of the xHCI spec.
- */
-uint8_t xhci_endpoint_dci(xhci_endpoint_t *ep)
-{
-	return (2 * ep->base.endpoint) +
-		(ep->base.transfer_type == USB_TRANSFER_CONTROL
-		 || ep->base.direction == USB_DIRECTION_IN);
-}
-
-/** 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 xhci_endpoint_dci(ep) - 1;
+xhci_trb_ring_t *xhci_endpoint_get_ring(xhci_endpoint_t *ep, uint32_t stream_id)
+{
+	if (ep->primary_stream_data_size == 0)
+		return stream_id == 0 ? &ep->ring : NULL;
+
+	xhci_stream_data_t *stream_data = xhci_get_stream_ctx_data(ep, stream_id);
+	if (stream_data == NULL) {
+		usb_log_warning("No transfer ring was found for stream %u.", stream_id);
+		return NULL;
+	}
+
+	return &stream_data->ring;
 }
 
@@ -435,48 +422,16 @@
 }
 
-uint8_t xhci_endpoint_get_state(xhci_endpoint_t *ep)
-{
-	assert(ep);
-
-	xhci_device_t *dev = xhci_device_get(ep->base.device);
-	if (!dev->slot_id)
-		return EP_STATE_DISABLED;
-
-	unsigned idx = xhci_endpoint_index(ep);
-	xhci_device_ctx_t *ctx = dev->dev_ctx.virt;
-	const xhci_hc_t * hc = bus_to_hc(dev->base.bus);
-	xhci_ep_ctx_t *ep_ctx = XHCI_GET_EP_CTX(ctx, hc, idx);
-
-	return XHCI_EP_STATE(*ep_ctx);
-}
-
 /**
  * Clear endpoint halt condition by resetting the endpoint and skipping the
  * offending transfer.
  */
-int xhci_endpoint_clear_halt(xhci_endpoint_t *ep, unsigned stream_id)
+int xhci_endpoint_clear_halt(xhci_endpoint_t *ep, uint32_t stream_id)
 {
 	int err;
 
-	xhci_device_t * const dev = xhci_device_get(ep->base.device);
-	xhci_bus_t * const bus = bus_to_xhci_bus(dev->base.bus);
-	xhci_hc_t * const hc = bus->hc;
-
-	const unsigned slot_id = dev->slot_id;
-	const unsigned dci = xhci_endpoint_dci(ep);
-
-	if ((err = hc_reset_endpoint(dev, dci)))
+	if ((err = hc_reset_endpoint(ep)))
 		return err;
 
-	uintptr_t addr;
-
-	xhci_trb_ring_reset_dequeue_state(&ep->ring, &addr);
-
-	if ((err = xhci_cmd_sync_inline(hc, SET_TR_DEQUEUE_POINTER,
-			    .slot_id = slot_id,
-			    .endpoint_id = dci,
-			    .stream_id = stream_id,
-			    .dequeue_ptr = addr,
-			)))
+	if ((err = hc_reset_ring(ep, stream_id)))
 		return err;
 
Index: uspace/drv/bus/usb/xhci/endpoint.h
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.h	(revision abb5d08b8dadddf815ac338a1b5357b8df0b66e6)
+++ uspace/drv/bus/usb/xhci/endpoint.h	(revision 51c1d500b4bb389b18317382df9d42881fe3471e)
@@ -113,8 +113,6 @@
 void xhci_endpoint_destroy(endpoint_t *);
 
-void xhci_endpoint_free_transfer_ds(xhci_endpoint_t *xhci_ep);
-
-uint8_t xhci_endpoint_dci(xhci_endpoint_t *);
-uint8_t xhci_endpoint_index(xhci_endpoint_t *);
+void xhci_endpoint_free_transfer_ds(xhci_endpoint_t *);
+xhci_trb_ring_t *xhci_endpoint_get_ring(xhci_endpoint_t *, uint32_t);
 
 void xhci_setup_endpoint_context(xhci_endpoint_t *, xhci_ep_ctx_t *);
@@ -133,6 +131,4 @@
 }
 
-uint8_t xhci_endpoint_get_state(xhci_endpoint_t *ep);
-
 #endif
 
Index: uspace/drv/bus/usb/xhci/hc.c
===================================================================
--- uspace/drv/bus/usb/xhci/hc.c	(revision abb5d08b8dadddf815ac338a1b5357b8df0b66e6)
+++ uspace/drv/bus/usb/xhci/hc.c	(revision 51c1d500b4bb389b18317382df9d42881fe3471e)
@@ -703,4 +703,10 @@
 }
 
+unsigned hc_speed_to_psiv(usb_speed_t speed)
+{
+	assert(speed < ARRAY_SIZE(usb_speed_to_psiv));
+	return usb_speed_to_psiv[speed];
+}
+
 /**
  * Ring a xHC Doorbell. Implements section 4.7.
@@ -715,4 +721,23 @@
 
 /**
+ * Return an index to device context.
+ */
+static uint8_t endpoint_dci(xhci_endpoint_t *ep)
+{
+	return (2 * ep->base.endpoint) +
+		(ep->base.transfer_type == USB_TRANSFER_CONTROL
+		 || ep->base.direction == USB_DIRECTION_IN);
+}
+
+void hc_ring_ep_doorbell(xhci_endpoint_t *ep, uint32_t stream_id)
+{
+	xhci_device_t * const dev = xhci_ep_to_dev(ep);
+	xhci_hc_t * const hc = bus_to_hc(dev->base.bus);
+	const uint8_t dci = endpoint_dci(ep);
+	const uint32_t target = (stream_id << 16) | (dci & 0x1ff);
+	hc_ring_doorbell(hc, dev->slot_id, target);
+}
+
+/**
  * Issue an Enable Slot command. Allocate memory for the slot and fill the
  * DCBAA with the newly created slot.
@@ -772,40 +797,4 @@
 
 /**
- * Fill a slot context that is part of an Input Context with appropriate
- * values.
- *
- * @param ctx Slot context, zeroed out.
- */
-static void xhci_setup_slot_context(xhci_device_t *dev, xhci_slot_ctx_t *ctx)
-{
-	/* Initialize slot_ctx according to section 4.3.3 point 3. */
-	XHCI_SLOT_ROOT_HUB_PORT_SET(*ctx, dev->rh_port);
-	XHCI_SLOT_ROUTE_STRING_SET(*ctx, dev->route_str);
-	XHCI_SLOT_SPEED_SET(*ctx, usb_speed_to_psiv[dev->base.speed]);
-
-	/*
-	 * Note: This function is used even before this flag can be set, to
-	 *       issue the address device command. It is OK, because these
-	 *       flags are not required to be valid for that command.
-	 */
-	if (dev->is_hub) {
-		XHCI_SLOT_HUB_SET(*ctx, 1);
-		XHCI_SLOT_NUM_PORTS_SET(*ctx, dev->num_ports);
-		XHCI_SLOT_TT_THINK_TIME_SET(*ctx, dev->tt_think_time);
-		XHCI_SLOT_MTT_SET(*ctx, 0); // MTT not supported yet
-	}
-
-	/* Setup Transaction Translation. TODO: Test this with HS hub. */
-	if (dev->base.tt.dev != NULL) {
-		xhci_device_t *hub = xhci_device_get(dev->base.tt.dev);
-		XHCI_SLOT_TT_HUB_SLOT_ID_SET(*ctx, hub->slot_id);
-		XHCI_SLOT_TT_HUB_PORT_SET(*ctx, dev->base.tt.port);
-	}
-
-	// As we always allocate space for whole input context, we can set this to maximum
-	XHCI_SLOT_CTX_ENTRIES_SET(*ctx, 31);
-}
-
-/**
  * Prepare an empty Endpoint Input Context inside a dma buffer.
  */
@@ -832,10 +821,10 @@
  *
  * @param dev Device to assing an address (unconfigured yet)
- * @param ep0 EP0 of device TODO remove, can be fetched from dev
- */
-int hc_address_device(xhci_device_t *dev, xhci_endpoint_t *ep0)
+ */
+int hc_address_device(xhci_device_t *dev)
 {
 	int err = ENOMEM;
 	xhci_hc_t * const hc = bus_to_hc(dev->base.bus);
+	xhci_endpoint_t *ep0 = xhci_endpoint_get(dev->base.endpoints[0]);
 
 	/* Although we have the precise PSIV value on devices of tier 1,
@@ -854,6 +843,7 @@
 	/* Copy endpoint 0 context and set A1 flag. */
 	XHCI_INPUT_CTRL_CTX_ADD_SET(*XHCI_GET_CTRL_CTX(ictx, hc), 1);
-	xhci_ep_ctx_t *ep_ctx = XHCI_GET_EP_CTX(XHCI_GET_DEVICE_CTX(ictx, hc), hc, 0);
+	xhci_ep_ctx_t *ep_ctx = XHCI_GET_EP_CTX(XHCI_GET_DEVICE_CTX(ictx, hc), hc, 1);
 	xhci_setup_endpoint_context(ep0, ep_ctx);
+
 	/* Address device needs Ctx entries set to 1 only */
 	xhci_slot_ctx_t *slot_ctx = XHCI_GET_SLOT_CTX(XHCI_GET_DEVICE_CTX(ictx, hc), hc);
@@ -909,6 +899,9 @@
  * @param ep_ctx Endpoint context of the endpoint
  */
-int hc_add_endpoint(xhci_device_t *dev, uint8_t ep_idx, xhci_ep_ctx_t *ep_ctx)
-{
+int hc_add_endpoint(xhci_endpoint_t *ep)
+{
+	xhci_device_t * const dev = xhci_ep_to_dev(ep);
+	const unsigned dci = endpoint_dci(ep);
+
 	/* Issue configure endpoint command (sec 4.3.5). */
 	dma_buffer_t ictx_dma_buf;
@@ -920,8 +913,8 @@
 
 	xhci_hc_t * const hc = bus_to_hc(dev->base.bus);
-	XHCI_INPUT_CTRL_CTX_ADD_SET(*XHCI_GET_CTRL_CTX(ictx, hc), ep_idx + 1); /* Preceded by slot ctx */
-
-	xhci_ep_ctx_t *_ep_ctx = XHCI_GET_EP_CTX(XHCI_GET_DEVICE_CTX(ictx, hc), hc, ep_idx);
-	memcpy(_ep_ctx, ep_ctx, XHCI_ONE_CTX_SIZE(hc));
+	XHCI_INPUT_CTRL_CTX_ADD_SET(*XHCI_GET_CTRL_CTX(ictx, hc), dci);
+
+	xhci_ep_ctx_t *ep_ctx = XHCI_GET_EP_CTX(XHCI_GET_DEVICE_CTX(ictx, hc), hc, dci);
+	xhci_setup_endpoint_context(ep, ep_ctx);
 
 	return xhci_cmd_sync_inline(hc, CONFIGURE_ENDPOINT, .slot_id = dev->slot_id, .input_ctx = ictx_dma_buf);
@@ -934,6 +927,9 @@
  * @param ep_idx Endpoint DCI in question
  */
-int hc_drop_endpoint(xhci_device_t *dev, uint8_t ep_idx)
-{
+int hc_drop_endpoint(xhci_endpoint_t *ep)
+{
+	xhci_device_t * const dev = xhci_ep_to_dev(ep);
+	const unsigned dci = endpoint_dci(ep);
+
 	/* Issue configure endpoint command (sec 4.3.5). */
 	dma_buffer_t ictx_dma_buf;
@@ -944,5 +940,5 @@
 	xhci_hc_t * const hc = bus_to_hc(dev->base.bus);
 	xhci_input_ctx_t *ictx = ictx_dma_buf.virt;
-	XHCI_INPUT_CTRL_CTX_DROP_SET(*XHCI_GET_CTRL_CTX(ictx, hc), ep_idx + 1); /* Preceded by slot ctx */
+	XHCI_INPUT_CTRL_CTX_DROP_SET(*XHCI_GET_CTRL_CTX(ictx, hc), dci);
 
 	return xhci_cmd_sync_inline(hc, CONFIGURE_ENDPOINT, .slot_id = dev->slot_id, .input_ctx = ictx_dma_buf);
@@ -957,6 +953,9 @@
  * @param ep_ctx Endpoint context of the endpoint
  */
-int hc_update_endpoint(xhci_device_t *dev, uint8_t ep_idx, xhci_ep_ctx_t *ep_ctx)
-{
+int hc_update_endpoint(xhci_endpoint_t *ep)
+{
+	xhci_device_t * const dev = xhci_ep_to_dev(ep);
+	const unsigned dci = endpoint_dci(ep);
+
 	dma_buffer_t ictx_dma_buf;
 	xhci_hc_t * const hc = bus_to_hc(dev->base.bus);
@@ -969,7 +968,7 @@
 	memset(ictx, 0, XHCI_INPUT_CTX_SIZE(hc));
 
-	XHCI_INPUT_CTRL_CTX_ADD_SET(*XHCI_GET_CTRL_CTX(ictx, hc), ep_idx + 1);
-	xhci_ep_ctx_t *_ep_ctx = XHCI_GET_EP_CTX(XHCI_GET_DEVICE_CTX(ictx, hc), hc, 0);
-	memcpy(_ep_ctx, ep_ctx, sizeof(xhci_ep_ctx_t));
+	XHCI_INPUT_CTRL_CTX_ADD_SET(*XHCI_GET_CTRL_CTX(ictx, hc), dci);
+	xhci_ep_ctx_t *ep_ctx = XHCI_GET_EP_CTX(XHCI_GET_DEVICE_CTX(ictx, hc), hc, dci);
+	xhci_setup_endpoint_context(ep, ep_ctx);
 
 	return xhci_cmd_sync_inline(hc, EVALUATE_CONTEXT, .slot_id = dev->slot_id, .input_ctx = ictx_dma_buf);
@@ -982,8 +981,10 @@
  * @param ep_idx Endpoint DCI in question
  */
-int hc_stop_endpoint(xhci_device_t *dev, uint8_t ep_idx)
-{
+int hc_stop_endpoint(xhci_endpoint_t *ep)
+{
+	xhci_device_t * const dev = xhci_ep_to_dev(ep);
+	const unsigned dci = endpoint_dci(ep);
 	xhci_hc_t * const hc = bus_to_hc(dev->base.bus);
-	return xhci_cmd_sync_inline(hc, STOP_ENDPOINT, .slot_id = dev->slot_id, .endpoint_id = ep_idx);
+	return xhci_cmd_sync_inline(hc, STOP_ENDPOINT, .slot_id = dev->slot_id, .endpoint_id = dci);
 }
 
@@ -994,8 +995,33 @@
  * @param ep_idx Endpoint DCI in question
  */
-int hc_reset_endpoint(xhci_device_t *dev, uint8_t ep_idx)
-{
+int hc_reset_endpoint(xhci_endpoint_t *ep)
+{
+	xhci_device_t * const dev = xhci_ep_to_dev(ep);
+	const unsigned dci = endpoint_dci(ep);
 	xhci_hc_t * const hc = bus_to_hc(dev->base.bus);
-	return xhci_cmd_sync_inline(hc, RESET_ENDPOINT, .slot_id = dev->slot_id, .endpoint_id = ep_idx);
+	return xhci_cmd_sync_inline(hc, RESET_ENDPOINT, .slot_id = dev->slot_id, .endpoint_id = dci);
+}
+
+/**
+ * Reset a ring position in both software and hardware.
+ *
+ * @param dev The owner of the endpoint
+ */
+int hc_reset_ring(xhci_endpoint_t *ep, uint32_t stream_id)
+{
+	xhci_device_t * const dev = xhci_ep_to_dev(ep);
+	const unsigned dci = endpoint_dci(ep);
+	uintptr_t addr;
+
+	xhci_trb_ring_t *ring = xhci_endpoint_get_ring(ep, stream_id);
+	xhci_trb_ring_reset_dequeue_state(ring, &addr);
+
+	xhci_hc_t * const hc = bus_to_hc(endpoint_get_bus(&ep->base));
+	return xhci_cmd_sync_inline(hc, SET_TR_DEQUEUE_POINTER,
+			    .slot_id = dev->slot_id,
+			    .endpoint_id = dci,
+			    .stream_id = stream_id,
+			    .dequeue_ptr = addr,
+			);
 }
 
Index: uspace/drv/bus/usb/xhci/hc.h
===================================================================
--- uspace/drv/bus/usb/xhci/hc.h	(revision abb5d08b8dadddf815ac338a1b5357b8df0b66e6)
+++ uspace/drv/bus/usb/xhci/hc.h	(revision 51c1d500b4bb389b18317382df9d42881fe3471e)
@@ -120,16 +120,20 @@
 int hc_start(xhci_hc_t *, bool);
 void hc_fini(xhci_hc_t *);
+
 void hc_ring_doorbell(xhci_hc_t *, unsigned, unsigned);
+void hc_ring_ep_doorbell(xhci_endpoint_t *, uint32_t);
+unsigned hc_speed_to_psiv(usb_speed_t);
 
 int hc_enable_slot(xhci_device_t *);
 int hc_disable_slot(xhci_device_t *);
-int hc_address_device(xhci_device_t *, xhci_endpoint_t *);
+int hc_address_device(xhci_device_t *);
 int hc_configure_device(xhci_device_t *);
 int hc_deconfigure_device(xhci_device_t *);
-int hc_add_endpoint(xhci_device_t *, uint8_t, xhci_ep_ctx_t *);
-int hc_drop_endpoint(xhci_device_t *, uint8_t);
-int hc_update_endpoint(xhci_device_t *, uint8_t, xhci_ep_ctx_t *);
-int hc_stop_endpoint(xhci_device_t *, uint8_t);
-int hc_reset_endpoint(xhci_device_t *, uint8_t);
+int hc_add_endpoint(xhci_endpoint_t *);
+int hc_drop_endpoint(xhci_endpoint_t *);
+int hc_update_endpoint(xhci_endpoint_t *);
+int hc_stop_endpoint(xhci_endpoint_t *);
+int hc_reset_endpoint(xhci_endpoint_t *);
+int hc_reset_ring(xhci_endpoint_t *, uint32_t);
 
 int hc_status(bus_t *, uint32_t *);
Index: uspace/drv/bus/usb/xhci/hw_struct/context.h
===================================================================
--- uspace/drv/bus/usb/xhci/hw_struct/context.h	(revision abb5d08b8dadddf815ac338a1b5357b8df0b66e6)
+++ uspace/drv/bus/usb/xhci/hw_struct/context.h	(revision 51c1d500b4bb389b18317382df9d42881fe3471e)
@@ -179,13 +179,12 @@
 #define XHCI_CTX_SIZE_SMALL 32
 #define XHCI_ONE_CTX_SIZE(hc) (XHCI_CTX_SIZE_SMALL << hc->csz)
-#define XHCI_SLOT_CTX_OFFSET 0
-#define XHCI_EP_ARRAY_OFFSET 1
-#define XHCI_DEVICE_CTX_SIZE(hc) ((XHCI_EP_ARRAY_OFFSET + XHCI_EP_COUNT) * XHCI_ONE_CTX_SIZE(hc))
+#define XHCI_DEVICE_CTX_SIZE(hc) ((1 + XHCI_EP_COUNT) * XHCI_ONE_CTX_SIZE(hc))
 
 /**
  * Device context: section 6.2.1
  */
-#define XHCI_GET_SLOT_CTX(dev_ctx, hc) (xhci_slot_ctx_t *)((char*)dev_ctx + XHCI_SLOT_CTX_OFFSET * XHCI_ONE_CTX_SIZE(hc))
-#define XHCI_GET_EP_CTX(dev_ctx, hc, dci) (xhci_ep_ctx_t *)((char*)dev_ctx + (dci + XHCI_EP_ARRAY_OFFSET) * XHCI_ONE_CTX_SIZE(hc))
+#define XHCI_GET_DC_FIELD(dev_ctx, hc, dci) ((char*)dev_ctx + (dci) * XHCI_ONE_CTX_SIZE(hc))
+#define XHCI_GET_EP_CTX(dev_ctx, hc, dci) ((xhci_ep_ctx_t *)   XHCI_GET_DC_FIELD(dev_ctx, hc, dci))
+#define XHCI_GET_SLOT_CTX(dev_ctx, hc)    ((xhci_slot_ctx_t *) XHCI_GET_DC_FIELD(dev_ctx, hc, 0))
 
 /**
Index: uspace/drv/bus/usb/xhci/isoch.c
===================================================================
--- uspace/drv/bus/usb/xhci/isoch.c	(revision abb5d08b8dadddf815ac338a1b5357b8df0b66e6)
+++ uspace/drv/bus/usb/xhci/isoch.c	(revision 51c1d500b4bb389b18317382df9d42881fe3471e)
@@ -347,7 +347,5 @@
 out:
 	if (fed) {
-		const uint8_t slot_id = xhci_device_get(ep->base.device)->slot_id;
-		const uint8_t target = xhci_endpoint_index(ep) + 1; /* EP Doorbells start at 1 */
-		hc_ring_doorbell(hc, slot_id, target);
+		hc_ring_ep_doorbell(ep, 0);
 		/* The ring may be dead. If no event happens until the delay, reset the endpoint. */
 		timer_schedule_reset(ep);
@@ -436,7 +434,5 @@
 
 	if (fed) {
-		const uint8_t slot_id = xhci_device_get(ep->base.device)->slot_id;
-		const uint8_t target = xhci_endpoint_index(ep) + 1; /* EP Doorbells start at 1 */
-		hc_ring_doorbell(hc, slot_id, target);
+		hc_ring_ep_doorbell(ep, 0);
 		/* The ring may be dead. If no event happens until the delay, reset the endpoint. */
 		timer_schedule_reset(ep);
Index: uspace/drv/bus/usb/xhci/streams.c
===================================================================
--- uspace/drv/bus/usb/xhci/streams.c	(revision abb5d08b8dadddf815ac338a1b5357b8df0b66e6)
+++ uspace/drv/bus/usb/xhci/streams.c	(revision 51c1d500b4bb389b18317382df9d42881fe3471e)
@@ -327,5 +327,5 @@
 	}
 
-	hc_stop_endpoint(dev, xhci_endpoint_index(xhci_ep));
+	hc_stop_endpoint(xhci_ep);
 	xhci_endpoint_free_transfer_ds(xhci_ep);
 
@@ -337,8 +337,5 @@
 	}
 
-	xhci_ep_ctx_t ep_ctx;
-	memset(&ep_ctx, 0, XHCI_ONE_CTX_SIZE(hc));
-	xhci_setup_endpoint_context(xhci_ep, &ep_ctx);
-	return hc_update_endpoint(dev, xhci_endpoint_index(xhci_ep), &ep_ctx);
+	return hc_update_endpoint(xhci_ep);
 }
 
@@ -361,5 +358,5 @@
 	 * Stop the endpoint, destroy the ring, and transition to streams.
 	 */
-	hc_stop_endpoint(dev, xhci_endpoint_index(xhci_ep));
+	hc_stop_endpoint(xhci_ep);
 	xhci_endpoint_free_transfer_ds(xhci_ep);
 
@@ -381,5 +378,5 @@
 	setup_stream_context(xhci_ep, &ep_ctx, pstreams, 1);
 
-	return hc_update_endpoint(dev, xhci_endpoint_index(xhci_ep), &ep_ctx);
+	return hc_update_endpoint(xhci_ep);
 }
 
@@ -434,5 +431,5 @@
 	 * Stop the endpoint, destroy the ring, and transition to streams.
 	 */
-	hc_stop_endpoint(dev, xhci_endpoint_index(xhci_ep));
+	hc_stop_endpoint(xhci_ep);
 	xhci_endpoint_free_transfer_ds(xhci_ep);
 
@@ -455,5 +452,5 @@
 	setup_stream_context(xhci_ep, &ep_ctx, pstreams, 0);
 
-	return hc_update_endpoint(dev, xhci_endpoint_index(xhci_ep), &ep_ctx);
+	return hc_update_endpoint(xhci_ep);
 
 err_init:
Index: uspace/drv/bus/usb/xhci/transfers.c
===================================================================
--- uspace/drv/bus/usb/xhci/transfers.c	(revision abb5d08b8dadddf815ac338a1b5357b8df0b66e6)
+++ uspace/drv/bus/usb/xhci/transfers.c	(revision 51c1d500b4bb389b18317382df9d42881fe3471e)
@@ -120,17 +120,8 @@
 }
 
-static xhci_trb_ring_t *get_ring(xhci_hc_t *hc, xhci_transfer_t *transfer)
-{
-	xhci_endpoint_t *ep = xhci_endpoint_get(transfer->batch.ep);
-	if (ep->primary_stream_data_size == 0) return &ep->ring;
-	uint32_t stream_id = transfer->batch.target.stream;
-
-	xhci_stream_data_t *stream_data = xhci_get_stream_ctx_data(ep, stream_id);
-	if (stream_data == NULL) {
-		usb_log_warning("No transfer ring was found for stream %u.", stream_id);
-		return NULL;
-	}
-
-	return &stream_data->ring;
+static xhci_trb_ring_t *get_ring(xhci_transfer_t *transfer)
+{
+	xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep);
+	return xhci_endpoint_get_ring(xhci_ep, transfer->batch.target.stream);
 }
 
@@ -138,5 +129,4 @@
 {
 	usb_transfer_batch_t *batch = &transfer->batch;
-	xhci_trb_ring_t *ring = get_ring(hc, transfer);
 	xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep);
 
@@ -202,5 +192,5 @@
 	}
 
-	return xhci_trb_ring_enqueue_multiple(ring, trbs, trbs_used, &transfer->interrupt_trb_phys);
+	return xhci_trb_ring_enqueue_multiple(get_ring(transfer), trbs, trbs_used, &transfer->interrupt_trb_phys);
 }
 
@@ -224,5 +214,5 @@
 		TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
 
-		xhci_trb_ring_t* ring = get_ring(hc, transfer);
+		xhci_trb_ring_t* ring = get_ring(transfer);
 		return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
 	}
@@ -233,5 +223,5 @@
 		TRB_CTRL_SET_ENT(trb, 1);
 
-		xhci_trb_ring_t* ring = get_ring(hc, transfer);
+		xhci_trb_ring_t* ring = get_ring(transfer);
 		if (!ring) {
 			return EINVAL;
@@ -269,5 +259,5 @@
 	TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
 
-	xhci_trb_ring_t* ring = get_ring(hc, transfer);
+	xhci_trb_ring_t* ring = get_ring(transfer);
 
 	return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
@@ -313,6 +303,5 @@
 		/* We are received transfer pointer instead - work with that */
 		transfer = (xhci_transfer_t *) addr;
-		xhci_trb_ring_t * ring = get_ring(hc, transfer);
-		xhci_trb_ring_update_dequeue(ring, transfer->interrupt_trb_phys);
+		xhci_trb_ring_update_dequeue(get_ring(transfer), transfer->interrupt_trb_phys);
 		batch = &transfer->batch;
 
@@ -497,12 +486,9 @@
 	}
 
+	hc_ring_ep_doorbell(xhci_ep, batch->target.stream);
+
 	/* 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;
-	/* EP Doorbells start at 1 */
-	const uint8_t target = (xhci_endpoint_index(xhci_ep) + 1) | (batch->target.stream << 16);
-	hc_ring_doorbell(hc, slot_id, target);
 	return EOK;
 }
