Index: uspace/lib/virtio/virtio-pci.h
===================================================================
--- uspace/lib/virtio/virtio-pci.h	(revision 3d135e92dfa5eada208677984fcd67d69711f95b)
+++ uspace/lib/virtio/virtio-pci.h	(revision b8ef198b865bb1e67719113decaabfc4685fe25c)
@@ -143,4 +143,5 @@
 	/** Virtual address of the used ring */
 	virtq_used_t *used;
+	uint16_t used_last_idx;
 
 	/** Address of the queue's notification register */
@@ -182,4 +183,6 @@
 
 extern void virtio_virtq_produce_available(virtio_dev_t *, uint16_t, uint16_t);
+extern bool virtio_virtq_consume_used(virtio_dev_t *, uint16_t, uint16_t *,
+    uint32_t *);
 
 extern errno_t virtio_virtq_setup(virtio_dev_t *, uint16_t, uint16_t);
Index: uspace/lib/virtio/virtio.c
===================================================================
--- uspace/lib/virtio/virtio.c	(revision 3d135e92dfa5eada208677984fcd67d69711f95b)
+++ uspace/lib/virtio/virtio.c	(revision b8ef198b865bb1e67719113decaabfc4685fe25c)
@@ -71,4 +71,21 @@
 }
 
+bool virtio_virtq_consume_used(virtio_dev_t *vdev, uint16_t num,
+    uint16_t *descno, uint32_t *len)
+{
+	virtq_t *q = &vdev->queues[num];
+
+	uint16_t last_idx = q->used_last_idx % q->queue_size;
+	if (last_idx == (pio_read_le16(&q->used->idx) % q->queue_size))
+		return false;
+
+	*descno = (uint16_t) pio_read_le32(&q->used->ring[last_idx].id);
+	*len = pio_read_le32(&q->used->ring[last_idx].len);
+
+	q->used_last_idx++;
+
+	return true;
+}
+
 errno_t virtio_virtq_setup(virtio_dev_t *vdev, uint16_t num, uint16_t size)
 {
@@ -120,4 +137,5 @@
 	q->avail = q->virt + avail_offset;
 	q->used = q->virt + used_offset;
+	q->used_last_idx = 0;
 
 	memset(q->virt, 0, q->size);
