summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2014-01-29 13:36:53 -0300
committerSeung-Woo Kim <sw0312.kim@samsung.com>2014-06-16 15:51:13 +0900
commit1770d2efa3197fcae93d787d8d912cece4aac250 (patch)
tree123e5ba6794636aa43dcdd039e24bfc5bb42b74c
parent87422075ff654e5f79e93edaed9944cf0b08f4f1 (diff)
downloadlinux-3.10-1770d2efa3197fcae93d787d8d912cece4aac250.tar.gz
linux-3.10-1770d2efa3197fcae93d787d8d912cece4aac250.tar.bz2
linux-3.10-1770d2efa3197fcae93d787d8d912cece4aac250.zip
vb2: fix buf_init/buf_cleanup call sequences
Ensure that these ops are properly balanced. There are two scenarios: 1) for MMAP buf_init is called when the buffers are created and buf_cleanup must be called when the queue is finally freed. This scenario was always working. 2) for USERPTR and DMABUF it is more complicated. When a buffer is queued the code checks if all planes of this buffer have been acquired before. If that's the case, then only buf_prepare has to be called. Otherwise buf_cleanup needs to be called if the buffer was acquired before, then, once all changed planes have been (re)acquired, buf_init has to be called followed by buf_prepare. Should buf_prepare fail, then buf_cleanup must be called on the newly acquired planes to release them in. Finally, in __vb2_queue_free we have to check if the buffer was actually acquired before calling buf_cleanup. While that it always true for MMAP mode, it is not necessarily true for the other modes. E.g. if you just call REQBUFS and close the file handle, then buffers were never queued and so no buf_init was ever called. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com> [Backport from upstream to support dmabuf memory] Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com> Change-Id: I9a020bd5bca6376f70f3a9a85cce63ff0ff555ed
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c91
1 files changed, 62 insertions, 29 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index e3bdc3be91e..9abb15e1471 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -286,9 +286,10 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
if (q->ops->buf_cleanup) {
for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
++buffer) {
- if (NULL == q->bufs[buffer])
- continue;
- q->ops->buf_cleanup(q->bufs[buffer]);
+ struct vb2_buffer *vb = q->bufs[buffer];
+
+ if (vb && vb->planes[0].mem_priv)
+ q->ops->buf_cleanup(vb);
}
}
@@ -962,6 +963,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
unsigned int plane;
int ret;
int write = !V4L2_TYPE_IS_OUTPUT(q->type);
+ bool reacquired = vb->planes[0].mem_priv == NULL;
/* Copy relevant information provided by the userspace */
__fill_vb2_buffer(vb, b, planes);
@@ -983,12 +985,16 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
}
/* Release previously acquired memory if present */
- if (vb->planes[plane].mem_priv)
+ if (vb->planes[plane].mem_priv) {
+ if (!reacquired) {
+ reacquired = true;
+ q->ops->buf_cleanup(vb);
+ }
call_memop(q, put_userptr, vb->planes[plane].mem_priv);
+ }
vb->planes[plane].mem_priv = NULL;
- vb->v4l2_planes[plane].m.userptr = 0;
- vb->v4l2_planes[plane].length = 0;
+ memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane));
/* Acquire each plane's memory */
mem_priv = call_memop(q, get_userptr, q->alloc_ctx[plane],
@@ -1004,22 +1010,32 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
}
/*
- * Call driver-specific initialization on the newly acquired buffer,
- * if provided.
- */
- ret = call_qop(q, buf_init, vb);
- if (ret) {
- dprintk(1, "qbuf: buffer initialization failed\n");
- goto err;
- }
-
- /*
* Now that everything is in order, copy relevant information
* provided by userspace.
*/
for (plane = 0; plane < vb->num_planes; ++plane)
vb->v4l2_planes[plane] = planes[plane];
+ if (reacquired) {
+ /*
+ * One or more planes changed, so we must call buf_init to do
+ * the driver-specific initialization on the newly acquired
+ * buffer, if provided.
+ */
+ ret = call_qop(q, buf_init, vb);
+ if (ret) {
+ dprintk(1, "qbuf: buffer initialization failed\n");
+ goto err;
+ }
+ }
+
+ ret = call_qop(q, buf_prepare, vb);
+ if (ret) {
+ dprintk(1, "qbuf: buffer preparation failed\n");
+ call_qop(q, buf_cleanup, vb);
+ goto err;
+ }
+
return 0;
err:
/* In case of errors, release planes that were already acquired */
@@ -1039,8 +1055,12 @@ err:
*/
static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b)
{
+ int ret;
+ struct vb2_queue *q = vb->vb2_queue;
+
__fill_vb2_buffer(vb, b, vb->v4l2_planes);
- return 0;
+ ret = call_qop(q, buf_prepare, vb);
+ return ret;
}
/**
@@ -1054,6 +1074,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
unsigned int plane;
int ret;
int write = !V4L2_TYPE_IS_OUTPUT(q->type);
+ bool reacquired = vb->planes[0].mem_priv == NULL;
/* Verify and copy relevant information provided by the userspace */
__fill_vb2_buffer(vb, b, planes);
@@ -1087,6 +1108,11 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
dprintk(1, "qbuf: buffer for plane %d changed\n", plane);
+ if (!reacquired) {
+ reacquired = true;
+ call_qop(q, buf_cleanup, vb);
+ }
+
/* Release previously acquired memory if present */
__vb2_plane_dmabuf_put(q, &vb->planes[plane]);
memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane));
@@ -1120,22 +1146,31 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
}
/*
- * Call driver-specific initialization on the newly acquired buffer,
- * if provided.
- */
- ret = call_qop(q, buf_init, vb);
- if (ret) {
- dprintk(1, "qbuf: buffer initialization failed\n");
- goto err;
- }
-
- /*
* Now that everything is in order, copy relevant information
* provided by userspace.
*/
for (plane = 0; plane < vb->num_planes; ++plane)
vb->v4l2_planes[plane] = planes[plane];
+ if (reacquired) {
+ /*
+ * Call driver-specific initialization on the newly acquired buffer,
+ * if provided.
+ */
+ ret = call_qop(q, buf_init, vb);
+ if (ret) {
+ dprintk(1, "qbuf: buffer initialization failed\n");
+ goto err;
+ }
+ }
+
+ ret = call_qop(q, buf_prepare, vb);
+ if (ret) {
+ dprintk(1, "qbuf: buffer preparation failed\n");
+ call_qop(q, buf_cleanup, vb);
+ goto err;
+ }
+
return 0;
err:
/* In case of errors, release planes that were already acquired */
@@ -1182,8 +1217,6 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
ret = -EINVAL;
}
- if (!ret)
- ret = call_qop(q, buf_prepare, vb);
if (ret)
dprintk(1, "qbuf: buffer preparation failed: %d\n", ret);
else