summaryrefslogtreecommitdiff
path: root/linux/drivers/media/common/saa7146_hlp.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/common/saa7146_hlp.c')
-rw-r--r--linux/drivers/media/common/saa7146_hlp.c141
1 files changed, 105 insertions, 36 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;
}