X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Fvideo-buf.c;h=5bac907dc9deb0f04ca9d9177f593bb98d07343f;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=c7c7465508f0389793b9a6375ba2f7be7a992991;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index c7c746550..5bac907dc 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -1,4 +1,6 @@ /* + * $Id: video-buf.c,v 1.17 2004/12/10 12:33:40 kraxel Exp $ + * * generic helper functions for video4linux capture buffers, to handle * memory management and PCI DMA. Right now bttv + saa7134 use it. * @@ -7,7 +9,7 @@ * into PAGE_SIZE chunks). They also assume the driver does not need * to touch the video data (thus it is probably not useful for USB 1.1 * as data often must be uncompressed by the drivers). - * + * * (c) 2001-2004 Gerd Knorr [SUSE Labs] * * This program is free software; you can redistribute it and/or modify @@ -18,6 +20,7 @@ #include #include +#include #include #include #include @@ -34,11 +37,11 @@ { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } static int debug = 0; +module_param(debug, int, 0644); MODULE_DESCRIPTION("helper module to manage video4linux pci dma buffers"); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); -MODULE_PARM(debug,"i"); #define dprintk(level, fmt, arg...) if (debug >= level) \ printk(KERN_DEBUG "vbuf: " fmt , ## arg) @@ -64,7 +67,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) sglist[i].length = PAGE_SIZE; } return sglist; - + err: kfree(sglist); return NULL; @@ -191,7 +194,7 @@ int videobuf_dma_pci_map(struct pci_dev *dev, struct videobuf_dmabuf *dma) { MAGIC_CHECK(dma->magic,MAGIC_DMABUF); BUG_ON(0 == dma->nr_pages); - + if (dma->pages) { dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, dma->offset); @@ -287,7 +290,7 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) { int retval = 0; DECLARE_WAITQUEUE(wait, current); - + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); add_wait_queue(&vb->done, &wait); while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { @@ -353,39 +356,39 @@ videobuf_iolock(struct pci_dev *pci, struct videobuf_buffer *vb, err = videobuf_dma_pci_map(pci,&vb->dma); if (0 != err) return err; - + return 0; } /* --------------------------------------------------------------------- */ -void -videobuf_queue_init(struct videobuf_queue *q, - struct videobuf_queue_ops *ops, - struct pci_dev *pci, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize) +void videobuf_queue_init(struct videobuf_queue* q, + struct videobuf_queue_ops *ops, + struct pci_dev *pci, + spinlock_t *irqlock, + enum v4l2_buf_type type, + enum v4l2_field field, + unsigned int msize, + void *priv) { memset(q,0,sizeof(*q)); - q->irqlock = irqlock; q->pci = pci; q->type = type; q->field = field; q->msize = msize; q->ops = ops; + q->priv_data = priv; init_MUTEX(&q->lock); INIT_LIST_HEAD(&q->stream); } -int +int videobuf_queue_is_busy(struct videobuf_queue *q) { int i; - + if (q->streaming) { dprintk(1,"busy: streaming active\n"); return 1; @@ -418,7 +421,7 @@ videobuf_queue_is_busy(struct videobuf_queue *q) } void -videobuf_queue_cancel(struct file *file, struct videobuf_queue *q) +videobuf_queue_cancel(struct videobuf_queue *q) { unsigned long flags; int i; @@ -439,7 +442,7 @@ videobuf_queue_cancel(struct file *file, struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - q->ops->buf_release(file,q->bufs[i]); + q->ops->buf_release(q,q->bufs[i]); } INIT_LIST_HEAD(&q->stream); } @@ -521,7 +524,7 @@ videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, } int -videobuf_reqbufs(struct file *file, struct videobuf_queue *q, +videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req) { unsigned int size,count; @@ -546,12 +549,12 @@ videobuf_reqbufs(struct file *file, struct videobuf_queue *q, if (count > VIDEO_MAX_FRAME) count = VIDEO_MAX_FRAME; size = 0; - q->ops->buf_setup(file,&count,&size); + q->ops->buf_setup(q,&count,&size); size = PAGE_ALIGN(size); dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", count, size, (count*size)>>PAGE_SHIFT); - retval = videobuf_mmap_setup(file,q,count,size,req->memory); + retval = videobuf_mmap_setup(q,count,size,req->memory); if (retval < 0) goto done; @@ -576,7 +579,7 @@ videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) } int -videobuf_qbuf(struct file *file, struct videobuf_queue *q, +videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b) { struct videobuf_buffer *buf; @@ -620,7 +623,7 @@ videobuf_qbuf(struct file *file, struct videobuf_queue *q, if (b->length < buf->bsize) goto done; if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) - q->ops->buf_release(file,buf); + q->ops->buf_release(q,buf); buf->baddr = b->m.userptr; break; case V4L2_MEMORY_OVERLAY: @@ -631,30 +634,30 @@ videobuf_qbuf(struct file *file, struct videobuf_queue *q, } field = videobuf_next_field(q); - retval = q->ops->buf_prepare(file,buf,field); + retval = q->ops->buf_prepare(q,buf,field); if (0 != retval) goto done; - + list_add_tail(&buf->stream,&q->stream); if (q->streaming) { spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(file,buf); + q->ops->buf_queue(q,buf); spin_unlock_irqrestore(q->irqlock,flags); } retval = 0; - + done: up(&q->lock); return retval; } int -videobuf_dqbuf(struct file *file, struct videobuf_queue *q, - struct v4l2_buffer *b) +videobuf_dqbuf(struct videobuf_queue *q, + struct v4l2_buffer *b, int nonblocking) { struct videobuf_buffer *buf; int retval; - + down(&q->lock); retval = -EBUSY; if (q->reading) @@ -665,7 +668,7 @@ videobuf_dqbuf(struct file *file, struct videobuf_queue *q, if (list_empty(&q->stream)) goto done; buf = list_entry(q->stream.next, struct videobuf_buffer, stream); - retval = videobuf_waiton(buf, file->f_flags & O_NONBLOCK, 1); + retval = videobuf_waiton(buf, nonblocking, 1); if (retval < 0) goto done; switch (buf->state) { @@ -689,13 +692,13 @@ videobuf_dqbuf(struct file *file, struct videobuf_queue *q, return retval; } -int videobuf_streamon(struct file *file, struct videobuf_queue *q) +int videobuf_streamon(struct videobuf_queue *q) { struct videobuf_buffer *buf; struct list_head *list; unsigned long flags; int retval; - + down(&q->lock); retval = -EBUSY; if (q->reading) @@ -708,7 +711,7 @@ int videobuf_streamon(struct file *file, struct videobuf_queue *q) list_for_each(list,&q->stream) { buf = list_entry(list, struct videobuf_buffer, stream); if (buf->state == STATE_PREPARED) - q->ops->buf_queue(file,buf); + q->ops->buf_queue(q,buf); } spin_unlock_irqrestore(q->irqlock,flags); @@ -717,14 +720,14 @@ int videobuf_streamon(struct file *file, struct videobuf_queue *q) return retval; } -int videobuf_streamoff(struct file *file, struct videobuf_queue *q) +int videobuf_streamoff(struct videobuf_queue *q) { int retval = -EINVAL; down(&q->lock); if (!q->streaming) goto done; - videobuf_queue_cancel(file,q); + videobuf_queue_cancel(q); q->streaming = 0; retval = 0; @@ -734,8 +737,8 @@ int videobuf_streamoff(struct file *file, struct videobuf_queue *q) } static ssize_t -videobuf_read_zerocopy(struct file *file, struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos) +videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data, + size_t count, loff_t *ppos) { enum v4l2_field field; unsigned long flags; @@ -751,13 +754,13 @@ videobuf_read_zerocopy(struct file *file, struct videobuf_queue *q, q->read_buf->baddr = (unsigned long)data; q->read_buf->bsize = count; field = videobuf_next_field(q); - retval = q->ops->buf_prepare(file,q->read_buf,field); + retval = q->ops->buf_prepare(q,q->read_buf,field); if (0 != retval) goto done; - + /* start capture & wait */ spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(file,q->read_buf); + q->ops->buf_queue(q,q->read_buf); spin_unlock_irqrestore(q->irqlock,flags); retval = videobuf_waiton(q->read_buf,0,0); if (0 == retval) { @@ -770,14 +773,15 @@ videobuf_read_zerocopy(struct file *file, struct videobuf_queue *q, done: /* cleanup */ - q->ops->buf_release(file,q->read_buf); + q->ops->buf_release(q,q->read_buf); kfree(q->read_buf); q->read_buf = NULL; return retval; } -ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q, - char __user *data, size_t count, loff_t *ppos) +ssize_t videobuf_read_one(struct videobuf_queue *q, + char __user *data, size_t count, loff_t *ppos, + int nonblocking) { enum v4l2_field field; unsigned long flags; @@ -787,11 +791,11 @@ ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q, down(&q->lock); nbufs = 1; size = 0; - q->ops->buf_setup(file,&nbufs,&size); + q->ops->buf_setup(q,&nbufs,&size); if (NULL == q->read_buf && count >= size && - !(file->f_flags & O_NONBLOCK)) { - retval = videobuf_read_zerocopy(file,q,data,count,ppos); + !nonblocking) { + retval = videobuf_read_zerocopy(q,data,count,ppos); if (retval >= 0 || retval == -EIO) /* ok, all done */ goto done; @@ -806,24 +810,24 @@ ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q, goto done; q->read_buf->memory = V4L2_MEMORY_USERPTR; field = videobuf_next_field(q); - retval = q->ops->buf_prepare(file,q->read_buf,field); + retval = q->ops->buf_prepare(q,q->read_buf,field); if (0 != retval) goto done; spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(file,q->read_buf); + q->ops->buf_queue(q,q->read_buf); spin_unlock_irqrestore(q->irqlock,flags); q->read_off = 0; } /* wait until capture is done */ - retval = videobuf_waiton(q->read_buf, file->f_flags & O_NONBLOCK, 1); + retval = videobuf_waiton(q->read_buf, nonblocking, 1); if (0 != retval) goto done; videobuf_dma_pci_sync(q->pci,&q->read_buf->dma); if (STATE_ERROR == q->read_buf->state) { /* catch I/O errors */ - q->ops->buf_release(file,q->read_buf); + q->ops->buf_release(q,q->read_buf); kfree(q->read_buf); q->read_buf = NULL; retval = -EIO; @@ -842,7 +846,7 @@ ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q, q->read_off += bytes; if (q->read_off == q->read_buf->size) { /* all data copied, cleanup */ - q->ops->buf_release(file,q->read_buf); + q->ops->buf_release(q,q->read_buf); kfree(q->read_buf); q->read_buf = NULL; } @@ -852,43 +856,44 @@ ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q, return retval; } -int videobuf_read_start(struct file *file, struct videobuf_queue *q) +int videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; unsigned long flags; int count = 0, size = 0; int err, i; - q->ops->buf_setup(file,&count,&size); + q->ops->buf_setup(q,&count,&size); if (count < 2) count = 2; if (count > VIDEO_MAX_FRAME) count = VIDEO_MAX_FRAME; size = PAGE_ALIGN(size); - err = videobuf_mmap_setup(file, q, count, size, V4L2_MEMORY_USERPTR); + err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); if (err) return err; for (i = 0; i < count; i++) { field = videobuf_next_field(q); - err = q->ops->buf_prepare(file,q->bufs[i],field); + err = q->ops->buf_prepare(q,q->bufs[i],field); if (err) return err; list_add_tail(&q->bufs[i]->stream, &q->stream); } spin_lock_irqsave(q->irqlock,flags); for (i = 0; i < count; i++) - q->ops->buf_queue(file,q->bufs[i]); + q->ops->buf_queue(q,q->bufs[i]); spin_unlock_irqrestore(q->irqlock,flags); q->reading = 1; return 0; } -void videobuf_read_stop(struct file *file, struct videobuf_queue *q) +void videobuf_read_stop(struct videobuf_queue *q) { int i; - - videobuf_queue_cancel(file,q); + + videobuf_queue_cancel(q); + videobuf_mmap_free(q); INIT_LIST_HEAD(&q->stream); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) @@ -900,20 +905,21 @@ void videobuf_read_stop(struct file *file, struct videobuf_queue *q) q->reading = 0; } -ssize_t videobuf_read_stream(struct file *file, struct videobuf_queue *q, +ssize_t videobuf_read_stream(struct videobuf_queue *q, char __user *data, size_t count, loff_t *ppos, - int vbihack) + int vbihack, int nonblocking) { unsigned int *fc, bytes; int err, retval; unsigned long flags; - + + dprintk(2,"%s\n",__FUNCTION__); down(&q->lock); retval = -EBUSY; if (q->streaming) goto done; if (!q->reading) { - retval = videobuf_read_start(file,q); + retval = videobuf_read_start(q); if (retval < 0) goto done; } @@ -928,8 +934,7 @@ ssize_t videobuf_read_stream(struct file *file, struct videobuf_queue *q, list_del(&q->read_buf->stream); q->read_off = 0; } - err = videobuf_waiton(q->read_buf, - file->f_flags & O_NONBLOCK,1); + err = videobuf_waiton(q->read_buf, nonblocking, 1); if (err < 0) { if (0 == retval) retval = err; @@ -947,7 +952,7 @@ ssize_t videobuf_read_stream(struct file *file, struct videobuf_queue *q, *fc = q->read_buf->field_count >> 1; dprintk(1,"vbihack: %d\n",*fc); } - + /* copy stuff */ bytes = count; if (bytes > q->read_buf->size - q->read_off) @@ -974,7 +979,7 @@ ssize_t videobuf_read_stream(struct file *file, struct videobuf_queue *q, list_add_tail(&q->read_buf->stream, &q->stream); spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(file,q->read_buf); + q->ops->buf_queue(q,q->read_buf); spin_unlock_irqrestore(q->irqlock,flags); q->read_buf = NULL; } @@ -1001,7 +1006,7 @@ unsigned int videobuf_poll_stream(struct file *file, struct videobuf_buffer, stream); } else { if (!q->reading) - videobuf_read_start(file,q); + videobuf_read_start(q); if (!q->reading) { rc = POLLERR; } else if (NULL == q->read_buf) { @@ -1042,29 +1047,30 @@ static void videobuf_vm_close(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; + struct videobuf_queue *q = map->q; int i; dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map, map->count,vma->vm_start,vma->vm_end); - /* down(&fh->lock); FIXME */ map->count--; if (0 == map->count) { - dprintk(1,"munmap %p\n",map); + dprintk(1,"munmap %p q=%p\n",map,q); + down(&q->lock); for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == map->q->bufs[i]) + if (NULL == q->bufs[i]) continue; - if (map->q->bufs[i]) + if (q->bufs[i]) ; - if (map->q->bufs[i]->map != map) + if (q->bufs[i]->map != map) continue; - map->q->bufs[i]->map = NULL; - map->q->bufs[i]->baddr = 0; - map->q->ops->buf_release(vma->vm_file,map->q->bufs[i]); + q->bufs[i]->map = NULL; + q->bufs[i]->baddr = 0; + q->ops->buf_release(q,q->bufs[i]); } + up(&q->lock); kfree(map); } - /* up(&fh->lock); FIXME */ return; } @@ -1100,14 +1106,14 @@ static struct vm_operations_struct videobuf_vm_ops = .nopage = videobuf_vm_nopage, }; -int videobuf_mmap_setup(struct file *file, struct videobuf_queue *q, +int videobuf_mmap_setup(struct videobuf_queue *q, unsigned int bcount, unsigned int bsize, enum v4l2_memory memory) { unsigned int i; int err; - err = videobuf_mmap_free(file,q); + err = videobuf_mmap_free(q); if (0 != err) return err; @@ -1132,7 +1138,7 @@ int videobuf_mmap_setup(struct file *file, struct videobuf_queue *q, return 0; } -int videobuf_mmap_free(struct file *file, struct videobuf_queue *q) +int videobuf_mmap_free(struct videobuf_queue *q) { int i; @@ -1142,15 +1148,15 @@ int videobuf_mmap_free(struct file *file, struct videobuf_queue *q) for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - q->ops->buf_release(file,q->bufs[i]); + q->ops->buf_release(q,q->bufs[i]); kfree(q->bufs[i]); q->bufs[i] = NULL; } return 0; } -int videobuf_mmap_mapper(struct vm_area_struct *vma, - struct videobuf_queue *q) +int videobuf_mmap_mapper(struct videobuf_queue *q, + struct vm_area_struct *vma) { struct videobuf_mapping *map; unsigned int first,last,size,i; @@ -1219,8 +1225,8 @@ int videobuf_mmap_mapper(struct vm_area_struct *vma, 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: %08lx-%08lx pgoff %08lx bufs %d-%d\n", - map,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: