diff options
author | Pawel Osciak <p.osciak@samsung.com> | 2010-12-23 02:15:27 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-21 19:31:33 -0400 |
commit | d14e6d76ebf740fd0d0bd296933993a555938896 (patch) | |
tree | d6b922de6d8849e379eea61f7d56bc67ed645126 /drivers/media/video/v4l2-ioctl.c | |
parent | f8f3914cf922f5f9e1d60e9e10f6fb92742907ad (diff) |
[media] v4l: Add multi-planar ioctl handling code
Add multi-planar API core ioctl handling and conversion functions.
[mchehab@redhat.com: CondingStyle fixup]
Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Marek Szyprowski <m.szyprowski@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-ioctl.c')
-rw-r--r-- | drivers/media/video/v4l2-ioctl.c | 453 |
1 files changed, 409 insertions, 44 deletions
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 1a9d90ab666b..8360ed2d933a 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c | |||
@@ -428,20 +428,33 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd, | |||
428 | struct v4l2_buffer *p) | 428 | struct v4l2_buffer *p) |
429 | { | 429 | { |
430 | struct v4l2_timecode *tc = &p->timecode; | 430 | struct v4l2_timecode *tc = &p->timecode; |
431 | struct v4l2_plane *plane; | ||
432 | int i; | ||
431 | 433 | ||
432 | dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " | 434 | dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " |
433 | "bytesused=%d, flags=0x%08d, " | 435 | "flags=0x%08d, field=%0d, sequence=%d, memory=%s\n", |
434 | "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n", | ||
435 | p->timestamp.tv_sec / 3600, | 436 | p->timestamp.tv_sec / 3600, |
436 | (int)(p->timestamp.tv_sec / 60) % 60, | 437 | (int)(p->timestamp.tv_sec / 60) % 60, |
437 | (int)(p->timestamp.tv_sec % 60), | 438 | (int)(p->timestamp.tv_sec % 60), |
438 | (long)p->timestamp.tv_usec, | 439 | (long)p->timestamp.tv_usec, |
439 | p->index, | 440 | p->index, |
440 | prt_names(p->type, v4l2_type_names), | 441 | prt_names(p->type, v4l2_type_names), |
441 | p->bytesused, p->flags, | 442 | p->flags, p->field, p->sequence, |
442 | p->field, p->sequence, | 443 | prt_names(p->memory, v4l2_memory_names)); |
443 | prt_names(p->memory, v4l2_memory_names), | 444 | |
444 | p->m.userptr, p->length); | 445 | if (V4L2_TYPE_IS_MULTIPLANAR(p->type) && p->m.planes) { |
446 | for (i = 0; i < p->length; ++i) { | ||
447 | plane = &p->m.planes[i]; | ||
448 | dbgarg2("plane %d: bytesused=%d, data_offset=0x%08x " | ||
449 | "offset/userptr=0x%08lx, length=%d\n", | ||
450 | i, plane->bytesused, plane->data_offset, | ||
451 | plane->m.userptr, plane->length); | ||
452 | } | ||
453 | } else { | ||
454 | dbgarg2("bytesused=%d, offset/userptr=0x%08lx, length=%d\n", | ||
455 | p->bytesused, p->m.userptr, p->length); | ||
456 | } | ||
457 | |||
445 | dbgarg2("timecode=%02d:%02d:%02d type=%d, " | 458 | dbgarg2("timecode=%02d:%02d:%02d type=%d, " |
446 | "flags=0x%08d, frames=%d, userbits=0x%08x\n", | 459 | "flags=0x%08d, frames=%d, userbits=0x%08x\n", |
447 | tc->hours, tc->minutes, tc->seconds, | 460 | tc->hours, tc->minutes, tc->seconds, |
@@ -469,6 +482,27 @@ static inline void v4l_print_pix_fmt(struct video_device *vfd, | |||
469 | fmt->bytesperline, fmt->sizeimage, fmt->colorspace); | 482 | fmt->bytesperline, fmt->sizeimage, fmt->colorspace); |
470 | }; | 483 | }; |
471 | 484 | ||
485 | static inline void v4l_print_pix_fmt_mplane(struct video_device *vfd, | ||
486 | struct v4l2_pix_format_mplane *fmt) | ||
487 | { | ||
488 | int i; | ||
489 | |||
490 | dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, " | ||
491 | "colorspace=%d, num_planes=%d\n", | ||
492 | fmt->width, fmt->height, | ||
493 | (fmt->pixelformat & 0xff), | ||
494 | (fmt->pixelformat >> 8) & 0xff, | ||
495 | (fmt->pixelformat >> 16) & 0xff, | ||
496 | (fmt->pixelformat >> 24) & 0xff, | ||
497 | prt_names(fmt->field, v4l2_field_names), | ||
498 | fmt->colorspace, fmt->num_planes); | ||
499 | |||
500 | for (i = 0; i < fmt->num_planes; ++i) | ||
501 | dbgarg2("plane %d: bytesperline=%d sizeimage=%d\n", i, | ||
502 | fmt->plane_fmt[i].bytesperline, | ||
503 | fmt->plane_fmt[i].sizeimage); | ||
504 | } | ||
505 | |||
472 | static inline void v4l_print_ext_ctrls(unsigned int cmd, | 506 | static inline void v4l_print_ext_ctrls(unsigned int cmd, |
473 | struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) | 507 | struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) |
474 | { | 508 | { |
@@ -522,7 +556,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) | |||
522 | 556 | ||
523 | switch (type) { | 557 | switch (type) { |
524 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 558 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
525 | if (ops->vidioc_g_fmt_vid_cap) | 559 | if (ops->vidioc_g_fmt_vid_cap || |
560 | ops->vidioc_g_fmt_vid_cap_mplane) | ||
561 | return 0; | ||
562 | break; | ||
563 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
564 | if (ops->vidioc_g_fmt_vid_cap_mplane) | ||
526 | return 0; | 565 | return 0; |
527 | break; | 566 | break; |
528 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 567 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
@@ -530,7 +569,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) | |||
530 | return 0; | 569 | return 0; |
531 | break; | 570 | break; |
532 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 571 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
533 | if (ops->vidioc_g_fmt_vid_out) | 572 | if (ops->vidioc_g_fmt_vid_out || |
573 | ops->vidioc_g_fmt_vid_out_mplane) | ||
574 | return 0; | ||
575 | break; | ||
576 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
577 | if (ops->vidioc_g_fmt_vid_out_mplane) | ||
534 | return 0; | 578 | return 0; |
535 | break; | 579 | break; |
536 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 580 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
@@ -561,12 +605,70 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) | |||
561 | return -EINVAL; | 605 | return -EINVAL; |
562 | } | 606 | } |
563 | 607 | ||
608 | /** | ||
609 | * fmt_sp_to_mp() - Convert a single-plane format to its multi-planar 1-plane | ||
610 | * equivalent | ||
611 | */ | ||
612 | static int fmt_sp_to_mp(const struct v4l2_format *f_sp, | ||
613 | struct v4l2_format *f_mp) | ||
614 | { | ||
615 | struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; | ||
616 | const struct v4l2_pix_format *pix = &f_sp->fmt.pix; | ||
617 | |||
618 | if (f_sp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
619 | f_mp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | ||
620 | else if (f_sp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
621 | f_mp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | ||
622 | else | ||
623 | return -EINVAL; | ||
624 | |||
625 | pix_mp->width = pix->width; | ||
626 | pix_mp->height = pix->height; | ||
627 | pix_mp->pixelformat = pix->pixelformat; | ||
628 | pix_mp->field = pix->field; | ||
629 | pix_mp->colorspace = pix->colorspace; | ||
630 | pix_mp->num_planes = 1; | ||
631 | pix_mp->plane_fmt[0].sizeimage = pix->sizeimage; | ||
632 | pix_mp->plane_fmt[0].bytesperline = pix->bytesperline; | ||
633 | |||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | /** | ||
638 | * fmt_mp_to_sp() - Convert a multi-planar 1-plane format to its single-planar | ||
639 | * equivalent | ||
640 | */ | ||
641 | static int fmt_mp_to_sp(const struct v4l2_format *f_mp, | ||
642 | struct v4l2_format *f_sp) | ||
643 | { | ||
644 | const struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; | ||
645 | struct v4l2_pix_format *pix = &f_sp->fmt.pix; | ||
646 | |||
647 | if (f_mp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | ||
648 | f_sp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
649 | else if (f_mp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
650 | f_sp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
651 | else | ||
652 | return -EINVAL; | ||
653 | |||
654 | pix->width = pix_mp->width; | ||
655 | pix->height = pix_mp->height; | ||
656 | pix->pixelformat = pix_mp->pixelformat; | ||
657 | pix->field = pix_mp->field; | ||
658 | pix->colorspace = pix_mp->colorspace; | ||
659 | pix->sizeimage = pix_mp->plane_fmt[0].sizeimage; | ||
660 | pix->bytesperline = pix_mp->plane_fmt[0].bytesperline; | ||
661 | |||
662 | return 0; | ||
663 | } | ||
664 | |||
564 | static long __video_do_ioctl(struct file *file, | 665 | static long __video_do_ioctl(struct file *file, |
565 | unsigned int cmd, void *arg) | 666 | unsigned int cmd, void *arg) |
566 | { | 667 | { |
567 | struct video_device *vfd = video_devdata(file); | 668 | struct video_device *vfd = video_devdata(file); |
568 | const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; | 669 | const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; |
569 | void *fh = file->private_data; | 670 | void *fh = file->private_data; |
671 | struct v4l2_format f_copy; | ||
570 | long ret = -EINVAL; | 672 | long ret = -EINVAL; |
571 | 673 | ||
572 | if (ops == NULL) { | 674 | if (ops == NULL) { |
@@ -635,6 +737,11 @@ static long __video_do_ioctl(struct file *file, | |||
635 | if (ops->vidioc_enum_fmt_vid_cap) | 737 | if (ops->vidioc_enum_fmt_vid_cap) |
636 | ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); | 738 | ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); |
637 | break; | 739 | break; |
740 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
741 | if (ops->vidioc_enum_fmt_vid_cap_mplane) | ||
742 | ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, | ||
743 | fh, f); | ||
744 | break; | ||
638 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 745 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
639 | if (ops->vidioc_enum_fmt_vid_overlay) | 746 | if (ops->vidioc_enum_fmt_vid_overlay) |
640 | ret = ops->vidioc_enum_fmt_vid_overlay(file, | 747 | ret = ops->vidioc_enum_fmt_vid_overlay(file, |
@@ -644,6 +751,11 @@ static long __video_do_ioctl(struct file *file, | |||
644 | if (ops->vidioc_enum_fmt_vid_out) | 751 | if (ops->vidioc_enum_fmt_vid_out) |
645 | ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); | 752 | ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); |
646 | break; | 753 | break; |
754 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
755 | if (ops->vidioc_enum_fmt_vid_out_mplane) | ||
756 | ret = ops->vidioc_enum_fmt_vid_out_mplane(file, | ||
757 | fh, f); | ||
758 | break; | ||
647 | case V4L2_BUF_TYPE_PRIVATE: | 759 | case V4L2_BUF_TYPE_PRIVATE: |
648 | if (ops->vidioc_enum_fmt_type_private) | 760 | if (ops->vidioc_enum_fmt_type_private) |
649 | ret = ops->vidioc_enum_fmt_type_private(file, | 761 | ret = ops->vidioc_enum_fmt_type_private(file, |
@@ -672,22 +784,90 @@ static long __video_do_ioctl(struct file *file, | |||
672 | 784 | ||
673 | switch (f->type) { | 785 | switch (f->type) { |
674 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 786 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
675 | if (ops->vidioc_g_fmt_vid_cap) | 787 | if (ops->vidioc_g_fmt_vid_cap) { |
676 | ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); | 788 | ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); |
789 | } else if (ops->vidioc_g_fmt_vid_cap_mplane) { | ||
790 | if (fmt_sp_to_mp(f, &f_copy)) | ||
791 | break; | ||
792 | ret = ops->vidioc_g_fmt_vid_cap_mplane(file, fh, | ||
793 | &f_copy); | ||
794 | if (ret) | ||
795 | break; | ||
796 | |||
797 | /* Driver is currently in multi-planar format, | ||
798 | * we can't return it in single-planar API*/ | ||
799 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
800 | ret = -EBUSY; | ||
801 | break; | ||
802 | } | ||
803 | |||
804 | ret = fmt_mp_to_sp(&f_copy, f); | ||
805 | } | ||
677 | if (!ret) | 806 | if (!ret) |
678 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 807 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
679 | break; | 808 | break; |
809 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
810 | if (ops->vidioc_g_fmt_vid_cap_mplane) { | ||
811 | ret = ops->vidioc_g_fmt_vid_cap_mplane(file, | ||
812 | fh, f); | ||
813 | } else if (ops->vidioc_g_fmt_vid_cap) { | ||
814 | if (fmt_mp_to_sp(f, &f_copy)) | ||
815 | break; | ||
816 | ret = ops->vidioc_g_fmt_vid_cap(file, | ||
817 | fh, &f_copy); | ||
818 | if (ret) | ||
819 | break; | ||
820 | |||
821 | ret = fmt_sp_to_mp(&f_copy, f); | ||
822 | } | ||
823 | if (!ret) | ||
824 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
825 | break; | ||
680 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 826 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
681 | if (ops->vidioc_g_fmt_vid_overlay) | 827 | if (ops->vidioc_g_fmt_vid_overlay) |
682 | ret = ops->vidioc_g_fmt_vid_overlay(file, | 828 | ret = ops->vidioc_g_fmt_vid_overlay(file, |
683 | fh, f); | 829 | fh, f); |
684 | break; | 830 | break; |
685 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 831 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
686 | if (ops->vidioc_g_fmt_vid_out) | 832 | if (ops->vidioc_g_fmt_vid_out) { |
687 | ret = ops->vidioc_g_fmt_vid_out(file, fh, f); | 833 | ret = ops->vidioc_g_fmt_vid_out(file, fh, f); |
834 | } else if (ops->vidioc_g_fmt_vid_out_mplane) { | ||
835 | if (fmt_sp_to_mp(f, &f_copy)) | ||
836 | break; | ||
837 | ret = ops->vidioc_g_fmt_vid_out_mplane(file, fh, | ||
838 | &f_copy); | ||
839 | if (ret) | ||
840 | break; | ||
841 | |||
842 | /* Driver is currently in multi-planar format, | ||
843 | * we can't return it in single-planar API*/ | ||
844 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
845 | ret = -EBUSY; | ||
846 | break; | ||
847 | } | ||
848 | |||
849 | ret = fmt_mp_to_sp(&f_copy, f); | ||
850 | } | ||
688 | if (!ret) | 851 | if (!ret) |
689 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 852 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
690 | break; | 853 | break; |
854 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
855 | if (ops->vidioc_g_fmt_vid_out_mplane) { | ||
856 | ret = ops->vidioc_g_fmt_vid_out_mplane(file, | ||
857 | fh, f); | ||
858 | } else if (ops->vidioc_g_fmt_vid_out) { | ||
859 | if (fmt_mp_to_sp(f, &f_copy)) | ||
860 | break; | ||
861 | ret = ops->vidioc_g_fmt_vid_out(file, | ||
862 | fh, &f_copy); | ||
863 | if (ret) | ||
864 | break; | ||
865 | |||
866 | ret = fmt_sp_to_mp(&f_copy, f); | ||
867 | } | ||
868 | if (!ret) | ||
869 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
870 | break; | ||
691 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 871 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
692 | if (ops->vidioc_g_fmt_vid_out_overlay) | 872 | if (ops->vidioc_g_fmt_vid_out_overlay) |
693 | ret = ops->vidioc_g_fmt_vid_out_overlay(file, | 873 | ret = ops->vidioc_g_fmt_vid_out_overlay(file, |
@@ -731,8 +911,44 @@ static long __video_do_ioctl(struct file *file, | |||
731 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 911 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
732 | CLEAR_AFTER_FIELD(f, fmt.pix); | 912 | CLEAR_AFTER_FIELD(f, fmt.pix); |
733 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 913 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
734 | if (ops->vidioc_s_fmt_vid_cap) | 914 | if (ops->vidioc_s_fmt_vid_cap) { |
735 | ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); | 915 | ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); |
916 | } else if (ops->vidioc_s_fmt_vid_cap_mplane) { | ||
917 | if (fmt_sp_to_mp(f, &f_copy)) | ||
918 | break; | ||
919 | ret = ops->vidioc_s_fmt_vid_cap_mplane(file, fh, | ||
920 | &f_copy); | ||
921 | if (ret) | ||
922 | break; | ||
923 | |||
924 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
925 | /* Drivers shouldn't adjust from 1-plane | ||
926 | * to more than 1-plane formats */ | ||
927 | ret = -EBUSY; | ||
928 | WARN_ON(1); | ||
929 | break; | ||
930 | } | ||
931 | |||
932 | ret = fmt_mp_to_sp(&f_copy, f); | ||
933 | } | ||
934 | break; | ||
935 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
936 | CLEAR_AFTER_FIELD(f, fmt.pix_mp); | ||
937 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
938 | if (ops->vidioc_s_fmt_vid_cap_mplane) { | ||
939 | ret = ops->vidioc_s_fmt_vid_cap_mplane(file, | ||
940 | fh, f); | ||
941 | } else if (ops->vidioc_s_fmt_vid_cap && | ||
942 | f->fmt.pix_mp.num_planes == 1) { | ||
943 | if (fmt_mp_to_sp(f, &f_copy)) | ||
944 | break; | ||
945 | ret = ops->vidioc_s_fmt_vid_cap(file, | ||
946 | fh, &f_copy); | ||
947 | if (ret) | ||
948 | break; | ||
949 | |||
950 | ret = fmt_sp_to_mp(&f_copy, f); | ||
951 | } | ||
736 | break; | 952 | break; |
737 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 953 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
738 | CLEAR_AFTER_FIELD(f, fmt.win); | 954 | CLEAR_AFTER_FIELD(f, fmt.win); |
@@ -743,8 +959,44 @@ static long __video_do_ioctl(struct file *file, | |||
743 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 959 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
744 | CLEAR_AFTER_FIELD(f, fmt.pix); | 960 | CLEAR_AFTER_FIELD(f, fmt.pix); |
745 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 961 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
746 | if (ops->vidioc_s_fmt_vid_out) | 962 | if (ops->vidioc_s_fmt_vid_out) { |
747 | ret = ops->vidioc_s_fmt_vid_out(file, fh, f); | 963 | ret = ops->vidioc_s_fmt_vid_out(file, fh, f); |
964 | } else if (ops->vidioc_s_fmt_vid_out_mplane) { | ||
965 | if (fmt_sp_to_mp(f, &f_copy)) | ||
966 | break; | ||
967 | ret = ops->vidioc_s_fmt_vid_out_mplane(file, fh, | ||
968 | &f_copy); | ||
969 | if (ret) | ||
970 | break; | ||
971 | |||
972 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
973 | /* Drivers shouldn't adjust from 1-plane | ||
974 | * to more than 1-plane formats */ | ||
975 | ret = -EBUSY; | ||
976 | WARN_ON(1); | ||
977 | break; | ||
978 | } | ||
979 | |||
980 | ret = fmt_mp_to_sp(&f_copy, f); | ||
981 | } | ||
982 | break; | ||
983 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
984 | CLEAR_AFTER_FIELD(f, fmt.pix_mp); | ||
985 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
986 | if (ops->vidioc_s_fmt_vid_out_mplane) { | ||
987 | ret = ops->vidioc_s_fmt_vid_out_mplane(file, | ||
988 | fh, f); | ||
989 | } else if (ops->vidioc_s_fmt_vid_out && | ||
990 | f->fmt.pix_mp.num_planes == 1) { | ||
991 | if (fmt_mp_to_sp(f, &f_copy)) | ||
992 | break; | ||
993 | ret = ops->vidioc_s_fmt_vid_out(file, | ||
994 | fh, &f_copy); | ||
995 | if (ret) | ||
996 | break; | ||
997 | |||
998 | ret = fmt_mp_to_sp(&f_copy, f); | ||
999 | } | ||
748 | break; | 1000 | break; |
749 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 1001 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
750 | CLEAR_AFTER_FIELD(f, fmt.win); | 1002 | CLEAR_AFTER_FIELD(f, fmt.win); |
@@ -793,11 +1045,47 @@ static long __video_do_ioctl(struct file *file, | |||
793 | switch (f->type) { | 1045 | switch (f->type) { |
794 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1046 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
795 | CLEAR_AFTER_FIELD(f, fmt.pix); | 1047 | CLEAR_AFTER_FIELD(f, fmt.pix); |
796 | if (ops->vidioc_try_fmt_vid_cap) | 1048 | if (ops->vidioc_try_fmt_vid_cap) { |
797 | ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); | 1049 | ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); |
1050 | } else if (ops->vidioc_try_fmt_vid_cap_mplane) { | ||
1051 | if (fmt_sp_to_mp(f, &f_copy)) | ||
1052 | break; | ||
1053 | ret = ops->vidioc_try_fmt_vid_cap_mplane(file, | ||
1054 | fh, &f_copy); | ||
1055 | if (ret) | ||
1056 | break; | ||
1057 | |||
1058 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
1059 | /* Drivers shouldn't adjust from 1-plane | ||
1060 | * to more than 1-plane formats */ | ||
1061 | ret = -EBUSY; | ||
1062 | WARN_ON(1); | ||
1063 | break; | ||
1064 | } | ||
1065 | ret = fmt_mp_to_sp(&f_copy, f); | ||
1066 | } | ||
798 | if (!ret) | 1067 | if (!ret) |
799 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 1068 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
800 | break; | 1069 | break; |
1070 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | ||
1071 | CLEAR_AFTER_FIELD(f, fmt.pix_mp); | ||
1072 | if (ops->vidioc_try_fmt_vid_cap_mplane) { | ||
1073 | ret = ops->vidioc_try_fmt_vid_cap_mplane(file, | ||
1074 | fh, f); | ||
1075 | } else if (ops->vidioc_try_fmt_vid_cap && | ||
1076 | f->fmt.pix_mp.num_planes == 1) { | ||
1077 | if (fmt_mp_to_sp(f, &f_copy)) | ||
1078 | break; | ||
1079 | ret = ops->vidioc_try_fmt_vid_cap(file, | ||
1080 | fh, &f_copy); | ||
1081 | if (ret) | ||
1082 | break; | ||
1083 | |||
1084 | ret = fmt_sp_to_mp(&f_copy, f); | ||
1085 | } | ||
1086 | if (!ret) | ||
1087 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
1088 | break; | ||
801 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | 1089 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: |
802 | CLEAR_AFTER_FIELD(f, fmt.win); | 1090 | CLEAR_AFTER_FIELD(f, fmt.win); |
803 | if (ops->vidioc_try_fmt_vid_overlay) | 1091 | if (ops->vidioc_try_fmt_vid_overlay) |
@@ -806,11 +1094,47 @@ static long __video_do_ioctl(struct file *file, | |||
806 | break; | 1094 | break; |
807 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 1095 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
808 | CLEAR_AFTER_FIELD(f, fmt.pix); | 1096 | CLEAR_AFTER_FIELD(f, fmt.pix); |
809 | if (ops->vidioc_try_fmt_vid_out) | 1097 | if (ops->vidioc_try_fmt_vid_out) { |
810 | ret = ops->vidioc_try_fmt_vid_out(file, fh, f); | 1098 | ret = ops->vidioc_try_fmt_vid_out(file, fh, f); |
1099 | } else if (ops->vidioc_try_fmt_vid_out_mplane) { | ||
1100 | if (fmt_sp_to_mp(f, &f_copy)) | ||
1101 | break; | ||
1102 | ret = ops->vidioc_try_fmt_vid_out_mplane(file, | ||
1103 | fh, &f_copy); | ||
1104 | if (ret) | ||
1105 | break; | ||
1106 | |||
1107 | if (f_copy.fmt.pix_mp.num_planes > 1) { | ||
1108 | /* Drivers shouldn't adjust from 1-plane | ||
1109 | * to more than 1-plane formats */ | ||
1110 | ret = -EBUSY; | ||
1111 | WARN_ON(1); | ||
1112 | break; | ||
1113 | } | ||
1114 | ret = fmt_mp_to_sp(&f_copy, f); | ||
1115 | } | ||
811 | if (!ret) | 1116 | if (!ret) |
812 | v4l_print_pix_fmt(vfd, &f->fmt.pix); | 1117 | v4l_print_pix_fmt(vfd, &f->fmt.pix); |
813 | break; | 1118 | break; |
1119 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | ||
1120 | CLEAR_AFTER_FIELD(f, fmt.pix_mp); | ||
1121 | if (ops->vidioc_try_fmt_vid_out_mplane) { | ||
1122 | ret = ops->vidioc_try_fmt_vid_out_mplane(file, | ||
1123 | fh, f); | ||
1124 | } else if (ops->vidioc_try_fmt_vid_out && | ||
1125 | f->fmt.pix_mp.num_planes == 1) { | ||
1126 | if (fmt_mp_to_sp(f, &f_copy)) | ||
1127 | break; | ||
1128 | ret = ops->vidioc_try_fmt_vid_out(file, | ||
1129 | fh, &f_copy); | ||
1130 | if (ret) | ||
1131 | break; | ||
1132 | |||
1133 | ret = fmt_sp_to_mp(&f_copy, f); | ||
1134 | } | ||
1135 | if (!ret) | ||
1136 | v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); | ||
1137 | break; | ||
814 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | 1138 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: |
815 | CLEAR_AFTER_FIELD(f, fmt.win); | 1139 | CLEAR_AFTER_FIELD(f, fmt.win); |
816 | if (ops->vidioc_try_fmt_vid_out_overlay) | 1140 | if (ops->vidioc_try_fmt_vid_out_overlay) |
@@ -1975,7 +2299,7 @@ static unsigned long cmd_input_size(unsigned int cmd) | |||
1975 | switch (cmd) { | 2299 | switch (cmd) { |
1976 | CMDINSIZE(ENUM_FMT, fmtdesc, type); | 2300 | CMDINSIZE(ENUM_FMT, fmtdesc, type); |
1977 | CMDINSIZE(G_FMT, format, type); | 2301 | CMDINSIZE(G_FMT, format, type); |
1978 | CMDINSIZE(QUERYBUF, buffer, type); | 2302 | CMDINSIZE(QUERYBUF, buffer, length); |
1979 | CMDINSIZE(G_PARM, streamparm, type); | 2303 | CMDINSIZE(G_PARM, streamparm, type); |
1980 | CMDINSIZE(ENUMSTD, standard, index); | 2304 | CMDINSIZE(ENUMSTD, standard, index); |
1981 | CMDINSIZE(ENUMINPUT, input, index); | 2305 | CMDINSIZE(ENUMINPUT, input, index); |
@@ -2000,6 +2324,49 @@ static unsigned long cmd_input_size(unsigned int cmd) | |||
2000 | } | 2324 | } |
2001 | } | 2325 | } |
2002 | 2326 | ||
2327 | static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, | ||
2328 | void * __user *user_ptr, void ***kernel_ptr) | ||
2329 | { | ||
2330 | int ret = 0; | ||
2331 | |||
2332 | switch (cmd) { | ||
2333 | case VIDIOC_QUERYBUF: | ||
2334 | case VIDIOC_QBUF: | ||
2335 | case VIDIOC_DQBUF: { | ||
2336 | struct v4l2_buffer *buf = parg; | ||
2337 | |||
2338 | if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->length > 0) { | ||
2339 | if (buf->length > VIDEO_MAX_PLANES) { | ||
2340 | ret = -EINVAL; | ||
2341 | break; | ||
2342 | } | ||
2343 | *user_ptr = (void __user *)buf->m.planes; | ||
2344 | *kernel_ptr = (void **)&buf->m.planes; | ||
2345 | *array_size = sizeof(struct v4l2_plane) * buf->length; | ||
2346 | ret = 1; | ||
2347 | } | ||
2348 | break; | ||
2349 | } | ||
2350 | |||
2351 | case VIDIOC_S_EXT_CTRLS: | ||
2352 | case VIDIOC_G_EXT_CTRLS: | ||
2353 | case VIDIOC_TRY_EXT_CTRLS: { | ||
2354 | struct v4l2_ext_controls *ctrls = parg; | ||
2355 | |||
2356 | if (ctrls->count != 0) { | ||
2357 | *user_ptr = (void __user *)ctrls->controls; | ||
2358 | *kernel_ptr = (void **)&ctrls->controls; | ||
2359 | *array_size = sizeof(struct v4l2_ext_control) | ||
2360 | * ctrls->count; | ||
2361 | ret = 1; | ||
2362 | } | ||
2363 | break; | ||
2364 | } | ||
2365 | } | ||
2366 | |||
2367 | return ret; | ||
2368 | } | ||
2369 | |||
2003 | long video_ioctl2(struct file *file, | 2370 | long video_ioctl2(struct file *file, |
2004 | unsigned int cmd, unsigned long arg) | 2371 | unsigned int cmd, unsigned long arg) |
2005 | { | 2372 | { |
@@ -2007,16 +2374,14 @@ long video_ioctl2(struct file *file, | |||
2007 | void *mbuf = NULL; | 2374 | void *mbuf = NULL; |
2008 | void *parg = (void *)arg; | 2375 | void *parg = (void *)arg; |
2009 | long err = -EINVAL; | 2376 | long err = -EINVAL; |
2010 | int is_ext_ctrl; | 2377 | bool has_array_args; |
2011 | size_t ctrls_size = 0; | 2378 | size_t array_size = 0; |
2012 | void __user *user_ptr = NULL; | 2379 | void __user *user_ptr = NULL; |
2380 | void **kernel_ptr = NULL; | ||
2013 | 2381 | ||
2014 | #ifdef __OLD_VIDIOC_ | 2382 | #ifdef __OLD_VIDIOC_ |
2015 | cmd = video_fix_command(cmd); | 2383 | cmd = video_fix_command(cmd); |
2016 | #endif | 2384 | #endif |
2017 | is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || | ||
2018 | cmd == VIDIOC_TRY_EXT_CTRLS); | ||
2019 | |||
2020 | /* Copy arguments into temp kernel buffer */ | 2385 | /* Copy arguments into temp kernel buffer */ |
2021 | if (_IOC_DIR(cmd) != _IOC_NONE) { | 2386 | if (_IOC_DIR(cmd) != _IOC_NONE) { |
2022 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { | 2387 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { |
@@ -2045,43 +2410,43 @@ long video_ioctl2(struct file *file, | |||
2045 | } | 2410 | } |
2046 | } | 2411 | } |
2047 | 2412 | ||
2048 | if (is_ext_ctrl) { | 2413 | err = check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr); |
2049 | struct v4l2_ext_controls *p = parg; | 2414 | if (err < 0) |
2415 | goto out; | ||
2416 | has_array_args = err; | ||
2050 | 2417 | ||
2051 | /* In case of an error, tell the caller that it wasn't | 2418 | if (has_array_args) { |
2052 | a specific control that caused it. */ | 2419 | /* |
2053 | p->error_idx = p->count; | 2420 | * When adding new types of array args, make sure that the |
2054 | user_ptr = (void __user *)p->controls; | 2421 | * parent argument to ioctl (which contains the pointer to the |
2055 | if (p->count) { | 2422 | * array) fits into sbuf (so that mbuf will still remain |
2056 | ctrls_size = sizeof(struct v4l2_ext_control) * p->count; | 2423 | * unused up to here). |
2057 | /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ | 2424 | */ |
2058 | mbuf = kmalloc(ctrls_size, GFP_KERNEL); | 2425 | mbuf = kmalloc(array_size, GFP_KERNEL); |
2059 | err = -ENOMEM; | 2426 | err = -ENOMEM; |
2060 | if (NULL == mbuf) | 2427 | if (NULL == mbuf) |
2061 | goto out_ext_ctrl; | 2428 | goto out_array_args; |
2062 | err = -EFAULT; | 2429 | err = -EFAULT; |
2063 | if (copy_from_user(mbuf, user_ptr, ctrls_size)) | 2430 | if (copy_from_user(mbuf, user_ptr, array_size)) |
2064 | goto out_ext_ctrl; | 2431 | goto out_array_args; |
2065 | p->controls = mbuf; | 2432 | *kernel_ptr = mbuf; |
2066 | } | ||
2067 | } | 2433 | } |
2068 | 2434 | ||
2069 | /* Handles IOCTL */ | 2435 | /* Handles IOCTL */ |
2070 | err = __video_do_ioctl(file, cmd, parg); | 2436 | err = __video_do_ioctl(file, cmd, parg); |
2071 | if (err == -ENOIOCTLCMD) | 2437 | if (err == -ENOIOCTLCMD) |
2072 | err = -EINVAL; | 2438 | err = -EINVAL; |
2073 | if (is_ext_ctrl) { | ||
2074 | struct v4l2_ext_controls *p = parg; | ||
2075 | 2439 | ||
2076 | p->controls = (void *)user_ptr; | 2440 | if (has_array_args) { |
2077 | if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) | 2441 | *kernel_ptr = user_ptr; |
2442 | if (copy_to_user(user_ptr, mbuf, array_size)) | ||
2078 | err = -EFAULT; | 2443 | err = -EFAULT; |
2079 | goto out_ext_ctrl; | 2444 | goto out_array_args; |
2080 | } | 2445 | } |
2081 | if (err < 0) | 2446 | if (err < 0) |
2082 | goto out; | 2447 | goto out; |
2083 | 2448 | ||
2084 | out_ext_ctrl: | 2449 | out_array_args: |
2085 | /* Copy results into user buffer */ | 2450 | /* Copy results into user buffer */ |
2086 | switch (_IOC_DIR(cmd)) { | 2451 | switch (_IOC_DIR(cmd)) { |
2087 | case _IOC_READ: | 2452 | case _IOC_READ: |