diff options
Diffstat (limited to 'drivers/media/video/v4l2-ioctl.c')
-rw-r--r-- | drivers/media/video/v4l2-ioctl.c | 669 |
1 files changed, 482 insertions, 187 deletions
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index f51327ef6757..a01ed39e6c16 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/types.h> | 17 | #include <linux/types.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | 19 | ||
20 | #define __OLD_VIDIOC_ /* To allow fixing old calls */ | ||
21 | #include <linux/videodev2.h> | 20 | #include <linux/videodev2.h> |
22 | 21 | ||
23 | #include <media/v4l2-common.h> | 22 | #include <media/v4l2-common.h> |
@@ -25,6 +24,7 @@ | |||
25 | #include <media/v4l2-ctrls.h> | 24 | #include <media/v4l2-ctrls.h> |
26 | #include <media/v4l2-fh.h> | 25 | #include <media/v4l2-fh.h> |
27 | #include <media/v4l2-event.h> | 26 | #include <media/v4l2-event.h> |
27 | #include <media/v4l2-device.h> | ||
28 | #include <media/v4l2-chip-ident.h> | 28 | #include <media/v4l2-chip-ident.h> |
29 | 29 | ||
30 | #define dbgarg(cmd, fmt, arg...) \ | 30 | #define dbgarg(cmd, fmt, arg...) \ |
@@ -165,6 +165,8 @@ const char *v4l2_type_names[] = { | |||
165 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", | 165 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", |
166 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", | 166 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", |
167 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay", | 167 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay", |
168 | [V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE] = "vid-cap-mplane", | ||
169 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane", | ||
168 | }; | 170 | }; |
169 | EXPORT_SYMBOL(v4l2_type_names); | 171 | EXPORT_SYMBOL(v4l2_type_names); |
170 | 172 | ||
@@ -293,153 +295,37 @@ void v4l_printk_ioctl(unsigned int cmd) | |||
293 | } | 295 | } |
294 | EXPORT_SYMBOL(v4l_printk_ioctl); | 296 | EXPORT_SYMBOL(v4l_printk_ioctl); |
295 | 297 | ||
296 | /* | ||
297 | * helper function -- handles userspace copying for ioctl arguments | ||
298 | */ | ||
299 | |||
300 | #ifdef __OLD_VIDIOC_ | ||
301 | static unsigned int | ||
302 | video_fix_command(unsigned int cmd) | ||
303 | { | ||
304 | switch (cmd) { | ||
305 | case VIDIOC_OVERLAY_OLD: | ||
306 | cmd = VIDIOC_OVERLAY; | ||
307 | break; | ||
308 | case VIDIOC_S_PARM_OLD: | ||
309 | cmd = VIDIOC_S_PARM; | ||
310 | break; | ||
311 | case VIDIOC_S_CTRL_OLD: | ||
312 | cmd = VIDIOC_S_CTRL; | ||
313 | break; | ||
314 | case VIDIOC_G_AUDIO_OLD: | ||
315 | cmd = VIDIOC_G_AUDIO; | ||
316 | break; | ||
317 | case VIDIOC_G_AUDOUT_OLD: | ||
318 | cmd = VIDIOC_G_AUDOUT; | ||
319 | break; | ||
320 | case VIDIOC_CROPCAP_OLD: | ||
321 | cmd = VIDIOC_CROPCAP; | ||
322 | break; | ||
323 | } | ||
324 | return cmd; | ||
325 | } | ||
326 | #endif | ||
327 | |||
328 | /* | ||
329 | * Obsolete usercopy function - Should be removed soon | ||
330 | */ | ||
331 | long | ||
332 | video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | ||
333 | v4l2_kioctl func) | ||
334 | { | ||
335 | char sbuf[128]; | ||
336 | void *mbuf = NULL; | ||
337 | void *parg = NULL; | ||
338 | long err = -EINVAL; | ||
339 | int is_ext_ctrl; | ||
340 | size_t ctrls_size = 0; | ||
341 | void __user *user_ptr = NULL; | ||
342 | |||
343 | #ifdef __OLD_VIDIOC_ | ||
344 | cmd = video_fix_command(cmd); | ||
345 | #endif | ||
346 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || | ||
347 | cmd == VIDIOC_TRY_EXT_CTRLS); | ||
348 | |||
349 | /* Copy arguments into temp kernel buffer */ | ||
350 | switch (_IOC_DIR(cmd)) { | ||
351 | case _IOC_NONE: | ||
352 | parg = NULL; | ||
353 | break; | ||
354 | case _IOC_READ: | ||
355 | case _IOC_WRITE: | ||
356 | case (_IOC_WRITE | _IOC_READ): | ||
357 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { | ||
358 | parg = sbuf; | ||
359 | } else { | ||
360 | /* too big to allocate from stack */ | ||
361 | mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); | ||
362 | if (NULL == mbuf) | ||
363 | return -ENOMEM; | ||
364 | parg = mbuf; | ||
365 | } | ||
366 | |||
367 | err = -EFAULT; | ||
368 | if (_IOC_DIR(cmd) & _IOC_WRITE) | ||
369 | if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) | ||
370 | goto out; | ||
371 | break; | ||
372 | } | ||
373 | if (is_ext_ctrl) { | ||
374 | struct v4l2_ext_controls *p = parg; | ||
375 | |||
376 | /* In case of an error, tell the caller that it wasn't | ||
377 | a specific control that caused it. */ | ||
378 | p->error_idx = p->count; | ||
379 | user_ptr = (void __user *)p->controls; | ||
380 | if (p->count) { | ||
381 | ctrls_size = sizeof(struct v4l2_ext_control) * p->count; | ||
382 | /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ | ||
383 | mbuf = kmalloc(ctrls_size, GFP_KERNEL); | ||
384 | err = -ENOMEM; | ||
385 | if (NULL == mbuf) | ||
386 | goto out_ext_ctrl; | ||
387 | err = -EFAULT; | ||
388 | if (copy_from_user(mbuf, user_ptr, ctrls_size)) | ||
389 | goto out_ext_ctrl; | ||
390 | p->controls = mbuf; | ||
391 | } | ||
392 | } | ||
393 | |||
394 | /* call driver */ | ||
395 | err = func(file, cmd, parg); | ||
396 | if (err == -ENOIOCTLCMD) | ||
397 | err = -EINVAL; | ||
398 | if (is_ext_ctrl) { | ||
399 | struct v4l2_ext_controls *p = parg; | ||
400 | |||
401 | p->controls = (void *)user_ptr; | ||
402 | if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) | ||
403 | err = -EFAULT; | ||
404 | goto out_ext_ctrl; | ||
405 | } | ||
406 | if (err < 0) | ||
407 | goto out; | ||
408 | |||
409 | out_ext_ctrl: | ||
410 | /* Copy results into user buffer */ | ||
411 | switch (_IOC_DIR(cmd)) { | ||
412 | case _IOC_READ: | ||
413 | case (_IOC_WRITE | _IOC_READ): | ||
414 | if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) | ||
415 | err = -EFAULT; | ||
416 | break; | ||
417 | } | ||
418 | |||
419 | out: | ||
420 | kfree(mbuf); | ||
421 | return err; | ||
422 | } | ||
423 | EXPORT_SYMBOL(video_usercopy); | ||
424 | |||
425 | static void dbgbuf(unsigned int cmd, struct video_device *vfd, | 298 | static void dbgbuf(unsigned int cmd, struct video_device *vfd, |
426 | struct v4l2_buffer *p) | 299 | struct v4l2_buffer *p) |
427 | { | 300 | { |
428 | struct v4l2_timecode *tc = &p->timecode; | 301 | struct v4l2_timecode *tc = &p->timecode; |
302 | struct v4l2_plane *plane; | ||
303 | int i; | ||
429 | 304 | ||
430 | dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " | 305 | dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " |
431 | "bytesused=%d, flags=0x%08d, " | 306 | "flags=0x%08d, field=%0d, sequence=%d, memory=%s\n", |
432 | "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n", | ||
433 | p->timestamp.tv_sec / 3600, | 307 | p->timestamp.tv_sec / 3600, |
434 | (int)(p->timestamp.tv_sec / 60) % 60, | 308 | (int)(p->timestamp.tv_sec / 60) % 60, |
435 | (int)(p->timestamp.tv_sec % 60), | 309 | (int)(p->timestamp.tv_sec % 60), |
436 | (long)p->timestamp.tv_usec, | 310 | (long)p->timestamp.tv_usec, |
437 | p->index, | 311 | p->index, |
438 | prt_names(p->type, v4l2_type_names), | 312 | prt_names(p->type, v4l2_type_names), |
439 | p->bytesused, p->flags, | 313 | p->flags, p->field, p->sequence, |
440 | p->field, p->sequence, | 314 | prt_names(p->memory, v4l2_memory_names)); |
441 | prt_names(p->memory, v4l2_memory_names), | 315 | |
442 | p->m.userptr, p->length); | 316 | if (V4L2_TYPE_IS_MULTIPLANAR(p->type) && p->m.planes) { |
317 | for (i = 0; i < p->length; ++i) { | ||
318 | plane = &p->m.planes[i]; | ||
319 | dbgarg2("plane %d: bytesused=%d, data_offset=0x%08x " | ||
320 | "offset/userptr=0x%08lx, length=%d\n", | ||
321 | i, plane->bytesused, plane->data_offset, | ||
322 | plane->m.userptr, plane->length); | ||
323 | } | ||
324 | } else { | ||
325 | dbgarg2("bytesused=%d, offset/userptr=0x%08lx, length=%d\n", | ||
326 | p->bytesused, p->m.userptr, p->length); | ||
327 | } | ||
328 | |||
443 | dbgarg2("timecode=%02d:%02d:%02d type=%d, " | 329 | dbgarg2("timecode=%02d:%02d:%02d type=%d, " |
444 | "flags=0x%08d, frames=%d, userbits=0x%08x\n", | 330 | "flags=0x%08d, frames=%d, userbits=0x%08x\n", |
445 | tc->hours, tc->minutes, tc->seconds, | 331 | tc->hours, tc->minutes, tc->seconds, |
@@ -467,6 +353,27 @@ static inline void v4l_print_pix_fmt(struct video_device *vfd, | |||
467 | fmt->bytesperline, fmt->sizeimage, fmt->colorspace); | 353 | fmt->bytesperline, fmt->sizeimage, fmt->colorspace); |
468 | }; | 354 | }; |
469 | 355 | ||
356 | static inline void v4l_print_pix_fmt_mplane(struct video_device *vfd, | ||
357 | struct v4l2_pix_format_mplane *fmt) | ||
358 | { | ||
359 | int i; | ||
360 | |||
361 | dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, " | ||
362 | "colorspace=%d, num_planes=%d\n", | ||
363 | fmt->width, fmt->height, | ||
364 | (fmt->pixelformat & 0xff), | ||
365 | (fmt->pixelformat >> 8) & 0xff, | ||
366 | (fmt->pixelformat >> 16) & 0xff, | ||
367 | (fmt->pixelformat >> 24) & 0xff, | ||
368 | prt_names(fmt->field, v4l2_field_names), | ||
369 | fmt->colorspace, fmt->num_planes); | ||
370 | |||
371 | for (i = 0; i < fmt->num_planes; ++i) | ||
372 | dbgarg2("plane %d: bytesperline=%d sizeimage=%d\n", i, | ||
373 | fmt->plane_fmt[i].bytesperline, | ||
374 | fmt->plane_fmt[i].sizeimage); | ||
375 | } | ||
376 | |||
470 | static inline void v4l_print_ext_ctrls(unsigned int cmd, | 377 | static inline void v4l_print_ext_ctrls(unsigned int cmd, |
471 | struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) | 378 | struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) |
472 | { | 379 | { |
@@ -520,7 +427,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) | |||
520 | 427 | ||
521 | switch (type) { | 428 | switch (type) { |
522 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 429 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
523 | if (ops->vidioc_g_fmt_vid_cap) | 430 | if (ops->vidioc_g_fmt_vid_cap || |
431 | ops->vidioc_g_fmt_vid_cap_mplane) | ||
432 | return 0; | ||
433 | break; | ||
434 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
435 | if (ops->vidioc_g_fmt_vid_cap_mplane) | ||
524 | return 0; | 436 | return 0; |
525 | break; | 437 | break; |
526 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 438 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
@@ -528,7 +440,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) | |||
528 | return 0; | 440 | return 0; |
529 | break; | 441 | break; |
530 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 442 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
531 | if (ops->vidioc_g_fmt_vid_out) | 443 | if (ops->vidioc_g_fmt_vid_out || |
444 | ops->vidioc_g_fmt_vid_out_mplane) | ||
445 | return 0; | ||
446 | break; | ||
447 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
448 | if (ops->vidioc_g_fmt_vid_out_mplane) | ||
532 | return 0; | 449 | return 0; |
533 | break; | 450 | break; |
534 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 451 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
@@ -559,12 +476,72 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) | |||
559 | return -EINVAL; | 476 | return -EINVAL; |
560 | } | 477 | } |
561 | 478 | ||
479 | /** | ||
480 | * fmt_sp_to_mp() - Convert a single-plane format to its multi-planar 1-plane | ||
481 | * equivalent | ||
482 | */ | ||
483 | static int fmt_sp_to_mp(const struct v4l2_format *f_sp, | ||
484 | struct v4l2_format *f_mp) | ||
485 | { | ||
486 | struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; | ||
487 | const struct v4l2_pix_format *pix = &f_sp->fmt.pix; | ||
488 | |||
489 | if (f_sp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
490 | f_mp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | ||
491 | else if (f_sp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
492 | f_mp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | ||
493 | else | ||
494 | return -EINVAL; | ||
495 | |||
496 | pix_mp->width = pix->width; | ||
497 | pix_mp->height = pix->height; | ||
498 | pix_mp->pixelformat = pix->pixelformat; | ||
499 | pix_mp->field = pix->field; | ||
500 | pix_mp->colorspace = pix->colorspace; | ||
501 | pix_mp->num_planes = 1; | ||
502 | pix_mp->plane_fmt[0].sizeimage = pix->sizeimage; | ||
503 | pix_mp->plane_fmt[0].bytesperline = pix->bytesperline; | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * fmt_mp_to_sp() - Convert a multi-planar 1-plane format to its single-planar | ||
510 | * equivalent | ||
511 | */ | ||
512 | static int fmt_mp_to_sp(const struct v4l2_format *f_mp, | ||
513 | struct v4l2_format *f_sp) | ||
514 | { | ||
515 | const struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; | ||
516 | struct v4l2_pix_format *pix = &f_sp->fmt.pix; | ||
517 | |||
518 | if (f_mp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | ||
519 | f_sp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
520 | else if (f_mp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
521 | f_sp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
522 | else | ||
523 | return -EINVAL; | ||
524 | |||
525 | pix->width = pix_mp->width; | ||
526 | pix->height = pix_mp->height; | ||
527 | pix->pixelformat = pix_mp->pixelformat; | ||
528 | pix->field = pix_mp->field; | ||
529 | pix->colorspace = pix_mp->colorspace; | ||
530 | pix->sizeimage = pix_mp->plane_fmt[0].sizeimage; | ||
531 | pix->bytesperline = pix_mp->plane_fmt[0].bytesperline; | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
562 | static long __video_do_ioctl(struct file *file, | 536 | static long __video_do_ioctl(struct file *file, |
563 | unsigned int cmd, void *arg) | 537 | unsigned int cmd, void *arg) |
564 | { | 538 | { |
565 | struct video_device *vfd = video_devdata(file); | 539 | struct video_device *vfd = video_devdata(file); |
566 | const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; | 540 | const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; |
567 | void *fh = file->private_data; | 541 | void *fh = file->private_data; |
542 | struct v4l2_fh *vfh = NULL; | ||
543 | struct v4l2_format f_copy; | ||
544 | int use_fh_prio = 0; | ||
568 | long ret = -EINVAL; | 545 | long ret = -EINVAL; |
569 | 546 | ||
570 | if (ops == NULL) { | 547 | if (ops == NULL) { |
@@ -579,6 +556,45 @@ static long __video_do_ioctl(struct file *file, | |||
579 | printk(KERN_CONT "\n"); | 556 | printk(KERN_CONT "\n"); |
580 | } | 557 | } |
581 | 558 | ||
559 | if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { | ||
560 | vfh = file->private_data; | ||
561 | use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); | ||
562 | } | ||
563 | |||
564 | if (use_fh_prio) { | ||
565 | switch (cmd) { | ||
566 | case VIDIOC_S_CTRL: | ||
567 | case VIDIOC_S_STD: | ||
568 | case VIDIOC_S_INPUT: | ||
569 | case VIDIOC_S_OUTPUT: | ||
570 | case VIDIOC_S_TUNER: | ||
571 | case VIDIOC_S_FREQUENCY: | ||
572 | case VIDIOC_S_FMT: | ||
573 | case VIDIOC_S_CROP: | ||
574 | case VIDIOC_S_AUDIO: | ||
575 | case VIDIOC_S_AUDOUT: | ||
576 | case VIDIOC_S_EXT_CTRLS: | ||
577 | case VIDIOC_S_FBUF: | ||
578 | case VIDIOC_S_PRIORITY: | ||
579 | case VIDIOC_S_DV_PRESET: | ||
580 | case VIDIOC_S_DV_TIMINGS: | ||
581 | case VIDIOC_S_JPEGCOMP: | ||
582 | case VIDIOC_S_MODULATOR: | ||
583 | case VIDIOC_S_PARM: | ||
584 | case VIDIOC_S_HW_FREQ_SEEK: | ||
585 | case VIDIOC_ENCODER_CMD: | ||
586 | case VIDIOC_OVERLAY: | ||
587 | case VIDIOC_REQBUFS: | ||
588 | case VIDIOC_STREAMON: | ||
589 | case VIDIOC_STREAMOFF: | ||
590 | ret = v4l2_prio_check(vfd->prio, vfh->prio); | ||
591 | if (ret) | ||
592 | goto exit_prio; | ||
593 | ret = -EINVAL; | ||
594 | break; | ||
595 | } | ||
596 | } | ||
597 | |||
582 | switch (cmd) { | 598 | switch (cmd) { |
583 | 599 | ||
584 | /* --- capabilities ------------------------------------------ */ | 600 | /* --- capabilities ------------------------------------------ */ |
@@ -605,9 +621,12 @@ static long __video_do_ioctl(struct file *file, | |||
605 | { | 621 | { |
606 | enum v4l2_priority *p = arg; | 622 | enum v4l2_priority *p = arg; |
607 | 623 | ||
608 | if (!ops->vidioc_g_priority) | 624 | if (ops->vidioc_g_priority) { |
609 | break; | 625 | ret = ops->vidioc_g_priority(file, fh, p); |
610 | ret = ops->vidioc_g_priority(file, fh, p); | 626 | } else if (use_fh_prio) { |
627 | *p = v4l2_prio_max(&vfd->v4l2_dev->prio); | ||
628 | ret = 0; | ||
629 | } | ||
611 | if (!ret) | 630 | if (!ret) |
612 | dbgarg(cmd, "priority is %d\n", *p); | 631 | dbgarg(cmd, "priority is %d\n", *p); |
613 | break; | 632 | break; |
@@ -616,10 +635,13 @@ static long __video_do_ioctl(struct file *file, | |||
616 | { | 635 | { |
617 | enum v4l2_priority *p = arg; | 636 | enum v4l2_priority *p = arg; |
618 | 637 | ||
619 | if (!ops->vidioc_s_priority) | 638 | if (!ops->vidioc_s_priority && !use_fh_prio) |
620 | break; | 639 | break; |
621 | dbgarg(cmd, "setting priority to %d\n", *p); | 640 | dbgarg(cmd, "setting priority to %d\n", *p); |
622 | ret = ops->vidioc_s_priority(file, fh, *p); | 641 | if (ops->vidioc_s_priority) |
642 | ret = ops->vidioc_s_priority(file, fh, *p); | ||
643 | else | ||
644 | ret = v4l2_prio_change(&vfd->v4l2_dev->prio, &vfh->prio, *p); | ||
623 | break; | 645 | break; |
624 | } | 646 | } |
625 | 647 | ||
@@ -633,6 +655,11 @@ static long __video_do_ioctl(struct file *file, | |||
633 | if (ops->vidioc_enum_fmt_vid_cap) | 655 | if (ops->vidioc_enum_fmt_vid_cap) |
634 | ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); | 656 | ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); |
635 | break; | 657 | break; |
658 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
659 | if (ops->vidioc_enum_fmt_vid_cap_mplane) | ||
660 | ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, | ||
661 | fh, f); | ||
662 | break; | ||
636 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 663 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
637 | if (ops->vidioc_enum_fmt_vid_overlay) | 664 | if (ops->vidioc_enum_fmt_vid_overlay) |
638 | ret = ops->vidioc_enum_fmt_vid_overlay(file, | 665 | ret = ops->vidioc_enum_fmt_vid_overlay(file, |
@@ -642,6 +669,11 @@ static long __video_do_ioctl(struct file *file, | |||
642 | if (ops->vidioc_enum_fmt_vid_out) | 669 | if (ops->vidioc_enum_fmt_vid_out) |
643 | ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); | 670 | ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); |
644 | break; | 671 | break; |
672 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
673 | if (ops->vidioc_enum_fmt_vid_out_mplane) | ||
674 | ret = ops->vidioc_enum_fmt_vid_out_mplane(file, | ||
675 | fh, f); | ||
676 | break; | ||
645 | case V4L2_BUF_TYPE_PRIVATE: | 677 | case V4L2_BUF_TYPE_PRIVATE: |
646 | if (ops->vidioc_enum_fmt_type_private) | 678 | if (ops->vidioc_enum_fmt_type_private) |
647 | ret = ops->vidioc_enum_fmt_type_private(file, | 679 | ret = ops->vidioc_enum_fmt_type_private(file, |
@@ -670,22 +702,90 @@ static long __video_do_ioctl(struct file *file, | |||
670 | 702 | ||
671 | switch (f->type) { | 703 | switch (f->type) { |
672 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 704 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
673 | if (ops->vidioc_g_fmt_vid_cap) | 705 | if (ops->vidioc_g_fmt_vid_cap) { |
674 | ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); | 706 | ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); |
707 | } else if (ops->vidioc_g_fmt_vid_cap_mplane) { | ||
708 | if (fmt_sp_to_mp(f, &f_copy)) | ||
709 | break; | ||
710 | ret = ops->vidioc_g_fmt_vid_cap_mplane(file, fh, | ||
711 | &f_copy); | ||
712 | if (ret) | ||
713 | break; | ||
714 | |||
715 | /* Driver is currently in multi-planar format, | ||
716 | * we can't return it in single-planar API*/ | ||
717 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
718 | ret = -EBUSY; | ||
719 | break; | ||
720 | } | ||
721 | |||
722 | ret = fmt_mp_to_sp(&f_copy, f); | ||
723 | } | ||
675 | if (!ret) | 724 | if (!ret) |
676 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 725 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
677 | break; | 726 | break; |
727 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
728 | if (ops->vidioc_g_fmt_vid_cap_mplane) { | ||
729 | ret = ops->vidioc_g_fmt_vid_cap_mplane(file, | ||
730 | fh, f); | ||
731 | } else if (ops->vidioc_g_fmt_vid_cap) { | ||
732 | if (fmt_mp_to_sp(f, &f_copy)) | ||
733 | break; | ||
734 | ret = ops->vidioc_g_fmt_vid_cap(file, | ||
735 | fh, &f_copy); | ||
736 | if (ret) | ||
737 | break; | ||
738 | |||
739 | ret = fmt_sp_to_mp(&f_copy, f); | ||
740 | } | ||
741 | if (!ret) | ||
742 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
743 | break; | ||
678 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 744 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
679 | if (ops->vidioc_g_fmt_vid_overlay) | 745 | if (ops->vidioc_g_fmt_vid_overlay) |
680 | ret = ops->vidioc_g_fmt_vid_overlay(file, | 746 | ret = ops->vidioc_g_fmt_vid_overlay(file, |
681 | fh, f); | 747 | fh, f); |
682 | break; | 748 | break; |
683 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 749 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
684 | if (ops->vidioc_g_fmt_vid_out) | 750 | if (ops->vidioc_g_fmt_vid_out) { |
685 | ret = ops->vidioc_g_fmt_vid_out(file, fh, f); | 751 | ret = ops->vidioc_g_fmt_vid_out(file, fh, f); |
752 | } else if (ops->vidioc_g_fmt_vid_out_mplane) { | ||
753 | if (fmt_sp_to_mp(f, &f_copy)) | ||
754 | break; | ||
755 | ret = ops->vidioc_g_fmt_vid_out_mplane(file, fh, | ||
756 | &f_copy); | ||
757 | if (ret) | ||
758 | break; | ||
759 | |||
760 | /* Driver is currently in multi-planar format, | ||
761 | * we can't return it in single-planar API*/ | ||
762 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
763 | ret = -EBUSY; | ||
764 | break; | ||
765 | } | ||
766 | |||
767 | ret = fmt_mp_to_sp(&f_copy, f); | ||
768 | } | ||
686 | if (!ret) | 769 | if (!ret) |
687 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 770 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
688 | break; | 771 | break; |
772 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
773 | if (ops->vidioc_g_fmt_vid_out_mplane) { | ||
774 | ret = ops->vidioc_g_fmt_vid_out_mplane(file, | ||
775 | fh, f); | ||
776 | } else if (ops->vidioc_g_fmt_vid_out) { | ||
777 | if (fmt_mp_to_sp(f, &f_copy)) | ||
778 | break; | ||
779 | ret = ops->vidioc_g_fmt_vid_out(file, | ||
780 | fh, &f_copy); | ||
781 | if (ret) | ||
782 | break; | ||
783 | |||
784 | ret = fmt_sp_to_mp(&f_copy, f); | ||
785 | } | ||
786 | if (!ret) | ||
787 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
788 | break; | ||
689 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 789 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
690 | if (ops->vidioc_g_fmt_vid_out_overlay) | 790 | if (ops->vidioc_g_fmt_vid_out_overlay) |
691 | ret = ops->vidioc_g_fmt_vid_out_overlay(file, | 791 | ret = ops->vidioc_g_fmt_vid_out_overlay(file, |
@@ -729,8 +829,44 @@ static long __video_do_ioctl(struct file *file, | |||
729 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 829 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
730 | CLEAR_AFTER_FIELD(f, fmt.pix); | 830 | CLEAR_AFTER_FIELD(f, fmt.pix); |
731 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 831 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
732 | if (ops->vidioc_s_fmt_vid_cap) | 832 | if (ops->vidioc_s_fmt_vid_cap) { |
733 | ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); | 833 | ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); |
834 | } else if (ops->vidioc_s_fmt_vid_cap_mplane) { | ||
835 | if (fmt_sp_to_mp(f, &f_copy)) | ||
836 | break; | ||
837 | ret = ops->vidioc_s_fmt_vid_cap_mplane(file, fh, | ||
838 | &f_copy); | ||
839 | if (ret) | ||
840 | break; | ||
841 | |||
842 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
843 | /* Drivers shouldn't adjust from 1-plane | ||
844 | * to more than 1-plane formats */ | ||
845 | ret = -EBUSY; | ||
846 | WARN_ON(1); | ||
847 | break; | ||
848 | } | ||
849 | |||
850 | ret = fmt_mp_to_sp(&f_copy, f); | ||
851 | } | ||
852 | break; | ||
853 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
854 | CLEAR_AFTER_FIELD(f, fmt.pix_mp); | ||
855 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
856 | if (ops->vidioc_s_fmt_vid_cap_mplane) { | ||
857 | ret = ops->vidioc_s_fmt_vid_cap_mplane(file, | ||
858 | fh, f); | ||
859 | } else if (ops->vidioc_s_fmt_vid_cap && | ||
860 | f->fmt.pix_mp.num_planes == 1) { | ||
861 | if (fmt_mp_to_sp(f, &f_copy)) | ||
862 | break; | ||
863 | ret = ops->vidioc_s_fmt_vid_cap(file, | ||
864 | fh, &f_copy); | ||
865 | if (ret) | ||
866 | break; | ||
867 | |||
868 | ret = fmt_sp_to_mp(&f_copy, f); | ||
869 | } | ||
734 | break; | 870 | break; |
735 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 871 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
736 | CLEAR_AFTER_FIELD(f, fmt.win); | 872 | CLEAR_AFTER_FIELD(f, fmt.win); |
@@ -741,8 +877,44 @@ static long __video_do_ioctl(struct file *file, | |||
741 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 877 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
742 | CLEAR_AFTER_FIELD(f, fmt.pix); | 878 | CLEAR_AFTER_FIELD(f, fmt.pix); |
743 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 879 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
744 | if (ops->vidioc_s_fmt_vid_out) | 880 | if (ops->vidioc_s_fmt_vid_out) { |
745 | ret = ops->vidioc_s_fmt_vid_out(file, fh, f); | 881 | ret = ops->vidioc_s_fmt_vid_out(file, fh, f); |
882 | } else if (ops->vidioc_s_fmt_vid_out_mplane) { | ||
883 | if (fmt_sp_to_mp(f, &f_copy)) | ||
884 | break; | ||
885 | ret = ops->vidioc_s_fmt_vid_out_mplane(file, fh, | ||
886 | &f_copy); | ||
887 | if (ret) | ||
888 | break; | ||
889 | |||
890 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
891 | /* Drivers shouldn't adjust from 1-plane | ||
892 | * to more than 1-plane formats */ | ||
893 | ret = -EBUSY; | ||
894 | WARN_ON(1); | ||
895 | break; | ||
896 | } | ||
897 | |||
898 | ret = fmt_mp_to_sp(&f_copy, f); | ||
899 | } | ||
900 | break; | ||
901 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
902 | CLEAR_AFTER_FIELD(f, fmt.pix_mp); | ||
903 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
904 | if (ops->vidioc_s_fmt_vid_out_mplane) { | ||
905 | ret = ops->vidioc_s_fmt_vid_out_mplane(file, | ||
906 | fh, f); | ||
907 | } else if (ops->vidioc_s_fmt_vid_out && | ||
908 | f->fmt.pix_mp.num_planes == 1) { | ||
909 | if (fmt_mp_to_sp(f, &f_copy)) | ||
910 | break; | ||
911 | ret = ops->vidioc_s_fmt_vid_out(file, | ||
912 | fh, &f_copy); | ||
913 | if (ret) | ||
914 | break; | ||
915 | |||
916 | ret = fmt_mp_to_sp(&f_copy, f); | ||
917 | } | ||
746 | break; | 918 | break; |
747 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 919 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
748 | CLEAR_AFTER_FIELD(f, fmt.win); | 920 | CLEAR_AFTER_FIELD(f, fmt.win); |
@@ -791,11 +963,47 @@ static long __video_do_ioctl(struct file *file, | |||
791 | switch (f->type) { | 963 | switch (f->type) { |
792 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 964 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
793 | CLEAR_AFTER_FIELD(f, fmt.pix); | 965 | CLEAR_AFTER_FIELD(f, fmt.pix); |
794 | if (ops->vidioc_try_fmt_vid_cap) | 966 | if (ops->vidioc_try_fmt_vid_cap) { |
795 | ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); | 967 | ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); |
968 | } else if (ops->vidioc_try_fmt_vid_cap_mplane) { | ||
969 | if (fmt_sp_to_mp(f, &f_copy)) | ||
970 | break; | ||
971 | ret = ops->vidioc_try_fmt_vid_cap_mplane(file, | ||
972 | fh, &f_copy); | ||
973 | if (ret) | ||
974 | break; | ||
975 | |||
976 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
977 | /* Drivers shouldn't adjust from 1-plane | ||
978 | * to more than 1-plane formats */ | ||
979 | ret = -EBUSY; | ||
980 | WARN_ON(1); | ||
981 | break; | ||
982 | } | ||
983 | ret = fmt_mp_to_sp(&f_copy, f); | ||
984 | } | ||
796 | if (!ret) | 985 | if (!ret) |
797 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 986 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
798 | break; | 987 | break; |
988 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
989 | CLEAR_AFTER_FIELD(f, fmt.pix_mp); | ||
990 | if (ops->vidioc_try_fmt_vid_cap_mplane) { | ||
991 | ret = ops->vidioc_try_fmt_vid_cap_mplane(file, | ||
992 | fh, f); | ||
993 | } else if (ops->vidioc_try_fmt_vid_cap && | ||
994 | f->fmt.pix_mp.num_planes == 1) { | ||
995 | if (fmt_mp_to_sp(f, &f_copy)) | ||
996 | break; | ||
997 | ret = ops->vidioc_try_fmt_vid_cap(file, | ||
998 | fh, &f_copy); | ||
999 | if (ret) | ||
1000 | break; | ||
1001 | |||
1002 | ret = fmt_sp_to_mp(&f_copy, f); | ||
1003 | } | ||
1004 | if (!ret) | ||
1005 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
1006 | break; | ||
799 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 1007 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
800 | CLEAR_AFTER_FIELD(f, fmt.win); | 1008 | CLEAR_AFTER_FIELD(f, fmt.win); |
801 | if (ops->vidioc_try_fmt_vid_overlay) | 1009 | if (ops->vidioc_try_fmt_vid_overlay) |
@@ -804,11 +1012,47 @@ static long __video_do_ioctl(struct file *file, | |||
804 | break; | 1012 | break; |
805 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 1013 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
806 | CLEAR_AFTER_FIELD(f, fmt.pix); | 1014 | CLEAR_AFTER_FIELD(f, fmt.pix); |
807 | if (ops->vidioc_try_fmt_vid_out) | 1015 | if (ops->vidioc_try_fmt_vid_out) { |
808 | ret = ops->vidioc_try_fmt_vid_out(file, fh, f); | 1016 | ret = ops->vidioc_try_fmt_vid_out(file, fh, f); |
1017 | } else if (ops->vidioc_try_fmt_vid_out_mplane) { | ||
1018 | if (fmt_sp_to_mp(f, &f_copy)) | ||
1019 | break; | ||
1020 | ret = ops->vidioc_try_fmt_vid_out_mplane(file, | ||
1021 | fh, &f_copy); | ||
1022 | if (ret) | ||
1023 | break; | ||
1024 | |||
1025 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
1026 | /* Drivers shouldn't adjust from 1-plane | ||
1027 | * to more than 1-plane formats */ | ||
1028 | ret = -EBUSY; | ||
1029 | WARN_ON(1); | ||
1030 | break; | ||
1031 | } | ||
1032 | ret = fmt_mp_to_sp(&f_copy, f); | ||
1033 | } | ||
809 | if (!ret) | 1034 | if (!ret) |
810 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 1035 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
811 | break; | 1036 | break; |
1037 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
1038 | CLEAR_AFTER_FIELD(f, fmt.pix_mp); | ||
1039 | if (ops->vidioc_try_fmt_vid_out_mplane) { | ||
1040 | ret = ops->vidioc_try_fmt_vid_out_mplane(file, | ||
1041 | fh, f); | ||
1042 | } else if (ops->vidioc_try_fmt_vid_out && | ||
1043 | f->fmt.pix_mp.num_planes == 1) { | ||
1044 | if (fmt_mp_to_sp(f, &f_copy)) | ||
1045 | break; | ||
1046 | ret = ops->vidioc_try_fmt_vid_out(file, | ||
1047 | fh, &f_copy); | ||
1048 | if (ret) | ||
1049 | break; | ||
1050 | |||
1051 | ret = fmt_sp_to_mp(&f_copy, f); | ||
1052 | } | ||
1053 | if (!ret) | ||
1054 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
1055 | break; | ||
812 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 1056 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
813 | CLEAR_AFTER_FIELD(f, fmt.win); | 1057 | CLEAR_AFTER_FIELD(f, fmt.win); |
814 | if (ops->vidioc_try_fmt_vid_out_overlay) | 1058 | if (ops->vidioc_try_fmt_vid_out_overlay) |
@@ -1942,13 +2186,18 @@ static long __video_do_ioctl(struct file *file, | |||
1942 | } | 2186 | } |
1943 | default: | 2187 | default: |
1944 | { | 2188 | { |
2189 | bool valid_prio = true; | ||
2190 | |||
1945 | if (!ops->vidioc_default) | 2191 | if (!ops->vidioc_default) |
1946 | break; | 2192 | break; |
1947 | ret = ops->vidioc_default(file, fh, cmd, arg); | 2193 | if (use_fh_prio) |
2194 | valid_prio = v4l2_prio_check(vfd->prio, vfh->prio) >= 0; | ||
2195 | ret = ops->vidioc_default(file, fh, valid_prio, cmd, arg); | ||
1948 | break; | 2196 | break; |
1949 | } | 2197 | } |
1950 | } /* switch */ | 2198 | } /* switch */ |
1951 | 2199 | ||
2200 | exit_prio: | ||
1952 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { | 2201 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { |
1953 | if (ret < 0) { | 2202 | if (ret < 0) { |
1954 | v4l_print_ioctl(vfd->name, cmd); | 2203 | v4l_print_ioctl(vfd->name, cmd); |
@@ -1973,7 +2222,7 @@ static unsigned long cmd_input_size(unsigned int cmd) | |||
1973 | switch (cmd) { | 2222 | switch (cmd) { |
1974 | CMDINSIZE(ENUM_FMT, fmtdesc, type); | 2223 | CMDINSIZE(ENUM_FMT, fmtdesc, type); |
1975 | CMDINSIZE(G_FMT, format, type); | 2224 | CMDINSIZE(G_FMT, format, type); |
1976 | CMDINSIZE(QUERYBUF, buffer, type); | 2225 | CMDINSIZE(QUERYBUF, buffer, length); |
1977 | CMDINSIZE(G_PARM, streamparm, type); | 2226 | CMDINSIZE(G_PARM, streamparm, type); |
1978 | CMDINSIZE(ENUMSTD, standard, index); | 2227 | CMDINSIZE(ENUMSTD, standard, index); |
1979 | CMDINSIZE(ENUMINPUT, input, index); | 2228 | CMDINSIZE(ENUMINPUT, input, index); |
@@ -1998,22 +2247,61 @@ static unsigned long cmd_input_size(unsigned int cmd) | |||
1998 | } | 2247 | } |
1999 | } | 2248 | } |
2000 | 2249 | ||
2001 | long video_ioctl2(struct file *file, | 2250 | static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, |
2002 | unsigned int cmd, unsigned long arg) | 2251 | void * __user *user_ptr, void ***kernel_ptr) |
2252 | { | ||
2253 | int ret = 0; | ||
2254 | |||
2255 | switch (cmd) { | ||
2256 | case VIDIOC_QUERYBUF: | ||
2257 | case VIDIOC_QBUF: | ||
2258 | case VIDIOC_DQBUF: { | ||
2259 | struct v4l2_buffer *buf = parg; | ||
2260 | |||
2261 | if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->length > 0) { | ||
2262 | if (buf->length > VIDEO_MAX_PLANES) { | ||
2263 | ret = -EINVAL; | ||
2264 | break; | ||
2265 | } | ||
2266 | *user_ptr = (void __user *)buf->m.planes; | ||
2267 | *kernel_ptr = (void **)&buf->m.planes; | ||
2268 | *array_size = sizeof(struct v4l2_plane) * buf->length; | ||
2269 | ret = 1; | ||
2270 | } | ||
2271 | break; | ||
2272 | } | ||
2273 | |||
2274 | case VIDIOC_S_EXT_CTRLS: | ||
2275 | case VIDIOC_G_EXT_CTRLS: | ||
2276 | case VIDIOC_TRY_EXT_CTRLS: { | ||
2277 | struct v4l2_ext_controls *ctrls = parg; | ||
2278 | |||
2279 | if (ctrls->count != 0) { | ||
2280 | *user_ptr = (void __user *)ctrls->controls; | ||
2281 | *kernel_ptr = (void **)&ctrls->controls; | ||
2282 | *array_size = sizeof(struct v4l2_ext_control) | ||
2283 | * ctrls->count; | ||
2284 | ret = 1; | ||
2285 | } | ||
2286 | break; | ||
2287 | } | ||
2288 | } | ||
2289 | |||
2290 | return ret; | ||
2291 | } | ||
2292 | |||
2293 | long | ||
2294 | video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | ||
2295 | v4l2_kioctl func) | ||
2003 | { | 2296 | { |
2004 | char sbuf[128]; | 2297 | char sbuf[128]; |
2005 | void *mbuf = NULL; | 2298 | void *mbuf = NULL; |
2006 | void *parg = (void *)arg; | 2299 | void *parg = (void *)arg; |
2007 | long err = -EINVAL; | 2300 | long err = -EINVAL; |
2008 | int is_ext_ctrl; | 2301 | bool has_array_args; |
2009 | size_t ctrls_size = 0; | 2302 | size_t array_size = 0; |
2010 | void __user *user_ptr = NULL; | 2303 | void __user *user_ptr = NULL; |
2011 | 2304 | void **kernel_ptr = NULL; | |
2012 | #ifdef __OLD_VIDIOC_ | ||
2013 | cmd = video_fix_command(cmd); | ||
2014 | #endif | ||
2015 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || | ||
2016 | cmd == VIDIOC_TRY_EXT_CTRLS); | ||
2017 | 2305 | ||
2018 | /* Copy arguments into temp kernel buffer */ | 2306 | /* Copy arguments into temp kernel buffer */ |
2019 | if (_IOC_DIR(cmd) != _IOC_NONE) { | 2307 | if (_IOC_DIR(cmd) != _IOC_NONE) { |
@@ -2043,43 +2331,43 @@ long video_ioctl2(struct file *file, | |||
2043 | } | 2331 | } |
2044 | } | 2332 | } |
2045 | 2333 | ||
2046 | if (is_ext_ctrl) { | 2334 | err = check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr); |
2047 | struct v4l2_ext_controls *p = parg; | 2335 | if (err < 0) |
2336 | goto out; | ||
2337 | has_array_args = err; | ||
2048 | 2338 | ||
2049 | /* In case of an error, tell the caller that it wasn't | 2339 | if (has_array_args) { |
2050 | a specific control that caused it. */ | 2340 | /* |
2051 | p->error_idx = p->count; | 2341 | * When adding new types of array args, make sure that the |
2052 | user_ptr = (void __user *)p->controls; | 2342 | * parent argument to ioctl (which contains the pointer to the |
2053 | if (p->count) { | 2343 | * array) fits into sbuf (so that mbuf will still remain |
2054 | ctrls_size = sizeof(struct v4l2_ext_control) * p->count; | 2344 | * unused up to here). |
2055 | /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ | 2345 | */ |
2056 | mbuf = kmalloc(ctrls_size, GFP_KERNEL); | 2346 | mbuf = kmalloc(array_size, GFP_KERNEL); |
2057 | err = -ENOMEM; | 2347 | err = -ENOMEM; |
2058 | if (NULL == mbuf) | 2348 | if (NULL == mbuf) |
2059 | goto out_ext_ctrl; | 2349 | goto out_array_args; |
2060 | err = -EFAULT; | 2350 | err = -EFAULT; |
2061 | if (copy_from_user(mbuf, user_ptr, ctrls_size)) | 2351 | if (copy_from_user(mbuf, user_ptr, array_size)) |
2062 | goto out_ext_ctrl; | 2352 | goto out_array_args; |
2063 | p->controls = mbuf; | 2353 | *kernel_ptr = mbuf; |
2064 | } | ||
2065 | } | 2354 | } |
2066 | 2355 | ||
2067 | /* Handles IOCTL */ | 2356 | /* Handles IOCTL */ |
2068 | err = __video_do_ioctl(file, cmd, parg); | 2357 | err = func(file, cmd, parg); |
2069 | if (err == -ENOIOCTLCMD) | 2358 | if (err == -ENOIOCTLCMD) |
2070 | err = -EINVAL; | 2359 | err = -EINVAL; |
2071 | if (is_ext_ctrl) { | ||
2072 | struct v4l2_ext_controls *p = parg; | ||
2073 | 2360 | ||
2074 | p->controls = (void *)user_ptr; | 2361 | if (has_array_args) { |
2075 | if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) | 2362 | *kernel_ptr = user_ptr; |
2363 | if (copy_to_user(user_ptr, mbuf, array_size)) | ||
2076 | err = -EFAULT; | 2364 | err = -EFAULT; |
2077 | goto out_ext_ctrl; | 2365 | goto out_array_args; |
2078 | } | 2366 | } |
2079 | if (err < 0) | 2367 | if (err < 0) |
2080 | goto out; | 2368 | goto out; |
2081 | 2369 | ||
2082 | out_ext_ctrl: | 2370 | out_array_args: |
2083 | /* Copy results into user buffer */ | 2371 | /* Copy results into user buffer */ |
2084 | switch (_IOC_DIR(cmd)) { | 2372 | switch (_IOC_DIR(cmd)) { |
2085 | case _IOC_READ: | 2373 | case _IOC_READ: |
@@ -2093,4 +2381,11 @@ out: | |||
2093 | kfree(mbuf); | 2381 | kfree(mbuf); |
2094 | return err; | 2382 | return err; |
2095 | } | 2383 | } |
2384 | EXPORT_SYMBOL(video_usercopy); | ||
2385 | |||
2386 | long video_ioctl2(struct file *file, | ||
2387 | unsigned int cmd, unsigned long arg) | ||
2388 | { | ||
2389 | return video_usercopy(file, cmd, arg, __video_do_ioctl); | ||
2390 | } | ||
2096 | EXPORT_SYMBOL(video_ioctl2); | 2391 | EXPORT_SYMBOL(video_ioctl2); |