aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ivtv
diff options
context:
space:
mode:
authorIan Armstrong <ian@iarmst.demon.co.uk>2007-11-05 12:27:09 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-01-25 16:03:11 -0500
commit77aded6ba51f01335840ce8e18b413067810b68e (patch)
tree2763dd287dd0f40bed5a1ba5262e0e13f58bf4e4 /drivers/media/video/ivtv
parent3b5c1c8e71eb8fe2297a5884db59108e3c8b44c5 (diff)
V4L/DVB (6717): ivtv: Initial merge of video48 yuv handling into the IVTV_IOC_DMA_FRAME framework
Previously, all yuv data written to /dev/video48 had only basic support with no double buffering to avoid display tearing. With this patch, yuv frames written to video48 are now handled by the existing IVTV_IOC_DMA_FRAME framework. As such, the frames are hardware buffered to avoid tearing, and honour scaling mode & field order options. Unlike the proprietary IVTV_IOC_DMA_FRAME ioctl, all parameters are controlled by the V4L2 API. Due to mpeg & yuv output restrictions being different, their V4L2 output controls have been separated. To control the yuv output, the V4L2 calls must be done via video48. If the ivtvfb module is loaded, there will be one side effect to this merge. The yuv output window will be constrained to the visible framebuffer area. In the event that a virtual framebuffer size is being used, the limit to the output size will be the virtual dimensions, but only the portion that falls within the currently visible area of the framebuffer will be shown. Like the IVTV_IOC_DMA_FRAME ioctl, the supplied frames must be padded to 720 pixels wide. However the height must only be padded up the nearest multiple of 32. This would mean an image of 102 lines must be padded to 128. As long as the true source image size is given, the padding will not be visible in the final output. Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk> Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/ivtv')
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c6
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h7
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c23
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c120
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c26
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c17
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.c58
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.h5
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c4
9 files changed, 196 insertions, 70 deletions
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index e3020f456641..7c600d0f48cd 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1117,6 +1117,12 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
1117 itv->is_50hz = 1; 1117 itv->is_50hz = 1;
1118 itv->is_out_50hz = 1; 1118 itv->is_out_50hz = 1;
1119 } 1119 }
1120
1121 itv->yuv_info.osd_full_w = 720;
1122 itv->yuv_info.osd_full_h = itv->is_out_50hz ? 576 : 480;
1123 itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w;
1124 itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h;
1125
1120 itv->params.video_gop_size = itv->is_60hz ? 15 : 12; 1126 itv->params.video_gop_size = itv->is_60hz ? 15 : 12;
1121 1127
1122 itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000; 1128 itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000;
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 0e4ad29821e0..19a9b3bac190 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -466,6 +466,9 @@ struct yuv_playback_info
466 u32 osd_vis_w; 466 u32 osd_vis_w;
467 u32 osd_vis_h; 467 u32 osd_vis_h;
468 468
469 u32 osd_full_w;
470 u32 osd_full_h;
471
469 int decode_height; 472 int decode_height;
470 473
471 int lace_mode; 474 int lace_mode;
@@ -491,6 +494,10 @@ struct yuv_playback_info
491 494
492 u8 draw_frame; /* PVR350 buffer to draw into */ 495 u8 draw_frame; /* PVR350 buffer to draw into */
493 u8 max_frames_buffered; /* Maximum number of frames to buffer */ 496 u8 max_frames_buffered; /* Maximum number of frames to buffer */
497
498 struct v4l2_rect main_rect;
499 u32 v4l2_src_w;
500 u32 v4l2_src_h;
494}; 501};
495 502
496#define IVTV_VBI_FRAMES 32 503#define IVTV_VBI_FRAMES 32
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 58ad0d9c680a..6fb96f19a866 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -581,6 +581,24 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
581 set_bit(IVTV_F_S_APPL_IO, &s->s_flags); 581 set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
582 582
583retry: 583retry:
584 /* If possible, just DMA the entire frame - Check the data transfer size
585 since we may get here before the stream has been fully set-up */
586 if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
587 while (count >= itv->dma_data_req_size) {
588 if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) {
589 bytes_written += itv->dma_data_req_size;
590 user_buf += itv->dma_data_req_size;
591 count -= itv->dma_data_req_size;
592 } else {
593 break;
594 }
595 }
596 if (count == 0) {
597 IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
598 return bytes_written;
599 }
600 }
601
584 for (;;) { 602 for (;;) {
585 /* Gather buffers */ 603 /* Gather buffers */
586 while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io))) 604 while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io)))
@@ -660,6 +678,9 @@ retry:
660 if (s->q_full.length >= itv->dma_data_req_size) { 678 if (s->q_full.length >= itv->dma_data_req_size) {
661 int got_sig; 679 int got_sig;
662 680
681 if (mode == OUT_YUV)
682 ivtv_yuv_setup_stream_frame(itv);
683
663 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); 684 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
664 while (!(got_sig = signal_pending(current)) && 685 while (!(got_sig = signal_pending(current)) &&
665 test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { 686 test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
@@ -946,7 +967,7 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
946 set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); 967 set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
947 /* For yuv, we need to know the dma size before we start */ 968 /* For yuv, we need to know the dma size before we start */
948 itv->dma_data_req_size = 969 itv->dma_data_req_size =
949 itv->params.width * itv->params.height * 3 / 2; 970 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
950 itv->yuv_info.stream_size = 0; 971 itv->yuv_info.stream_size = 0;
951 } 972 }
952 return 0; 973 return 0;
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index fd6826f472e3..57eb8dfe53fa 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -372,7 +372,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
372 fmt->fmt.pix.height = itv->main_rect.height; 372 fmt->fmt.pix.height = itv->main_rect.height;
373 fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 373 fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
374 fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; 374 fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
375 if (itv->output_mode == OUT_UDMA_YUV) { 375 if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
376 switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { 376 switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
377 case IVTV_YUV_MODE_INTERLACED: 377 case IVTV_YUV_MODE_INTERLACED:
378 fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? 378 fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
@@ -386,14 +386,13 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
386 break; 386 break;
387 } 387 }
388 fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; 388 fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
389 fmt->fmt.pix.bytesperline = 720;
390 fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
391 fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
389 /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ 392 /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
390 fmt->fmt.pix.sizeimage = 393 fmt->fmt.pix.sizeimage =
391 fmt->fmt.pix.height * fmt->fmt.pix.width + 394 1080 * ((fmt->fmt.pix.height + 31) & ~31);
392 fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); 395 } else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) {
393 }
394 else if (itv->output_mode == OUT_YUV ||
395 streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
396 streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
397 fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; 396 fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
398 /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ 397 /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
399 fmt->fmt.pix.sizeimage = 398 fmt->fmt.pix.sizeimage =
@@ -490,6 +489,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
490static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, 489static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
491 struct v4l2_format *fmt, int set_fmt) 490 struct v4l2_format *fmt, int set_fmt)
492{ 491{
492 struct yuv_playback_info *yi = &itv->yuv_info;
493 struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; 493 struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
494 u16 set; 494 u16 set;
495 495
@@ -505,39 +505,52 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
505 r.width = fmt->fmt.pix.width; 505 r.width = fmt->fmt.pix.width;
506 r.height = fmt->fmt.pix.height; 506 r.height = fmt->fmt.pix.height;
507 ivtv_get_fmt(itv, streamtype, fmt); 507 ivtv_get_fmt(itv, streamtype, fmt);
508 if (itv->output_mode != OUT_UDMA_YUV) { 508 fmt->fmt.pix.width = r.width;
509 /* TODO: would setting the rect also be valid for this mode? */ 509 fmt->fmt.pix.height = r.height;
510 fmt->fmt.pix.width = r.width; 510 if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
511 fmt->fmt.pix.height = r.height;
512 }
513 if (itv->output_mode == OUT_UDMA_YUV) {
514 /* TODO: add checks for validity */
515 fmt->fmt.pix.field = field; 511 fmt->fmt.pix.field = field;
512 if (fmt->fmt.pix.width < 2)
513 fmt->fmt.pix.width = 2;
514 if (fmt->fmt.pix.width > 720)
515 fmt->fmt.pix.width = 720;
516 if (fmt->fmt.pix.height < 2)
517 fmt->fmt.pix.height = 2;
518 if (fmt->fmt.pix.height > 576)
519 fmt->fmt.pix.height = 576;
516 } 520 }
517 if (set_fmt) { 521 if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
518 if (itv->output_mode == OUT_UDMA_YUV) { 522 /* Return now if we already have some frame data */
519 switch (field) { 523 if (yi->stream_size)
520 case V4L2_FIELD_NONE: 524 return -EBUSY;
521 itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
522 break;
523 case V4L2_FIELD_ANY:
524 itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO;
525 break;
526 case V4L2_FIELD_INTERLACED_BT:
527 itv->yuv_info.lace_mode =
528 IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
529 break;
530 case V4L2_FIELD_INTERLACED_TB:
531 default:
532 itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED;
533 break;
534 }
535 itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
536 525
537 /* Force update of yuv registers */ 526 yi->v4l2_src_w = r.width;
538 itv->yuv_info.yuv_forced_update = 1; 527 yi->v4l2_src_h = r.height;
539 return 0; 528
529 switch (field) {
530 case V4L2_FIELD_NONE:
531 yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
532 break;
533 case V4L2_FIELD_ANY:
534 yi->lace_mode = IVTV_YUV_MODE_AUTO;
535 break;
536 case V4L2_FIELD_INTERLACED_BT:
537 yi->lace_mode =
538 IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
539 break;
540 case V4L2_FIELD_INTERLACED_TB:
541 default:
542 yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
543 break;
540 } 544 }
545 yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
546
547 if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
548 itv->dma_data_req_size =
549 1080 * ((yi->v4l2_src_h + 31) & ~31);
550
551 /* Force update of yuv registers */
552 yi->yuv_forced_update = 1;
553 return 0;
541 } 554 }
542 return 0; 555 return 0;
543 } 556 }
@@ -703,8 +716,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
703{ 716{
704 struct ivtv_open_id *id = NULL; 717 struct ivtv_open_id *id = NULL;
705 u32 data[CX2341X_MBOX_MAX_DATA]; 718 u32 data[CX2341X_MBOX_MAX_DATA];
719 int streamtype = 0;
706 720
707 if (filp) id = (struct ivtv_open_id *)filp->private_data; 721 if (filp) {
722 id = (struct ivtv_open_id *)filp->private_data;
723 streamtype = id->type;
724 }
708 725
709 switch (cmd) { 726 switch (cmd) {
710 case VIDIOC_G_PRIORITY: 727 case VIDIOC_G_PRIORITY:
@@ -822,6 +839,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
822 cropcap->bounds.height = itv->is_50hz ? 576 : 480; 839 cropcap->bounds.height = itv->is_50hz ? 576 : 480;
823 cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; 840 cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
824 cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; 841 cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
842 } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
843 cropcap->bounds.width = itv->yuv_info.osd_full_w;
844 cropcap->bounds.height = itv->yuv_info.osd_full_h;
845 cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
846 cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
825 } else { 847 } else {
826 cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; 848 cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
827 cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; 849 cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
@@ -836,10 +858,15 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
836 858
837 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && 859 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
838 (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { 860 (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
839 if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, 861 if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
840 crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { 862 itv->yuv_info.main_rect = crop->c;
841 itv->main_rect = crop->c;
842 return 0; 863 return 0;
864 } else {
865 if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
866 crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
867 itv->main_rect = crop->c;
868 return 0;
869 }
843 } 870 }
844 return -EINVAL; 871 return -EINVAL;
845 } 872 }
@@ -853,7 +880,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
853 880
854 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && 881 if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
855 (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { 882 (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
856 crop->c = itv->main_rect; 883 if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
884 crop->c = itv->yuv_info.main_rect;
885 else
886 crop->c = itv->main_rect;
857 return 0; 887 return 0;
858 } 888 }
859 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 889 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -864,7 +894,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
864 case VIDIOC_ENUM_FMT: { 894 case VIDIOC_ENUM_FMT: {
865 static struct v4l2_fmtdesc formats[] = { 895 static struct v4l2_fmtdesc formats[] = {
866 { 0, 0, 0, 896 { 0, 0, 0,
867 "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, 897 "HM12 (YUV 4:2:2)", V4L2_PIX_FMT_HM12,
868 { 0, 0, 0, 0 } 898 { 0, 0, 0, 0 }
869 }, 899 },
870 { 1, 0, V4L2_FMT_FLAG_COMPRESSED, 900 { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
@@ -1043,6 +1073,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
1043 itv->main_rect.height = itv->params.height; 1073 itv->main_rect.height = itv->params.height;
1044 ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, 1074 ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
1045 720, itv->main_rect.height, 0, 0); 1075 720, itv->main_rect.height, 0, 0);
1076 itv->yuv_info.main_rect = itv->main_rect;
1077 if (!itv->osd_info) {
1078 itv->yuv_info.osd_full_w = 720;
1079 itv->yuv_info.osd_full_h =
1080 itv->is_out_50hz ? 576 : 480;
1081 }
1046 } 1082 }
1047 break; 1083 break;
1048 } 1084 }
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index dd0dd8d126de..ebc200320e6f 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -302,8 +302,11 @@ static void dma_post(struct ivtv_stream *s)
302void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) 302void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
303{ 303{
304 struct ivtv *itv = s->itv; 304 struct ivtv *itv = s->itv;
305 struct yuv_playback_info *yi = &itv->yuv_info;
306 u8 frame = yi->draw_frame;
307 struct yuv_frame_info *f = &yi->new_frame_info[frame];
305 struct ivtv_buffer *buf; 308 struct ivtv_buffer *buf;
306 u32 y_size = itv->params.height * itv->params.width; 309 u32 y_size = 720 * ((f->src_h + 31) & ~31);
307 u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; 310 u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
308 int y_done = 0; 311 int y_done = 0;
309 int bytes_written = 0; 312 int bytes_written = 0;
@@ -311,6 +314,18 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
311 int idx = 0; 314 int idx = 0;
312 315
313 IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); 316 IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
317
318 /* Insert buffer block for YUV if needed */
319 if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) {
320 if (yi->blanking_dmaptr) {
321 s->sg_pending[idx].src = yi->blanking_dmaptr;
322 s->sg_pending[idx].dst = offset;
323 s->sg_pending[idx].size = 720 * 16;
324 }
325 offset += 720 * 16;
326 idx++;
327 }
328
314 list_for_each_entry(buf, &s->q_predma.list, list) { 329 list_for_each_entry(buf, &s->q_predma.list, list) {
315 /* YUV UV Offset from Y Buffer */ 330 /* YUV UV Offset from Y Buffer */
316 if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && 331 if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done &&
@@ -713,8 +728,11 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
713 ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data); 728 ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data);
714 729
715 if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { 730 if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
716 itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2; 731 itv->dma_data_req_size =
717 itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0]; 732 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
733 itv->dma_data_req_offset = data[1];
734 if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0)
735 ivtv_yuv_frame_complete(itv);
718 s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; 736 s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
719 } 737 }
720 else { 738 else {
@@ -728,6 +746,8 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
728 set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); 746 set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
729 } 747 }
730 else { 748 else {
749 if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
750 ivtv_yuv_setup_stream_frame(itv);
731 clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); 751 clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
732 ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); 752 ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
733 ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0); 753 ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0);
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index a5bfbd98a490..3ca2a1a62a71 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -661,27 +661,12 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
661 661
662 IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); 662 IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
663 663
664 /* Clear Streamoff */
665 if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
666 /* Initialize Decoder */
667 /* Reprogram Decoder YUV Buffers for YUV */
668 write_reg(yuv_offset[0] >> 4, 0x82c);
669 write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
670 write_reg(yuv_offset[0] >> 4, 0x834);
671 write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
672
673 write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24);
674
675 write_reg_sync(0x00108080, 0x2898);
676 /* Enable YUV decoder output */
677 write_reg_sync(0x01, IVTV_REG_VDM);
678 }
679
680 ivtv_setup_v4l2_decode_stream(s); 664 ivtv_setup_v4l2_decode_stream(s);
681 665
682 /* set dma size to 65536 bytes */ 666 /* set dma size to 65536 bytes */
683 ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); 667 ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
684 668
669 /* Clear Streamoff */
685 clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); 670 clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
686 671
687 /* Zero out decoder counters */ 672 /* Zero out decoder counters */
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index cd42db9b5a15..711ce5b5a20f 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -1035,17 +1035,11 @@ void ivtv_yuv_frame_complete(struct ivtv *itv)
1035 (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS); 1035 (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
1036} 1036}
1037 1037
1038int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) 1038int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1039{ 1039{
1040 DEFINE_WAIT(wait); 1040 DEFINE_WAIT(wait);
1041 int rc = 0; 1041 int rc = 0;
1042 int got_sig = 0; 1042 int got_sig = 0;
1043
1044 IVTV_DEBUG_INFO("yuv_prep_frame\n");
1045
1046 ivtv_yuv_next_free(itv);
1047 ivtv_yuv_setup_frame(itv, args);
1048
1049 /* DMA the frame */ 1043 /* DMA the frame */
1050 mutex_lock(&itv->udma.lock); 1044 mutex_lock(&itv->udma.lock);
1051 1045
@@ -1084,6 +1078,56 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1084 return rc; 1078 return rc;
1085} 1079}
1086 1080
1081/* Setup frame according to V4L2 parameters */
1082void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
1083{
1084 struct yuv_playback_info *yi = &itv->yuv_info;
1085 struct ivtv_dma_frame dma_args;
1086
1087 ivtv_yuv_next_free(itv);
1088
1089 /* Copy V4L2 parameters to an ivtv_dma_frame struct... */
1090 dma_args.y_source = 0L;
1091 dma_args.uv_source = 0L;
1092 dma_args.src.left = 0;
1093 dma_args.src.top = 0;
1094 dma_args.src.width = yi->v4l2_src_w;
1095 dma_args.src.height = yi->v4l2_src_h;
1096 dma_args.dst = yi->main_rect;
1097 dma_args.src_width = yi->v4l2_src_w;
1098 dma_args.src_height = yi->v4l2_src_h;
1099
1100 /* ... and use the same setup routine as ivtv_yuv_prep_frame */
1101 ivtv_yuv_setup_frame(itv, &dma_args);
1102
1103 if (!itv->dma_data_req_offset)
1104 itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
1105}
1106
1107/* Attempt to dma a frame from a user buffer */
1108int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src)
1109{
1110 struct yuv_playback_info *yi = &itv->yuv_info;
1111 struct ivtv_dma_frame dma_args;
1112
1113 ivtv_yuv_setup_stream_frame(itv);
1114
1115 /* We only need to supply source addresses for this */
1116 dma_args.y_source = src;
1117 dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
1118 return ivtv_yuv_udma_frame(itv, &dma_args);
1119}
1120
1121/* IVTV_IOC_DMA_FRAME ioctl handler */
1122int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
1123{
1124 IVTV_DEBUG_INFO("yuv_prep_frame\n");
1125
1126 ivtv_yuv_next_free(itv);
1127 ivtv_yuv_setup_frame(itv, args);
1128 return ivtv_yuv_udma_frame(itv, args);
1129}
1130
1087void ivtv_yuv_close(struct ivtv *itv) 1131void ivtv_yuv_close(struct ivtv *itv)
1088{ 1132{
1089 int h_filter, v_filter_1, v_filter_2; 1133 int h_filter, v_filter_1, v_filter_2;
diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h
index 3b290927d367..2fe5f1250762 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.h
+++ b/drivers/media/video/ivtv/ivtv-yuv.h
@@ -34,8 +34,11 @@
34extern const u32 yuv_offset[IVTV_YUV_BUFFERS]; 34extern const u32 yuv_offset[IVTV_YUV_BUFFERS];
35 35
36int ivtv_yuv_filter_check(struct ivtv *itv); 36int ivtv_yuv_filter_check(struct ivtv *itv);
37void ivtv_yuv_setup_stream_frame(struct ivtv *itv);
38int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src);
39void ivtv_yuv_frame_complete(struct ivtv *itv);
37int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); 40int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
38void ivtv_yuv_close(struct ivtv *itv); 41void ivtv_yuv_close(struct ivtv *itv);
39void ivtv_yuv_work_handler (struct ivtv *itv); 42void ivtv_yuv_work_handler(struct ivtv *itv);
40 43
41#endif 44#endif
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 52ffd154a3d8..1a73038ea811 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -504,6 +504,10 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
504 504
505 ivtvfb_set_display_window(itv, &ivtv_window); 505 ivtvfb_set_display_window(itv, &ivtv_window);
506 506
507 /* Pass screen size back to yuv handler */
508 itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
509 itv->yuv_info.osd_full_h = ivtv_osd.lines;
510
507 /* Force update of yuv registers */ 511 /* Force update of yuv registers */
508 itv->yuv_info.yuv_forced_update = 1; 512 itv->yuv_info.yuv_forced_update = 1;
509 513