diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-01-25 03:00:01 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-02-21 10:34:55 -0500 |
commit | b50e7fe99317c05b0bb8ba6338bc6aa7da3b918e (patch) | |
tree | 32124766d993a7d65b49555f6f65a04508ecc318 | |
parent | 52ebc763d8e0c9f2ab48af89a75e90e2318bac86 (diff) |
V4L/DVB (5147): Make vivi driver to use vmalloced pointers
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-- | drivers/media/video/video-buf.c | 3 | ||||
-rw-r--r-- | drivers/media/video/vivi.c | 83 | ||||
-rw-r--r-- | include/media/video-buf.h | 3 |
3 files changed, 78 insertions, 11 deletions
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index 6504a5866849..459786ff459a 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c | |||
@@ -148,6 +148,8 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, | |||
148 | dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", | 148 | dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", |
149 | data,size,dma->nr_pages); | 149 | data,size,dma->nr_pages); |
150 | 150 | ||
151 | dma->varea = (void *) data; | ||
152 | |||
151 | down_read(¤t->mm->mmap_sem); | 153 | down_read(¤t->mm->mmap_sem); |
152 | err = get_user_pages(current,current->mm, | 154 | err = get_user_pages(current,current->mm, |
153 | data & PAGE_MASK, dma->nr_pages, | 155 | data & PAGE_MASK, dma->nr_pages, |
@@ -285,6 +287,7 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) | |||
285 | 287 | ||
286 | vfree(dma->vmalloc); | 288 | vfree(dma->vmalloc); |
287 | dma->vmalloc = NULL; | 289 | dma->vmalloc = NULL; |
290 | dma->varea = NULL; | ||
288 | 291 | ||
289 | if (dma->bus_addr) { | 292 | if (dma->bus_addr) { |
290 | dma->bus_addr = 0; | 293 | dma->bus_addr = 0; |
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 178441922738..0fb6d520d1d0 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c | |||
@@ -145,7 +145,9 @@ struct vivi_buffer { | |||
145 | 145 | ||
146 | struct vivi_fmt *fmt; | 146 | struct vivi_fmt *fmt; |
147 | 147 | ||
148 | #ifdef CONFIG_VIVI_SCATTER | ||
148 | struct sg_to_addr *to_addr; | 149 | struct sg_to_addr *to_addr; |
150 | #endif | ||
149 | }; | 151 | }; |
150 | 152 | ||
151 | struct vivi_dmaqueue { | 153 | struct vivi_dmaqueue { |
@@ -230,6 +232,7 @@ static u8 bars[8][3] = { | |||
230 | #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 | 232 | #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 |
231 | #define TSTAMP_MIN_X 64 | 233 | #define TSTAMP_MIN_X 64 |
232 | 234 | ||
235 | #ifdef CONFIG_VIVI_SCATTER | ||
233 | static void prep_to_addr(struct sg_to_addr to_addr[], | 236 | static void prep_to_addr(struct sg_to_addr to_addr[], |
234 | struct videobuf_buffer *vb) | 237 | struct videobuf_buffer *vb) |
235 | { | 238 | { |
@@ -262,14 +265,24 @@ static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[]) | |||
262 | 265 | ||
263 | return (p1); | 266 | return (p1); |
264 | } | 267 | } |
268 | #endif | ||
265 | 269 | ||
270 | #ifdef CONFIG_VIVI_SCATTER | ||
266 | static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, | 271 | static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, |
267 | int hmax, int line, char *timestr) | 272 | int hmax, int line, char *timestr) |
273 | #else | ||
274 | static void gen_line(char *basep,int inipos,int wmax, | ||
275 | int hmax, int line, char *timestr) | ||
276 | #endif | ||
268 | { | 277 | { |
269 | int w,i,j,pos=inipos,pgpos,oldpg,y; | 278 | int w,i,j,pos=inipos,y; |
270 | char *p,*s,*basep; | 279 | char *p,*s; |
271 | struct page *pg; | ||
272 | u8 chr,r,g,b,color; | 280 | u8 chr,r,g,b,color; |
281 | #ifdef CONFIG_VIVI_SCATTER | ||
282 | int pgpos,oldpg; | ||
283 | char *basep; | ||
284 | struct page *pg; | ||
285 | |||
273 | unsigned long flags; | 286 | unsigned long flags; |
274 | spinlock_t spinlock; | 287 | spinlock_t spinlock; |
275 | 288 | ||
@@ -280,6 +293,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, | |||
280 | pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT); | 293 | pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT); |
281 | spin_lock_irqsave(&spinlock,flags); | 294 | spin_lock_irqsave(&spinlock,flags); |
282 | basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset; | 295 | basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset; |
296 | #endif | ||
283 | 297 | ||
284 | /* We will just duplicate the second pixel at the packet */ | 298 | /* We will just duplicate the second pixel at the packet */ |
285 | wmax/=2; | 299 | wmax/=2; |
@@ -291,6 +305,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, | |||
291 | b=bars[w*7/wmax][2]; | 305 | b=bars[w*7/wmax][2]; |
292 | 306 | ||
293 | for (color=0;color<4;color++) { | 307 | for (color=0;color<4;color++) { |
308 | #ifdef CONFIG_VIVI_SCATTER | ||
294 | pgpos=get_addr_pos(pos,pages,to_addr); | 309 | pgpos=get_addr_pos(pos,pages,to_addr); |
295 | if (pgpos!=oldpg) { | 310 | if (pgpos!=oldpg) { |
296 | pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT); | 311 | pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT); |
@@ -299,6 +314,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, | |||
299 | oldpg=pgpos; | 314 | oldpg=pgpos; |
300 | } | 315 | } |
301 | p=basep+pos-to_addr[pgpos].pos; | 316 | p=basep+pos-to_addr[pgpos].pos; |
317 | #else | ||
318 | p=basep+pos; | ||
319 | #endif | ||
302 | 320 | ||
303 | switch (color) { | 321 | switch (color) { |
304 | case 0: | 322 | case 0: |
@@ -343,6 +361,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, | |||
343 | 361 | ||
344 | pos=inipos+j*2; | 362 | pos=inipos+j*2; |
345 | for (color=0;color<4;color++) { | 363 | for (color=0;color<4;color++) { |
364 | #ifdef CONFIG_VIVI_SCATTER | ||
346 | pgpos=get_addr_pos(pos,pages,to_addr); | 365 | pgpos=get_addr_pos(pos,pages,to_addr); |
347 | if (pgpos!=oldpg) { | 366 | if (pgpos!=oldpg) { |
348 | pg=pfn_to_page(sg_dma_address( | 367 | pg=pfn_to_page(sg_dma_address( |
@@ -356,6 +375,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, | |||
356 | oldpg=pgpos; | 375 | oldpg=pgpos; |
357 | } | 376 | } |
358 | p=basep+pos-to_addr[pgpos].pos; | 377 | p=basep+pos-to_addr[pgpos].pos; |
378 | #else | ||
379 | p=basep+pos; | ||
380 | #endif | ||
359 | 381 | ||
360 | y=TO_Y(r,g,b); | 382 | y=TO_Y(r,g,b); |
361 | 383 | ||
@@ -380,19 +402,27 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax, | |||
380 | 402 | ||
381 | 403 | ||
382 | end: | 404 | end: |
405 | #ifdef CONFIG_VIVI_SCATTER | ||
383 | kunmap_atomic(basep, KM_BOUNCE_READ); | 406 | kunmap_atomic(basep, KM_BOUNCE_READ); |
384 | spin_unlock_irqrestore(&spinlock,flags); | 407 | spin_unlock_irqrestore(&spinlock,flags); |
385 | 408 | #else | |
409 | return; | ||
410 | #endif | ||
386 | } | 411 | } |
387 | static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) | 412 | static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) |
388 | { | 413 | { |
389 | int h,pos=0; | 414 | int h,pos=0; |
390 | int hmax = buf->vb.height; | 415 | int hmax = buf->vb.height; |
391 | int wmax = buf->vb.width; | 416 | int wmax = buf->vb.width; |
392 | struct videobuf_buffer *vb=&buf->vb; | ||
393 | struct sg_to_addr *to_addr=buf->to_addr; | ||
394 | struct timeval ts; | 417 | struct timeval ts; |
418 | #ifdef CONFIG_VIVI_SCATTER | ||
419 | struct sg_to_addr *to_addr=buf->to_addr; | ||
420 | struct videobuf_buffer *vb=&buf->vb; | ||
421 | #else | ||
422 | char *tmpbuf; | ||
423 | #endif | ||
395 | 424 | ||
425 | #ifdef CONFIG_VIVI_SCATTER | ||
396 | /* Test if DMA mapping is ready */ | 426 | /* Test if DMA mapping is ready */ |
397 | if (!sg_dma_address(&vb->dma.sglist[0])) | 427 | if (!sg_dma_address(&vb->dma.sglist[0])) |
398 | return; | 428 | return; |
@@ -401,9 +431,27 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) | |||
401 | 431 | ||
402 | /* Check if there is enough memory */ | 432 | /* Check if there is enough memory */ |
403 | BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2); | 433 | BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2); |
434 | #else | ||
435 | if (buf->vb.dma.varea) { | ||
436 | tmpbuf=kmalloc (wmax*2, GFP_KERNEL); | ||
437 | } else { | ||
438 | tmpbuf=buf->vb.dma.vmalloc; | ||
439 | } | ||
440 | |||
441 | #endif | ||
404 | 442 | ||
405 | for (h=0;h<hmax;h++) { | 443 | for (h=0;h<hmax;h++) { |
444 | #ifdef CONFIG_VIVI_SCATTER | ||
406 | gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr); | 445 | gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr); |
446 | #else | ||
447 | if (buf->vb.dma.varea) { | ||
448 | gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr); | ||
449 | /* FIXME: replacing to __copy_to_user */ | ||
450 | copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2); | ||
451 | } else { | ||
452 | gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr); | ||
453 | } | ||
454 | #endif | ||
407 | pos += wmax*2; | 455 | pos += wmax*2; |
408 | } | 456 | } |
409 | 457 | ||
@@ -429,7 +477,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) | |||
429 | dev->h,dev->m,dev->s,(dev->us+500)/1000); | 477 | dev->h,dev->m,dev->s,(dev->us+500)/1000); |
430 | 478 | ||
431 | dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, | 479 | dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, |
432 | (unsigned long)buf->vb.dma.vmalloc,pos); | 480 | (unsigned long)buf->vb.dma.varea,pos); |
433 | 481 | ||
434 | /* Advice that buffer was filled */ | 482 | /* Advice that buffer was filled */ |
435 | buf->vb.state = STATE_DONE; | 483 | buf->vb.state = STATE_DONE; |
@@ -668,9 +716,11 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) | |||
668 | if (in_interrupt()) | 716 | if (in_interrupt()) |
669 | BUG(); | 717 | BUG(); |
670 | 718 | ||
719 | #ifdef CONFIG_VIVI_SCATTER | ||
671 | /*FIXME: Maybe a spinlock is required here */ | 720 | /*FIXME: Maybe a spinlock is required here */ |
672 | kfree(buf->to_addr); | 721 | kfree(buf->to_addr); |
673 | buf->to_addr=NULL; | 722 | buf->to_addr=NULL; |
723 | #endif | ||
674 | 724 | ||
675 | videobuf_waiton(&buf->vb,0,0); | 725 | videobuf_waiton(&buf->vb,0,0); |
676 | videobuf_dma_unmap(vq, &buf->vb.dma); | 726 | videobuf_dma_unmap(vq, &buf->vb.dma); |
@@ -716,11 +766,12 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, | |||
716 | 766 | ||
717 | buf->vb.state = STATE_PREPARED; | 767 | buf->vb.state = STATE_PREPARED; |
718 | 768 | ||
769 | #ifdef CONFIG_VIVI_SCATTER | ||
719 | if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) { | 770 | if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) { |
720 | rc=-ENOMEM; | 771 | rc=-ENOMEM; |
721 | goto fail; | 772 | goto fail; |
722 | } | 773 | } |
723 | 774 | #endif | |
724 | return 0; | 775 | return 0; |
725 | 776 | ||
726 | fail: | 777 | fail: |
@@ -785,6 +836,7 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb | |||
785 | free_buffer(vq,buf); | 836 | free_buffer(vq,buf); |
786 | } | 837 | } |
787 | 838 | ||
839 | #ifdef CONFIG_VIVI_SCATTER | ||
788 | static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents, | 840 | static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents, |
789 | int direction) | 841 | int direction) |
790 | { | 842 | { |
@@ -817,6 +869,7 @@ static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages, | |||
817 | // flush_write_buffers(); | 869 | // flush_write_buffers(); |
818 | return 0; | 870 | return 0; |
819 | } | 871 | } |
872 | #endif | ||
820 | 873 | ||
821 | static struct videobuf_queue_ops vivi_video_qops = { | 874 | static struct videobuf_queue_ops vivi_video_qops = { |
822 | .buf_setup = buffer_setup, | 875 | .buf_setup = buffer_setup, |
@@ -825,9 +878,9 @@ static struct videobuf_queue_ops vivi_video_qops = { | |||
825 | .buf_release = buffer_release, | 878 | .buf_release = buffer_release, |
826 | 879 | ||
827 | /* Non-pci handling routines */ | 880 | /* Non-pci handling routines */ |
828 | .vb_map_sg = vivi_map_sg, | 881 | // .vb_map_sg = vivi_map_sg, |
829 | .vb_dma_sync_sg = vivi_dma_sync_sg, | 882 | // .vb_dma_sync_sg = vivi_dma_sync_sg, |
830 | .vb_unmap_sg = vivi_unmap_sg, | 883 | // .vb_unmap_sg = vivi_unmap_sg, |
831 | }; | 884 | }; |
832 | 885 | ||
833 | /* ------------------------------------------------------------------ | 886 | /* ------------------------------------------------------------------ |
@@ -1205,11 +1258,19 @@ static int vivi_open(struct inode *inode, struct file *file) | |||
1205 | sprintf(dev->timestr,"%02d:%02d:%02d:%03d", | 1258 | sprintf(dev->timestr,"%02d:%02d:%02d:%03d", |
1206 | dev->h,dev->m,dev->s,(dev->us+500)/1000); | 1259 | dev->h,dev->m,dev->s,(dev->us+500)/1000); |
1207 | 1260 | ||
1261 | #ifdef CONFIG_VIVI_SCATTER | ||
1262 | videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops, | ||
1263 | NULL, NULL, | ||
1264 | fh->type, | ||
1265 | V4L2_FIELD_INTERLACED, | ||
1266 | sizeof(struct vivi_buffer),fh); | ||
1267 | #else | ||
1208 | videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops, | 1268 | videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops, |
1209 | NULL, NULL, | 1269 | NULL, NULL, |
1210 | fh->type, | 1270 | fh->type, |
1211 | V4L2_FIELD_INTERLACED, | 1271 | V4L2_FIELD_INTERLACED, |
1212 | sizeof(struct vivi_buffer),fh); | 1272 | sizeof(struct vivi_buffer),fh); |
1273 | #endif | ||
1213 | 1274 | ||
1214 | return 0; | 1275 | return 0; |
1215 | } | 1276 | } |
diff --git a/include/media/video-buf.h b/include/media/video-buf.h index 1115a256969f..d6f079476db3 100644 --- a/include/media/video-buf.h +++ b/include/media/video-buf.h | |||
@@ -78,6 +78,9 @@ struct videobuf_dmabuf { | |||
78 | /* for kernel buffers */ | 78 | /* for kernel buffers */ |
79 | void *vmalloc; | 79 | void *vmalloc; |
80 | 80 | ||
81 | /* Stores the userspace pointer to vmalloc area */ | ||
82 | void *varea; | ||
83 | |||
81 | /* for overlay buffers (pci-pci dma) */ | 84 | /* for overlay buffers (pci-pci dma) */ |
82 | dma_addr_t bus_addr; | 85 | dma_addr_t bus_addr; |
83 | 86 | ||