summaryrefslogtreecommitdiff
path: root/linux/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media')
-rw-r--r--linux/drivers/media/common/saa7146_hlp.c141
-rw-r--r--linux/drivers/media/common/saa7146_video.c46
-rw-r--r--linux/drivers/media/common/saa7146_vv.h1
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