aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/videobuf-dma-sg.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2007-08-23 15:26:14 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-10-09 21:14:55 -0400
commit7a7d9a89d0307b1743d782197e2c5fc5ddf183f3 (patch)
treef5b1b220672128d089b5a6c469608e90482a6f60 /drivers/media/video/videobuf-dma-sg.c
parent7c596fa964806acb3b5ababb7ec4e1da35b140b3 (diff)
V4L/DVB (6251): Replace video-buf to a more generic approach
video-buf currently does two different tasks: - Manages video buffers with a common code that allows implementing all the V4L2 different modes of buffering; - Controls memory allocations While the first task is generic, the second were written to support PCI DMA Scatter/Gather needs. The original approach can't even work for those video capture hardware that don't support scatter/gather. I did one approach to make it more generic. While the approach worked fine for vivi driver, it were not generic enough to handle USB needs. This patch creates two different modules, one containing the generic video buffer handling (videobuf-core) and another with PCI DMA S/G. After this patch, it would be simpler to write an USB video-buf and a non-SG DMA module. Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org> http://thread.gmane.org/gmane.comp.video.video4linux/34978/focus=34981 Reviewed-by: Ricardo Cerqueira <v4l@cerqueira.org>
Diffstat (limited to 'drivers/media/video/videobuf-dma-sg.c')
-rw-r--r--drivers/media/video/videobuf-dma-sg.c772
1 files changed, 772 insertions, 0 deletions
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
new file mode 100644
index 000000000000..3345877c47d4
--- /dev/null
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -0,0 +1,772 @@
1/*
2 * helper functions for PCI DMA video4linux capture buffers
3 *
4 * The functions expect the hardware being able to scatter gatter
5 * (i.e. the buffers are not linear in physical memory, but fragmented
6 * into PAGE_SIZE chunks). They also assume the driver does not need
7 * to touch the video data.
8 *
9 * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
10 *
11 * Highly based on video-buf written originally by:
12 * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
13 * (c) 2006 Mauro Carvalho Chehab, <mchehab@infradead.org>
14 * (c) 2006 Ted Walther and John Sokol
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2
19 */
20
21#include <linux/init.h>
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/slab.h>
25#include <linux/interrupt.h>
26
27#include <linux/pci.h>
28#include <linux/vmalloc.h>
29#include <linux/pagemap.h>
30#include <asm/page.h>
31#include <asm/pgtable.h>
32
33#include <media/videobuf-dma-sg.h>
34
35#define MAGIC_DMABUF 0x19721112
36#define MAGIC_SG_MEM 0x17890714
37
38#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
39 { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
40
41static int debug = 0;
42module_param(debug, int, 0644);
43
44MODULE_DESCRIPTION("helper module to manage video4linux pci dma sg buffers");
45MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
46MODULE_LICENSE("GPL");
47
48#define dprintk(level, fmt, arg...) if (debug >= level) \
49 printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
50
51/* --------------------------------------------------------------------- */
52
53struct scatterlist*
54videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
55{
56 struct scatterlist *sglist;
57 struct page *pg;
58 int i;
59
60 sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
61 if (NULL == sglist)
62 return NULL;
63 for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
64 pg = vmalloc_to_page(virt);
65 if (NULL == pg)
66 goto err;
67 BUG_ON(PageHighMem(pg));
68 sglist[i].page = pg;
69 sglist[i].length = PAGE_SIZE;
70 }
71 return sglist;
72
73 err:
74 kfree(sglist);
75 return NULL;
76}
77
78struct scatterlist*
79videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
80{
81 struct scatterlist *sglist;
82 int i = 0;
83
84 if (NULL == pages[0])
85 return NULL;
86 sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL);
87 if (NULL == sglist)
88 return NULL;
89
90 if (NULL == pages[0])
91 goto nopage;
92 if (PageHighMem(pages[0]))
93 /* DMA to highmem pages might not work */
94 goto highmem;
95 sglist[0].page = pages[0];
96 sglist[0].offset = offset;
97 sglist[0].length = PAGE_SIZE - offset;
98 for (i = 1; i < nr_pages; i++) {
99 if (NULL == pages[i])
100 goto nopage;
101 if (PageHighMem(pages[i]))
102 goto highmem;
103 sglist[i].page = pages[i];
104 sglist[i].length = PAGE_SIZE;
105 }
106 return sglist;
107
108 nopage:
109 dprintk(2,"sgl: oops - no page\n");
110 kfree(sglist);
111 return NULL;
112
113 highmem:
114 dprintk(2,"sgl: oops - highmem page\n");
115 kfree(sglist);
116 return NULL;
117}
118
119/* --------------------------------------------------------------------- */
120
121struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf)
122{
123 struct videbuf_pci_sg_memory *mem=buf->priv;
124 BUG_ON (!mem);
125
126 MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
127
128 return &mem->dma;
129}
130
131void videobuf_dma_init(struct videobuf_dmabuf *dma)
132{
133 memset(dma,0,sizeof(*dma));
134 dma->magic = MAGIC_DMABUF;
135}
136
137int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
138 unsigned long data, unsigned long size)
139{
140 unsigned long first,last;
141 int err, rw = 0;
142
143 dma->direction = direction;
144 switch (dma->direction) {
145 case PCI_DMA_FROMDEVICE: rw = READ; break;
146 case PCI_DMA_TODEVICE: rw = WRITE; break;
147 default: BUG();
148 }
149
150 first = (data & PAGE_MASK) >> PAGE_SHIFT;
151 last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
152 dma->offset = data & ~PAGE_MASK;
153 dma->nr_pages = last-first+1;
154 dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
155 GFP_KERNEL);
156 if (NULL == dma->pages)
157 return -ENOMEM;
158 dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
159 data,size,dma->nr_pages);
160
161 dma->varea = (void *) data;
162
163 down_read(&current->mm->mmap_sem);
164 err = get_user_pages(current,current->mm,
165 data & PAGE_MASK, dma->nr_pages,
166 rw == READ, 1, /* force */
167 dma->pages, NULL);
168 up_read(&current->mm->mmap_sem);
169 if (err != dma->nr_pages) {
170 dma->nr_pages = (err >= 0) ? err : 0;
171 dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages);
172 return err < 0 ? err : -EINVAL;
173 }
174 return 0;
175}
176
177int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
178 int nr_pages)
179{
180 dprintk(1,"init kernel [%d pages]\n",nr_pages);
181 dma->direction = direction;
182 dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
183 if (NULL == dma->vmalloc) {
184 dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages);
185 return -ENOMEM;
186 }
187 dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
188 (unsigned long)dma->vmalloc,
189 nr_pages << PAGE_SHIFT);
190 memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT);
191 dma->nr_pages = nr_pages;
192 return 0;
193}
194
195int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
196 dma_addr_t addr, int nr_pages)
197{
198 dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n",
199 nr_pages,(unsigned long)addr);
200 dma->direction = direction;
201 if (0 == addr)
202 return -EINVAL;
203
204 dma->bus_addr = addr;
205 dma->nr_pages = nr_pages;
206 return 0;
207}
208
209int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
210{
211 void *dev=q->dev;
212 struct videobuf_dma_sg_ops *ops=q->priv_ops;
213
214 MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
215 BUG_ON(0 == dma->nr_pages);
216
217 if (dma->pages) {
218 dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
219 dma->offset);
220 }
221 if (dma->vmalloc) {
222 dma->sglist = videobuf_vmalloc_to_sg
223 (dma->vmalloc,dma->nr_pages);
224 }
225 if (dma->bus_addr) {
226 dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
227 if (NULL != dma->sglist) {
228 dma->sglen = 1;
229 sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
230 dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK;
231 sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE;
232 }
233 }
234 if (NULL == dma->sglist) {
235 dprintk(1,"scatterlist is NULL\n");
236 return -ENOMEM;
237 }
238 if (!dma->bus_addr) {
239 if (ops && ops->vb_map_sg) {
240 dma->sglen = ops->vb_map_sg(dev,dma->sglist,
241 dma->nr_pages, dma->direction);
242 }
243 if (0 == dma->sglen) {
244 printk(KERN_WARNING
245 "%s: videobuf_map_sg failed\n",__FUNCTION__);
246 kfree(dma->sglist);
247 dma->sglist = NULL;
248 dma->sglen = 0;
249 return -EIO;
250 }
251 }
252 return 0;
253}
254
255int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma)
256{
257 void *dev=q->dev;
258 struct videobuf_dma_sg_ops *ops=q->priv_ops;
259
260 MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
261 BUG_ON(!dma->sglen);
262
263 if (!dma->bus_addr && ops && ops->vb_dma_sync_sg)
264 ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages,
265 dma->direction);
266
267 return 0;
268}
269
270int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
271{
272 void *dev=q->dev;
273 struct videobuf_dma_sg_ops *ops=q->priv_ops;
274
275 MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
276 if (!dma->sglen)
277 return 0;
278
279 if (!dma->bus_addr && ops && ops->vb_unmap_sg)
280 ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages,
281 dma->direction);
282 kfree(dma->sglist);
283 dma->sglist = NULL;
284 dma->sglen = 0;
285 return 0;
286}
287
288int videobuf_dma_free(struct videobuf_dmabuf *dma)
289{
290 MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
291 BUG_ON(dma->sglen);
292
293 if (dma->pages) {
294 int i;
295 for (i=0; i < dma->nr_pages; i++)
296 page_cache_release(dma->pages[i]);
297 kfree(dma->pages);
298 dma->pages = NULL;
299 }
300
301 vfree(dma->vmalloc);
302 dma->vmalloc = NULL;
303 dma->varea = NULL;
304
305 if (dma->bus_addr) {
306 dma->bus_addr = 0;
307 }
308 dma->direction = PCI_DMA_NONE;
309 return 0;
310}
311
312/* --------------------------------------------------------------------- */
313
314int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma)
315{
316 struct videobuf_queue q;
317 struct videobuf_dma_sg_ops qops;
318
319 q.dev=pci;
320 qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg;
321 qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
322 q.priv_ops = &qops;
323
324 return (videobuf_dma_map(&q,dma));
325}
326
327int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma)
328{
329 struct videobuf_queue q;
330 struct videobuf_dma_sg_ops qops;
331
332 q.dev=pci;
333 qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg;
334 qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
335 q.priv_ops = &qops;
336
337 return (videobuf_dma_unmap(&q,dma));
338}
339
340/* --------------------------------------------------------------------- */
341
342static void
343videobuf_vm_open(struct vm_area_struct *vma)
344{
345 struct videobuf_mapping *map = vma->vm_private_data;
346
347 dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
348 map->count,vma->vm_start,vma->vm_end);
349 map->count++;
350}
351
352static void
353videobuf_vm_close(struct vm_area_struct *vma)
354{
355 struct videobuf_mapping *map = vma->vm_private_data;
356 struct videobuf_queue *q = map->q;
357 struct videbuf_pci_sg_memory *mem;
358 int i;
359
360 dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
361 map->count,vma->vm_start,vma->vm_end);
362
363 map->count--;
364 if (0 == map->count) {
365 dprintk(1,"munmap %p q=%p\n",map,q);
366 mutex_lock(&q->lock);
367 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
368 if (NULL == q->bufs[i])
369 continue;
370 mem=q->bufs[i]->priv;
371
372 if (!mem)
373 continue;
374
375 MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
376
377 if (mem->map != map)
378 continue;
379 mem->map = NULL;
380 q->bufs[i]->baddr = 0;
381 q->ops->buf_release(q,q->bufs[i]);
382 }
383 mutex_unlock(&q->lock);
384 kfree(map);
385 }
386 return;
387}
388
389/*
390 * Get a anonymous page for the mapping. Make sure we can DMA to that
391 * memory location with 32bit PCI devices (i.e. don't use highmem for
392 * now ...). Bounce buffers don't work very well for the data rates
393 * video capture has.
394 */
395static struct page*
396videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
397 int *type)
398{
399 struct page *page;
400
401 dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
402 vaddr,vma->vm_start,vma->vm_end);
403 if (vaddr > vma->vm_end)
404 return NOPAGE_SIGBUS;
405 page = alloc_page(GFP_USER | __GFP_DMA32);
406 if (!page)
407 return NOPAGE_OOM;
408 clear_user_page(page_address(page), vaddr, page);
409 if (type)
410 *type = VM_FAULT_MINOR;
411 return page;
412}
413
414static struct vm_operations_struct videobuf_vm_ops =
415{
416 .open = videobuf_vm_open,
417 .close = videobuf_vm_close,
418 .nopage = videobuf_vm_nopage,
419};
420
421/* ---------------------------------------------------------------------
422 * PCI handlers for the generic methods
423 */
424
425/* Allocated area consists on 3 parts:
426 struct video_buffer
427 struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
428 struct videobuf_pci_sg_memory
429 */
430
431static void *__videobuf_alloc(size_t size)
432{
433 struct videbuf_pci_sg_memory *mem;
434 struct videobuf_buffer *vb;
435
436 vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
437
438 mem = vb->priv = ((char *)vb)+size;
439 mem->magic=MAGIC_SG_MEM;
440
441 videobuf_dma_init(&mem->dma);
442
443 dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
444 __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
445 mem,(long)sizeof(*mem));
446
447 return vb;
448}
449
450static int __videobuf_iolock (struct videobuf_queue* q,
451 struct videobuf_buffer *vb,
452 struct v4l2_framebuffer *fbuf)
453{
454 int err,pages;
455 dma_addr_t bus;
456 struct videbuf_pci_sg_memory *mem=vb->priv;
457 BUG_ON(!mem);
458
459 MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
460
461 switch (vb->memory) {
462 case V4L2_MEMORY_MMAP:
463 case V4L2_MEMORY_USERPTR:
464 if (0 == vb->baddr) {
465 /* no userspace addr -- kernel bounce buffer */
466 pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
467 err = videobuf_dma_init_kernel( &mem->dma,
468 PCI_DMA_FROMDEVICE,
469 pages );
470 if (0 != err)
471 return err;
472 } else {
473 /* dma directly to userspace */
474 err = videobuf_dma_init_user( &mem->dma,
475 PCI_DMA_FROMDEVICE,
476 vb->baddr,vb->bsize );
477 if (0 != err)
478 return err;
479 }
480 break;
481 case V4L2_MEMORY_OVERLAY:
482 if (NULL == fbuf)
483 return -EINVAL;
484 /* FIXME: need sanity checks for vb->boff */
485 /*
486 * Using a double cast to avoid compiler warnings when
487 * building for PAE. Compiler doesn't like direct casting
488 * of a 32 bit ptr to 64 bit integer.
489 */
490 bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
491 pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
492 err = videobuf_dma_init_overlay(&mem->dma,PCI_DMA_FROMDEVICE,
493 bus, pages);
494 if (0 != err)
495 return err;
496 break;
497 default:
498 BUG();
499 }
500 err = videobuf_dma_map(q,&mem->dma);
501 if (0 != err)
502 return err;
503
504 return 0;
505}
506
507static int __videobuf_sync(struct videobuf_queue *q,
508 struct videobuf_buffer *buf)
509{
510 struct videbuf_pci_sg_memory *mem=buf->priv;
511 BUG_ON (!mem);
512 MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
513
514 return videobuf_dma_sync(q,&mem->dma);
515}
516
517static int __videobuf_mmap_free(struct videobuf_queue *q)
518{
519 int i;
520
521 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
522 if (q->bufs[i]) {
523 struct videbuf_pci_sg_memory *mem=q->bufs[i]->priv;
524 if (mem && mem->map)
525 return -EBUSY;
526 }
527 }
528
529 return 0;
530}
531
532static int __videobuf_mmap_mapper(struct videobuf_queue *q,
533 struct vm_area_struct *vma)
534{
535 struct videbuf_pci_sg_memory *mem;
536 struct videobuf_mapping *map;
537 unsigned int first,last,size,i;
538 int retval;
539
540 retval = -EINVAL;
541 if (!(vma->vm_flags & VM_WRITE)) {
542 dprintk(1,"mmap app bug: PROT_WRITE please\n");
543 goto done;
544 }
545 if (!(vma->vm_flags & VM_SHARED)) {
546 dprintk(1,"mmap app bug: MAP_SHARED please\n");
547 goto done;
548 }
549
550 /* look for first buffer to map */
551 for (first = 0; first < VIDEO_MAX_FRAME; first++) {
552 if (NULL == q->bufs[first])
553 continue;
554 mem=q->bufs[first]->priv;
555 BUG_ON (!mem);
556 MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
557
558 if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
559 continue;
560 if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
561 break;
562 }
563 if (VIDEO_MAX_FRAME == first) {
564 dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
565 (vma->vm_pgoff << PAGE_SHIFT));
566 goto done;
567 }
568
569 /* look for last buffer to map */
570 for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
571 if (NULL == q->bufs[last])
572 continue;
573 if (V4L2_MEMORY_MMAP != q->bufs[last]->memory)
574 continue;
575 mem=q->bufs[last]->priv;
576 if (mem->map) {
577 retval = -EBUSY;
578 goto done;
579 }
580 size += q->bufs[last]->bsize;
581 if (size == (vma->vm_end - vma->vm_start))
582 break;
583 }
584 if (VIDEO_MAX_FRAME == last) {
585 dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n",
586 (vma->vm_end - vma->vm_start));
587 goto done;
588 }
589
590 /* create mapping + update buffer list */
591 retval = -ENOMEM;
592 map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
593 if (NULL == map)
594 goto done;
595 for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) {
596 mem=q->bufs[i]->priv;
597 mem->map = map;
598 q->bufs[i]->baddr = vma->vm_start + size;
599 }
600 map->count = 1;
601 map->start = vma->vm_start;
602 map->end = vma->vm_end;
603 map->q = q;
604 vma->vm_ops = &videobuf_vm_ops;
605 vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
606 vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
607 vma->vm_private_data = map;
608 dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
609 map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);
610 retval = 0;
611
612 done:
613 return retval;
614}
615
616static int __videobuf_is_mmapped (struct videobuf_buffer *buf)
617{
618 struct videbuf_pci_sg_memory *mem=buf->priv;
619
620 BUG_ON (!mem);
621 MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
622
623 return (mem->map)?1:0;
624}
625
626static int __videobuf_copy_to_user ( struct videobuf_queue *q,
627 char __user *data, size_t count,
628 int nonblocking )
629{
630 struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
631 BUG_ON (!mem);
632 MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
633
634 /* copy to userspace */
635 if (count > q->read_buf->size - q->read_off)
636 count = q->read_buf->size - q->read_off;
637
638 if (copy_to_user(data, mem->dma.vmalloc+q->read_off, count))
639 return -EFAULT;
640
641 return count;
642}
643
644static int __videobuf_copy_stream ( struct videobuf_queue *q,
645 char __user *data, size_t count, size_t pos,
646 int vbihack, int nonblocking )
647{
648 unsigned int *fc;
649 struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
650 BUG_ON (!mem);
651 MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
652
653 if (vbihack) {
654 /* dirty, undocumented hack -- pass the frame counter
655 * within the last four bytes of each vbi data block.
656 * We need that one to maintain backward compatibility
657 * to all vbi decoding software out there ... */
658 fc = (unsigned int*)mem->dma.vmalloc;
659 fc += (q->read_buf->size>>2) -1;
660 *fc = q->read_buf->field_count >> 1;
661 dprintk(1,"vbihack: %d\n",*fc);
662 }
663
664 /* copy stuff using the common method */
665 count = __videobuf_copy_to_user (q,data,count,nonblocking);
666
667 if ( (count==-EFAULT) && (0 == pos) )
668 return -EFAULT;
669
670 return count;
671}
672
673static struct videobuf_qtype_ops pci_ops = {
674 .magic = MAGIC_QTYPE_OPS,
675
676 .alloc = __videobuf_alloc,
677 .iolock = __videobuf_iolock,
678 .sync = __videobuf_sync,
679 .mmap_free = __videobuf_mmap_free,
680 .mmap_mapper = __videobuf_mmap_mapper,
681 .is_mmapped = __videobuf_is_mmapped,
682 .copy_to_user = __videobuf_copy_to_user,
683 .copy_stream = __videobuf_copy_stream,
684};
685
686void *videobuf_pci_alloc (size_t size)
687{
688 struct videobuf_queue q;
689
690 /* Required to make generic handler to call __videobuf_alloc */
691 q.int_ops=&pci_ops;
692
693 q.msize=size;
694
695 return videobuf_alloc (&q);
696}
697
698void videobuf_queue_pci_init(struct videobuf_queue* q,
699 struct videobuf_queue_ops *ops,
700 void *dev,
701 spinlock_t *irqlock,
702 enum v4l2_buf_type type,
703 enum v4l2_field field,
704 unsigned int msize,
705 void *priv)
706{
707 struct videobuf_dma_sg_ops *priv_ops;
708
709 videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv);
710 q->int_ops=&pci_ops;
711
712 /* FIXME: the code bellow should be removed after having a proper
713 * memory allocation method for vivi and tm6000
714 */
715 q->priv_ops= kzalloc(sizeof(struct videobuf_dma_sg_ops), GFP_KERNEL);
716 BUG_ON (!q->priv_ops);
717
718 priv_ops=q->priv_ops;
719
720 /* Sets default methods for handling Scatter Gather mapping */
721 priv_ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg;
722 priv_ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
723 priv_ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu;
724}
725
726void videobuf_set_pci_ops (struct videobuf_queue* q,
727 struct videobuf_dma_sg_ops *ops)
728{
729 kfree (q->priv_ops);
730
731 q->priv_ops=ops;
732
733 if (!ops)
734 return;
735
736 /* If not specified, defaults to PCI map sg */
737 if (!ops->vb_map_sg)
738 ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg;
739
740 if (!ops->vb_dma_sync_sg)
741 ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu;
742 if (!ops->vb_unmap_sg)
743 ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
744}
745
746
747/* --------------------------------------------------------------------- */
748
749EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
750
751EXPORT_SYMBOL_GPL(videobuf_to_dma);
752EXPORT_SYMBOL_GPL(videobuf_dma_init);
753EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
754EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
755EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
756EXPORT_SYMBOL_GPL(videobuf_dma_map);
757EXPORT_SYMBOL_GPL(videobuf_dma_sync);
758EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
759EXPORT_SYMBOL_GPL(videobuf_dma_free);
760
761EXPORT_SYMBOL_GPL(videobuf_pci_dma_map);
762EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap);
763EXPORT_SYMBOL_GPL(videobuf_pci_alloc);
764
765EXPORT_SYMBOL_GPL(videobuf_queue_pci_init);
766EXPORT_SYMBOL_GPL(videobuf_set_pci_ops);
767
768/*
769 * Local variables:
770 * c-basic-offset: 8
771 * End:
772 */