mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-19 18:53:52 +08:00
[media] videobuf2-core: move plane verification out of __fill_v4l2/vb_buffer
The plane verification should be done before actually queuing or dequeuing buffers, so move it out of __fill_v4l2_buffer and __fill_vb_buffer and call it as a separate step. This also makes it possible to change the return type of __fill_v4l2/vb_buffer to void. The dqbuf case took some special care: before removing a buffer from the done_list you have to verify that the receiving v4l2_buffer has enough room for all the planes. The number of planes can differ between buffers due to the fact that buffers for other formats can be prepared using VIDIOC_PREPARE_BUF. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Tested-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
626d533f8c
commit
32a7726031
@ -276,6 +276,9 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
|
|||||||
*/
|
*/
|
||||||
static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b)
|
static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b)
|
||||||
{
|
{
|
||||||
|
if (!V4L2_TYPE_IS_MULTIPLANAR(b->type))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Is memory for copying plane information present? */
|
/* Is memory for copying plane information present? */
|
||||||
if (NULL == b->m.planes) {
|
if (NULL == b->m.planes) {
|
||||||
dprintk(1, "Multi-planar buffer passed but "
|
dprintk(1, "Multi-planar buffer passed but "
|
||||||
@ -331,10 +334,9 @@ static bool __buffers_in_use(struct vb2_queue *q)
|
|||||||
* __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
|
* __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
|
||||||
* returned to userspace
|
* returned to userspace
|
||||||
*/
|
*/
|
||||||
static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
|
static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
|
||||||
{
|
{
|
||||||
struct vb2_queue *q = vb->vb2_queue;
|
struct vb2_queue *q = vb->vb2_queue;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Copy back data such as timestamp, flags, etc. */
|
/* Copy back data such as timestamp, flags, etc. */
|
||||||
memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
|
memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m));
|
||||||
@ -342,13 +344,9 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
|
|||||||
b->reserved = vb->v4l2_buf.reserved;
|
b->reserved = vb->v4l2_buf.reserved;
|
||||||
|
|
||||||
if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) {
|
if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) {
|
||||||
ret = __verify_planes_array(vb, b);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fill in plane-related data if userspace provided an array
|
* Fill in plane-related data if userspace provided an array
|
||||||
* for it. The memory and size is verified above.
|
* for it. The caller has already verified memory and size.
|
||||||
*/
|
*/
|
||||||
memcpy(b->m.planes, vb->v4l2_planes,
|
memcpy(b->m.planes, vb->v4l2_planes,
|
||||||
b->length * sizeof(struct v4l2_plane));
|
b->length * sizeof(struct v4l2_plane));
|
||||||
@ -391,8 +389,6 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
|
|||||||
|
|
||||||
if (__buffer_in_use(q, vb))
|
if (__buffer_in_use(q, vb))
|
||||||
b->flags |= V4L2_BUF_FLAG_MAPPED;
|
b->flags |= V4L2_BUF_FLAG_MAPPED;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -411,6 +407,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
|
|||||||
int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
|
int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
|
||||||
{
|
{
|
||||||
struct vb2_buffer *vb;
|
struct vb2_buffer *vb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (b->type != q->type) {
|
if (b->type != q->type) {
|
||||||
dprintk(1, "querybuf: wrong buffer type\n");
|
dprintk(1, "querybuf: wrong buffer type\n");
|
||||||
@ -422,8 +419,10 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
vb = q->bufs[b->index];
|
vb = q->bufs[b->index];
|
||||||
|
ret = __verify_planes_array(vb, b);
|
||||||
return __fill_v4l2_buffer(vb, b);
|
if (!ret)
|
||||||
|
__fill_v4l2_buffer(vb, b);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(vb2_querybuf);
|
EXPORT_SYMBOL(vb2_querybuf);
|
||||||
|
|
||||||
@ -813,24 +812,16 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
|
|||||||
EXPORT_SYMBOL_GPL(vb2_buffer_done);
|
EXPORT_SYMBOL_GPL(vb2_buffer_done);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __fill_vb2_buffer() - fill a vb2_buffer with information provided in
|
* __fill_vb2_buffer() - fill a vb2_buffer with information provided in a
|
||||||
* a v4l2_buffer by the userspace
|
* v4l2_buffer by the userspace. The caller has already verified that struct
|
||||||
|
* v4l2_buffer has a valid number of planes.
|
||||||
*/
|
*/
|
||||||
static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b,
|
static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b,
|
||||||
struct v4l2_plane *v4l2_planes)
|
struct v4l2_plane *v4l2_planes)
|
||||||
{
|
{
|
||||||
unsigned int plane;
|
unsigned int plane;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
|
if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
|
||||||
/*
|
|
||||||
* Verify that the userspace gave us a valid array for
|
|
||||||
* plane information.
|
|
||||||
*/
|
|
||||||
ret = __verify_planes_array(vb, b);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* Fill in driver-provided information for OUTPUT types */
|
/* Fill in driver-provided information for OUTPUT types */
|
||||||
if (V4L2_TYPE_IS_OUTPUT(b->type)) {
|
if (V4L2_TYPE_IS_OUTPUT(b->type)) {
|
||||||
/*
|
/*
|
||||||
@ -872,8 +863,6 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b,
|
|||||||
vb->v4l2_buf.field = b->field;
|
vb->v4l2_buf.field = b->field;
|
||||||
vb->v4l2_buf.timestamp = b->timestamp;
|
vb->v4l2_buf.timestamp = b->timestamp;
|
||||||
vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS;
|
vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -888,10 +877,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
|
|||||||
int ret;
|
int ret;
|
||||||
int write = !V4L2_TYPE_IS_OUTPUT(q->type);
|
int write = !V4L2_TYPE_IS_OUTPUT(q->type);
|
||||||
|
|
||||||
/* Verify and copy relevant information provided by the userspace */
|
/* Copy relevant information provided by the userspace */
|
||||||
ret = __fill_vb2_buffer(vb, b, planes);
|
__fill_vb2_buffer(vb, b, planes);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
for (plane = 0; plane < vb->num_planes; ++plane) {
|
for (plane = 0; plane < vb->num_planes; ++plane) {
|
||||||
/* Skip the plane if already verified */
|
/* Skip the plane if already verified */
|
||||||
@ -966,7 +953,8 @@ err:
|
|||||||
*/
|
*/
|
||||||
static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b)
|
static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b)
|
||||||
{
|
{
|
||||||
return __fill_vb2_buffer(vb, b, vb->v4l2_planes);
|
__fill_vb2_buffer(vb, b, vb->v4l2_planes);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1059,7 +1047,9 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
|
|||||||
dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state);
|
dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
ret = __verify_planes_array(vb, b);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
ret = __buf_prepare(vb, b);
|
ret = __buf_prepare(vb, b);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
@ -1147,6 +1137,9 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
|
|||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
ret = __verify_planes_array(vb, b);
|
||||||
|
if (ret)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
switch (vb->state) {
|
switch (vb->state) {
|
||||||
case VB2_BUF_STATE_DEQUEUED:
|
case VB2_BUF_STATE_DEQUEUED:
|
||||||
@ -1243,9 +1236,11 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
|
|||||||
* the locks or return an error if one occurred.
|
* the locks or return an error if one occurred.
|
||||||
*/
|
*/
|
||||||
call_qop(q, wait_finish, q);
|
call_qop(q, wait_finish, q);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
dprintk(1, "Sleep was interrupted\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1255,7 +1250,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
|
|||||||
* Will sleep if required for nonblocking == false.
|
* Will sleep if required for nonblocking == false.
|
||||||
*/
|
*/
|
||||||
static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
|
static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
|
||||||
int nonblocking)
|
struct v4l2_buffer *b, int nonblocking)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
@ -1273,10 +1268,16 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
|
|||||||
*/
|
*/
|
||||||
spin_lock_irqsave(&q->done_lock, flags);
|
spin_lock_irqsave(&q->done_lock, flags);
|
||||||
*vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
|
*vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry);
|
||||||
|
/*
|
||||||
|
* Only remove the buffer from done_list if v4l2_buffer can handle all
|
||||||
|
* the planes.
|
||||||
|
*/
|
||||||
|
ret = __verify_planes_array(*vb, b);
|
||||||
|
if (!ret)
|
||||||
list_del(&(*vb)->done_entry);
|
list_del(&(*vb)->done_entry);
|
||||||
spin_unlock_irqrestore(&q->done_lock, flags);
|
spin_unlock_irqrestore(&q->done_lock, flags);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1335,12 +1336,9 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
|
|||||||
dprintk(1, "dqbuf: invalid buffer type\n");
|
dprintk(1, "dqbuf: invalid buffer type\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
ret = __vb2_get_done_vb(q, &vb, b, nonblocking);
|
||||||
ret = __vb2_get_done_vb(q, &vb, nonblocking);
|
if (ret < 0)
|
||||||
if (ret < 0) {
|
|
||||||
dprintk(1, "dqbuf: error getting next done buffer\n");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
ret = call_qop(q, buf_finish, vb);
|
ret = call_qop(q, buf_finish, vb);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
Loading…
Reference in New Issue
Block a user