Drivers are now required to implement the stop_streaming() callback to ensure that all ongoing hardware operations are finished and their ownership of buffers is ceded. Drivers do not have to call vb2_buffer_done() for each buffer they own anymore. Also remove the return value from the callback. Signed-off-by: Pawel Osciak <pawel@xxxxxxxxxx> --- drivers/media/video/videobuf2-core.c | 16 ++++++++++++++-- include/media/videobuf2-core.h | 16 +++++++--------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 6e69584..59d5e8b 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -640,6 +640,9 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) struct vb2_queue *q = vb->vb2_queue; unsigned long flags; + if (atomic_read(&q->queued_count) == 0) + return; + if (vb->state != VB2_BUF_STATE_ACTIVE) return; @@ -1178,12 +1181,20 @@ static void __vb2_queue_cancel(struct vb2_queue *q) unsigned int i; /* - * Tell driver to stop all transactions and release all queued + * Tell the driver to stop all transactions and release all queued * buffers. */ if (q->streaming) call_qop(q, stop_streaming, q); + + /* + * All buffers should now not be in use by the driver anymore, but we + * have to manually set queued_count to 0, as the driver was not + * required to call vb2_buffer_done() from stop_streaming() for all + * buffers it had queued. + */ q->streaming = 0; + atomic_set(&q->queued_count, 0); /* * Remove all buffers from videobuf's list... @@ -1197,7 +1208,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) wake_up_all(&q->done_wq); /* - * Reinitialize all buffers for next use. + * Reinitialize all buffers for future use. */ for (i = 0; i < q->num_buffers; ++i) q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED; @@ -1440,6 +1451,7 @@ int vb2_queue_init(struct vb2_queue *q) BUG_ON(!q->ops->queue_setup); BUG_ON(!q->ops->buf_queue); + BUG_ON(!q->ops->stop_streaming); INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index f3bdbb2..8115fe9 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -184,7 +184,7 @@ struct vb2_buffer { /** * struct vb2_ops - driver-specific callbacks to be implemented by the driver - * Required: queue_setup, buf_queue. The rest is optional. + * Required: queue_setup, buf_queue, stop_streaming. The rest is optional. * * @queue_setup: used to negotiate queue parameters between the userspace * and the driver; called before memory allocation; @@ -231,13 +231,11 @@ struct vb2_buffer { * the driver before streaming begins (such as enabling * the device); * @stop_streaming: called when the 'streaming' state must be disabled; - * drivers should stop any DMA transactions here (or wait - * until they are finished) and give back all the buffers - * received via buf_queue() by calling vb2_buffer_done() - * for each of them; - * drivers can use the vb2_wait_for_all_buffers() function - * here to wait for asynchronous completion events that - * call vb2_buffer_done(), such as ISRs; + * drivers should stop any DMA transactions here (or wait + * until they are finished) before returning; + * drivers can use the vb2_wait_for_all_buffers() function + * here to wait for asynchronous completion events, such + * as ISRs; * @buf_queue: passes a buffer to the driver; the driver may start * a hardware operation on that buffer; this callback * MUST return immediately, i.e. it may NOT wait for @@ -259,7 +257,7 @@ struct vb2_ops { void (*buf_cleanup)(struct vb2_buffer *vb); int (*start_streaming)(struct vb2_queue *q); - int (*stop_streaming)(struct vb2_queue *q); + void (*stop_streaming)(struct vb2_queue *q); void (*buf_queue)(struct vb2_buffer *vb); }; -- 1.7.4.2 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html