diff options
Diffstat (limited to 'linux/drivers/media')
-rw-r--r-- | linux/drivers/media/common/saa7146_hlp.c | 141 | ||||
-rw-r--r-- | linux/drivers/media/common/saa7146_video.c | 46 | ||||
-rw-r--r-- | linux/drivers/media/common/saa7146_vv.h | 1 |
3 files changed, 142 insertions, 46 deletions
diff --git a/linux/drivers/media/common/saa7146_hlp.c b/linux/drivers/media/common/saa7146_hlp.c index 884ba270c..e3cfddb42 100644 --- a/linux/drivers/media/common/saa7146_hlp.c +++ b/linux/drivers/media/common/saa7146_hlp.c @@ -796,6 +796,73 @@ int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf } static +int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) +{ + int height = buf->fmt->height; + int width = buf->fmt->width; + + vdma2->pitch = width; + vdma3->pitch = width; + + if( 0 != vv->vflip ) { + vdma2->prot_addr = buf->pt[1].offset; + vdma2->base_even = ((vdma2->pitch/2)*height)+buf->pt[1].offset; + vdma2->base_odd = vdma2->base_even - (vdma2->pitch/2); + + vdma3->prot_addr = buf->pt[2].offset; + vdma3->base_even = ((vdma3->pitch/2)*height)+buf->pt[2].offset; + vdma3->base_odd = vdma3->base_even - (vdma3->pitch/2); + + } else { + vdma3->base_even = buf->pt[2].offset; + vdma3->base_odd = vdma3->base_even + (vdma3->pitch/2); + vdma3->prot_addr = (vdma3->pitch/2)*height+buf->pt[2].offset; + + vdma2->base_even = buf->pt[1].offset; + vdma2->base_odd = vdma2->base_even + (vdma2->pitch/2); + vdma2->prot_addr = (vdma2->pitch/2)*height+buf->pt[1].offset; + } + + return 0; +} + +static +int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3) +{ + int height = buf->fmt->height; + int width = buf->fmt->width; + + vdma2->pitch = width/2; + vdma3->pitch = width/2; + + if( 0 != vv->vflip ) { + vdma2->prot_addr = buf->pt[2].offset; + vdma2->base_even = ((vdma2->pitch/2)*height)+buf->pt[2].offset; + vdma2->base_odd = vdma2->base_even - (vdma2->pitch/2); + + vdma3->prot_addr = buf->pt[1].offset; + vdma3->base_even = ((vdma3->pitch/2)*height)+buf->pt[1].offset; + vdma3->base_odd = vdma3->base_even - (vdma3->pitch/2); + + } else { + vdma3->base_even = buf->pt[2].offset; + vdma3->base_odd = vdma3->base_even + (vdma3->pitch); + vdma3->prot_addr = (vdma3->pitch/2)*height+buf->pt[2].offset; + + vdma2->base_even = buf->pt[1].offset; + vdma2->base_odd = vdma2->base_even + (vdma2->pitch); + vdma2->prot_addr = (vdma2->pitch/2)*height+buf->pt[1].offset; + + printk("vdma3->base_even: 0x%08x\n",vdma3->base_even); + printk("vdma3->base_odd: 0x%08x\n",vdma3->base_odd); + printk("vdma3->prot_addr: 0x%08x\n",vdma3->prot_addr); + + } + return 0; +} + + +static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf) { struct saa7146_vv *vv = dev->vv_data; @@ -803,6 +870,8 @@ int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf struct saa7146_video_dma vdma2; struct saa7146_video_dma vdma3; + struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + int width = buf->fmt->width; int height = buf->fmt->height; enum v4l2_field field = buf->fmt->field; @@ -814,53 +883,49 @@ int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf DEB_CAP(("[size=%dx%d,fields=%s]\n", width,height,v4l2_field_names[field])); - vdma1.pitch = width*2; - vdma1.num_line_byte = ((vv->standard->v_field<<16) + vv->standard->h_pixels); - vdma1.base_page = buf->pt[0].dma | ME1; - - /* fscking saa7146! due to the "byte-swap bug", video-dma2 - writes the v data and not the u data, video-dma3 writes - the u data, not the v data. but because we have a planar - format, we can simply switch the video-dmas... */ - - vdma3.pitch = width; - vdma3.num_line_byte = 0; /* unused */ - vdma3.base_page = buf->pt[1].dma | ME1; - - vdma2.pitch = width; - vdma2.num_line_byte = 0; /* unused */ - vdma2.base_page = buf->pt[2].dma | ME1; - /* fixme: what happens for user space buffers here?. The offsets are most likely wrong, this version here only works for page-aligned buffers, modifications to the pagetable-functions are necessary...*/ + vdma1.pitch = width*2; + vdma1.num_line_byte = ((vv->standard->v_field<<16) + vv->standard->h_pixels); + vdma1.base_page = buf->pt[0].dma | ME1; + if( 0 != vv->vflip ) { vdma1.prot_addr = buf->pt[0].offset; vdma1.base_even = ((vdma1.pitch/2)*height)+buf->pt[0].offset; vdma1.base_odd = vdma1.base_even - (vdma1.pitch/2); - - vdma2.prot_addr = buf->pt[2].offset; - vdma2.base_even = ((vdma2.pitch/2)*height)+buf->pt[2].offset; - vdma2.base_odd = vdma2.base_even - (vdma2.pitch/2); - - vdma3.prot_addr = buf->pt[1].offset; - vdma3.base_even = ((vdma3.pitch/2)*height)+buf->pt[1].offset; - vdma3.base_odd = vdma3.base_even - (vdma3.pitch/2); - } else { vdma1.base_even = buf->pt[0].offset; vdma1.base_odd = vdma1.base_even + (vdma1.pitch/2); vdma1.prot_addr = (vdma1.pitch/2)*height+buf->pt[0].offset; + } + + /* fixme */ +/* + vdma1.base_even = 0; // buf->pt[0].offset; + vdma1.base_odd = 0; // vdma1.base_even + (vdma1.pitch/2); + vdma1.prot_addr = 0; // (vdma1.pitch/2)*height+buf->pt[0].offset; +*/ + + vdma2.num_line_byte = 0; /* unused */ + vdma2.base_page = buf->pt[1].dma | ME1; - /* switched, see above */ - vdma3.base_even = buf->pt[1].offset; - vdma3.base_odd = vdma3.base_even + (vdma3.pitch/2); - vdma3.prot_addr = (vdma3.pitch/2)*height+buf->pt[1].offset; + vdma3.num_line_byte = 0; /* unused */ + vdma3.base_page = buf->pt[2].dma | ME1; - vdma2.base_even = buf->pt[2].offset; - vdma2.base_odd = vdma2.base_even + (vdma2.pitch/2); - vdma2.prot_addr = (vdma2.pitch/2)*height+buf->pt[2].offset; + switch( sfmt->depth ) { + case 12: { + calc_planar_420(vv,buf,&vdma2,&vdma3); + break; + } + case 16: { + calc_planar_422(vv,buf,&vdma2,&vdma3); + break; + } + default: { + return -1; + } } if (V4L2_FIELD_HAS_BOTH(field)) { @@ -890,9 +955,13 @@ int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf } saa7146_write_out_dma(dev, 1, &vdma1); - saa7146_write_out_dma(dev, 2, &vdma2); - saa7146_write_out_dma(dev, 3, &vdma3); - + if( sfmt->swap != 0 ) { + saa7146_write_out_dma(dev, 3, &vdma2); + saa7146_write_out_dma(dev, 2, &vdma3); + } else { + saa7146_write_out_dma(dev, 2, &vdma2); + saa7146_write_out_dma(dev, 3, &vdma3); + } return 0; } diff --git a/linux/drivers/media/common/saa7146_video.c b/linux/drivers/media/common/saa7146_video.c index cdeeada3b..e6bf86e0a 100644 --- a/linux/drivers/media/common/saa7146_video.c +++ b/linux/drivers/media/common/saa7146_video.c @@ -43,12 +43,19 @@ struct saa7146_format formats[] = { .pixelformat = V4L2_PIX_FMT_YUV422P, .trans = YUV422_DECOMPOSED, .depth = 16, + .swap = 1, }, { - .name = "YUV 4:2:0 planar (Y-Cb-Cr)", + .name = "YVU 4:2:0 planar (Y-Cb-Cr)", .pixelformat = V4L2_PIX_FMT_YVU420, .trans = YUV420_DECOMPOSED, .depth = 12, }, { + .name = "YUV 4:2:0 planar (Y-Cb-Cr)", + .pixelformat = V4L2_PIX_FMT_YUV420, + .trans = YUV420_DECOMPOSED, + .depth = 12, + .swap = 1, + }, { .name = "YUV 4:2:2 (U-Y-V-Y)", .pixelformat = V4L2_PIX_FMT_UYVY, .trans = YUV422_COMPOSED, @@ -57,7 +64,7 @@ struct saa7146_format formats[] = { }; /* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps. - due to this, it's impossible to provide additional formats, which are simply byte swapped + due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped (like V4L2_PIX_FMT_YUYV) ... 8-( */ static @@ -557,8 +564,34 @@ int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf) u32 *ptr1, *ptr2, *ptr3; u32 fill; - int size = ((buf->fmt->width*buf->fmt->height*sfmt->depth)/8)/2; + int size = buf->fmt->width*buf->fmt->height; int i,p,m1,m2,m3,o1,o2; + + switch( sfmt->depth ) { + case 12: { + /* create some offsets inside the page table */ + m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; + m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1; + m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; + o1 = size%PAGE_SIZE; + o2 = (size+(size/4))%PAGE_SIZE; + printk("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2); + break; + } + case 16: { + /* create some offsets inside the page table */ + m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; + m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; + m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1; + o1 = size%PAGE_SIZE; + o2 = (size+(size/2))%PAGE_SIZE; + printk("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2); + break; + } + default: { + return -1; + } + } ptr1 = pt1->cpu; ptr2 = pt2->cpu; @@ -576,13 +609,6 @@ int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf) printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); } */ - /* create some offsets inside the page table */ - m1 = ((size+PAGE_SIZE-1)/PAGE_SIZE)-1; - m2 = ((size+(size/2)+PAGE_SIZE-1)/PAGE_SIZE)-1; - m3 = ((2*size+PAGE_SIZE-1)/PAGE_SIZE)-1; - - o1 = size%PAGE_SIZE; - o2 = (size+(size/2))%PAGE_SIZE; /* if we have a user buffer, the first page may not be aligned to a page boundary. */ diff --git a/linux/drivers/media/common/saa7146_vv.h b/linux/drivers/media/common/saa7146_vv.h index 062622329..a22ebe560 100644 --- a/linux/drivers/media/common/saa7146_vv.h +++ b/linux/drivers/media/common/saa7146_vv.h @@ -23,6 +23,7 @@ struct saa7146_format { int pixelformat; u32 trans; u8 depth; + int swap; }; struct saa7146_standard |