diff options
author | Pawel Osciak <p.osciak@samsung.com> | 2010-07-29 13:56:47 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-21 19:31:33 -0400 |
commit | 52a3082fea41ffe77003be76ac1496d60bb7908e (patch) | |
tree | 77724c1a8e010237369c39eb55e3677dcc3dec67 /drivers/media/video/v4l2-compat-ioctl32.c | |
parent | d14e6d76ebf740fd0d0bd296933993a555938896 (diff) |
[media] v4l: Add compat functions for the multi-planar API
Add multi-planar ioctl handling to the 32bit compatibility layer.
[mchehab@redhat.com: Merged with a fixup patch from Pawel]
Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/v4l2-compat-ioctl32.c')
-rw-r--r-- | drivers/media/video/v4l2-compat-ioctl32.c | 229 |
1 files changed, 195 insertions, 34 deletions
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index dc82eb83c1d..c19208a07b4 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c | |||
@@ -97,6 +97,14 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi | |||
97 | return 0; | 97 | return 0; |
98 | } | 98 | } |
99 | 99 | ||
100 | static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, | ||
101 | struct v4l2_pix_format_mplane __user *up) | ||
102 | { | ||
103 | if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) | ||
104 | return -EFAULT; | ||
105 | return 0; | ||
106 | } | ||
107 | |||
100 | static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) | 108 | static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) |
101 | { | 109 | { |
102 | if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) | 110 | if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) |
@@ -104,6 +112,14 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi | |||
104 | return 0; | 112 | return 0; |
105 | } | 113 | } |
106 | 114 | ||
115 | static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, | ||
116 | struct v4l2_pix_format_mplane __user *up) | ||
117 | { | ||
118 | if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) | ||
119 | return -EFAULT; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
107 | static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) | 123 | static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) |
108 | { | 124 | { |
109 | if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) | 125 | if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) |
@@ -136,6 +152,7 @@ struct v4l2_format32 { | |||
136 | enum v4l2_buf_type type; | 152 | enum v4l2_buf_type type; |
137 | union { | 153 | union { |
138 | struct v4l2_pix_format pix; | 154 | struct v4l2_pix_format pix; |
155 | struct v4l2_pix_format_mplane pix_mp; | ||
139 | struct v4l2_window32 win; | 156 | struct v4l2_window32 win; |
140 | struct v4l2_vbi_format vbi; | 157 | struct v4l2_vbi_format vbi; |
141 | struct v4l2_sliced_vbi_format sliced; | 158 | struct v4l2_sliced_vbi_format sliced; |
@@ -152,6 +169,10 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user | |||
152 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 169 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
153 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 170 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
154 | return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); | 171 | return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); |
172 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
173 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
174 | return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp, | ||
175 | &up->fmt.pix_mp); | ||
155 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 176 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
156 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 177 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
157 | return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); | 178 | return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); |
@@ -181,6 +202,10 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user | |||
181 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 202 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
182 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 203 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
183 | return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); | 204 | return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); |
205 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
206 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
207 | return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp, | ||
208 | &up->fmt.pix_mp); | ||
184 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 209 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
185 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 210 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
186 | return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); | 211 | return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); |
@@ -232,6 +257,17 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 | |||
232 | return 0; | 257 | return 0; |
233 | } | 258 | } |
234 | 259 | ||
260 | struct v4l2_plane32 { | ||
261 | __u32 bytesused; | ||
262 | __u32 length; | ||
263 | union { | ||
264 | __u32 mem_offset; | ||
265 | compat_long_t userptr; | ||
266 | } m; | ||
267 | __u32 data_offset; | ||
268 | __u32 reserved[11]; | ||
269 | }; | ||
270 | |||
235 | struct v4l2_buffer32 { | 271 | struct v4l2_buffer32 { |
236 | __u32 index; | 272 | __u32 index; |
237 | enum v4l2_buf_type type; | 273 | enum v4l2_buf_type type; |
@@ -247,14 +283,64 @@ struct v4l2_buffer32 { | |||
247 | union { | 283 | union { |
248 | __u32 offset; | 284 | __u32 offset; |
249 | compat_long_t userptr; | 285 | compat_long_t userptr; |
286 | compat_caddr_t planes; | ||
250 | } m; | 287 | } m; |
251 | __u32 length; | 288 | __u32 length; |
252 | __u32 input; | 289 | __u32 input; |
253 | __u32 reserved; | 290 | __u32 reserved; |
254 | }; | 291 | }; |
255 | 292 | ||
293 | static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, | ||
294 | enum v4l2_memory memory) | ||
295 | { | ||
296 | void __user *up_pln; | ||
297 | compat_long_t p; | ||
298 | |||
299 | if (copy_in_user(up, up32, 2 * sizeof(__u32)) || | ||
300 | copy_in_user(&up->data_offset, &up32->data_offset, | ||
301 | sizeof(__u32))) | ||
302 | return -EFAULT; | ||
303 | |||
304 | if (memory == V4L2_MEMORY_USERPTR) { | ||
305 | if (get_user(p, &up32->m.userptr)) | ||
306 | return -EFAULT; | ||
307 | up_pln = compat_ptr(p); | ||
308 | if (put_user((unsigned long)up_pln, &up->m.userptr)) | ||
309 | return -EFAULT; | ||
310 | } else { | ||
311 | if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, | ||
312 | sizeof(__u32))) | ||
313 | return -EFAULT; | ||
314 | } | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, | ||
320 | enum v4l2_memory memory) | ||
321 | { | ||
322 | if (copy_in_user(up32, up, 2 * sizeof(__u32)) || | ||
323 | copy_in_user(&up32->data_offset, &up->data_offset, | ||
324 | sizeof(__u32))) | ||
325 | return -EFAULT; | ||
326 | |||
327 | /* For MMAP, driver might've set up the offset, so copy it back. | ||
328 | * USERPTR stays the same (was userspace-provided), so no copying. */ | ||
329 | if (memory == V4L2_MEMORY_MMAP) | ||
330 | if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, | ||
331 | sizeof(__u32))) | ||
332 | return -EFAULT; | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
256 | static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) | 337 | static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) |
257 | { | 338 | { |
339 | struct v4l2_plane32 __user *uplane32; | ||
340 | struct v4l2_plane __user *uplane; | ||
341 | compat_caddr_t p; | ||
342 | int num_planes; | ||
343 | int ret; | ||
258 | 344 | ||
259 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || | 345 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || |
260 | get_user(kp->index, &up->index) || | 346 | get_user(kp->index, &up->index) || |
@@ -263,33 +349,84 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user | |||
263 | get_user(kp->memory, &up->memory) || | 349 | get_user(kp->memory, &up->memory) || |
264 | get_user(kp->input, &up->input)) | 350 | get_user(kp->input, &up->input)) |
265 | return -EFAULT; | 351 | return -EFAULT; |
266 | switch (kp->memory) { | 352 | |
267 | case V4L2_MEMORY_MMAP: | 353 | if (V4L2_TYPE_IS_OUTPUT(kp->type)) |
268 | if (get_user(kp->length, &up->length) || | 354 | if (get_user(kp->bytesused, &up->bytesused) || |
269 | get_user(kp->m.offset, &up->m.offset)) | 355 | get_user(kp->field, &up->field) || |
356 | get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || | ||
357 | get_user(kp->timestamp.tv_usec, | ||
358 | &up->timestamp.tv_usec)) | ||
270 | return -EFAULT; | 359 | return -EFAULT; |
271 | break; | ||
272 | case V4L2_MEMORY_USERPTR: | ||
273 | { | ||
274 | compat_long_t tmp; | ||
275 | 360 | ||
276 | if (get_user(kp->length, &up->length) || | 361 | if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { |
277 | get_user(tmp, &up->m.userptr)) | 362 | if (get_user(kp->length, &up->length)) |
278 | return -EFAULT; | 363 | return -EFAULT; |
279 | 364 | ||
280 | kp->m.userptr = (unsigned long)compat_ptr(tmp); | 365 | num_planes = kp->length; |
366 | if (num_planes == 0) { | ||
367 | kp->m.planes = NULL; | ||
368 | /* num_planes == 0 is legal, e.g. when userspace doesn't | ||
369 | * need planes array on DQBUF*/ | ||
370 | return 0; | ||
281 | } | 371 | } |
282 | break; | 372 | |
283 | case V4L2_MEMORY_OVERLAY: | 373 | if (get_user(p, &up->m.planes)) |
284 | if (get_user(kp->m.offset, &up->m.offset)) | ||
285 | return -EFAULT; | 374 | return -EFAULT; |
286 | break; | 375 | |
376 | uplane32 = compat_ptr(p); | ||
377 | if (!access_ok(VERIFY_READ, uplane32, | ||
378 | num_planes * sizeof(struct v4l2_plane32))) | ||
379 | return -EFAULT; | ||
380 | |||
381 | /* We don't really care if userspace decides to kill itself | ||
382 | * by passing a very big num_planes value */ | ||
383 | uplane = compat_alloc_user_space(num_planes * | ||
384 | sizeof(struct v4l2_plane)); | ||
385 | kp->m.planes = uplane; | ||
386 | |||
387 | while (--num_planes >= 0) { | ||
388 | ret = get_v4l2_plane32(uplane, uplane32, kp->memory); | ||
389 | if (ret) | ||
390 | return ret; | ||
391 | ++uplane; | ||
392 | ++uplane32; | ||
393 | } | ||
394 | } else { | ||
395 | switch (kp->memory) { | ||
396 | case V4L2_MEMORY_MMAP: | ||
397 | if (get_user(kp->length, &up->length) || | ||
398 | get_user(kp->m.offset, &up->m.offset)) | ||
399 | return -EFAULT; | ||
400 | break; | ||
401 | case V4L2_MEMORY_USERPTR: | ||
402 | { | ||
403 | compat_long_t tmp; | ||
404 | |||
405 | if (get_user(kp->length, &up->length) || | ||
406 | get_user(tmp, &up->m.userptr)) | ||
407 | return -EFAULT; | ||
408 | |||
409 | kp->m.userptr = (unsigned long)compat_ptr(tmp); | ||
410 | } | ||
411 | break; | ||
412 | case V4L2_MEMORY_OVERLAY: | ||
413 | if (get_user(kp->m.offset, &up->m.offset)) | ||
414 | return -EFAULT; | ||
415 | break; | ||
416 | } | ||
287 | } | 417 | } |
418 | |||
288 | return 0; | 419 | return 0; |
289 | } | 420 | } |
290 | 421 | ||
291 | static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) | 422 | static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) |
292 | { | 423 | { |
424 | struct v4l2_plane32 __user *uplane32; | ||
425 | struct v4l2_plane __user *uplane; | ||
426 | compat_caddr_t p; | ||
427 | int num_planes; | ||
428 | int ret; | ||
429 | |||
293 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || | 430 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || |
294 | put_user(kp->index, &up->index) || | 431 | put_user(kp->index, &up->index) || |
295 | put_user(kp->type, &up->type) || | 432 | put_user(kp->type, &up->type) || |
@@ -297,22 +434,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user | |||
297 | put_user(kp->memory, &up->memory) || | 434 | put_user(kp->memory, &up->memory) || |
298 | put_user(kp->input, &up->input)) | 435 | put_user(kp->input, &up->input)) |
299 | return -EFAULT; | 436 | return -EFAULT; |
300 | switch (kp->memory) { | 437 | |
301 | case V4L2_MEMORY_MMAP: | ||
302 | if (put_user(kp->length, &up->length) || | ||
303 | put_user(kp->m.offset, &up->m.offset)) | ||
304 | return -EFAULT; | ||
305 | break; | ||
306 | case V4L2_MEMORY_USERPTR: | ||
307 | if (put_user(kp->length, &up->length) || | ||
308 | put_user(kp->m.userptr, &up->m.userptr)) | ||
309 | return -EFAULT; | ||
310 | break; | ||
311 | case V4L2_MEMORY_OVERLAY: | ||
312 | if (put_user(kp->m.offset, &up->m.offset)) | ||
313 | return -EFAULT; | ||
314 | break; | ||
315 | } | ||
316 | if (put_user(kp->bytesused, &up->bytesused) || | 438 | if (put_user(kp->bytesused, &up->bytesused) || |
317 | put_user(kp->field, &up->field) || | 439 | put_user(kp->field, &up->field) || |
318 | put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || | 440 | put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || |
@@ -321,6 +443,43 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user | |||
321 | put_user(kp->sequence, &up->sequence) || | 443 | put_user(kp->sequence, &up->sequence) || |
322 | put_user(kp->reserved, &up->reserved)) | 444 | put_user(kp->reserved, &up->reserved)) |
323 | return -EFAULT; | 445 | return -EFAULT; |
446 | |||
447 | if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { | ||
448 | num_planes = kp->length; | ||
449 | if (num_planes == 0) | ||
450 | return 0; | ||
451 | |||
452 | uplane = kp->m.planes; | ||
453 | if (get_user(p, &up->m.planes)) | ||
454 | return -EFAULT; | ||
455 | uplane32 = compat_ptr(p); | ||
456 | |||
457 | while (--num_planes >= 0) { | ||
458 | ret = put_v4l2_plane32(uplane, uplane32, kp->memory); | ||
459 | if (ret) | ||
460 | return ret; | ||
461 | ++uplane; | ||
462 | ++uplane32; | ||
463 | } | ||
464 | } else { | ||
465 | switch (kp->memory) { | ||
466 | case V4L2_MEMORY_MMAP: | ||
467 | if (put_user(kp->length, &up->length) || | ||
468 | put_user(kp->m.offset, &up->m.offset)) | ||
469 | return -EFAULT; | ||
470 | break; | ||
471 | case V4L2_MEMORY_USERPTR: | ||
472 | if (put_user(kp->length, &up->length) || | ||
473 | put_user(kp->m.userptr, &up->m.userptr)) | ||
474 | return -EFAULT; | ||
475 | break; | ||
476 | case V4L2_MEMORY_OVERLAY: | ||
477 | if (put_user(kp->m.offset, &up->m.offset)) | ||
478 | return -EFAULT; | ||
479 | break; | ||
480 | } | ||
481 | } | ||
482 | |||
324 | return 0; | 483 | return 0; |
325 | } | 484 | } |
326 | 485 | ||
@@ -442,12 +601,13 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext | |||
442 | if (get_user(p, &up->controls)) | 601 | if (get_user(p, &up->controls)) |
443 | return -EFAULT; | 602 | return -EFAULT; |
444 | ucontrols = compat_ptr(p); | 603 | ucontrols = compat_ptr(p); |
445 | if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control))) | 604 | if (!access_ok(VERIFY_READ, ucontrols, |
605 | n * sizeof(struct v4l2_ext_control32))) | ||
446 | return -EFAULT; | 606 | return -EFAULT; |
447 | kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); | 607 | kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); |
448 | kp->controls = kcontrols; | 608 | kp->controls = kcontrols; |
449 | while (--n >= 0) { | 609 | while (--n >= 0) { |
450 | if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols))) | 610 | if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) |
451 | return -EFAULT; | 611 | return -EFAULT; |
452 | if (ctrl_is_pointer(kcontrols->id)) { | 612 | if (ctrl_is_pointer(kcontrols->id)) { |
453 | void __user *s; | 613 | void __user *s; |
@@ -483,7 +643,8 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext | |||
483 | if (get_user(p, &up->controls)) | 643 | if (get_user(p, &up->controls)) |
484 | return -EFAULT; | 644 | return -EFAULT; |
485 | ucontrols = compat_ptr(p); | 645 | ucontrols = compat_ptr(p); |
486 | if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control))) | 646 | if (!access_ok(VERIFY_WRITE, ucontrols, |
647 | n * sizeof(struct v4l2_ext_control32))) | ||
487 | return -EFAULT; | 648 | return -EFAULT; |
488 | 649 | ||
489 | while (--n >= 0) { | 650 | while (--n >= 0) { |