Associate a buffer to a request when it is queued and disassociate when it is done. Signed-off-by: Sakari Ailus <sakari.ailus@xxxxxxxxxxxxxxx> --- drivers/media/common/videobuf2/videobuf2-core.c | 43 ++++++++++++++++++++++++- drivers/media/common/videobuf2/videobuf2-v4l2.c | 40 ++++++++++++++++++++++- include/media/videobuf2-core.h | 19 +++++++++++ include/media/videobuf2-v4l2.h | 28 ++++++++++++++++ 4 files changed, 128 insertions(+), 2 deletions(-) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index d3f7bb3..b8535de 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -346,6 +346,9 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, break; } + if (q->class) + media_request_object_init(q->class, &vb->req_obj); + vb->state = VB2_BUF_STATE_DEQUEUED; vb->vb2_queue = q; vb->num_planes = num_planes; @@ -520,7 +523,10 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) /* Free videobuf buffers */ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; ++buffer) { - kfree(q->bufs[buffer]); + if (q->class) + media_request_object_put(&q->bufs[buffer]->req_obj); + else + kfree(q->bufs[buffer]); q->bufs[buffer] = NULL; } @@ -944,6 +950,10 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) default: /* Inform any processes that may be waiting for buffers */ wake_up(&q->done_wq); + if (vb->req_ref) { + media_request_ref_complete(vb->req_ref); + vb->req_ref = NULL; + } break; } } @@ -1249,6 +1259,32 @@ static int __buf_prepare(struct vb2_buffer *vb, const void *pb) return -EIO; } + if (vb->request_fd) { + struct media_request *req; + struct media_request_ref *ref; + + if (!q->class) { + dprintk(1, "requests not enabled for the queue\n"); + return -EINVAL; + } + + req = media_request_find(q->class->mdev, vb->request_fd); + if (IS_ERR(req)) { + dprintk(1, "no request found for fd %d (%ld)\n", + vb->request_fd, PTR_ERR(req)); + return PTR_ERR(req); + } + + ref = media_request_object_bind(req, + &q->bufs[vb->index]->req_obj); + media_request_put(req); + + if (IS_ERR(ref)) + return PTR_ERR(ref); + + vb->req_ref = ref; + } + vb->state = VB2_BUF_STATE_PREPARING; switch (q->memory) { @@ -1269,6 +1305,8 @@ static int __buf_prepare(struct vb2_buffer *vb, const void *pb) if (ret) { dprintk(1, "buffer preparation failed: %d\n", ret); vb->state = VB2_BUF_STATE_DEQUEUED; + media_request_ref_unbind(vb->req_ref); + vb->req_ref = NULL; return ret; } @@ -2037,6 +2075,9 @@ void vb2_core_queue_release(struct vb2_queue *q) mutex_lock(&q->mmap_lock); __vb2_queue_free(q, q->num_buffers); mutex_unlock(&q->mmap_lock); + media_request_class_unregister(q->class); + kfree(q->class); + q->class = NULL; } EXPORT_SYMBOL_GPL(vb2_core_queue_release); diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 6d4d184..30047b9 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -196,6 +196,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) b->index = vb->index; b->type = vb->type; b->memory = vb->memory; + b->request_fd = vb->request_fd; b->bytesused = 0; b->flags = vbuf->flags; @@ -203,7 +204,6 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) b->timestamp = ns_to_timeval(vb->timestamp); b->timecode = vbuf->timecode; b->sequence = vbuf->sequence; - b->request_fd = 0; b->reserved = 0; if (q->is_multiplanar) { @@ -319,6 +319,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, return -EINVAL; } vb->timestamp = 0; + vb->request_fd = b->request_fd; vbuf->sequence = 0; if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { @@ -667,6 +668,43 @@ int vb2_queue_init(struct vb2_queue *q) } EXPORT_SYMBOL_GPL(vb2_queue_init); +static void vb2_media_req_obj_release(struct media_request_object *obj) +{ + struct vb2_v4l2_buffer *vbuf = + to_vb2_v4l2_buffer(media_request_object_to_vb2_buffer(obj)); + + kfree(vbuf); +} + +static void vb2_media_req_ref_unbind(struct media_request_ref *ref) +{ + struct vb2_v4l2_buffer *vbuf = + to_vb2_v4l2_buffer( + media_request_object_to_vb2_buffer(ref->new)); + + vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_ERROR); +} + +void vb2_queue_deny_requests(struct vb2_queue *q) +{ + media_request_class_unregister(q->class); +} +EXPORT_SYMBOL_GPL(vb2_queue_deny_requests); + +int vb2_queue_allow_requests(struct vb2_queue *q, struct media_device *mdev) +{ + q->class = kzalloc(sizeof(*q->class), GFP_KERNEL); + if (!q->class) + return -ENOMEM; + + media_request_class_register(mdev, q->class, + vb2_media_req_ref_unbind, + vb2_media_req_obj_release, true); + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_queue_allow_requests); + void vb2_queue_release(struct vb2_queue *q) { vb2_core_queue_release(q); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index f6818f73..68013e8 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -18,6 +18,8 @@ #include <linux/dma-buf.h> #include <linux/bitops.h> +#include <media/media-request.h> + #define VB2_MAX_FRAME (32) #define VB2_MAX_PLANES (8) @@ -42,6 +44,8 @@ enum vb2_memory { VB2_MEMORY_DMABUF = 4, }; +struct media_request_class; +struct media_request_ref; struct vb2_fileio_data; struct vb2_threadio_data; @@ -255,12 +259,19 @@ struct vb2_buffer { * done_entry: entry on the list that stores all buffers ready * to be dequeued to userspace * vb2_plane: per-plane information; do not change + * req_obj: media request object + * req_ref: media request reference (stored between qbuf -- + * dqbuf) + * request_fd file descriptor of the request */ enum vb2_buffer_state state; struct vb2_plane planes[VB2_MAX_PLANES]; struct list_head queued_entry; struct list_head done_entry; + struct media_request_object req_obj; + struct media_request_ref *req_ref; + int request_fd; #ifdef CONFIG_VIDEO_ADV_DEBUG /* * Counters for how often these buffer-related ops are @@ -293,6 +304,12 @@ struct vb2_buffer { #endif }; +static inline struct vb2_buffer * +media_request_object_to_vb2_buffer(struct media_request_object *obj) +{ + return container_of(obj, struct vb2_buffer, req_obj); +} + /** * struct vb2_ops - driver-specific callbacks. * @@ -505,6 +522,7 @@ struct vb2_buf_ops { * when a buffer with the %V4L2_BUF_FLAG_LAST is dequeued. * @fileio: file io emulator internal data, used only if emulator is active * @threadio: thread io internal data, used only if thread is active + * @req_class: The media request class for buffers in this queue */ struct vb2_queue { unsigned int type; @@ -558,6 +576,7 @@ struct vb2_queue { struct vb2_fileio_data *fileio; struct vb2_threadio_data *threadio; + struct media_request_class *class; #ifdef CONFIG_VIDEO_ADV_DEBUG /* diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h index 3d5e2d7..82e9284 100644 --- a/include/media/videobuf2-v4l2.h +++ b/include/media/videobuf2-v4l2.h @@ -32,6 +32,7 @@ * &enum v4l2_field. * @timecode: frame timecode. * @sequence: sequence count of this frame. + * @request: request used by the buffer * * Should contain enough information to be able to cover all the fields * of &struct v4l2_buffer at ``videodev2.h``. @@ -43,6 +44,7 @@ struct vb2_v4l2_buffer { __u32 field; struct v4l2_timecode timecode; __u32 sequence; + __u32 request; }; /* @@ -204,6 +206,32 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type); int __must_check vb2_queue_init(struct vb2_queue *q); /** + * vb2_queue_allow_requests - Allow requests on a videobuf2 queue + * + * @q: pointer to &struct vb2_queue with videobuf2 queue + * @mdev: the media device that contains the request queue + * + * Allow using requests on a VB2 queue. This allocates and registers a + * request class with the media device. To clean up, either release + * the queue using @vb2_queue_release or if that is not practical, + * @vb2_queue_deny_requests may also be used to unregister and free + * the request class. + */ +int vb2_queue_allow_requests(struct vb2_queue *q, struct media_device *mdev); + +/** + * vb2_queue_deny_requests - Deny requests on a videobuf2 queue + * + * @q: pointer to &struct vb2_queue with videobuf2 queue + * + * Deny requests on a VB2 queue. This function may only be called on + * an unused queue in error handling paths. Do not use it in other + * circumstances; @vb2_queue_release is enough to release the + * resources related to request management. + */ +void vb2_queue_deny_requests(struct vb2_queue *q); + +/** * vb2_queue_release() - stop streaming, release the queue and free memory * @q: pointer to &struct vb2_queue with videobuf2 queue. * -- 2.7.4