Index: uspace/drv/bus/usb/xhci/endpoint.c
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.c	(revision 5dfb70c9d83e87a81d5521cc846a48fe8f84f09b)
+++ uspace/drv/bus/usb/xhci/endpoint.c	(revision 5c75456d1c46306b7feaa50f199fd4f6d059a601)
@@ -64,4 +64,7 @@
 	xhci_ep->mult = desc->usb3.mult;
 
+	// TODO: process according to 6.2.3.6 of XHCI specification; hardcoded for HS/SS EPs
+	xhci_ep->interval = desc->interval - 1;
+
 	if (xhci_ep->base.transfer_type == USB_TRANSFER_ISOCHRONOUS) {
 		xhci_ep->isoch_max_size = desc->usb3.bytes_per_interval
@@ -72,5 +75,5 @@
 		/* Allocate and setup isochronous-specific structures. */
 		xhci_ep->isoch_enqueue = 0;
-		xhci_ep->isoch_dequeue = XHCI_ISOCH_BUFFER_COUNT - 1;
+		xhci_ep->isoch_dequeue = 0;
 		xhci_ep->isoch_started = false;
 
@@ -402,4 +405,5 @@
 	XHCI_EP_TR_DPTR_SET(*ctx, ep->ring.dequeue);
 	XHCI_EP_DCS_SET(*ctx, 1);
+	XHCI_EP_INTERVAL_SET(*ctx, ep->interval);
 
 	XHCI_EP_MAX_ESIT_PAYLOAD_LO_SET(*ctx, ep->isoch_max_size & 0xFFFF);
@@ -420,4 +424,6 @@
 	XHCI_EP_TR_DPTR_SET(*ctx, ep->ring.dequeue);
 	XHCI_EP_DCS_SET(*ctx, 1);
+
+	XHCI_EP_INTERVAL_SET(*ctx, ep->interval);
 	// TODO: max ESIT payload
 }
Index: uspace/drv/bus/usb/xhci/endpoint.h
===================================================================
--- uspace/drv/bus/usb/xhci/endpoint.h	(revision 5dfb70c9d83e87a81d5521cc846a48fe8f84f09b)
+++ uspace/drv/bus/usb/xhci/endpoint.h	(revision 5c75456d1c46306b7feaa50f199fd4f6d059a601)
@@ -89,4 +89,7 @@
 	/** Maximum number of bursts within an interval that this endpoint supports */
 	uint8_t mult;
+
+	/** Scheduling interval for periodic endpoints */
+	size_t interval;
 
 	/** The maximum size of an isochronous transfer and therefore the size of buffers */
