summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c68
-rw-r--r--include/media/videobuf2-core.h15
2 files changed, 66 insertions, 17 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index 14a360490be9..0d5b84f3b570 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -1378,6 +1378,39 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
}
EXPORT_SYMBOL_GPL(vb2_prepare_buf);
+/**
+ * vb2_start_streaming() - Attempt to start streaming.
+ * @q: videobuf2 queue
+ *
+ * If there are not enough buffers, then retry_start_streaming is set to
+ * 1 and 0 is returned. The next time a buffer is queued and
+ * retry_start_streaming is 1, this function will be called again to
+ * retry starting the DMA engine.
+ */
+static int vb2_start_streaming(struct vb2_queue *q)
+{
+ int ret;
+
+ /* Tell the driver to start streaming */
+ ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
+
+ /*
+ * If there are not enough buffers queued to start streaming, then
+ * the start_streaming operation will return -ENOBUFS and you have to
+ * retry when the next buffer is queued.
+ */
+ if (ret == -ENOBUFS) {
+ dprintk(1, "qbuf: not enough buffers, retry when more buffers are queued.\n");
+ q->retry_start_streaming = 1;
+ return 0;
+ }
+ if (ret)
+ dprintk(1, "qbuf: driver refused to start streaming\n");
+ else
+ q->retry_start_streaming = 0;
+ return ret;
+}
+
static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
{
int ret = vb2_queue_or_prepare_buf(q, b, "qbuf");
@@ -1426,6 +1459,12 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
/* Fill buffer information for the userspace */
__fill_v4l2_buffer(vb, b);
+ if (q->retry_start_streaming) {
+ ret = vb2_start_streaming(q);
+ if (ret)
+ return ret;
+ }
+
dprintk(1, "%s() of buffer %d succeeded\n", __func__, vb->v4l2_buf.index);
return 0;
}
@@ -1575,7 +1614,8 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q)
return -EINVAL;
}
- wait_event(q->done_wq, !atomic_read(&q->queued_count));
+ if (!q->retry_start_streaming)
+ wait_event(q->done_wq, !atomic_read(&q->queued_count));
return 0;
}
EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers);
@@ -1689,6 +1729,11 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
{
unsigned int i;
+ if (q->retry_start_streaming) {
+ q->retry_start_streaming = 0;
+ q->streaming = 0;
+ }
+
/*
* Tell driver to stop all transactions and release all queued
* buffers.
@@ -1738,12 +1783,9 @@ static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
list_for_each_entry(vb, &q->queued_list, queued_entry)
__enqueue_in_driver(vb);
- /*
- * Let driver notice that streaming state has been enabled.
- */
- ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
+ /* Tell driver to start streaming. */
+ ret = vb2_start_streaming(q);
if (ret) {
- dprintk(1, "streamon: driver refused to start streaming\n");
__vb2_queue_cancel(q);
return ret;
}
@@ -2313,15 +2355,15 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
goto err_reqbufs;
fileio->bufs[i].queued = 1;
}
-
- /*
- * Start streaming.
- */
- ret = vb2_streamon(q, q->type);
- if (ret)
- goto err_reqbufs;
}
+ /*
+ * Start streaming.
+ */
+ ret = vb2_streamon(q, q->type);
+ if (ret)
+ goto err_reqbufs;
+
q->fileio = fileio;
return ret;
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index ea766525a268..bef53ce555d2 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -252,10 +252,13 @@ struct vb2_buffer {
* receive buffers with @buf_queue callback before
* @start_streaming is called; the driver gets the number
* of already queued buffers in count parameter; driver
- * can return an error if hardware fails or not enough
- * buffers has been queued, in such case all buffers that
- * have been already given by the @buf_queue callback are
- * invalidated.
+ * can return an error if hardware fails, in that case all
+ * buffers that have been already given by the @buf_queue
+ * callback are invalidated.
+ * If there were not enough queued buffers to start
+ * streaming, then this callback returns -ENOBUFS, and the
+ * vb2 core will retry calling @start_streaming when a new
+ * buffer is queued.
* @stop_streaming: called when 'streaming' state must be disabled; driver
* should stop any DMA transactions or wait until they
* finish and give back all buffers it got from buf_queue()
@@ -323,6 +326,9 @@ struct v4l2_fh;
* @done_wq: waitqueue for processes waiting for buffers ready to be dequeued
* @alloc_ctx: memory type/allocator-specific contexts for each plane
* @streaming: current streaming state
+ * @retry_start_streaming: start_streaming() was called, but there were not enough
+ * buffers queued. If set, then retry calling start_streaming when
+ * queuing a new buffer.
* @fileio: file io emulator internal data, used only if emulator is active
*/
struct vb2_queue {
@@ -355,6 +361,7 @@ struct vb2_queue {
unsigned int plane_sizes[VIDEO_MAX_PLANES];
unsigned int streaming:1;
+ unsigned int retry_start_streaming:1;
struct vb2_fileio_data *fileio;
};