diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-09-28 05:12:53 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-10-05 21:21:40 -0400 |
commit | 32a772603173f9e1bf675c01e4649e3fe3b794bc (patch) | |
tree | 090dec95f087913c5e74c52ee76a65d9e7b5efb0 /drivers/media/v4l2-core | |
parent | 626d533f8cb63b6c0cd6b83e1ce7e7656ccaba84 (diff) |
[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>
Diffstat (limited to 'drivers/media/v4l2-core')
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-core.c | 78 |
1 files changed, 38 insertions, 40 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index e6a26b433e87..5a132b286894 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c | |||
@@ -276,6 +276,9 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) | |||
276 | */ | 276 | */ |
277 | static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b) | 277 | static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b) |
278 | { | 278 | { |
279 | if (!V4L2_TYPE_IS_MULTIPLANAR(b->type)) | ||
280 | return 0; | ||
281 | |||
279 | /* Is memory for copying plane information present? */ | 282 | /* Is memory for copying plane information present? */ |
280 | if (NULL == b->m.planes) { | 283 | if (NULL == b->m.planes) { |
281 | dprintk(1, "Multi-planar buffer passed but " | 284 | dprintk(1, "Multi-planar buffer passed but " |
@@ -331,10 +334,9 @@ static bool __buffers_in_use(struct vb2_queue *q) | |||
331 | * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be | 334 | * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be |
332 | * returned to userspace | 335 | * returned to userspace |
333 | */ | 336 | */ |
334 | static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) | 337 | static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) |
335 | { | 338 | { |
336 | struct vb2_queue *q = vb->vb2_queue; | 339 | struct vb2_queue *q = vb->vb2_queue; |
337 | int ret; | ||
338 | 340 | ||
339 | /* Copy back data such as timestamp, flags, etc. */ | 341 | /* Copy back data such as timestamp, flags, etc. */ |
340 | memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); | 342 | 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) | |||
342 | b->reserved = vb->v4l2_buf.reserved; | 344 | b->reserved = vb->v4l2_buf.reserved; |
343 | 345 | ||
344 | if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) { | 346 | if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) { |
345 | ret = __verify_planes_array(vb, b); | ||
346 | if (ret) | ||
347 | return ret; | ||
348 | |||
349 | /* | 347 | /* |
350 | * Fill in plane-related data if userspace provided an array | 348 | * Fill in plane-related data if userspace provided an array |
351 | * for it. The memory and size is verified above. | 349 | * for it. The caller has already verified memory and size. |
352 | */ | 350 | */ |
353 | memcpy(b->m.planes, vb->v4l2_planes, | 351 | memcpy(b->m.planes, vb->v4l2_planes, |
354 | b->length * sizeof(struct v4l2_plane)); | 352 | b->length * sizeof(struct v4l2_plane)); |
@@ -391,8 +389,6 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) | |||
391 | 389 | ||
392 | if (__buffer_in_use(q, vb)) | 390 | if (__buffer_in_use(q, vb)) |
393 | b->flags |= V4L2_BUF_FLAG_MAPPED; | 391 | b->flags |= V4L2_BUF_FLAG_MAPPED; |
394 | |||
395 | return 0; | ||
396 | } | 392 | } |
397 | 393 | ||
398 | /** | 394 | /** |
@@ -411,6 +407,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) | |||
411 | int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) | 407 | int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) |
412 | { | 408 | { |
413 | struct vb2_buffer *vb; | 409 | struct vb2_buffer *vb; |
410 | int ret; | ||
414 | 411 | ||
415 | if (b->type != q->type) { | 412 | if (b->type != q->type) { |
416 | dprintk(1, "querybuf: wrong buffer type\n"); | 413 | dprintk(1, "querybuf: wrong buffer type\n"); |
@@ -422,8 +419,10 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) | |||
422 | return -EINVAL; | 419 | return -EINVAL; |
423 | } | 420 | } |
424 | vb = q->bufs[b->index]; | 421 | vb = q->bufs[b->index]; |
425 | 422 | ret = __verify_planes_array(vb, b); | |
426 | return __fill_v4l2_buffer(vb, b); | 423 | if (!ret) |
424 | __fill_v4l2_buffer(vb, b); | ||
425 | return ret; | ||
427 | } | 426 | } |
428 | EXPORT_SYMBOL(vb2_querybuf); | 427 | EXPORT_SYMBOL(vb2_querybuf); |
429 | 428 | ||
@@ -813,24 +812,16 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) | |||
813 | EXPORT_SYMBOL_GPL(vb2_buffer_done); | 812 | EXPORT_SYMBOL_GPL(vb2_buffer_done); |
814 | 813 | ||
815 | /** | 814 | /** |
816 | * __fill_vb2_buffer() - fill a vb2_buffer with information provided in | 815 | * __fill_vb2_buffer() - fill a vb2_buffer with information provided in a |
817 | * a v4l2_buffer by the userspace | 816 | * v4l2_buffer by the userspace. The caller has already verified that struct |
817 | * v4l2_buffer has a valid number of planes. | ||
818 | */ | 818 | */ |
819 | static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, | 819 | static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, |
820 | struct v4l2_plane *v4l2_planes) | 820 | struct v4l2_plane *v4l2_planes) |
821 | { | 821 | { |
822 | unsigned int plane; | 822 | unsigned int plane; |
823 | int ret; | ||
824 | 823 | ||
825 | if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { | 824 | if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { |
826 | /* | ||
827 | * Verify that the userspace gave us a valid array for | ||
828 | * plane information. | ||
829 | */ | ||
830 | ret = __verify_planes_array(vb, b); | ||
831 | if (ret) | ||
832 | return ret; | ||
833 | |||
834 | /* Fill in driver-provided information for OUTPUT types */ | 825 | /* Fill in driver-provided information for OUTPUT types */ |
835 | if (V4L2_TYPE_IS_OUTPUT(b->type)) { | 826 | if (V4L2_TYPE_IS_OUTPUT(b->type)) { |
836 | /* | 827 | /* |
@@ -872,8 +863,6 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, | |||
872 | vb->v4l2_buf.field = b->field; | 863 | vb->v4l2_buf.field = b->field; |
873 | vb->v4l2_buf.timestamp = b->timestamp; | 864 | vb->v4l2_buf.timestamp = b->timestamp; |
874 | vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS; | 865 | vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS; |
875 | |||
876 | return 0; | ||
877 | } | 866 | } |
878 | 867 | ||
879 | /** | 868 | /** |
@@ -888,10 +877,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) | |||
888 | int ret; | 877 | int ret; |
889 | int write = !V4L2_TYPE_IS_OUTPUT(q->type); | 878 | int write = !V4L2_TYPE_IS_OUTPUT(q->type); |
890 | 879 | ||
891 | /* Verify and copy relevant information provided by the userspace */ | 880 | /* Copy relevant information provided by the userspace */ |
892 | ret = __fill_vb2_buffer(vb, b, planes); | 881 | __fill_vb2_buffer(vb, b, planes); |
893 | if (ret) | ||
894 | return ret; | ||
895 | 882 | ||
896 | for (plane = 0; plane < vb->num_planes; ++plane) { | 883 | for (plane = 0; plane < vb->num_planes; ++plane) { |
897 | /* Skip the plane if already verified */ | 884 | /* Skip the plane if already verified */ |
@@ -966,7 +953,8 @@ err: | |||
966 | */ | 953 | */ |
967 | static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) | 954 | static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) |
968 | { | 955 | { |
969 | return __fill_vb2_buffer(vb, b, vb->v4l2_planes); | 956 | __fill_vb2_buffer(vb, b, vb->v4l2_planes); |
957 | return 0; | ||
970 | } | 958 | } |
971 | 959 | ||
972 | /** | 960 | /** |
@@ -1059,7 +1047,9 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) | |||
1059 | dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state); | 1047 | dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state); |
1060 | return -EINVAL; | 1048 | return -EINVAL; |
1061 | } | 1049 | } |
1062 | 1050 | ret = __verify_planes_array(vb, b); | |
1051 | if (ret < 0) | ||
1052 | return ret; | ||
1063 | ret = __buf_prepare(vb, b); | 1053 | ret = __buf_prepare(vb, b); |
1064 | if (ret < 0) | 1054 | if (ret < 0) |
1065 | return ret; | 1055 | return ret; |
@@ -1147,6 +1137,9 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) | |||
1147 | ret = -EINVAL; | 1137 | ret = -EINVAL; |
1148 | goto unlock; | 1138 | goto unlock; |
1149 | } | 1139 | } |
1140 | ret = __verify_planes_array(vb, b); | ||
1141 | if (ret) | ||
1142 | goto unlock; | ||
1150 | 1143 | ||
1151 | switch (vb->state) { | 1144 | switch (vb->state) { |
1152 | case VB2_BUF_STATE_DEQUEUED: | 1145 | case VB2_BUF_STATE_DEQUEUED: |
@@ -1243,8 +1236,10 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) | |||
1243 | * the locks or return an error if one occurred. | 1236 | * the locks or return an error if one occurred. |
1244 | */ | 1237 | */ |
1245 | call_qop(q, wait_finish, q); | 1238 | call_qop(q, wait_finish, q); |
1246 | if (ret) | 1239 | if (ret) { |
1240 | dprintk(1, "Sleep was interrupted\n"); | ||
1247 | return ret; | 1241 | return ret; |
1242 | } | ||
1248 | } | 1243 | } |
1249 | return 0; | 1244 | return 0; |
1250 | } | 1245 | } |
@@ -1255,7 +1250,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) | |||
1255 | * Will sleep if required for nonblocking == false. | 1250 | * Will sleep if required for nonblocking == false. |
1256 | */ | 1251 | */ |
1257 | static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, | 1252 | static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, |
1258 | int nonblocking) | 1253 | struct v4l2_buffer *b, int nonblocking) |
1259 | { | 1254 | { |
1260 | unsigned long flags; | 1255 | unsigned long flags; |
1261 | int ret; | 1256 | int ret; |
@@ -1273,10 +1268,16 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, | |||
1273 | */ | 1268 | */ |
1274 | spin_lock_irqsave(&q->done_lock, flags); | 1269 | spin_lock_irqsave(&q->done_lock, flags); |
1275 | *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry); | 1270 | *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry); |
1276 | list_del(&(*vb)->done_entry); | 1271 | /* |
1272 | * Only remove the buffer from done_list if v4l2_buffer can handle all | ||
1273 | * the planes. | ||
1274 | */ | ||
1275 | ret = __verify_planes_array(*vb, b); | ||
1276 | if (!ret) | ||
1277 | list_del(&(*vb)->done_entry); | ||
1277 | spin_unlock_irqrestore(&q->done_lock, flags); | 1278 | spin_unlock_irqrestore(&q->done_lock, flags); |
1278 | 1279 | ||
1279 | return 0; | 1280 | return ret; |
1280 | } | 1281 | } |
1281 | 1282 | ||
1282 | /** | 1283 | /** |
@@ -1335,12 +1336,9 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) | |||
1335 | dprintk(1, "dqbuf: invalid buffer type\n"); | 1336 | dprintk(1, "dqbuf: invalid buffer type\n"); |
1336 | return -EINVAL; | 1337 | return -EINVAL; |
1337 | } | 1338 | } |
1338 | 1339 | ret = __vb2_get_done_vb(q, &vb, b, nonblocking); | |
1339 | ret = __vb2_get_done_vb(q, &vb, nonblocking); | 1340 | if (ret < 0) |
1340 | if (ret < 0) { | ||
1341 | dprintk(1, "dqbuf: error getting next done buffer\n"); | ||
1342 | return ret; | 1341 | return ret; |
1343 | } | ||
1344 | 1342 | ||
1345 | ret = call_qop(q, buf_finish, vb); | 1343 | ret = call_qop(q, buf_finish, vb); |
1346 | if (ret) { | 1344 | if (ret) { |