Index: uspace/drv/bus/usb/xhci/transfers.c
===================================================================
--- uspace/drv/bus/usb/xhci/transfers.c	(revision 5dfb70c9d83e87a81d5521cc846a48fe8f84f09b)
+++ uspace/drv/bus/usb/xhci/transfers.c	(revision 5c75456d1c46306b7feaa50f199fd4f6d059a601)
@@ -234,5 +234,5 @@
 
 static xhci_isoch_transfer_t* isoch_transfer_get_enqueue(xhci_endpoint_t *ep) {
-	if ((ep->isoch_enqueue % XHCI_ISOCH_BUFFER_COUNT) == ep->isoch_dequeue) {
+	if (((ep->isoch_enqueue + 1) % XHCI_ISOCH_BUFFER_COUNT) == ep->isoch_dequeue) {
 		/* None ready */
 		return NULL;
@@ -303,6 +303,6 @@
 
 	/* If not yet started, start the isochronous endpoint transfers - after buffer count - 1 writes */
-	/* The -2 is there because of the enqueue != dequeue check. The buffer must have at least 2 transfers. */
-	if (xhci_ep->isoch_enqueue == XHCI_ISOCH_BUFFER_COUNT - 2 && !xhci_ep->isoch_started) {
+	/* The -1 is there because of the enqueue != dequeue check. The buffer must have at least 2 transfers. */
+	if (((xhci_ep->isoch_enqueue + 1) % XHCI_ISOCH_BUFFER_COUNT) == xhci_ep->isoch_dequeue && !xhci_ep->isoch_started) {
 		const uint8_t slot_id = xhci_dev->slot_id;
 		const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */
@@ -322,4 +322,20 @@
 }
 
+static int schedule_isochronous_in_trbs(xhci_endpoint_t *xhci_ep, xhci_trb_ring_t *ring) {
+	xhci_trb_t trb;
+	xhci_isoch_transfer_t *isoch_transfer;
+	while ((isoch_transfer = isoch_transfer_get_enqueue(xhci_ep)) != NULL) {
+		xhci_trb_clean(&trb);
+		trb.parameter = isoch_transfer->data.phys;
+		isoch_transfer->size = xhci_ep->isoch_max_size;
+
+		int err = schedule_isochronous_trb(ring, xhci_ep, &trb, isoch_transfer->size,
+			&isoch_transfer->interrupt_trb_phys);
+		if (err)
+			return err;
+	}
+	return EOK;
+}
+
 static int schedule_isochronous_in(xhci_hc_t* hc, xhci_transfer_t* transfer, xhci_endpoint_t *xhci_ep,
 	xhci_device_t *xhci_dev)
@@ -328,7 +344,15 @@
 	/* If not yet started, start the isochronous endpoint transfers - before first read */
 	if (!xhci_ep->isoch_started) {
+		xhci_trb_ring_t *ring = get_ring(hc, transfer);
+		/* Fill the TRB ring. */
+		int err = schedule_isochronous_in_trbs(xhci_ep, ring);
+		if (err) {
+			fibril_mutex_unlock(&xhci_ep->isoch_guard);
+			return err;
+		}
+		/* Ring the doorbell to start it. */
 		const uint8_t slot_id = xhci_dev->slot_id;
 		const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */
-		int err = hc_ring_doorbell(hc, slot_id, target);
+		err = hc_ring_doorbell(hc, slot_id, target);
 		if (err) {
 			fibril_mutex_unlock(&xhci_ep->isoch_guard);
@@ -406,6 +430,9 @@
 		case XHCI_TRBC_RING_OVERRUN:
 		case XHCI_TRBC_RING_UNDERRUN:
-			// TODO: abort the phone; rings are unscheduled by xHC by now
+			/* Rings are unscheduled by xHC now */
 			ep->isoch_started = false;
+			/* For OUT, there was nothing to process */
+			/* For IN, the buffer has overfilled, we empty the buffers and readd TRBs */
+			ep->isoch_enqueue = ep->isoch_dequeue = 0;
 			err = EIO;
 			break;
Index: uspace/lib/drv/include/usb_iface.h
===================================================================
--- uspace/lib/drv/include/usb_iface.h	(revision 5dfb70c9d83e87a81d5521cc846a48fe8f84f09b)
+++ uspace/lib/drv/include/usb_iface.h	(revision 5c75456d1c46306b7feaa50f199fd4f6d059a601)
@@ -115,4 +115,7 @@
 	size_t max_packet_size;
 
+	/** Scheduling interval for HC. Only valid for interrupt/isoch transfer. */
+	size_t interval;
+
 	/** Number of packets per frame/uframe.
 	 * Only valid for HS INT and ISO transfers. All others should set to 1*/
Index: uspace/lib/usbdev/src/pipes.c
===================================================================
--- uspace/lib/usbdev/src/pipes.c	(revision 5dfb70c9d83e87a81d5521cc846a48fe8f84f09b)
+++ uspace/lib/usbdev/src/pipes.c	(revision 5c75456d1c46306b7feaa50f199fd4f6d059a601)
@@ -299,4 +299,7 @@
 	pipe->bus_session = bus_session;
 
+	// TODO: hardcoded, remake to receive from device descriptors
+	pipe->desc.interval = 14;
+
 	if (transfer_type == USB_TRANSFER_ISOCHRONOUS) {
 		ret = usb_isoch_session_initialize(pipe);
