VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / media / video / video-buf.c
index f541a06..c7c7465 100644 (file)
@@ -5,10 +5,10 @@
  * The functions expect the hardware being able to scatter gatter
  * (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 (thus it is probably not useful for USB as
- * data often must be uncompressed by the drivers).
+ * 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,02 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2001-2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include <media/video-buf.h>
 
+#define MAGIC_DMABUF 0x19721112
+#define MAGIC_BUFFER 0x20040302
+#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;
 
 MODULE_DESCRIPTION("helper module to manage video4linux pci dma buffers");
@@ -109,6 +114,12 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
 
 /* --------------------------------------------------------------------- */
 
+void videobuf_dma_init(struct videobuf_dmabuf *dma)
+{
+       memset(dma,0,sizeof(*dma));
+       dma->magic = MAGIC_DMABUF;
+}
+
 int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
                           unsigned long data, unsigned long size)
 {
@@ -178,8 +189,8 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
 
 int videobuf_dma_pci_map(struct pci_dev *dev, struct videobuf_dmabuf *dma)
 {
-       if (0 == dma->nr_pages)
-               BUG();
+       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,
@@ -211,8 +222,8 @@ int videobuf_dma_pci_map(struct pci_dev *dev, struct videobuf_dmabuf *dma)
 
 int videobuf_dma_pci_sync(struct pci_dev *dev, struct videobuf_dmabuf *dma)
 {
-       if (!dma->sglen)
-               BUG();
+       MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+       BUG_ON(!dma->sglen);
 
        if (!dma->bus_addr)
                pci_dma_sync_sg_for_cpu(dev,dma->sglist,dma->nr_pages,dma->direction);
@@ -221,6 +232,7 @@ int videobuf_dma_pci_sync(struct pci_dev *dev, struct videobuf_dmabuf *dma)
 
 int videobuf_dma_pci_unmap(struct pci_dev *dev, struct videobuf_dmabuf *dma)
 {
+       MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
        if (!dma->sglen)
                return 0;
 
@@ -234,8 +246,8 @@ int videobuf_dma_pci_unmap(struct pci_dev *dev, struct videobuf_dmabuf *dma)
 
 int videobuf_dma_free(struct videobuf_dmabuf *dma)
 {
-       if (dma->sglen)
-               BUG();
+       MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+       BUG_ON(dma->sglen);
 
        if (dma->pages) {
                int i;
@@ -264,7 +276,9 @@ void* videobuf_alloc(unsigned int size)
        vb = kmalloc(size,GFP_KERNEL);
        if (NULL != vb) {
                memset(vb,0,size);
+               videobuf_dma_init(&vb->dma);
                init_waitqueue_head(&vb->done);
+               vb->magic     = MAGIC_BUFFER;
        }
        return vb;
 }
@@ -274,6 +288,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) {
                if (non_blocking) {
@@ -302,6 +317,7 @@ videobuf_iolock(struct pci_dev *pci, struct videobuf_buffer *vb,
        int err,pages;
        dma_addr_t bus;
 
+       MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
        switch (vb->memory) {
        case V4L2_MEMORY_MMAP:
        case V4L2_MEMORY_USERPTR:
@@ -453,6 +469,8 @@ void
 videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
                enum v4l2_buf_type type)
 {
+       MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
+
        b->index    = vb->i;
        b->type     = type;
 
@@ -491,6 +509,11 @@ videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
                break;
        }
 
+       if (vb->input != UNSET) {
+               b->flags |= V4L2_BUF_FLAG_INPUT;
+               b->input  = vb->input;
+       }
+
        b->field     = vb->field;
        b->timestamp = vb->ts;
        b->bytesused = vb->size;
@@ -513,6 +536,11 @@ videobuf_reqbufs(struct file *file, struct videobuf_queue *q,
            req->memory != V4L2_MEMORY_OVERLAY)
                return -EINVAL;
 
+       if (q->streaming)
+               return -EBUSY;
+       if (!list_empty(&q->stream))
+               return -EBUSY;
+
        down(&q->lock);
        count = req->count;
        if (count > VIDEO_MAX_FRAME)
@@ -568,12 +596,21 @@ videobuf_qbuf(struct file *file, struct videobuf_queue *q,
        buf = q->bufs[b->index];
        if (NULL == buf)
                goto done;
+       MAGIC_CHECK(buf->magic,MAGIC_BUFFER);
        if (buf->memory != b->memory)
                goto done;
        if (buf->state == STATE_QUEUED ||
            buf->state == STATE_ACTIVE)
                goto done;
 
+       if (b->flags & V4L2_BUF_FLAG_INPUT) {
+               if (b->input >= q->inputs)
+                       goto done;
+               buf->input = b->input;
+       } else {
+               buf->input = UNSET;
+       }
+
        switch (b->memory) {
        case V4L2_MEMORY_MMAP:
                if (0 == buf->baddr)
@@ -582,6 +619,8 @@ videobuf_qbuf(struct file *file, struct videobuf_queue *q,
        case V4L2_MEMORY_USERPTR:
                if (b->length < buf->bsize)
                        goto done;
+               if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr)
+                       q->ops->buf_release(file,buf);
                buf->baddr = b->m.userptr;
                break;
        case V4L2_MEMORY_OVERLAY:
@@ -696,7 +735,7 @@ int videobuf_streamoff(struct file *file, struct videobuf_queue *q)
 
 static ssize_t
 videobuf_read_zerocopy(struct file *file, struct videobuf_queue *q,
-                      char *data, size_t count, loff_t *ppos)
+                      char __user *data, size_t count, loff_t *ppos)
 {
        enum v4l2_field field;
        unsigned long flags;
@@ -738,7 +777,7 @@ videobuf_read_zerocopy(struct file *file, struct videobuf_queue *q,
 }
 
 ssize_t videobuf_read_one(struct file *file, struct videobuf_queue *q,
-                         char *data, size_t count, loff_t *ppos)
+                         char __user *data, size_t count, loff_t *ppos)
 {
        enum v4l2_field field;
        unsigned long flags;
@@ -862,7 +901,7 @@ void videobuf_read_stop(struct file *file, struct videobuf_queue *q)
 }
 
 ssize_t videobuf_read_stream(struct file *file, struct videobuf_queue *q,
-                            char *data, size_t count, loff_t *ppos,
+                            char __user *data, size_t count, loff_t *ppos,
                             int vbihack)
 {
        unsigned int *fc, bytes;
@@ -1075,6 +1114,7 @@ int videobuf_mmap_setup(struct file *file, struct videobuf_queue *q,
        for (i = 0; i < bcount; i++) {
                q->bufs[i] = videobuf_alloc(q->msize);
                q->bufs[i]->i      = i;
+               q->bufs[i]->input  = UNSET;
                q->bufs[i]->memory = memory;
                q->bufs[i]->bsize  = bsize;
                switch (memory) {
@@ -1085,7 +1125,7 @@ int videobuf_mmap_setup(struct file *file, struct videobuf_queue *q,
                case V4L2_MEMORY_OVERLAY:
                        /* nothing */
                        break;
-               };
+               }
        }
        dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
                bcount,bsize);
@@ -1192,6 +1232,7 @@ int videobuf_mmap_mapper(struct vm_area_struct *vma,
 
 EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
 
+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);