diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-01-25 06:00:01 -0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-01-25 06:00:01 -0200 |
commit | a17249c51910dd58481bf09e5eff56d6ec9d0dd4 (patch) | |
tree | a14cdb3c750ff88610dd39565814c79f353bb6d4 | |
parent | 0f5b64e7c37c66e5cd7693eb7f9fc011e62eee33 (diff) | |
download | mediapointer-dvb-s2-a17249c51910dd58481bf09e5eff56d6ec9d0dd4.tar.gz mediapointer-dvb-s2-a17249c51910dd58481bf09e5eff56d6ec9d0dd4.tar.bz2 |
Make vivi driver to use vmalloced pointers
From: Mauro Carvalho Chehab <mchehab@infradead.org>
Before this patch, vivi were simulating a scatter gather DMA transfer.
While this is academic, showing how stuff really works on a real PCI
device, this means a non-optimized code.
There are only two memory models that vivi implements:
1) kernel alloced memory. This is also used by read() method.
On this case, a vmalloc32 buffer is allocated at kernel;
2) userspace allocated memory. This is used by most userspace apps.
video-buf will store this pointer.
a simple copy_to_user is enough to transfer data.
The third memory model scenario supported by video-buf is overlay mode.
This model is not implemented on vivi and unlikely to be implemented on
newer drivers, since now, most userspace apps do some post-processing
(like de-interlacing).
After this patch, some cleanups may be done at video-buf.c to avoid
allocating pages, when the driver doesn't need a PCI buffer. This is the
case of vivi and usb drivers.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | linux/drivers/media/video/video-buf.c | 3 | ||||
-rw-r--r-- | linux/drivers/media/video/vivi.c | 83 | ||||
-rw-r--r-- | linux/include/media/video-buf.h | 3 |
3 files changed, 78 insertions, 11 deletions
diff --git a/linux/drivers/media/video/video-buf.c b/linux/drivers/media/video/video-buf.c index 4e359bc33..a2251c7e3 100644 --- a/linux/drivers/media/video/video-buf.c +++ b/linux/drivers/media/video/video-buf.c @@ -149,6 +149,8 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", data,size,dma->nr_pages); + dma->varea = (void *) data; + down_read(¤t->mm->mmap_sem); err = get_user_pages(current,current->mm, data & PAGE_MASK, dma->nr_pages, @@ -286,6 +288,7 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) vfree(dma->vmalloc); dma->vmalloc = NULL; + dma->varea = NULL; if (dma->bus_addr) { dma->bus_addr = 0; diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c index ddedd7fbb..1756ff277 100644 --- a/linux/drivers/media/video/vivi.c +++ b/linux/drivers/media/video/vivi.c @@ -150,7 +150,9 @@ struct vivi_buffer { struct vivi_fmt *fmt; +#ifdef CONFIG_VIVI_SCATTER struct sg_to_addr *to_addr; +#endif }; struct vivi_dmaqueue { @@ -239,6 +241,7 @@ static u8 bars[8][3] = { #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 #define TSTAMP_MIN_X 64 +#ifdef CONFIG_VIVI_SCATTER static void prep_to_addr(struct sg_to_addr to_addr[], struct videobuf_buffer *vb) { @@ -271,14 +274,24 @@ static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[]) return (p1); } +#endif +#ifdef CONFIG_VIVI_SCATTER static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, int hmax, int line, char *timestr) +#else +static void gen_line(char *basep,int inipos,int wmax, + int hmax, int line, char *timestr) +#endif { - int w,i,j,pos=inipos,pgpos,oldpg,y; - char *p,*s,*basep; - struct page *pg; + int w,i,j,pos=inipos,y; + char *p,*s; u8 chr,r,g,b,color; +#ifdef CONFIG_VIVI_SCATTER + int pgpos,oldpg; + char *basep; + struct page *pg; + unsigned long flags; spinlock_t spinlock; @@ -289,6 +302,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT); spin_lock_irqsave(&spinlock,flags); basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset; +#endif /* We will just duplicate the second pixel at the packet */ wmax/=2; @@ -300,6 +314,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, b=bars[w*7/wmax][2]; for (color=0;color<4;color++) { +#ifdef CONFIG_VIVI_SCATTER pgpos=get_addr_pos(pos,pages,to_addr); if (pgpos!=oldpg) { pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT); @@ -308,6 +323,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, oldpg=pgpos; } p=basep+pos-to_addr[pgpos].pos; +#else + p=basep+pos; +#endif switch (color) { case 0: @@ -352,6 +370,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, pos=inipos+j*2; for (color=0;color<4;color++) { +#ifdef CONFIG_VIVI_SCATTER pgpos=get_addr_pos(pos,pages,to_addr); if (pgpos!=oldpg) { pg=pfn_to_page(sg_dma_address( @@ -365,6 +384,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, oldpg=pgpos; } p=basep+pos-to_addr[pgpos].pos; +#else + p=basep+pos; +#endif y=TO_Y(r,g,b); @@ -401,19 +423,27 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, #endif end: +#ifdef CONFIG_VIVI_SCATTER kunmap_atomic(basep, KM_BOUNCE_READ); spin_unlock_irqrestore(&spinlock,flags); - +#else + return; +#endif } static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) { int h,pos=0; int hmax = buf->vb.height; int wmax = buf->vb.width; - struct videobuf_buffer *vb=&buf->vb; - struct sg_to_addr *to_addr=buf->to_addr; struct timeval ts; +#ifdef CONFIG_VIVI_SCATTER + struct sg_to_addr *to_addr=buf->to_addr; + struct videobuf_buffer *vb=&buf->vb; +#else + char *tmpbuf; +#endif +#ifdef CONFIG_VIVI_SCATTER /* Test if DMA mapping is ready */ if (!sg_dma_address(&vb->dma.sglist[0])) return; @@ -422,9 +452,27 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) /* Check if there is enough memory */ BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2); +#else + if (buf->vb.dma.varea) { + tmpbuf=kmalloc (wmax*2, GFP_KERNEL); + } else { + tmpbuf=buf->vb.dma.vmalloc; + } + +#endif for (h=0;h<hmax;h++) { +#ifdef CONFIG_VIVI_SCATTER gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr); +#else + if (buf->vb.dma.varea) { + gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); + /* FIXME: replacing to __copy_to_user */ + copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2); + } else { + gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr); + } +#endif pos += wmax*2; } @@ -450,7 +498,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) dev->h,dev->m,dev->s,(dev->us+500)/1000); dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, - (unsigned long)buf->vb.dma.vmalloc,pos); + (unsigned long)buf->vb.dma.varea,pos); /* Advice that buffer was filled */ buf->vb.state = STATE_DONE; @@ -753,9 +801,11 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) if (in_interrupt()) BUG(); +#ifdef CONFIG_VIVI_SCATTER /*FIXME: Maybe a spinlock is required here */ kfree(buf->to_addr); buf->to_addr=NULL; +#endif videobuf_waiton(&buf->vb,0,0); videobuf_dma_unmap(vq, &buf->vb.dma); @@ -801,11 +851,12 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, buf->vb.state = STATE_PREPARED; +#ifdef CONFIG_VIVI_SCATTER if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) { rc=-ENOMEM; goto fail; } - +#endif return 0; fail: @@ -870,6 +921,7 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb free_buffer(vq,buf); } +#ifdef CONFIG_VIVI_SCATTER static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents, int direction) { @@ -902,6 +954,7 @@ static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages, // flush_write_buffers(); return 0; } +#endif static struct videobuf_queue_ops vivi_video_qops = { .buf_setup = buffer_setup, @@ -910,9 +963,9 @@ static struct videobuf_queue_ops vivi_video_qops = { .buf_release = buffer_release, /* Non-pci handling routines */ - .vb_map_sg = vivi_map_sg, - .vb_dma_sync_sg = vivi_dma_sync_sg, - .vb_unmap_sg = vivi_unmap_sg, +// .vb_map_sg = vivi_map_sg, +// .vb_dma_sync_sg = vivi_dma_sync_sg, +// .vb_unmap_sg = vivi_unmap_sg, }; /* ------------------------------------------------------------------ @@ -1296,11 +1349,19 @@ static int vivi_open(struct inode *inode, struct file *file) sprintf(dev->timestr,"%02d:%02d:%02d:%03d", dev->h,dev->m,dev->s,(dev->us+500)/1000); +#ifdef CONFIG_VIVI_SCATTER + videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops, + NULL, NULL, + fh->type, + V4L2_FIELD_INTERLACED, + sizeof(struct vivi_buffer),fh); +#else videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops, NULL, NULL, fh->type, V4L2_FIELD_INTERLACED, sizeof(struct vivi_buffer),fh); +#endif return 0; } diff --git a/linux/include/media/video-buf.h b/linux/include/media/video-buf.h index ae694cfbc..cb216d0ab 100644 --- a/linux/include/media/video-buf.h +++ b/linux/include/media/video-buf.h @@ -78,6 +78,9 @@ struct videobuf_dmabuf { /* for kernel buffers */ void *vmalloc; + /* Stores the userspace pointer to vmalloc area */ + void *varea; + /* for overlay buffers (pci-pci dma) */ dma_addr_t bus_addr; |