diff options
author | Simon Farnsworth <simon.farnsworth@onelan.co.uk> | 2011-05-03 07:57:40 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-05-20 08:30:22 -0400 |
commit | 1bf5842fe3b61d2dbbced96dbd27ad26fe93444a (patch) | |
tree | 26c19327c2668ca8690e3a47b0846f9825beb991 /drivers/media/video/cx18 | |
parent | 81dfea886c73ea36439672b90626a354354dadd2 (diff) |
[media] cx18: Clean up mmap() support for raw YUV
The initial version of this patch (commit
d5976931639176bb6777755d96b9f8d959f79e9e) had some issues:
* It didn't correctly calculate the size of the YUV buffer for 4:2:2,
resulting in capture sometimes being offset by 1/3rd of a picture.
* There were a lot of variables duplicating information the driver
already knew, which have been removed.
* There was an in-kernel format conversion - libv4l can do this one,
and is the right place to do format conversions anyway.
* Some magic numbers weren't properly explained.
Fix all these issues, leaving just the move from videobuf to videobuf2
to do.
Signed-off-by: Simon Farnsworth <simon.farnsworth@onelan.co.uk>
Acked-by: Andy Walls <awalls@md.metrocast.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18')
-rw-r--r-- | drivers/media/video/cx18/Kconfig | 1 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.h | 8 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-fileops.c | 167 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 84 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.c | 17 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 160 |
6 files changed, 225 insertions, 212 deletions
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig index 9c232022403a..53b3c7702573 100644 --- a/drivers/media/video/cx18/Kconfig +++ b/drivers/media/video/cx18/Kconfig | |||
@@ -2,7 +2,6 @@ config VIDEO_CX18 | |||
2 | tristate "Conexant cx23418 MPEG encoder support" | 2 | tristate "Conexant cx23418 MPEG encoder support" |
3 | depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL | 3 | depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL |
4 | select I2C_ALGOBIT | 4 | select I2C_ALGOBIT |
5 | select VIDEOBUF_DVB | ||
6 | select VIDEOBUF_VMALLOC | 5 | select VIDEOBUF_VMALLOC |
7 | depends on RC_CORE | 6 | depends on RC_CORE |
8 | select VIDEO_TUNER | 7 | select VIDEO_TUNER |
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index 70e1e0401645..086427288de8 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h | |||
@@ -412,11 +412,11 @@ struct cx18_stream { | |||
412 | u32 pixelformat; | 412 | u32 pixelformat; |
413 | struct list_head vb_capture; /* video capture queue */ | 413 | struct list_head vb_capture; /* video capture queue */ |
414 | spinlock_t vb_lock; | 414 | spinlock_t vb_lock; |
415 | struct v4l2_framebuffer fbuf; | ||
416 | v4l2_std_id tvnorm; /* selected tv norm */ | ||
417 | struct timer_list vb_timeout; | 415 | struct timer_list vb_timeout; |
418 | int vbwidth; | 416 | |
419 | int vbheight; | 417 | struct videobuf_queue vbuf_q; |
418 | spinlock_t vbuf_q_lock; /* Protect vbuf_q */ | ||
419 | enum v4l2_buf_type vb_type; | ||
420 | }; | 420 | }; |
421 | 421 | ||
422 | struct cx18_videobuf_buffer { | 422 | struct cx18_videobuf_buffer { |
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index c74eafd67f98..6609222eccf8 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c | |||
@@ -598,9 +598,9 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, | |||
598 | if (rc) | 598 | if (rc) |
599 | return rc; | 599 | return rc; |
600 | 600 | ||
601 | if ((id->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && | 601 | if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
602 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { | 602 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { |
603 | return videobuf_read_stream(&id->vbuf_q, buf, count, pos, 0, | 603 | return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0, |
604 | filp->f_flags & O_NONBLOCK); | 604 | filp->f_flags & O_NONBLOCK); |
605 | } | 605 | } |
606 | 606 | ||
@@ -629,9 +629,13 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) | |||
629 | CX18_DEBUG_FILE("Encoder poll started capture\n"); | 629 | CX18_DEBUG_FILE("Encoder poll started capture\n"); |
630 | } | 630 | } |
631 | 631 | ||
632 | if ((id->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && | 632 | if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
633 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { | 633 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { |
634 | return videobuf_poll_stream(filp, &id->vbuf_q, wait); | 634 | int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait); |
635 | if (eof && videobuf_poll == POLLERR) | ||
636 | return POLLHUP; | ||
637 | else | ||
638 | return videobuf_poll; | ||
635 | } | 639 | } |
636 | 640 | ||
637 | /* add stream's waitq to the poll list */ | 641 | /* add stream's waitq to the poll list */ |
@@ -652,7 +656,7 @@ int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma) | |||
652 | struct cx18_stream *s = &cx->streams[id->type]; | 656 | struct cx18_stream *s = &cx->streams[id->type]; |
653 | int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); | 657 | int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); |
654 | 658 | ||
655 | if ((id->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && | 659 | if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
656 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { | 660 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { |
657 | 661 | ||
658 | /* Start a capture if there is none */ | 662 | /* Start a capture if there is none */ |
@@ -668,10 +672,10 @@ int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma) | |||
668 | s->name, rc); | 672 | s->name, rc); |
669 | return -EINVAL; | 673 | return -EINVAL; |
670 | } | 674 | } |
671 | CX18_DEBUG_FILE("Encoder poll started capture\n"); | 675 | CX18_DEBUG_FILE("Encoder mmap started capture\n"); |
672 | } | 676 | } |
673 | 677 | ||
674 | return videobuf_mmap_mapper(&id->vbuf_q, vma); | 678 | return videobuf_mmap_mapper(&s->vbuf_q, vma); |
675 | } | 679 | } |
676 | 680 | ||
677 | return -EINVAL; | 681 | return -EINVAL; |
@@ -788,142 +792,6 @@ int cx18_v4l2_close(struct file *filp) | |||
788 | return 0; | 792 | return 0; |
789 | } | 793 | } |
790 | 794 | ||
791 | void cx18_dma_free(struct videobuf_queue *q, | ||
792 | struct cx18_stream *s, struct cx18_videobuf_buffer *buf) | ||
793 | { | ||
794 | videobuf_waiton(q, &buf->vb, 0, 0); | ||
795 | videobuf_vmalloc_free(&buf->vb); | ||
796 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
797 | } | ||
798 | |||
799 | static int cx18_prepare_buffer(struct videobuf_queue *q, | ||
800 | struct cx18_stream *s, | ||
801 | struct cx18_videobuf_buffer *buf, | ||
802 | u32 pixelformat, | ||
803 | unsigned int width, unsigned int height, | ||
804 | enum v4l2_field field) | ||
805 | { | ||
806 | int rc = 0; | ||
807 | |||
808 | /* check settings */ | ||
809 | buf->bytes_used = 0; | ||
810 | |||
811 | if ((width < 48) || (height < 32)) | ||
812 | return -EINVAL; | ||
813 | |||
814 | buf->vb.size = (width * height * 16 /*fmt->depth*/) >> 3; | ||
815 | if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) | ||
816 | return -EINVAL; | ||
817 | |||
818 | /* alloc + fill struct (if changed) */ | ||
819 | if (buf->vb.width != width || buf->vb.height != height || | ||
820 | buf->vb.field != field || s->pixelformat != pixelformat || | ||
821 | buf->tvnorm != s->tvnorm) { | ||
822 | |||
823 | buf->vb.width = width; | ||
824 | buf->vb.height = height; | ||
825 | buf->vb.field = field; | ||
826 | buf->tvnorm = s->tvnorm; | ||
827 | s->pixelformat = pixelformat; | ||
828 | |||
829 | cx18_dma_free(q, s, buf); | ||
830 | } | ||
831 | |||
832 | if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) | ||
833 | return -EINVAL; | ||
834 | |||
835 | if (buf->vb.field == 0) | ||
836 | buf->vb.field = V4L2_FIELD_INTERLACED; | ||
837 | |||
838 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
839 | buf->vb.width = width; | ||
840 | buf->vb.height = height; | ||
841 | buf->vb.field = field; | ||
842 | buf->tvnorm = s->tvnorm; | ||
843 | s->pixelformat = pixelformat; | ||
844 | |||
845 | rc = videobuf_iolock(q, &buf->vb, &s->fbuf); | ||
846 | if (rc != 0) | ||
847 | goto fail; | ||
848 | } | ||
849 | buf->vb.state = VIDEOBUF_PREPARED; | ||
850 | return 0; | ||
851 | |||
852 | fail: | ||
853 | cx18_dma_free(q, s, buf); | ||
854 | return rc; | ||
855 | |||
856 | } | ||
857 | |||
858 | #define VB_MIN_BUFFERS 32 | ||
859 | #define VB_MIN_BUFSIZE 0x208000 | ||
860 | |||
861 | static int buffer_setup(struct videobuf_queue *q, | ||
862 | unsigned int *count, unsigned int *size) | ||
863 | { | ||
864 | struct cx18_open_id *id = q->priv_data; | ||
865 | struct cx18 *cx = id->cx; | ||
866 | struct cx18_stream *s = &cx->streams[id->type]; | ||
867 | |||
868 | *size = 2 * s->vbwidth * s->vbheight; | ||
869 | if (*count == 0) | ||
870 | *count = VB_MIN_BUFFERS; | ||
871 | |||
872 | while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE) | ||
873 | (*count)--; | ||
874 | |||
875 | q->field = V4L2_FIELD_INTERLACED; | ||
876 | q->last = V4L2_FIELD_INTERLACED; | ||
877 | |||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | static int buffer_prepare(struct videobuf_queue *q, | ||
882 | struct videobuf_buffer *vb, | ||
883 | enum v4l2_field field) | ||
884 | { | ||
885 | struct cx18_videobuf_buffer *buf = | ||
886 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
887 | struct cx18_open_id *id = q->priv_data; | ||
888 | struct cx18 *cx = id->cx; | ||
889 | struct cx18_stream *s = &cx->streams[id->type]; | ||
890 | |||
891 | return cx18_prepare_buffer(q, s, buf, s->pixelformat, | ||
892 | s->vbwidth, s->vbheight, field); | ||
893 | } | ||
894 | |||
895 | static void buffer_release(struct videobuf_queue *q, | ||
896 | struct videobuf_buffer *vb) | ||
897 | { | ||
898 | struct cx18_videobuf_buffer *buf = | ||
899 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
900 | struct cx18_open_id *id = q->priv_data; | ||
901 | struct cx18 *cx = id->cx; | ||
902 | struct cx18_stream *s = &cx->streams[id->type]; | ||
903 | |||
904 | cx18_dma_free(q, s, buf); | ||
905 | } | ||
906 | |||
907 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
908 | { | ||
909 | struct cx18_videobuf_buffer *buf = | ||
910 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
911 | struct cx18_open_id *id = q->priv_data; | ||
912 | struct cx18 *cx = id->cx; | ||
913 | struct cx18_stream *s = &cx->streams[id->type]; | ||
914 | |||
915 | buf->vb.state = VIDEOBUF_QUEUED; | ||
916 | |||
917 | list_add_tail(&buf->vb.queue, &s->vb_capture); | ||
918 | } | ||
919 | |||
920 | static struct videobuf_queue_ops cx18_videobuf_qops = { | ||
921 | .buf_setup = buffer_setup, | ||
922 | .buf_prepare = buffer_prepare, | ||
923 | .buf_queue = buffer_queue, | ||
924 | .buf_release = buffer_release, | ||
925 | }; | ||
926 | |||
927 | static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) | 795 | static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) |
928 | { | 796 | { |
929 | struct cx18 *cx = s->cx; | 797 | struct cx18 *cx = s->cx; |
@@ -942,8 +810,8 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) | |||
942 | item->cx = cx; | 810 | item->cx = cx; |
943 | item->type = s->type; | 811 | item->type = s->type; |
944 | 812 | ||
945 | spin_lock_init(&item->s_lock); | 813 | spin_lock_init(&s->vbuf_q_lock); |
946 | item->vb_type = 0; | 814 | s->vb_type = 0; |
947 | 815 | ||
948 | item->open_id = cx->open_id++; | 816 | item->open_id = cx->open_id++; |
949 | filp->private_data = &item->fh; | 817 | filp->private_data = &item->fh; |
@@ -979,15 +847,6 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) | |||
979 | /* Done! Unmute and continue. */ | 847 | /* Done! Unmute and continue. */ |
980 | cx18_unmute(cx); | 848 | cx18_unmute(cx); |
981 | } | 849 | } |
982 | if (item->type == CX18_ENC_STREAM_TYPE_YUV) { | ||
983 | item->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
984 | videobuf_queue_vmalloc_init(&item->vbuf_q, &cx18_videobuf_qops, | ||
985 | &cx->pci_dev->dev, &item->s_lock, | ||
986 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
987 | V4L2_FIELD_INTERLACED, | ||
988 | sizeof(struct cx18_videobuf_buffer), | ||
989 | item, &cx->serialize_lock); | ||
990 | } | ||
991 | v4l2_fh_add(&item->fh); | 850 | v4l2_fh_add(&item->fh); |
992 | return 0; | 851 | return 0; |
993 | } | 852 | } |
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 777d7265c8a8..1933d4d11bf2 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c | |||
@@ -41,18 +41,6 @@ | |||
41 | #include <media/tveeprom.h> | 41 | #include <media/tveeprom.h> |
42 | #include <media/v4l2-chip-ident.h> | 42 | #include <media/v4l2-chip-ident.h> |
43 | 43 | ||
44 | static struct v4l2_fmtdesc formats[] = { | ||
45 | { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, | ||
46 | "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } | ||
47 | }, | ||
48 | { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED, | ||
49 | "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } | ||
50 | }, | ||
51 | { 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, | ||
52 | "YUYV 4:2:2", V4L2_PIX_FMT_YUYV, { 0, 0, 0, 0 } | ||
53 | }, | ||
54 | }; | ||
55 | |||
56 | u16 cx18_service2vbi(int type) | 44 | u16 cx18_service2vbi(int type) |
57 | { | 45 | { |
58 | switch (type) { | 46 | switch (type) { |
@@ -172,8 +160,12 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, | |||
172 | pixfmt->priv = 0; | 160 | pixfmt->priv = 0; |
173 | if (id->type == CX18_ENC_STREAM_TYPE_YUV) { | 161 | if (id->type == CX18_ENC_STREAM_TYPE_YUV) { |
174 | pixfmt->pixelformat = s->pixelformat; | 162 | pixfmt->pixelformat = s->pixelformat; |
175 | /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */ | 163 | /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) |
176 | pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; | 164 | UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ |
165 | if (s->pixelformat == V4L2_PIX_FMT_HM12) | ||
166 | pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; | ||
167 | else | ||
168 | pixfmt->sizeimage = pixfmt->height * 720 * 2; | ||
177 | pixfmt->bytesperline = 720; | 169 | pixfmt->bytesperline = 720; |
178 | } else { | 170 | } else { |
179 | pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; | 171 | pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; |
@@ -296,16 +288,15 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, | |||
296 | w = fmt->fmt.pix.width; | 288 | w = fmt->fmt.pix.width; |
297 | h = fmt->fmt.pix.height; | 289 | h = fmt->fmt.pix.height; |
298 | 290 | ||
299 | s->pixelformat = fmt->fmt.pix.pixelformat; | 291 | if (cx->cxhdl.width == w && cx->cxhdl.height == h && |
300 | s->vbheight = h; | 292 | s->pixelformat == fmt->fmt.pix.pixelformat) |
301 | s->vbwidth = w; | ||
302 | |||
303 | if (cx->cxhdl.width == w && cx->cxhdl.height == h) | ||
304 | return 0; | 293 | return 0; |
305 | 294 | ||
306 | if (atomic_read(&cx->ana_capturing) > 0) | 295 | if (atomic_read(&cx->ana_capturing) > 0) |
307 | return -EBUSY; | 296 | return -EBUSY; |
308 | 297 | ||
298 | s->pixelformat = fmt->fmt.pix.pixelformat; | ||
299 | |||
309 | mbus_fmt.width = cx->cxhdl.width = w; | 300 | mbus_fmt.width = cx->cxhdl.width = w; |
310 | mbus_fmt.height = cx->cxhdl.height = h; | 301 | mbus_fmt.height = cx->cxhdl.height = h; |
311 | mbus_fmt.code = V4L2_MBUS_FMT_FIXED; | 302 | mbus_fmt.code = V4L2_MBUS_FMT_FIXED; |
@@ -557,6 +548,18 @@ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) | |||
557 | static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, | 548 | static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, |
558 | struct v4l2_fmtdesc *fmt) | 549 | struct v4l2_fmtdesc *fmt) |
559 | { | 550 | { |
551 | static const struct v4l2_fmtdesc formats[] = { | ||
552 | { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, | ||
553 | "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } | ||
554 | }, | ||
555 | { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED, | ||
556 | "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } | ||
557 | }, | ||
558 | { 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, | ||
559 | "UYVY 4:2:2", V4L2_PIX_FMT_UYVY, { 0, 0, 0, 0 } | ||
560 | }, | ||
561 | }; | ||
562 | |||
560 | if (fmt->index > ARRAY_SIZE(formats) - 1) | 563 | if (fmt->index > ARRAY_SIZE(formats) - 1) |
561 | return -EINVAL; | 564 | return -EINVAL; |
562 | *fmt = formats[fmt->index]; | 565 | *fmt = formats[fmt->index]; |
@@ -874,10 +877,12 @@ static int cx18_g_enc_index(struct file *file, void *fh, | |||
874 | static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id) | 877 | static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id) |
875 | { | 878 | { |
876 | struct videobuf_queue *q = NULL; | 879 | struct videobuf_queue *q = NULL; |
880 | struct cx18 *cx = id->cx; | ||
881 | struct cx18_stream *s = &cx->streams[id->type]; | ||
877 | 882 | ||
878 | switch (id->vb_type) { | 883 | switch (s->vb_type) { |
879 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 884 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
880 | q = &id->vbuf_q; | 885 | q = &s->vbuf_q; |
881 | break; | 886 | break; |
882 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 887 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
883 | break; | 888 | break; |
@@ -895,15 +900,15 @@ static int cx18_streamon(struct file *file, void *priv, | |||
895 | struct cx18_stream *s = &cx->streams[id->type]; | 900 | struct cx18_stream *s = &cx->streams[id->type]; |
896 | 901 | ||
897 | /* Start the hardware only if we're the video device */ | 902 | /* Start the hardware only if we're the video device */ |
898 | if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | 903 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
899 | (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | 904 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) |
900 | return -EINVAL; | 905 | return -EINVAL; |
901 | 906 | ||
902 | if (id->type != CX18_ENC_STREAM_TYPE_YUV) | 907 | if (id->type != CX18_ENC_STREAM_TYPE_YUV) |
903 | return -EINVAL; | 908 | return -EINVAL; |
904 | 909 | ||
905 | /* Establish a buffer timeout */ | 910 | /* Establish a buffer timeout */ |
906 | mod_timer(&s->vb_timeout, jiffies + (HZ * 2)); | 911 | mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); |
907 | 912 | ||
908 | return videobuf_streamon(cx18_vb_queue(id)); | 913 | return videobuf_streamon(cx18_vb_queue(id)); |
909 | } | 914 | } |
@@ -912,10 +917,12 @@ static int cx18_streamoff(struct file *file, void *priv, | |||
912 | enum v4l2_buf_type type) | 917 | enum v4l2_buf_type type) |
913 | { | 918 | { |
914 | struct cx18_open_id *id = file->private_data; | 919 | struct cx18_open_id *id = file->private_data; |
920 | struct cx18 *cx = id->cx; | ||
921 | struct cx18_stream *s = &cx->streams[id->type]; | ||
915 | 922 | ||
916 | /* Start the hardware only if we're the video device */ | 923 | /* Start the hardware only if we're the video device */ |
917 | if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | 924 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
918 | (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | 925 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) |
919 | return -EINVAL; | 926 | return -EINVAL; |
920 | 927 | ||
921 | if (id->type != CX18_ENC_STREAM_TYPE_YUV) | 928 | if (id->type != CX18_ENC_STREAM_TYPE_YUV) |
@@ -928,9 +935,11 @@ static int cx18_reqbufs(struct file *file, void *priv, | |||
928 | struct v4l2_requestbuffers *rb) | 935 | struct v4l2_requestbuffers *rb) |
929 | { | 936 | { |
930 | struct cx18_open_id *id = file->private_data; | 937 | struct cx18_open_id *id = file->private_data; |
938 | struct cx18 *cx = id->cx; | ||
939 | struct cx18_stream *s = &cx->streams[id->type]; | ||
931 | 940 | ||
932 | if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | 941 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
933 | (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | 942 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) |
934 | return -EINVAL; | 943 | return -EINVAL; |
935 | 944 | ||
936 | return videobuf_reqbufs(cx18_vb_queue(id), rb); | 945 | return videobuf_reqbufs(cx18_vb_queue(id), rb); |
@@ -940,9 +949,11 @@ static int cx18_querybuf(struct file *file, void *priv, | |||
940 | struct v4l2_buffer *b) | 949 | struct v4l2_buffer *b) |
941 | { | 950 | { |
942 | struct cx18_open_id *id = file->private_data; | 951 | struct cx18_open_id *id = file->private_data; |
952 | struct cx18 *cx = id->cx; | ||
953 | struct cx18_stream *s = &cx->streams[id->type]; | ||
943 | 954 | ||
944 | if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | 955 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
945 | (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | 956 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) |
946 | return -EINVAL; | 957 | return -EINVAL; |
947 | 958 | ||
948 | return videobuf_querybuf(cx18_vb_queue(id), b); | 959 | return videobuf_querybuf(cx18_vb_queue(id), b); |
@@ -951,9 +962,11 @@ static int cx18_querybuf(struct file *file, void *priv, | |||
951 | static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) | 962 | static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) |
952 | { | 963 | { |
953 | struct cx18_open_id *id = file->private_data; | 964 | struct cx18_open_id *id = file->private_data; |
965 | struct cx18 *cx = id->cx; | ||
966 | struct cx18_stream *s = &cx->streams[id->type]; | ||
954 | 967 | ||
955 | if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | 968 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && |
956 | (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | 969 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) |
957 | return -EINVAL; | 970 | return -EINVAL; |
958 | 971 | ||
959 | return videobuf_qbuf(cx18_vb_queue(id), b); | 972 | return videobuf_qbuf(cx18_vb_queue(id), b); |
@@ -962,8 +975,11 @@ static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) | |||
962 | static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | 975 | static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) |
963 | { | 976 | { |
964 | struct cx18_open_id *id = file->private_data; | 977 | struct cx18_open_id *id = file->private_data; |
965 | if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | 978 | struct cx18 *cx = id->cx; |
966 | (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | 979 | struct cx18_stream *s = &cx->streams[id->type]; |
980 | |||
981 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
982 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
967 | return -EINVAL; | 983 | return -EINVAL; |
968 | 984 | ||
969 | return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK); | 985 | return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK); |
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index d4d88738d893..5ecae931ac36 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c | |||
@@ -177,7 +177,7 @@ static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, | |||
177 | if (list_empty(&s->vb_capture)) | 177 | if (list_empty(&s->vb_capture)) |
178 | goto out; | 178 | goto out; |
179 | 179 | ||
180 | vb_buf = list_entry(s->vb_capture.next, struct cx18_videobuf_buffer, | 180 | vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer, |
181 | vb.queue); | 181 | vb.queue); |
182 | 182 | ||
183 | p = videobuf_to_vmalloc(&vb_buf->vb); | 183 | p = videobuf_to_vmalloc(&vb_buf->vb); |
@@ -202,25 +202,14 @@ static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, | |||
202 | vb_buf->bytes_used = 0; | 202 | vb_buf->bytes_used = 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | /* */ | ||
206 | if (dispatch) { | 205 | if (dispatch) { |
207 | 206 | ktime_get_ts(&vb_buf->vb.ts); | |
208 | if (s->pixelformat == V4L2_PIX_FMT_YUYV) { | ||
209 | /* UYVY to YUYV */ | ||
210 | for (i = 0; i < (720 * 480 * 2); i += 2) { | ||
211 | u = *(p + i); | ||
212 | *(p + i) = *(p + i + 1); | ||
213 | *(p + i + 1) = u; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | do_gettimeofday(&vb_buf->vb.ts); | ||
218 | list_del(&vb_buf->vb.queue); | 207 | list_del(&vb_buf->vb.queue); |
219 | vb_buf->vb.state = VIDEOBUF_DONE; | 208 | vb_buf->vb.state = VIDEOBUF_DONE; |
220 | wake_up(&vb_buf->vb.done); | 209 | wake_up(&vb_buf->vb.done); |
221 | } | 210 | } |
222 | 211 | ||
223 | mod_timer(&s->vb_timeout, jiffies + (HZ / 10)); | 212 | mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); |
224 | 213 | ||
225 | out: | 214 | out: |
226 | spin_unlock(&s->vb_lock); | 215 | spin_unlock(&s->vb_lock); |
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index eeb455a8b726..3995af71b820 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -98,6 +98,141 @@ static struct { | |||
98 | }, | 98 | }, |
99 | }; | 99 | }; |
100 | 100 | ||
101 | |||
102 | void cx18_dma_free(struct videobuf_queue *q, | ||
103 | struct cx18_stream *s, struct cx18_videobuf_buffer *buf) | ||
104 | { | ||
105 | videobuf_waiton(q, &buf->vb, 0, 0); | ||
106 | videobuf_vmalloc_free(&buf->vb); | ||
107 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
108 | } | ||
109 | |||
110 | static int cx18_prepare_buffer(struct videobuf_queue *q, | ||
111 | struct cx18_stream *s, | ||
112 | struct cx18_videobuf_buffer *buf, | ||
113 | u32 pixelformat, | ||
114 | unsigned int width, unsigned int height, | ||
115 | enum v4l2_field field) | ||
116 | { | ||
117 | struct cx18 *cx = s->cx; | ||
118 | int rc = 0; | ||
119 | |||
120 | /* check settings */ | ||
121 | buf->bytes_used = 0; | ||
122 | |||
123 | if ((width < 48) || (height < 32)) | ||
124 | return -EINVAL; | ||
125 | |||
126 | buf->vb.size = (width * height * 2); | ||
127 | if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) | ||
128 | return -EINVAL; | ||
129 | |||
130 | /* alloc + fill struct (if changed) */ | ||
131 | if (buf->vb.width != width || buf->vb.height != height || | ||
132 | buf->vb.field != field || s->pixelformat != pixelformat || | ||
133 | buf->tvnorm != cx->std) { | ||
134 | |||
135 | buf->vb.width = width; | ||
136 | buf->vb.height = height; | ||
137 | buf->vb.field = field; | ||
138 | buf->tvnorm = cx->std; | ||
139 | s->pixelformat = pixelformat; | ||
140 | |||
141 | cx18_dma_free(q, s, buf); | ||
142 | } | ||
143 | |||
144 | if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) | ||
145 | return -EINVAL; | ||
146 | |||
147 | if (buf->vb.field == 0) | ||
148 | buf->vb.field = V4L2_FIELD_INTERLACED; | ||
149 | |||
150 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
151 | buf->vb.width = width; | ||
152 | buf->vb.height = height; | ||
153 | buf->vb.field = field; | ||
154 | buf->tvnorm = cx->std; | ||
155 | s->pixelformat = pixelformat; | ||
156 | |||
157 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
158 | if (rc != 0) | ||
159 | goto fail; | ||
160 | } | ||
161 | buf->vb.state = VIDEOBUF_PREPARED; | ||
162 | return 0; | ||
163 | |||
164 | fail: | ||
165 | cx18_dma_free(q, s, buf); | ||
166 | return rc; | ||
167 | |||
168 | } | ||
169 | |||
170 | /* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576) | ||
171 | 1440 is a single line of 4:2:2 YUV at 720 luma samples wide | ||
172 | */ | ||
173 | #define VB_MIN_BUFFERS 32 | ||
174 | #define VB_MIN_BUFSIZE 4147200 | ||
175 | |||
176 | static int buffer_setup(struct videobuf_queue *q, | ||
177 | unsigned int *count, unsigned int *size) | ||
178 | { | ||
179 | struct cx18_stream *s = q->priv_data; | ||
180 | struct cx18 *cx = s->cx; | ||
181 | |||
182 | *size = 2 * cx->cxhdl.width * cx->cxhdl.height; | ||
183 | if (*count == 0) | ||
184 | *count = VB_MIN_BUFFERS; | ||
185 | |||
186 | while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE) | ||
187 | (*count)--; | ||
188 | |||
189 | q->field = V4L2_FIELD_INTERLACED; | ||
190 | q->last = V4L2_FIELD_INTERLACED; | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int buffer_prepare(struct videobuf_queue *q, | ||
196 | struct videobuf_buffer *vb, | ||
197 | enum v4l2_field field) | ||
198 | { | ||
199 | struct cx18_videobuf_buffer *buf = | ||
200 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
201 | struct cx18_stream *s = q->priv_data; | ||
202 | struct cx18 *cx = s->cx; | ||
203 | |||
204 | return cx18_prepare_buffer(q, s, buf, s->pixelformat, | ||
205 | cx->cxhdl.width, cx->cxhdl.height, field); | ||
206 | } | ||
207 | |||
208 | static void buffer_release(struct videobuf_queue *q, | ||
209 | struct videobuf_buffer *vb) | ||
210 | { | ||
211 | struct cx18_videobuf_buffer *buf = | ||
212 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
213 | struct cx18_stream *s = q->priv_data; | ||
214 | |||
215 | cx18_dma_free(q, s, buf); | ||
216 | } | ||
217 | |||
218 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
219 | { | ||
220 | struct cx18_videobuf_buffer *buf = | ||
221 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
222 | struct cx18_stream *s = q->priv_data; | ||
223 | |||
224 | buf->vb.state = VIDEOBUF_QUEUED; | ||
225 | |||
226 | list_add_tail(&buf->vb.queue, &s->vb_capture); | ||
227 | } | ||
228 | |||
229 | static struct videobuf_queue_ops cx18_videobuf_qops = { | ||
230 | .buf_setup = buffer_setup, | ||
231 | .buf_prepare = buffer_prepare, | ||
232 | .buf_queue = buffer_queue, | ||
233 | .buf_release = buffer_release, | ||
234 | }; | ||
235 | |||
101 | static void cx18_stream_init(struct cx18 *cx, int type) | 236 | static void cx18_stream_init(struct cx18 *cx, int type) |
102 | { | 237 | { |
103 | struct cx18_stream *s = &cx->streams[type]; | 238 | struct cx18_stream *s = &cx->streams[type]; |
@@ -139,9 +274,18 @@ static void cx18_stream_init(struct cx18 *cx, int type) | |||
139 | s->vb_timeout.data = (unsigned long)s; | 274 | s->vb_timeout.data = (unsigned long)s; |
140 | init_timer(&s->vb_timeout); | 275 | init_timer(&s->vb_timeout); |
141 | spin_lock_init(&s->vb_lock); | 276 | spin_lock_init(&s->vb_lock); |
142 | 277 | if (type == CX18_ENC_STREAM_TYPE_YUV) { | |
143 | /* Assume the previous pixel default */ | 278 | s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
144 | s->pixelformat = V4L2_PIX_FMT_HM12; | 279 | videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops, |
280 | &cx->pci_dev->dev, &s->vbuf_q_lock, | ||
281 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
282 | V4L2_FIELD_INTERLACED, | ||
283 | sizeof(struct cx18_videobuf_buffer), | ||
284 | s, &cx->serialize_lock); | ||
285 | |||
286 | /* Assume the previous pixel default */ | ||
287 | s->pixelformat = V4L2_PIX_FMT_HM12; | ||
288 | } | ||
145 | } | 289 | } |
146 | 290 | ||
147 | static int cx18_prep_dev(struct cx18 *cx, int type) | 291 | static int cx18_prep_dev(struct cx18 *cx, int type) |
@@ -382,6 +526,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) | |||
382 | if (vdev == NULL) | 526 | if (vdev == NULL) |
383 | continue; | 527 | continue; |
384 | 528 | ||
529 | if (type == CX18_ENC_STREAM_TYPE_YUV) | ||
530 | videobuf_mmap_free(&cx->streams[type].vbuf_q); | ||
531 | |||
385 | cx18_stream_free(&cx->streams[type]); | 532 | cx18_stream_free(&cx->streams[type]); |
386 | 533 | ||
387 | /* Unregister or release device */ | 534 | /* Unregister or release device */ |
@@ -591,7 +738,10 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s) | |||
591 | * Set the MDL size to the exact size needed for one frame. | 738 | * Set the MDL size to the exact size needed for one frame. |
592 | * Use enough buffers per MDL to cover the MDL size | 739 | * Use enough buffers per MDL to cover the MDL size |
593 | */ | 740 | */ |
594 | s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; | 741 | if (s->pixelformat == V4L2_PIX_FMT_HM12) |
742 | s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; | ||
743 | else | ||
744 | s->mdl_size = 720 * s->cx->cxhdl.height * 2; | ||
595 | s->bufs_per_mdl = s->mdl_size / s->buf_size; | 745 | s->bufs_per_mdl = s->mdl_size / s->buf_size; |
596 | if (s->mdl_size % s->buf_size) | 746 | if (s->mdl_size % s->buf_size) |
597 | s->bufs_per_mdl++; | 747 | s->bufs_per_mdl++; |
@@ -744,7 +894,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
744 | * rather than the default HM12 Macroblovk 4:2:0 support. | 894 | * rather than the default HM12 Macroblovk 4:2:0 support. |
745 | */ | 895 | */ |
746 | if (captype == CAPTURE_CHANNEL_TYPE_YUV) { | 896 | if (captype == CAPTURE_CHANNEL_TYPE_YUV) { |
747 | if (s->pixelformat == V4L2_PIX_FMT_YUYV) | 897 | if (s->pixelformat == V4L2_PIX_FMT_UYVY) |
748 | cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, | 898 | cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, |
749 | s->handle, 1); | 899 | s->handle, 1); |
750 | else | 900 | else |