aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/bt8xx/bttv-risc.c
diff options
context:
space:
mode:
authorMichael Schimek <mschimek@gmx.at>2007-01-18 14:17:39 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-02-21 10:34:36 -0500
commite5bd0260e7d3d806e66c12859f50733dca43bbcf (patch)
tree7a726da52b8155357a08e4feb7e0e79084673fa0 /drivers/media/video/bt8xx/bttv-risc.c
parent13071f0a58f285eee81f63c917078bb2a48cf51e (diff)
V4L/DVB (5077): Bttv cropping support
Adds the missing VIDIOC_CROPCAP, G_CROP and S_CROP ioctls, permitting applications to capture or overlay a subsection of the picture or to extend the capture window beyond active video, into the VBI area and the horizontal blanking. VBI capturing can start and end on any line, including the picture area, and apps can capture different lines of each field and single fields. For compatibility with existing applications, the open() function resets the cropping and VBI capturing parameters and a VIDIOC_S_CROP call is necessary to actually enable cropping. Regrettably in PAL-M, PAL-N, PAL-Nc and NTSC-JP mode the maximum image width will increase from 640 and 768 to 747 and 923 pixels respectively. Like the VBI changes however, this should only affect applications which depend on former driver limitations, such as never getting more than 640 pixels regardless of the requested width. Also, new freedoms require additional checks for conflicts and some applications may not expect an EBUSY error from the VIDIOC_QBUF and VIDIOCMCAPTURE ioctls. These errors should be rare though. So far, the patch has been tested on a UP machine with a bt878 in PAL- BGHI and NTSC-M mode using xawtv, tvtime, mplayer/mencoder, zapping/ libzvbi and these tools: http://zapping.sf.net/bttv-crop-test.tar.bz2 I'd be grateful about comments or bug reports. Signed-off-by: Michael H. Schimek <mschimek@gmx.at> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/bt8xx/bttv-risc.c')
-rw-r--r--drivers/media/video/bt8xx/bttv-risc.c171
1 files changed, 140 insertions, 31 deletions
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index afcfe71e3792..e7104d9cb4bd 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -43,7 +43,8 @@ int
43bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, 43bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
44 struct scatterlist *sglist, 44 struct scatterlist *sglist,
45 unsigned int offset, unsigned int bpl, 45 unsigned int offset, unsigned int bpl,
46 unsigned int padding, unsigned int lines) 46 unsigned int padding, unsigned int skip_lines,
47 unsigned int store_lines)
47{ 48{
48 u32 instructions,line,todo; 49 u32 instructions,line,todo;
49 struct scatterlist *sg; 50 struct scatterlist *sg;
@@ -54,9 +55,11 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
54 one write per scan line + sync + jump (all 2 dwords). padding 55 one write per scan line + sync + jump (all 2 dwords). padding
55 can cause next bpl to start close to a page border. First DMA 56 can cause next bpl to start close to a page border. First DMA
56 region may be smaller than PAGE_SIZE */ 57 region may be smaller than PAGE_SIZE */
57 instructions = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines; 58 instructions = skip_lines * 4;
58 instructions += 2; 59 instructions += (1 + ((bpl + padding) * store_lines)
59 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) 60 / PAGE_SIZE + store_lines) * 8;
61 instructions += 2 * 8;
62 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
60 return rc; 63 return rc;
61 64
62 /* sync instruction */ 65 /* sync instruction */
@@ -64,11 +67,16 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
64 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); 67 *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
65 *(rp++) = cpu_to_le32(0); 68 *(rp++) = cpu_to_le32(0);
66 69
70 while (skip_lines-- > 0) {
71 *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
72 BT848_RISC_EOL | bpl);
73 }
74
67 /* scan lines */ 75 /* scan lines */
68 sg = sglist; 76 sg = sglist;
69 for (line = 0; line < lines; line++) { 77 for (line = 0; line < store_lines; line++) {
70 if ((btv->opt_vcr_hack) && 78 if ((btv->opt_vcr_hack) &&
71 (line >= (lines - VCR_HACK_LINES))) 79 (line >= (store_lines - VCR_HACK_LINES)))
72 continue; 80 continue;
73 while (offset && offset >= sg_dma_len(sg)) { 81 while (offset && offset >= sg_dma_len(sg)) {
74 offset -= sg_dma_len(sg); 82 offset -= sg_dma_len(sg);
@@ -130,7 +138,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
130 /* estimate risc mem: worst case is one write per page border + 138 /* estimate risc mem: worst case is one write per page border +
131 one write per scan line (5 dwords) 139 one write per scan line (5 dwords)
132 plus sync + jump (2 dwords) */ 140 plus sync + jump (2 dwords) */
133 instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines; 141 instructions = ((3 + (ybpl + ypadding) * ylines * 2)
142 / PAGE_SIZE) + ylines;
134 instructions += 2; 143 instructions += 2;
135 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0) 144 if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
136 return rc; 145 return rc;
@@ -317,10 +326,10 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
317/* ---------------------------------------------------------- */ 326/* ---------------------------------------------------------- */
318 327
319static void 328static void
320bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo, 329bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
321 int width, int height, int interleaved, int norm) 330 int width, int height, int interleaved,
331 const struct bttv_tvnorm *tvnorm)
322{ 332{
323 const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
324 u32 xsf, sr; 333 u32 xsf, sr;
325 int vdelay; 334 int vdelay;
326 335
@@ -361,6 +370,62 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
361} 370}
362 371
363static void 372static void
373bttv_calc_geo (struct bttv * btv,
374 struct bttv_geometry * geo,
375 unsigned int width,
376 unsigned int height,
377 int both_fields,
378 const struct bttv_tvnorm * tvnorm,
379 const struct v4l2_rect * crop)
380{
381 unsigned int c_width;
382 unsigned int c_height;
383 u32 sr;
384
385 if ((crop->left == tvnorm->cropcap.defrect.left
386 && crop->top == tvnorm->cropcap.defrect.top
387 && crop->width == tvnorm->cropcap.defrect.width
388 && crop->height == tvnorm->cropcap.defrect.height
389 && width <= tvnorm->swidth /* see PAL-Nc et al */)
390 || bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
391 bttv_calc_geo_old(btv, geo, width, height,
392 both_fields, tvnorm);
393 return;
394 }
395
396 /* For bug compatibility the image size checks permit scale
397 factors > 16. See bttv_crop_calc_limits(). */
398 c_width = min((unsigned int) crop->width, width * 16);
399 c_height = min((unsigned int) crop->height, height * 16);
400
401 geo->width = width;
402 geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
403 /* Even to store Cb first, odd for Cr. */
404 geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
405
406 geo->sheight = c_height;
407 geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
408 sr = c_height >> !both_fields;
409 sr = (sr * 512U + (height >> 1)) / height - 512;
410 geo->vscale = (0x10000UL - sr) & 0x1fff;
411 geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
412 geo->vtotal = tvnorm->vtotal;
413
414 geo->crop = (((geo->width >> 8) & 0x03) |
415 ((geo->hdelay >> 6) & 0x0c) |
416 ((geo->sheight >> 4) & 0x30) |
417 ((geo->vdelay >> 2) & 0xc0));
418
419 if (btv->opt_combfilter) {
420 geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
421 geo->comb = (width < 769) ? 1 : 0;
422 } else {
423 geo->vtc = 0;
424 geo->comb = 0;
425 }
426}
427
428static void
364bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd) 429bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
365{ 430{
366 int off = odd ? 0x80 : 0x00; 431 int off = odd ? 0x80 : 0x00;
@@ -522,16 +587,51 @@ int
522bttv_buffer_activate_vbi(struct bttv *btv, 587bttv_buffer_activate_vbi(struct bttv *btv,
523 struct bttv_buffer *vbi) 588 struct bttv_buffer *vbi)
524{ 589{
525 /* vbi capture */ 590 struct btcx_riscmem *top;
591 struct btcx_riscmem *bottom;
592 int top_irq_flags;
593 int bottom_irq_flags;
594
595 top = NULL;
596 bottom = NULL;
597 top_irq_flags = 0;
598 bottom_irq_flags = 0;
599
526 if (vbi) { 600 if (vbi) {
601 unsigned int crop, vdelay;
602
527 vbi->vb.state = STATE_ACTIVE; 603 vbi->vb.state = STATE_ACTIVE;
528 list_del(&vbi->vb.queue); 604 list_del(&vbi->vb.queue);
529 bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top, 0); 605
530 bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4); 606 /* VDELAY is start of video, end of VBI capturing. */
531 } else { 607 crop = btread(BT848_E_CROP);
532 bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0); 608 vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
533 bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0); 609
610 if (vbi->geo.vdelay > vdelay) {
611 vdelay = vbi->geo.vdelay & 0xfe;
612 crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
613
614 btwrite(vdelay, BT848_E_VDELAY_LO);
615 btwrite(crop, BT848_E_CROP);
616 btwrite(vdelay, BT848_O_VDELAY_LO);
617 btwrite(crop, BT848_O_CROP);
618 }
619
620 if (vbi->vbi_count[0] > 0) {
621 top = &vbi->top;
622 top_irq_flags = 4;
623 }
624
625 if (vbi->vbi_count[1] > 0) {
626 top_irq_flags = 0;
627 bottom = &vbi->bottom;
628 bottom_irq_flags = 4;
629 }
534 } 630 }
631
632 bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
633 bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
634
535 return 0; 635 return 0;
536} 636}
537 637
@@ -611,28 +711,31 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
611 int bpf = bpl * (buf->vb.height >> 1); 711 int bpf = bpl * (buf->vb.height >> 1);
612 712
613 bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height, 713 bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
614 V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm); 714 V4L2_FIELD_HAS_BOTH(buf->vb.field),
715 tvnorm,&buf->crop);
615 716
616 switch (buf->vb.field) { 717 switch (buf->vb.field) {
617 case V4L2_FIELD_TOP: 718 case V4L2_FIELD_TOP:
618 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, 719 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
619 0,bpl,0,buf->vb.height); 720 /* offset */ 0,bpl,
721 /* padding */ 0,/* skip_lines */ 0,
722 buf->vb.height);
620 break; 723 break;
621 case V4L2_FIELD_BOTTOM: 724 case V4L2_FIELD_BOTTOM:
622 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, 725 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
623 0,bpl,0,buf->vb.height); 726 0,bpl,0,0,buf->vb.height);
624 break; 727 break;
625 case V4L2_FIELD_INTERLACED: 728 case V4L2_FIELD_INTERLACED:
626 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, 729 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
627 0,bpl,bpl,buf->vb.height >> 1); 730 0,bpl,bpl,0,buf->vb.height >> 1);
628 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, 731 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
629 bpl,bpl,bpl,buf->vb.height >> 1); 732 bpl,bpl,bpl,0,buf->vb.height >> 1);
630 break; 733 break;
631 case V4L2_FIELD_SEQ_TB: 734 case V4L2_FIELD_SEQ_TB:
632 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, 735 bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
633 0,bpl,0,buf->vb.height >> 1); 736 0,bpl,0,0,buf->vb.height >> 1);
634 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, 737 bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
635 bpf,bpl,0,buf->vb.height >> 1); 738 bpf,bpl,0,0,buf->vb.height >> 1);
636 break; 739 break;
637 default: 740 default:
638 BUG(); 741 BUG();
@@ -662,7 +765,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
662 switch (buf->vb.field) { 765 switch (buf->vb.field) {
663 case V4L2_FIELD_TOP: 766 case V4L2_FIELD_TOP:
664 bttv_calc_geo(btv,&buf->geo,buf->vb.width, 767 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
665 buf->vb.height,0,buf->tvnorm); 768 buf->vb.height,/* both_fields */ 0,
769 tvnorm,&buf->crop);
666 bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist, 770 bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
667 0,buf->vb.width,0,buf->vb.height, 771 0,buf->vb.width,0,buf->vb.height,
668 uoffset,voffset,buf->fmt->hshift, 772 uoffset,voffset,buf->fmt->hshift,
@@ -670,7 +774,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
670 break; 774 break;
671 case V4L2_FIELD_BOTTOM: 775 case V4L2_FIELD_BOTTOM:
672 bttv_calc_geo(btv,&buf->geo,buf->vb.width, 776 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
673 buf->vb.height,0,buf->tvnorm); 777 buf->vb.height,0,
778 tvnorm,&buf->crop);
674 bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist, 779 bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
675 0,buf->vb.width,0,buf->vb.height, 780 0,buf->vb.width,0,buf->vb.height,
676 uoffset,voffset,buf->fmt->hshift, 781 uoffset,voffset,buf->fmt->hshift,
@@ -678,7 +783,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
678 break; 783 break;
679 case V4L2_FIELD_INTERLACED: 784 case V4L2_FIELD_INTERLACED:
680 bttv_calc_geo(btv,&buf->geo,buf->vb.width, 785 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
681 buf->vb.height,1,buf->tvnorm); 786 buf->vb.height,1,
787 tvnorm,&buf->crop);
682 lines = buf->vb.height >> 1; 788 lines = buf->vb.height >> 1;
683 ypadding = buf->vb.width; 789 ypadding = buf->vb.width;
684 cpadding = buf->vb.width >> buf->fmt->hshift; 790 cpadding = buf->vb.width >> buf->fmt->hshift;
@@ -700,7 +806,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
700 break; 806 break;
701 case V4L2_FIELD_SEQ_TB: 807 case V4L2_FIELD_SEQ_TB:
702 bttv_calc_geo(btv,&buf->geo,buf->vb.width, 808 bttv_calc_geo(btv,&buf->geo,buf->vb.width,
703 buf->vb.height,1,buf->tvnorm); 809 buf->vb.height,1,
810 tvnorm,&buf->crop);
704 lines = buf->vb.height >> 1; 811 lines = buf->vb.height >> 1;
705 ypadding = buf->vb.width; 812 ypadding = buf->vb.width;
706 cpadding = buf->vb.width >> buf->fmt->hshift; 813 cpadding = buf->vb.width >> buf->fmt->hshift;
@@ -731,11 +838,12 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
731 /* build risc code */ 838 /* build risc code */
732 buf->vb.field = V4L2_FIELD_SEQ_TB; 839 buf->vb.field = V4L2_FIELD_SEQ_TB;
733 bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, 840 bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
734 1,buf->tvnorm); 841 1,tvnorm,&buf->crop);
735 bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist, 842 bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
736 0, RAW_BPL, 0, RAW_LINES); 843 /* offset */ 0, RAW_BPL, /* padding */ 0,
844 /* skip_lines */ 0, RAW_LINES);
737 bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist, 845 bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
738 buf->vb.size/2 , RAW_BPL, 0, RAW_LINES); 846 buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
739 } 847 }
740 848
741 /* copy format info */ 849 /* copy format info */
@@ -761,7 +869,8 @@ bttv_overlay_risc(struct bttv *btv,
761 869
762 /* calculate geometry */ 870 /* calculate geometry */
763 bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, 871 bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
764 V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm); 872 V4L2_FIELD_HAS_BOTH(ov->field),
873 &bttv_tvnorms[ov->tvnorm],&buf->crop);
765 874
766 /* build risc code */ 875 /* build risc code */
767 switch (ov->field) { 876 switch (ov->field) {