X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Fvideobuf-dma-sg.c;h=43e78ee24a1099f829e7c4c0d5fe3f52d9661a80;hb=037c75eb14cd6adb837f81f0c2b2a52c31c91e69;hp=05dd38343fa36171d187b50979380ffcb2640b80;hpb=9900132f3437e9373aa030cdb5bd2d5db15566e3;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 05dd383..43e78ee 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -1,7 +1,7 @@ /* - * helper functions for PCI DMA video4linux capture buffers + * helper functions for SG DMA video4linux capture buffers * - * The functions expect the hardware being able to scatter gatter + * The functions expect the hardware being able to scatter gather * (i.e. the buffers are not linear in physical memory, but fragmented * into PAGE_SIZE chunks). They also assume the driver does not need * to touch the video data. @@ -21,12 +21,14 @@ #include #include #include +#include #include #include -#include +#include #include #include +#include #include #include @@ -35,140 +37,146 @@ #define MAGIC_DMABUF 0x19721112 #define MAGIC_SG_MEM 0x17890714 -#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ - { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } +#define MAGIC_CHECK(is, should) \ + if (unlikely((is) != (should))) { \ + printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \ + is, should); \ + BUG(); \ + } -static int debug = 0; +static int debug; module_param(debug, int, 0644); -MODULE_DESCRIPTION("helper module to manage video4linux pci dma sg buffers"); +MODULE_DESCRIPTION("helper module to manage video4linux dma sg buffers"); MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_LICENSE("GPL"); -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) +#define dprintk(level, fmt, arg...) \ + if (debug >= level) \ + printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) /* --------------------------------------------------------------------- */ -struct scatterlist* -videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) +struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) { struct scatterlist *sglist; struct page *pg; int i; - sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); + sglist = vmalloc(nr_pages * sizeof(*sglist)); if (NULL == sglist) return NULL; + memset(sglist, 0, nr_pages * sizeof(*sglist)); + sg_init_table(sglist, nr_pages); for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { pg = vmalloc_to_page(virt); if (NULL == pg) goto err; BUG_ON(PageHighMem(pg)); - sglist[i].page = pg; - sglist[i].length = PAGE_SIZE; + sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); } return sglist; - err: - kfree(sglist); +err: + vfree(sglist); return NULL; } +EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); -struct scatterlist* -videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) +struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages, + int offset) { struct scatterlist *sglist; - int i = 0; + int i; if (NULL == pages[0]) return NULL; - sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL); + sglist = vmalloc(nr_pages * sizeof(*sglist)); if (NULL == sglist) return NULL; + sg_init_table(sglist, nr_pages); - if (NULL == pages[0]) - goto nopage; if (PageHighMem(pages[0])) /* DMA to highmem pages might not work */ goto highmem; - sglist[0].page = pages[0]; - sglist[0].offset = offset; - sglist[0].length = PAGE_SIZE - offset; + sg_set_page(&sglist[0], pages[0], PAGE_SIZE - offset, offset); for (i = 1; i < nr_pages; i++) { if (NULL == pages[i]) goto nopage; if (PageHighMem(pages[i])) goto highmem; - sglist[i].page = pages[i]; - sglist[i].length = PAGE_SIZE; + sg_set_page(&sglist[i], pages[i], PAGE_SIZE, 0); } return sglist; - nopage: - dprintk(2,"sgl: oops - no page\n"); - kfree(sglist); +nopage: + dprintk(2, "sgl: oops - no page\n"); + vfree(sglist); return NULL; - highmem: - dprintk(2,"sgl: oops - highmem page\n"); - kfree(sglist); +highmem: + dprintk(2, "sgl: oops - highmem page\n"); + vfree(sglist); return NULL; } /* --------------------------------------------------------------------- */ -struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf) +struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf) { - struct videbuf_pci_sg_memory *mem=buf->priv; - BUG_ON (!mem); + struct videobuf_dma_sg_memory *mem = buf->priv; + BUG_ON(!mem); - MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); return &mem->dma; } +EXPORT_SYMBOL_GPL(videobuf_to_dma); void videobuf_dma_init(struct videobuf_dmabuf *dma) { - memset(dma,0,sizeof(*dma)); + memset(dma, 0, sizeof(*dma)); dma->magic = MAGIC_DMABUF; } +EXPORT_SYMBOL_GPL(videobuf_dma_init); static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, int direction, unsigned long data, unsigned long size) { - unsigned long first,last; + unsigned long first, last; int err, rw = 0; dma->direction = direction; switch (dma->direction) { - case PCI_DMA_FROMDEVICE: rw = READ; break; - case PCI_DMA_TODEVICE: rw = WRITE; break; - default: BUG(); + case DMA_FROM_DEVICE: + rw = READ; + break; + case DMA_TO_DEVICE: + rw = WRITE; + break; + default: + BUG(); } first = (data & PAGE_MASK) >> PAGE_SHIFT; last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; dma->offset = data & ~PAGE_MASK; dma->nr_pages = last-first+1; - dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), - GFP_KERNEL); + dma->pages = kmalloc(dma->nr_pages * sizeof(struct page *), GFP_KERNEL); if (NULL == dma->pages) return -ENOMEM; - dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", - data,size,dma->nr_pages); - - dma->varea = (void *) data; + dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n", + data, size, dma->nr_pages); - err = get_user_pages(current,current->mm, + err = get_user_pages(current, current->mm, data & PAGE_MASK, dma->nr_pages, rw == READ, 1, /* force */ dma->pages, NULL); if (err != dma->nr_pages) { dma->nr_pages = (err >= 0) ? err : 0; - dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); + dprintk(1, "get_user_pages: err=%d [%d]\n", err, dma->nr_pages); return err < 0 ? err : -EINVAL; } return 0; @@ -178,51 +186,58 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, unsigned long data, unsigned long size) { int ret; + down_read(¤t->mm->mmap_sem); ret = videobuf_dma_init_user_locked(dma, direction, data, size); up_read(¤t->mm->mmap_sem); return ret; } +EXPORT_SYMBOL_GPL(videobuf_dma_init_user); int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, int nr_pages) { - dprintk(1,"init kernel [%d pages]\n",nr_pages); + dprintk(1, "init kernel [%d pages]\n", nr_pages); + dma->direction = direction; dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT); if (NULL == dma->vmalloc) { - dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages); + dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages); return -ENOMEM; } - dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", + + dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", (unsigned long)dma->vmalloc, nr_pages << PAGE_SHIFT); - memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT); + + memset(dma->vmalloc, 0, nr_pages << PAGE_SHIFT); dma->nr_pages = nr_pages; + return 0; } +EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction, dma_addr_t addr, int nr_pages) { - dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n", - nr_pages,(unsigned long)addr); + dprintk(1, "init overlay [%d pages @ bus 0x%lx]\n", + nr_pages, (unsigned long)addr); dma->direction = direction; + if (0 == addr) return -EINVAL; dma->bus_addr = addr; dma->nr_pages = nr_pages; + return 0; } +EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); -int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) +int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma) { - void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + MAGIC_CHECK(dma->magic, MAGIC_DMABUF); BUG_ON(0 == dma->nr_pages); if (dma->pages) { @@ -230,80 +245,76 @@ int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma) dma->offset); } if (dma->vmalloc) { - dma->sglist = videobuf_vmalloc_to_sg - (dma->vmalloc,dma->nr_pages); + dma->sglist = videobuf_vmalloc_to_sg(dma->vmalloc, + dma->nr_pages); } if (dma->bus_addr) { - dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); + dma->sglist = vmalloc(sizeof(*dma->sglist)); if (NULL != dma->sglist) { - dma->sglen = 1; - sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; - dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; - sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; + dma->sglen = 1; + sg_dma_address(&dma->sglist[0]) = dma->bus_addr + & PAGE_MASK; + dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; + sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; } } if (NULL == dma->sglist) { - dprintk(1,"scatterlist is NULL\n"); + dprintk(1, "scatterlist is NULL\n"); return -ENOMEM; } if (!dma->bus_addr) { - if (ops && ops->vb_map_sg) { - dma->sglen = ops->vb_map_sg(dev,dma->sglist, + dma->sglen = dma_map_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction); - } if (0 == dma->sglen) { printk(KERN_WARNING - "%s: videobuf_map_sg failed\n",__FUNCTION__); - kfree(dma->sglist); + "%s: videobuf_map_sg failed\n", __func__); + vfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; - return -EIO; + return -ENOMEM; } } + return 0; } +EXPORT_SYMBOL_GPL(videobuf_dma_map); -int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma) +int videobuf_dma_sync(struct videobuf_queue *q, struct videobuf_dmabuf *dma) { - void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; - - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + MAGIC_CHECK(dma->magic, MAGIC_DMABUF); BUG_ON(!dma->sglen); - if (!dma->bus_addr && ops && ops->vb_dma_sync_sg) - ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); + dma_sync_sg_for_cpu(q->dev, dma->sglist, dma->nr_pages, dma->direction); return 0; } +EXPORT_SYMBOL_GPL(videobuf_dma_sync); -int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) +int videobuf_dma_unmap(struct videobuf_queue *q, struct videobuf_dmabuf *dma) { - void *dev=q->dev; - struct videobuf_dma_sg_ops *ops=q->priv_ops; + MAGIC_CHECK(dma->magic, MAGIC_DMABUF); - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); if (!dma->sglen) return 0; - if (!dma->bus_addr && ops && ops->vb_unmap_sg) - ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); - kfree(dma->sglist); + dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction); + + vfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; + return 0; } +EXPORT_SYMBOL_GPL(videobuf_dma_unmap); int videobuf_dma_free(struct videobuf_dmabuf *dma) { - MAGIC_CHECK(dma->magic,MAGIC_DMABUF); + int i; + MAGIC_CHECK(dma->magic, MAGIC_DMABUF); BUG_ON(dma->sglen); if (dma->pages) { - int i; - for (i=0; i < dma->nr_pages; i++) + for (i = 0; i < dma->nr_pages; i++) page_cache_release(dma->pages[i]); kfree(dma->pages); dma->pages = NULL; @@ -311,87 +322,79 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) vfree(dma->vmalloc); dma->vmalloc = NULL; - dma->varea = NULL; - if (dma->bus_addr) { + if (dma->bus_addr) dma->bus_addr = 0; - } - dma->direction = PCI_DMA_NONE; + dma->direction = DMA_NONE; + return 0; } +EXPORT_SYMBOL_GPL(videobuf_dma_free); /* --------------------------------------------------------------------- */ -int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) +int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma) { struct videobuf_queue q; - struct videobuf_dma_sg_ops qops; - q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.priv_ops = &qops; + q.dev = dev; - return (videobuf_dma_map(&q,dma)); + return videobuf_dma_map(&q, dma); } +EXPORT_SYMBOL_GPL(videobuf_sg_dma_map); -int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) +int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma) { struct videobuf_queue q; - struct videobuf_dma_sg_ops qops; - q.dev=pci; - qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; - qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - q.priv_ops = &qops; + q.dev = dev; - return (videobuf_dma_unmap(&q,dma)); + return videobuf_dma_unmap(&q, dma); } +EXPORT_SYMBOL_GPL(videobuf_sg_dma_unmap); /* --------------------------------------------------------------------- */ -static void -videobuf_vm_open(struct vm_area_struct *vma) +static void videobuf_vm_open(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; - dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map, - map->count,vma->vm_start,vma->vm_end); + dprintk(2, "vm_open %p [count=%d,vma=%08lx-%08lx]\n", map, + map->count, vma->vm_start, vma->vm_end); + map->count++; } -static void -videobuf_vm_close(struct vm_area_struct *vma) +static void videobuf_vm_close(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_queue *q = map->q; - struct videbuf_pci_sg_memory *mem; + struct videobuf_dma_sg_memory *mem; int i; - dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, - map->count,vma->vm_start,vma->vm_end); + dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map, + map->count, vma->vm_start, vma->vm_end); map->count--; if (0 == map->count) { - dprintk(1,"munmap %p q=%p\n",map,q); - mutex_lock(&q->lock); + dprintk(1, "munmap %p q=%p\n", map, q); + mutex_lock(&q->vb_lock); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - mem=q->bufs[i]->priv; - + mem = q->bufs[i]->priv; if (!mem) continue; - MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); if (q->bufs[i]->map != map) continue; q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; - q->ops->buf_release(q,q->bufs[i]); + q->ops->buf_release(q, q->bufs[i]); } - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); kfree(map); } return; @@ -403,71 +406,80 @@ videobuf_vm_close(struct vm_area_struct *vma) * now ...). Bounce buffers don't work very well for the data rates * video capture has. */ -static struct page* -videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, - int *type) +static int videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct page *page; - dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", - vaddr,vma->vm_start,vma->vm_end); - if (vaddr > vma->vm_end) - return NOPAGE_SIGBUS; + dprintk(3, "fault: fault @ %08lx [vma %08lx-%08lx]\n", + (unsigned long)vmf->virtual_address, + vma->vm_start, vma->vm_end); + page = alloc_page(GFP_USER | __GFP_DMA32); if (!page) - return NOPAGE_OOM; - clear_user_page(page_address(page), vaddr, page); - if (type) - *type = VM_FAULT_MINOR; - return page; + return VM_FAULT_OOM; + clear_user_highpage(page, (unsigned long)vmf->virtual_address); + vmf->page = page; + + return 0; } -static struct vm_operations_struct videobuf_vm_ops = -{ - .open = videobuf_vm_open, - .close = videobuf_vm_close, - .nopage = videobuf_vm_nopage, +static const struct vm_operations_struct videobuf_vm_ops = { + .open = videobuf_vm_open, + .close = videobuf_vm_close, + .fault = videobuf_vm_fault, }; /* --------------------------------------------------------------------- - * PCI handlers for the generic methods + * SG handlers for the generic methods */ /* Allocated area consists on 3 parts: struct video_buffer struct _buffer (cx88_buffer, saa7134_buf, ...) - struct videobuf_pci_sg_memory + struct videobuf_dma_sg_memory */ -static void *__videobuf_alloc(size_t size) +static struct videobuf_buffer *__videobuf_alloc(size_t size) { - struct videbuf_pci_sg_memory *mem; + struct videobuf_dma_sg_memory *mem; struct videobuf_buffer *vb; - vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); + vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); + if (!vb) + return vb; - mem = vb->priv = ((char *)vb)+size; - mem->magic=MAGIC_SG_MEM; + mem = vb->priv = ((char *)vb) + size; + mem->magic = MAGIC_SG_MEM; videobuf_dma_init(&mem->dma); - dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", - __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), - mem,(long)sizeof(*mem)); + dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n", + __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb), + mem, (long)sizeof(*mem)); return vb; } -static int __videobuf_iolock (struct videobuf_queue* q, - struct videobuf_buffer *vb, - struct v4l2_framebuffer *fbuf) +static void *__videobuf_to_vaddr(struct videobuf_buffer *buf) +{ + struct videobuf_dma_sg_memory *mem = buf->priv; + BUG_ON(!mem); + + MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); + + return mem->dma.vmalloc; +} + +static int __videobuf_iolock(struct videobuf_queue *q, + struct videobuf_buffer *vb, + struct v4l2_framebuffer *fbuf) { - int err,pages; + int err, pages; dma_addr_t bus; - struct videbuf_pci_sg_memory *mem=vb->priv; + struct videobuf_dma_sg_memory *mem = vb->priv; BUG_ON(!mem); - MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); switch (vb->memory) { case V4L2_MEMORY_MMAP: @@ -475,16 +487,16 @@ static int __videobuf_iolock (struct videobuf_queue* q, if (0 == vb->baddr) { /* no userspace addr -- kernel bounce buffer */ pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_kernel( &mem->dma, - PCI_DMA_FROMDEVICE, - pages ); + err = videobuf_dma_init_kernel(&mem->dma, + DMA_FROM_DEVICE, + pages); if (0 != err) return err; } else if (vb->memory == V4L2_MEMORY_USERPTR) { /* dma directly to userspace */ - err = videobuf_dma_init_user( &mem->dma, - PCI_DMA_FROMDEVICE, - vb->baddr,vb->bsize ); + err = videobuf_dma_init_user(&mem->dma, + DMA_FROM_DEVICE, + vb->baddr, vb->bsize); if (0 != err) return err; } else { @@ -494,7 +506,7 @@ static int __videobuf_iolock (struct videobuf_queue* q, locking inversion, so don't take it here */ err = videobuf_dma_init_user_locked(&mem->dma, - PCI_DMA_FROMDEVICE, + DMA_FROM_DEVICE, vb->baddr, vb->bsize); if (0 != err) return err; @@ -511,7 +523,7 @@ static int __videobuf_iolock (struct videobuf_queue* q, */ bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff; pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - err = videobuf_dma_init_overlay(&mem->dma,PCI_DMA_FROMDEVICE, + err = videobuf_dma_init_overlay(&mem->dma, DMA_FROM_DEVICE, bus, pages); if (0 != err) return err; @@ -519,7 +531,7 @@ static int __videobuf_iolock (struct videobuf_queue* q, default: BUG(); } - err = videobuf_dma_map(q,&mem->dma); + err = videobuf_dma_map(q, &mem->dma); if (0 != err) return err; @@ -529,52 +541,46 @@ static int __videobuf_iolock (struct videobuf_queue* q, static int __videobuf_sync(struct videobuf_queue *q, struct videobuf_buffer *buf) { - struct videbuf_pci_sg_memory *mem=buf->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); - - return videobuf_dma_sync(q,&mem->dma); -} - -static int __videobuf_mmap_free(struct videobuf_queue *q) -{ - int i; - - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (q->bufs[i]) { - if (q->bufs[i]->map) - return -EBUSY; - } - } + struct videobuf_dma_sg_memory *mem = buf->priv; + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); - return 0; + return videobuf_dma_sync(q, &mem->dma); } static int __videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma) { - struct videbuf_pci_sg_memory *mem; + struct videobuf_dma_sg_memory *mem; struct videobuf_mapping *map; - unsigned int first,last,size,i; + unsigned int first, last, size, i; int retval; retval = -EINVAL; if (!(vma->vm_flags & VM_WRITE)) { - dprintk(1,"mmap app bug: PROT_WRITE please\n"); + dprintk(1, "mmap app bug: PROT_WRITE please\n"); goto done; } if (!(vma->vm_flags & VM_SHARED)) { - dprintk(1,"mmap app bug: MAP_SHARED please\n"); + dprintk(1, "mmap app bug: MAP_SHARED please\n"); goto done; } + /* This function maintains backwards compatibility with V4L1 and will + * map more than one buffer if the vma length is equal to the combined + * size of multiple buffers than it will map them together. See + * VIDIOCGMBUF in the v4l spec + * + * TODO: Allow drivers to specify if they support this mode + */ + /* look for first buffer to map */ for (first = 0; first < VIDEO_MAX_FRAME; first++) { if (NULL == q->bufs[first]) continue; - mem=q->bufs[first]->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + mem = q->bufs[first]->priv; + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) continue; @@ -582,7 +588,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, break; } if (VIDEO_MAX_FRAME == first) { - dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", + dprintk(1, "mmap app bug: offset invalid [offset=0x%lx]\n", (vma->vm_pgoff << PAGE_SHIFT)); goto done; } @@ -597,25 +603,31 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, retval = -EBUSY; goto done; } - size += q->bufs[last]->bsize; + size += PAGE_ALIGN(q->bufs[last]->bsize); if (size == (vma->vm_end - vma->vm_start)) break; } if (VIDEO_MAX_FRAME == last) { - dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n", + dprintk(1, "mmap app bug: size invalid [size=0x%lx]\n", (vma->vm_end - vma->vm_start)); goto done; } /* create mapping + update buffer list */ retval = -ENOMEM; - map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + map = kmalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); if (NULL == map) goto done; - for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { + + size = 0; + for (i = first; i <= last; i++) { + if (NULL == q->bufs[i]) + continue; q->bufs[i]->map = map; q->bufs[i]->baddr = vma->vm_start + size; + size += PAGE_ALIGN(q->bufs[i]->bsize); } + map->count = 1; map->start = vma->vm_start; map->end = vma->vm_end; @@ -624,21 +636,21 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ vma->vm_private_data = map; - dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", - map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); + dprintk(1, "mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", + map, q, vma->vm_start, vma->vm_end, vma->vm_pgoff, first, last); retval = 0; - done: +done: return retval; } -static int __videobuf_copy_to_user ( struct videobuf_queue *q, +static int __videobuf_copy_to_user(struct videobuf_queue *q, char __user *data, size_t count, - int nonblocking ) + int nonblocking) { - struct videbuf_pci_sg_memory *mem=q->read_buf->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + struct videobuf_dma_sg_memory *mem = q->read_buf->priv; + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); /* copy to userspace */ if (count > q->read_buf->size - q->read_off) @@ -650,131 +662,71 @@ static int __videobuf_copy_to_user ( struct videobuf_queue *q, return count; } -static int __videobuf_copy_stream ( struct videobuf_queue *q, +static int __videobuf_copy_stream(struct videobuf_queue *q, char __user *data, size_t count, size_t pos, - int vbihack, int nonblocking ) + int vbihack, int nonblocking) { - unsigned int *fc; - struct videbuf_pci_sg_memory *mem=q->read_buf->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_SG_MEM); + unsigned int *fc; + struct videobuf_dma_sg_memory *mem = q->read_buf->priv; + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); if (vbihack) { /* dirty, undocumented hack -- pass the frame counter - * within the last four bytes of each vbi data block. - * We need that one to maintain backward compatibility - * to all vbi decoding software out there ... */ - fc = (unsigned int*)mem->dma.vmalloc; - fc += (q->read_buf->size>>2) -1; + * within the last four bytes of each vbi data block. + * We need that one to maintain backward compatibility + * to all vbi decoding software out there ... */ + fc = (unsigned int *)mem->dma.vmalloc; + fc += (q->read_buf->size >> 2) - 1; *fc = q->read_buf->field_count >> 1; - dprintk(1,"vbihack: %d\n",*fc); + dprintk(1, "vbihack: %d\n", *fc); } /* copy stuff using the common method */ - count = __videobuf_copy_to_user (q,data,count,nonblocking); + count = __videobuf_copy_to_user(q, data, count, nonblocking); - if ( (count==-EFAULT) && (0 == pos) ) + if ((count == -EFAULT) && (0 == pos)) return -EFAULT; return count; } -static struct videobuf_qtype_ops pci_ops = { +static struct videobuf_qtype_ops sg_ops = { .magic = MAGIC_QTYPE_OPS, .alloc = __videobuf_alloc, .iolock = __videobuf_iolock, .sync = __videobuf_sync, - .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, - .copy_to_user = __videobuf_copy_to_user, + .video_copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, + .vaddr = __videobuf_to_vaddr, }; -void *videobuf_pci_alloc (size_t size) +void *videobuf_sg_alloc(size_t size) { struct videobuf_queue q; /* Required to make generic handler to call __videobuf_alloc */ - q.int_ops=&pci_ops; + q.int_ops = &sg_ops; - q.msize=size; + q.msize = size; - return videobuf_alloc (&q); + return videobuf_alloc(&q); } +EXPORT_SYMBOL_GPL(videobuf_sg_alloc); -void videobuf_queue_pci_init(struct videobuf_queue* q, - struct videobuf_queue_ops *ops, - void *dev, +void videobuf_queue_sg_init(struct videobuf_queue *q, + const struct videobuf_queue_ops *ops, + struct device *dev, spinlock_t *irqlock, enum v4l2_buf_type type, enum v4l2_field field, unsigned int msize, void *priv) { - struct videobuf_dma_sg_ops *priv_ops; - - videobuf_queue_init(q, ops, dev, irqlock, type, field, msize, priv); - q->int_ops=&pci_ops; - - /* FIXME: the code bellow should be removed after having a proper - * memory allocation method for vivi and tm6000 - */ - q->priv_ops= kzalloc(sizeof(struct videobuf_dma_sg_ops), GFP_KERNEL); - BUG_ON (!q->priv_ops); - - priv_ops=q->priv_ops; - - /* Sets default methods for handling Scatter Gather mapping */ - priv_ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - priv_ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; - priv_ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; -} - -void videobuf_set_pci_ops (struct videobuf_queue* q, - struct videobuf_dma_sg_ops *ops) -{ - kfree (q->priv_ops); - - q->priv_ops=ops; - - if (!ops) - return; - - /* If not specified, defaults to PCI map sg */ - if (!ops->vb_map_sg) - ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg; - - if (!ops->vb_dma_sync_sg) - ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu; - if (!ops->vb_unmap_sg) - ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, + priv, &sg_ops); } +EXPORT_SYMBOL_GPL(videobuf_queue_sg_init); - -/* --------------------------------------------------------------------- */ - -EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); - -EXPORT_SYMBOL_GPL(videobuf_to_dma); -EXPORT_SYMBOL_GPL(videobuf_dma_init); -EXPORT_SYMBOL_GPL(videobuf_dma_init_user); -EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); -EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay); -EXPORT_SYMBOL_GPL(videobuf_dma_map); -EXPORT_SYMBOL_GPL(videobuf_dma_sync); -EXPORT_SYMBOL_GPL(videobuf_dma_unmap); -EXPORT_SYMBOL_GPL(videobuf_dma_free); - -EXPORT_SYMBOL_GPL(videobuf_pci_dma_map); -EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap); -EXPORT_SYMBOL_GPL(videobuf_pci_alloc); - -EXPORT_SYMBOL_GPL(videobuf_queue_pci_init); -EXPORT_SYMBOL_GPL(videobuf_set_pci_ops); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */