aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18
diff options
context:
space:
mode:
authorSteven Toth <stoth@kernellabs.com>2011-04-06 07:32:56 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-05-20 08:28:43 -0400
commitb7101de3fff596b35e45cd9fb7007caa07e97c9a (patch)
tree1c11baca827c290a1e312180204e8dc0472eabb9 /drivers/media/video/cx18
parent5ed9bd02444a00bb1e8ecc1baa8ecdb633afc126 (diff)
[media] cx18: mmap() support for raw YUV video capture
Add support for mmap method streaming of raw YUV video on cx18-based hardware, in addition to the existing support for read() streaming of raw YUV and MPEG-2 encoded video. [simon.farnsworth@onelan.co.uk: I forward-ported this from Steven's original work, done under contract to ONELAN. The original code is at http://www.kernellabs.com/hg/~stoth/cx18-videobuf] Signed-off-by: Steven Toth <stoth@kernellabs.com> Signed-off-by: Simon Farnsworth <simon.farnsworth@onelan.co.uk> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18')
-rw-r--r--drivers/media/video/cx18/Kconfig2
-rw-r--r--drivers/media/video/cx18/cx18-driver.h25
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c214
-rw-r--r--drivers/media/video/cx18/cx18-fileops.h2
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c136
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c70
-rw-r--r--drivers/media/video/cx18/cx18-streams.c23
-rw-r--r--drivers/media/video/cx18/cx23418.h6
8 files changed, 466 insertions, 12 deletions
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
index d788ad6f5c48..9c232022403a 100644
--- a/drivers/media/video/cx18/Kconfig
+++ b/drivers/media/video/cx18/Kconfig
@@ -2,6 +2,8 @@ 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 depends on RC_CORE 7 depends on RC_CORE
6 select VIDEO_TUNER 8 select VIDEO_TUNER
7 select VIDEO_TVEEPROM 9 select VIDEO_TVEEPROM
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index b86a740c68df..70e1e0401645 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -65,6 +65,10 @@
65#include "dvb_net.h" 65#include "dvb_net.h"
66#include "dvbdev.h" 66#include "dvbdev.h"
67 67
68/* Videobuf / YUV support */
69#include <media/videobuf-core.h>
70#include <media/videobuf-vmalloc.h>
71
68#ifndef CONFIG_PCI 72#ifndef CONFIG_PCI
69# error "This driver requires kernel PCI support." 73# error "This driver requires kernel PCI support."
70#endif 74#endif
@@ -403,6 +407,23 @@ struct cx18_stream {
403 struct cx18_queue q_idle; /* idle - not in rotation */ 407 struct cx18_queue q_idle; /* idle - not in rotation */
404 408
405 struct work_struct out_work_order; 409 struct work_struct out_work_order;
410
411 /* Videobuf for YUV video */
412 u32 pixelformat;
413 struct list_head vb_capture; /* video capture queue */
414 spinlock_t vb_lock;
415 struct v4l2_framebuffer fbuf;
416 v4l2_std_id tvnorm; /* selected tv norm */
417 struct timer_list vb_timeout;
418 int vbwidth;
419 int vbheight;
420};
421
422struct cx18_videobuf_buffer {
423 /* Common video buffer sub-system struct */
424 struct videobuf_buffer vb;
425 v4l2_std_id tvnorm; /* selected tv norm */
426 u32 bytes_used;
406}; 427};
407 428
408struct cx18_open_id { 429struct cx18_open_id {
@@ -410,6 +431,10 @@ struct cx18_open_id {
410 u32 open_id; 431 u32 open_id;
411 int type; 432 int type;
412 struct cx18 *cx; 433 struct cx18 *cx;
434
435 struct videobuf_queue vbuf_q;
436 spinlock_t s_lock; /* Protect vbuf_q */
437 enum v4l2_buf_type vb_type;
413}; 438};
414 439
415static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) 440static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh)
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index e9802d99439b..c74eafd67f98 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -597,6 +597,13 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
597 mutex_unlock(&cx->serialize_lock); 597 mutex_unlock(&cx->serialize_lock);
598 if (rc) 598 if (rc)
599 return rc; 599 return rc;
600
601 if ((id->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
602 (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
603 return videobuf_read_stream(&id->vbuf_q, buf, count, pos, 0,
604 filp->f_flags & O_NONBLOCK);
605 }
606
600 return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); 607 return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
601} 608}
602 609
@@ -622,6 +629,11 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
622 CX18_DEBUG_FILE("Encoder poll started capture\n"); 629 CX18_DEBUG_FILE("Encoder poll started capture\n");
623 } 630 }
624 631
632 if ((id->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
633 (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
634 return videobuf_poll_stream(filp, &id->vbuf_q, wait);
635 }
636
625 /* add stream's waitq to the poll list */ 637 /* add stream's waitq to the poll list */
626 CX18_DEBUG_HI_FILE("Encoder poll\n"); 638 CX18_DEBUG_HI_FILE("Encoder poll\n");
627 poll_wait(filp, &s->waitq, wait); 639 poll_wait(filp, &s->waitq, wait);
@@ -633,6 +645,58 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
633 return 0; 645 return 0;
634} 646}
635 647
648int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
649{
650 struct cx18_open_id *id = file->private_data;
651 struct cx18 *cx = id->cx;
652 struct cx18_stream *s = &cx->streams[id->type];
653 int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
654
655 if ((id->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
656 (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
657
658 /* Start a capture if there is none */
659 if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
660 int rc;
661
662 mutex_lock(&cx->serialize_lock);
663 rc = cx18_start_capture(id);
664 mutex_unlock(&cx->serialize_lock);
665 if (rc) {
666 CX18_DEBUG_INFO(
667 "Could not start capture for %s (%d)\n",
668 s->name, rc);
669 return -EINVAL;
670 }
671 CX18_DEBUG_FILE("Encoder poll started capture\n");
672 }
673
674 return videobuf_mmap_mapper(&id->vbuf_q, vma);
675 }
676
677 return -EINVAL;
678}
679
680void cx18_vb_timeout(unsigned long data)
681{
682 struct cx18_stream *s = (struct cx18_stream *)data;
683 struct cx18_videobuf_buffer *buf;
684 unsigned long flags;
685
686 /* Return all of the buffers in error state, so the vbi/vid inode
687 * can return from blocking.
688 */
689 spin_lock_irqsave(&s->vb_lock, flags);
690 while (!list_empty(&s->vb_capture)) {
691 buf = list_entry(s->vb_capture.next,
692 struct cx18_videobuf_buffer, vb.queue);
693 list_del(&buf->vb.queue);
694 buf->vb.state = VIDEOBUF_ERROR;
695 wake_up(&buf->vb.done);
696 }
697 spin_unlock_irqrestore(&s->vb_lock, flags);
698}
699
636void cx18_stop_capture(struct cx18_open_id *id, int gop_end) 700void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
637{ 701{
638 struct cx18 *cx = id->cx; 702 struct cx18 *cx = id->cx;
@@ -716,12 +780,150 @@ int cx18_v4l2_close(struct file *filp)
716 cx18_release_stream(s); 780 cx18_release_stream(s);
717 } else { 781 } else {
718 cx18_stop_capture(id, 0); 782 cx18_stop_capture(id, 0);
783 if (id->type == CX18_ENC_STREAM_TYPE_YUV)
784 videobuf_mmap_free(&id->vbuf_q);
719 } 785 }
720 kfree(id); 786 kfree(id);
721 mutex_unlock(&cx->serialize_lock); 787 mutex_unlock(&cx->serialize_lock);
722 return 0; 788 return 0;
723} 789}
724 790
791void 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
799static 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
852fail:
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
861static 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
881static 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
895static 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
907static 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
920static 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
725static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) 927static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
726{ 928{
727 struct cx18 *cx = s->cx; 929 struct cx18 *cx = s->cx;
@@ -740,6 +942,9 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
740 item->cx = cx; 942 item->cx = cx;
741 item->type = s->type; 943 item->type = s->type;
742 944
945 spin_lock_init(&item->s_lock);
946 item->vb_type = 0;
947
743 item->open_id = cx->open_id++; 948 item->open_id = cx->open_id++;
744 filp->private_data = &item->fh; 949 filp->private_data = &item->fh;
745 950
@@ -774,6 +979,15 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
774 /* Done! Unmute and continue. */ 979 /* Done! Unmute and continue. */
775 cx18_unmute(cx); 980 cx18_unmute(cx);
776 } 981 }
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 }
777 v4l2_fh_add(&item->fh); 991 v4l2_fh_add(&item->fh);
778 return 0; 992 return 0;
779} 993}
diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h
index 5c8fcb884f0a..b9e5110ad043 100644
--- a/drivers/media/video/cx18/cx18-fileops.h
+++ b/drivers/media/video/cx18/cx18-fileops.h
@@ -33,6 +33,8 @@ int cx18_start_capture(struct cx18_open_id *id);
33void cx18_stop_capture(struct cx18_open_id *id, int gop_end); 33void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
34void cx18_mute(struct cx18 *cx); 34void cx18_mute(struct cx18 *cx);
35void cx18_unmute(struct cx18 *cx); 35void cx18_unmute(struct cx18 *cx);
36int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma);
37void cx18_vb_timeout(unsigned long data);
36 38
37/* Shared with cx18-alsa module */ 39/* Shared with cx18-alsa module */
38int cx18_claim_stream(struct cx18_open_id *id, int type); 40int cx18_claim_stream(struct cx18_open_id *id, int type);
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 4f041c033c54..777d7265c8a8 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -41,6 +41,18 @@
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
44static 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
44u16 cx18_service2vbi(int type) 56u16 cx18_service2vbi(int type)
45{ 57{
46 switch (type) { 58 switch (type) {
@@ -150,6 +162,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
150{ 162{
151 struct cx18_open_id *id = fh2id(fh); 163 struct cx18_open_id *id = fh2id(fh);
152 struct cx18 *cx = id->cx; 164 struct cx18 *cx = id->cx;
165 struct cx18_stream *s = &cx->streams[id->type];
153 struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; 166 struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
154 167
155 pixfmt->width = cx->cxhdl.width; 168 pixfmt->width = cx->cxhdl.width;
@@ -158,7 +171,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
158 pixfmt->field = V4L2_FIELD_INTERLACED; 171 pixfmt->field = V4L2_FIELD_INTERLACED;
159 pixfmt->priv = 0; 172 pixfmt->priv = 0;
160 if (id->type == CX18_ENC_STREAM_TYPE_YUV) { 173 if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
161 pixfmt->pixelformat = V4L2_PIX_FMT_HM12; 174 pixfmt->pixelformat = s->pixelformat;
162 /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */ 175 /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
163 pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; 176 pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
164 pixfmt->bytesperline = 720; 177 pixfmt->bytesperline = 720;
@@ -237,7 +250,6 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
237 h = min(h, cx->is_50hz ? 576 : 480); 250 h = min(h, cx->is_50hz ? 576 : 480);
238 h = max(h, min_h); 251 h = max(h, min_h);
239 252
240 cx18_g_fmt_vid_cap(file, fh, fmt);
241 fmt->fmt.pix.width = w; 253 fmt->fmt.pix.width = w;
242 fmt->fmt.pix.height = h; 254 fmt->fmt.pix.height = h;
243 return 0; 255 return 0;
@@ -274,6 +286,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
274 struct cx18_open_id *id = fh2id(fh); 286 struct cx18_open_id *id = fh2id(fh);
275 struct cx18 *cx = id->cx; 287 struct cx18 *cx = id->cx;
276 struct v4l2_mbus_framefmt mbus_fmt; 288 struct v4l2_mbus_framefmt mbus_fmt;
289 struct cx18_stream *s = &cx->streams[id->type];
277 int ret; 290 int ret;
278 int w, h; 291 int w, h;
279 292
@@ -283,6 +296,10 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
283 w = fmt->fmt.pix.width; 296 w = fmt->fmt.pix.width;
284 h = fmt->fmt.pix.height; 297 h = fmt->fmt.pix.height;
285 298
299 s->pixelformat = fmt->fmt.pix.pixelformat;
300 s->vbheight = h;
301 s->vbwidth = w;
302
286 if (cx->cxhdl.width == w && cx->cxhdl.height == h) 303 if (cx->cxhdl.width == w && cx->cxhdl.height == h)
287 return 0; 304 return 0;
288 305
@@ -540,16 +557,7 @@ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
540static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, 557static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
541 struct v4l2_fmtdesc *fmt) 558 struct v4l2_fmtdesc *fmt)
542{ 559{
543 static struct v4l2_fmtdesc formats[] = { 560 if (fmt->index > ARRAY_SIZE(formats) - 1)
544 { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
545 "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
546 },
547 { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
548 "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
549 }
550 };
551
552 if (fmt->index > 1)
553 return -EINVAL; 561 return -EINVAL;
554 *fmt = formats[fmt->index]; 562 *fmt = formats[fmt->index];
555 return 0; 563 return 0;
@@ -863,6 +871,104 @@ static int cx18_g_enc_index(struct file *file, void *fh,
863 return 0; 871 return 0;
864} 872}
865 873
874static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id)
875{
876 struct videobuf_queue *q = NULL;
877
878 switch (id->vb_type) {
879 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
880 q = &id->vbuf_q;
881 break;
882 case V4L2_BUF_TYPE_VBI_CAPTURE:
883 break;
884 default:
885 break;
886 }
887 return q;
888}
889
890static int cx18_streamon(struct file *file, void *priv,
891 enum v4l2_buf_type type)
892{
893 struct cx18_open_id *id = file->private_data;
894 struct cx18 *cx = id->cx;
895 struct cx18_stream *s = &cx->streams[id->type];
896
897 /* Start the hardware only if we're the video device */
898 if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
899 (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
900 return -EINVAL;
901
902 if (id->type != CX18_ENC_STREAM_TYPE_YUV)
903 return -EINVAL;
904
905 /* Establish a buffer timeout */
906 mod_timer(&s->vb_timeout, jiffies + (HZ * 2));
907
908 return videobuf_streamon(cx18_vb_queue(id));
909}
910
911static int cx18_streamoff(struct file *file, void *priv,
912 enum v4l2_buf_type type)
913{
914 struct cx18_open_id *id = file->private_data;
915
916 /* Start the hardware only if we're the video device */
917 if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
918 (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
919 return -EINVAL;
920
921 if (id->type != CX18_ENC_STREAM_TYPE_YUV)
922 return -EINVAL;
923
924 return videobuf_streamoff(cx18_vb_queue(id));
925}
926
927static int cx18_reqbufs(struct file *file, void *priv,
928 struct v4l2_requestbuffers *rb)
929{
930 struct cx18_open_id *id = file->private_data;
931
932 if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
933 (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
934 return -EINVAL;
935
936 return videobuf_reqbufs(cx18_vb_queue(id), rb);
937}
938
939static int cx18_querybuf(struct file *file, void *priv,
940 struct v4l2_buffer *b)
941{
942 struct cx18_open_id *id = file->private_data;
943
944 if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
945 (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
946 return -EINVAL;
947
948 return videobuf_querybuf(cx18_vb_queue(id), b);
949}
950
951static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
952{
953 struct cx18_open_id *id = file->private_data;
954
955 if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
956 (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
957 return -EINVAL;
958
959 return videobuf_qbuf(cx18_vb_queue(id), b);
960}
961
962static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
963{
964 struct cx18_open_id *id = file->private_data;
965 if ((id->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
966 (id->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
967 return -EINVAL;
968
969 return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK);
970}
971
866static int cx18_encoder_cmd(struct file *file, void *fh, 972static int cx18_encoder_cmd(struct file *file, void *fh,
867 struct v4l2_encoder_cmd *enc) 973 struct v4l2_encoder_cmd *enc)
868{ 974{
@@ -1081,6 +1187,12 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
1081 .vidioc_s_register = cx18_s_register, 1187 .vidioc_s_register = cx18_s_register,
1082#endif 1188#endif
1083 .vidioc_default = cx18_default, 1189 .vidioc_default = cx18_default,
1190 .vidioc_streamon = cx18_streamon,
1191 .vidioc_streamoff = cx18_streamoff,
1192 .vidioc_reqbufs = cx18_reqbufs,
1193 .vidioc_querybuf = cx18_querybuf,
1194 .vidioc_qbuf = cx18_qbuf,
1195 .vidioc_dqbuf = cx18_dqbuf,
1084}; 1196};
1085 1197
1086void cx18_set_funcs(struct video_device *vdev) 1198void cx18_set_funcs(struct video_device *vdev)
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 9605d54bd083..d4d88738d893 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -81,6 +81,7 @@ static const struct cx18_api_info api_info[] = {
81 API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), 81 API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0),
82 API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), 82 API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0),
83 API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), 83 API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
84 API_ENTRY(CPU, CX18_CPU_SET_VFC_PARAM, 0),
84 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), 85 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
85 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), 86 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
86 API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), 87 API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW),
@@ -158,6 +159,72 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
158 } 159 }
159} 160}
160 161
162static void cx18_mdl_send_to_videobuf(struct cx18_stream *s,
163 struct cx18_mdl *mdl)
164{
165 struct cx18_videobuf_buffer *vb_buf;
166 struct cx18_buffer *buf;
167 u8 *p, u;
168 u32 offset = 0;
169 int dispatch = 0;
170 int i;
171
172 if (mdl->bytesused == 0)
173 return;
174
175 /* Acquire a videobuf buffer, clone to and and release it */
176 spin_lock(&s->vb_lock);
177 if (list_empty(&s->vb_capture))
178 goto out;
179
180 vb_buf = list_entry(s->vb_capture.next, struct cx18_videobuf_buffer,
181 vb.queue);
182
183 p = videobuf_to_vmalloc(&vb_buf->vb);
184 if (!p)
185 goto out;
186
187 offset = vb_buf->bytes_used;
188 list_for_each_entry(buf, &mdl->buf_list, list) {
189 if (buf->bytesused == 0)
190 break;
191
192 if ((offset + buf->bytesused) <= vb_buf->vb.bsize) {
193 memcpy(p + offset, buf->buf, buf->bytesused);
194 offset += buf->bytesused;
195 vb_buf->bytes_used += buf->bytesused;
196 }
197 }
198
199 /* If we've filled the buffer as per the callers res then dispatch it */
200 if (vb_buf->bytes_used >= (vb_buf->vb.width * vb_buf->vb.height * 2)) {
201 dispatch = 1;
202 vb_buf->bytes_used = 0;
203 }
204
205 /* */
206 if (dispatch) {
207
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);
219 vb_buf->vb.state = VIDEOBUF_DONE;
220 wake_up(&vb_buf->vb.done);
221 }
222
223 mod_timer(&s->vb_timeout, jiffies + (HZ / 10));
224
225out:
226 spin_unlock(&s->vb_lock);
227}
161 228
162static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s, 229static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s,
163 struct cx18_mdl *mdl) 230 struct cx18_mdl *mdl)
@@ -263,6 +330,9 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
263 } else { 330 } else {
264 cx18_enqueue(s, mdl, &s->q_full); 331 cx18_enqueue(s, mdl, &s->q_full);
265 } 332 }
333 } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) {
334 cx18_mdl_send_to_videobuf(s, mdl);
335 cx18_enqueue(s, mdl, &s->q_free);
266 } else { 336 } else {
267 cx18_enqueue(s, mdl, &s->q_full); 337 cx18_enqueue(s, mdl, &s->q_full);
268 if (s->type == CX18_ENC_STREAM_TYPE_IDX) 338 if (s->type == CX18_ENC_STREAM_TYPE_IDX)
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 6fbc356113c1..eeb455a8b726 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -44,6 +44,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = {
44 .unlocked_ioctl = cx18_v4l2_ioctl, 44 .unlocked_ioctl = cx18_v4l2_ioctl,
45 .release = cx18_v4l2_close, 45 .release = cx18_v4l2_close,
46 .poll = cx18_v4l2_enc_poll, 46 .poll = cx18_v4l2_enc_poll,
47 .mmap = cx18_v4l2_mmap,
47}; 48};
48 49
49/* offset from 0 to register ts v4l2 minors on */ 50/* offset from 0 to register ts v4l2 minors on */
@@ -132,6 +133,15 @@ static void cx18_stream_init(struct cx18 *cx, int type)
132 cx18_queue_init(&s->q_idle); 133 cx18_queue_init(&s->q_idle);
133 134
134 INIT_WORK(&s->out_work_order, cx18_out_work_handler); 135 INIT_WORK(&s->out_work_order, cx18_out_work_handler);
136
137 INIT_LIST_HEAD(&s->vb_capture);
138 s->vb_timeout.function = cx18_vb_timeout;
139 s->vb_timeout.data = (unsigned long)s;
140 init_timer(&s->vb_timeout);
141 spin_lock_init(&s->vb_lock);
142
143 /* Assume the previous pixel default */
144 s->pixelformat = V4L2_PIX_FMT_HM12;
135} 145}
136 146
137static int cx18_prep_dev(struct cx18 *cx, int type) 147static int cx18_prep_dev(struct cx18 *cx, int type)
@@ -729,6 +739,19 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
729 test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) 739 test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
730 cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, 740 cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
731 (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); 741 (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1);
742
743 /* Enable the Video Format Converter for UYVY 4:2:2 support,
744 * rather than the default HM12 Macroblovk 4:2:0 support.
745 */
746 if (captype == CAPTURE_CHANNEL_TYPE_YUV) {
747 if (s->pixelformat == V4L2_PIX_FMT_YUYV)
748 cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
749 s->handle, 1);
750 else
751 /* If in doubt, default to HM12 */
752 cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
753 s->handle, 0);
754 }
732 } 755 }
733 756
734 if (atomic_read(&cx->tot_capturing) == 0) { 757 if (atomic_read(&cx->tot_capturing) == 0) {
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
index 935f557acbd0..767a8d23e3f2 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/video/cx18/cx23418.h
@@ -342,6 +342,12 @@
342 ReturnCode */ 342 ReturnCode */
343#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022) 343#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022)
344 344
345/* Description: Set VFC parameters
346 IN[0] - task handle
347 IN[1] - VFC enable flag, 1 - enable, 0 - disable
348*/
349#define CX18_CPU_SET_VFC_PARAM (CPU_CMD_MASK_CAPTURE | 0x0023)
350
345/* Below is the list of commands related to the data exchange */ 351/* Below is the list of commands related to the data exchange */
346#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000) 352#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000)
347 353