headers: remove sched.h from interrupt.h
[safe/jmp/linux-2.6] / drivers / media / video / videobuf-core.c
index f5c5ea8..8e93c6f 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 
 #include <media/videobuf-core.h>
 
 #define MAGIC_BUFFER 0x20070728
-#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) do {                                      \
+       if (unlikely((is) != (should))) {                                  \
+       printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \
+       BUG(); } } while (0)
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 
 MODULE_DESCRIPTION("helper module to manage video4linux buffers");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
 
-#define dprintk(level, fmt, arg...)    if (debug >= level) \
-       printk(KERN_DEBUG "vbuf: " fmt , ## arg)
+#define dprintk(level, fmt, arg...) do {                       \
+       if (debug >= level)                                     \
+       printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0)
 
 /* --------------------------------------------------------------------- */
 
 #define CALL(q, f, arg...)                                             \
-       ( (q->int_ops->f)? q->int_ops->f(arg) : 0)
+       ((q->int_ops->f) ? q->int_ops->f(arg) : 0)
 
-void* videobuf_alloc(struct videobuf_queue* q)
+void *videobuf_alloc(struct videobuf_queue *q)
 {
        struct videobuf_buffer *vb;
 
-       BUG_ON (q->msize<sizeof(*vb));
+       BUG_ON(q->msize < sizeof(*vb));
 
        if (!q->int_ops || !q->int_ops->alloc) {
                printk(KERN_ERR "No specific ops defined!\n");
@@ -61,56 +66,52 @@ void* videobuf_alloc(struct videobuf_queue* q)
        return vb;
 }
 
+#define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\
+                               vb->state != VIDEOBUF_QUEUED)
 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);
 
-       MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
-       add_wait_queue(&vb->done, &wait);
-       while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) {
-               if (non_blocking) {
-                       retval = -EAGAIN;
-                       break;
-               }
-               set_current_state(intr  ? TASK_INTERRUPTIBLE
-                                       : TASK_UNINTERRUPTIBLE);
-               if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED)
-                       schedule();
-               set_current_state(TASK_RUNNING);
-               if (intr && signal_pending(current)) {
-                       dprintk(1,"buffer waiton: -EINTR\n");
-                       retval = -EINTR;
-                       break;
-               }
+       if (non_blocking) {
+               if (WAITON_CONDITION)
+                       return 0;
+               else
+                       return -EAGAIN;
        }
-       remove_wait_queue(&vb->done, &wait);
-       return retval;
+
+       if (intr)
+               return wait_event_interruptible(vb->done, WAITON_CONDITION);
+       else
+               wait_event(vb->done, WAITON_CONDITION);
+
+       return 0;
 }
 
-int videobuf_iolock(struct videobuf_queueq, struct videobuf_buffer *vb,
+int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
                    struct v4l2_framebuffer *fbuf)
 {
-       MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-
-       /* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper()
-          method should be called before _iolock.
-          On some cases, the mmap_mapper() is called only after scheduling.
+       MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-          However, this way is just too dirty! Better to wait for some event.
-        */
-       schedule_timeout(HZ);
+       return CALL(q, iolock, q, vb, fbuf);
+}
 
-       return CALL(q,iolock,q,vb,fbuf);
+void *videobuf_queue_to_vmalloc (struct videobuf_queue *q,
+                          struct videobuf_buffer *buf)
+{
+       if (q->int_ops->vmalloc)
+               return q->int_ops->vmalloc(buf);
+       else
+               return NULL;
 }
+EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc);
 
 /* --------------------------------------------------------------------- */
 
 
-void videobuf_queue_core_init(struct videobuf_queueq,
+void videobuf_queue_core_init(struct videobuf_queue *q,
                         struct videobuf_queue_ops *ops,
-                        void *dev,
+                        struct device *dev,
                         spinlock_t *irqlock,
                         enum v4l2_buf_type type,
                         enum v4l2_field field,
@@ -118,7 +119,8 @@ void videobuf_queue_core_init(struct videobuf_queue* q,
                         void *priv,
                         struct videobuf_qtype_ops *int_ops)
 {
-       memset(q,0,sizeof(*q));
+       BUG_ON(!q);
+       memset(q, 0, sizeof(*q));
        q->irqlock   = irqlock;
        q->dev       = dev;
        q->type      = type;
@@ -129,85 +131,95 @@ void videobuf_queue_core_init(struct videobuf_queue* q,
        q->int_ops   = int_ops;
 
        /* All buffer operations are mandatory */
-       BUG_ON (!q->ops->buf_setup);
-       BUG_ON (!q->ops->buf_prepare);
-       BUG_ON (!q->ops->buf_queue);
-       BUG_ON (!q->ops->buf_release);
+       BUG_ON(!q->ops->buf_setup);
+       BUG_ON(!q->ops->buf_prepare);
+       BUG_ON(!q->ops->buf_queue);
+       BUG_ON(!q->ops->buf_release);
+
+       /* Lock is mandatory for queue_cancel to work */
+       BUG_ON(!irqlock);
 
        /* Having implementations for abstract methods are mandatory */
-       BUG_ON (!q->int_ops);
+       BUG_ON(!q->int_ops);
 
-       mutex_init(&q->lock);
+       mutex_init(&q->vb_lock);
+       init_waitqueue_head(&q->wait);
        INIT_LIST_HEAD(&q->stream);
 }
 
+/* Locking: Only usage in bttv unsafe find way to remove */
 int videobuf_queue_is_busy(struct videobuf_queue *q)
 {
        int i;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        if (q->streaming) {
-               dprintk(1,"busy: streaming active\n");
+               dprintk(1, "busy: streaming active\n");
                return 1;
        }
        if (q->reading) {
-               dprintk(1,"busy: pending read #1\n");
+               dprintk(1, "busy: pending read #1\n");
                return 1;
        }
        if (q->read_buf) {
-               dprintk(1,"busy: pending read #2\n");
+               dprintk(1, "busy: pending read #2\n");
                return 1;
        }
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                if (NULL == q->bufs[i])
                        continue;
                if (q->bufs[i]->map) {
-                       dprintk(1,"busy: buffer #%d mapped\n",i);
+                       dprintk(1, "busy: buffer #%d mapped\n", i);
                        return 1;
                }
-               if (q->bufs[i]->state == STATE_QUEUED) {
-                       dprintk(1,"busy: buffer #%d queued\n",i);
+               if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
+                       dprintk(1, "busy: buffer #%d queued\n", i);
                        return 1;
                }
-               if (q->bufs[i]->state == STATE_ACTIVE) {
-                       dprintk(1,"busy: buffer #%d avtive\n",i);
+               if (q->bufs[i]->state == VIDEOBUF_ACTIVE) {
+                       dprintk(1, "busy: buffer #%d avtive\n", i);
                        return 1;
                }
        }
        return 0;
 }
 
+/* Locking: Caller holds q->vb_lock */
 void videobuf_queue_cancel(struct videobuf_queue *q)
 {
-       unsigned long flags=0;
+       unsigned long flags = 0;
        int i;
 
+       q->streaming = 0;
+       q->reading  = 0;
+       wake_up_interruptible_sync(&q->wait);
+
        /* remove queued buffers from list */
-       if (q->irqlock)
-               spin_lock_irqsave(q->irqlock,flags);
+       spin_lock_irqsave(q->irqlock, flags);
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                if (NULL == q->bufs[i])
                        continue;
-               if (q->bufs[i]->state == STATE_QUEUED) {
+               if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
                        list_del(&q->bufs[i]->queue);
-                       q->bufs[i]->state = STATE_ERROR;
+                       q->bufs[i]->state = VIDEOBUF_ERROR;
+                       wake_up_all(&q->bufs[i]->done);
                }
        }
-       if (q->irqlock)
-               spin_unlock_irqrestore(q->irqlock,flags);
+       spin_unlock_irqrestore(q->irqlock, flags);
 
        /* free all buffers + clear queue */
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                if (NULL == q->bufs[i])
                        continue;
-               q->ops->buf_release(q,q->bufs[i]);
+               q->ops->buf_release(q, q->bufs[i]);
        }
        INIT_LIST_HEAD(&q->stream);
 }
 
 /* --------------------------------------------------------------------- */
 
+/* Locking: Caller holds q->vb_lock */
 enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
 {
        enum v4l2_field field = q->field;
@@ -226,11 +238,12 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
        return field;
 }
 
+/* Locking: Caller holds q->vb_lock */
 static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
                            struct videobuf_buffer *vb, enum v4l2_buf_type type)
 {
-       MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        b->index    = vb->i;
        b->type     = type;
@@ -255,17 +268,17 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
                b->flags |= V4L2_BUF_FLAG_MAPPED;
 
        switch (vb->state) {
-       case STATE_PREPARED:
-       case STATE_QUEUED:
-       case STATE_ACTIVE:
+       case VIDEOBUF_PREPARED:
+       case VIDEOBUF_QUEUED:
+       case VIDEOBUF_ACTIVE:
                b->flags |= V4L2_BUF_FLAG_QUEUED;
                break;
-       case STATE_DONE:
-       case STATE_ERROR:
+       case VIDEOBUF_DONE:
+       case VIDEOBUF_ERROR:
                b->flags |= V4L2_BUF_FLAG_DONE;
                break;
-       case STATE_NEEDS_INIT:
-       case STATE_IDLE:
+       case VIDEOBUF_NEEDS_INIT:
+       case VIDEOBUF_IDLE:
                /* nothing */
                break;
        }
@@ -281,35 +294,133 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
        b->sequence  = vb->field_count >> 1;
 }
 
+/* Locking: Caller holds q->vb_lock */
+static int __videobuf_mmap_free(struct videobuf_queue *q)
+{
+       int i;
+       int rc;
+
+       if (!q)
+               return 0;
+
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+
+
+       rc  = CALL(q, mmap_free, q);
+
+       q->is_mmapped = 0;
+
+       if (rc < 0)
+               return rc;
+
+       for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+               if (NULL == q->bufs[i])
+                       continue;
+               q->ops->buf_release(q, q->bufs[i]);
+               kfree(q->bufs[i]);
+               q->bufs[i] = NULL;
+       }
+
+       return rc;
+}
+
+int videobuf_mmap_free(struct videobuf_queue *q)
+{
+       int ret;
+       mutex_lock(&q->vb_lock);
+       ret = __videobuf_mmap_free(q);
+       mutex_unlock(&q->vb_lock);
+       return ret;
+}
+
+/* Locking: Caller holds q->vb_lock */
+int __videobuf_mmap_setup(struct videobuf_queue *q,
+                       unsigned int bcount, unsigned int bsize,
+                       enum v4l2_memory memory)
+{
+       unsigned int i;
+       int err;
+
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+
+       err = __videobuf_mmap_free(q);
+       if (0 != err)
+               return err;
+
+       /* Allocate and initialize buffers */
+       for (i = 0; i < bcount; i++) {
+               q->bufs[i] = videobuf_alloc(q);
+
+               if (q->bufs[i] == NULL)
+                       break;
+
+               q->bufs[i]->i      = i;
+               q->bufs[i]->input  = UNSET;
+               q->bufs[i]->memory = memory;
+               q->bufs[i]->bsize  = bsize;
+               switch (memory) {
+               case V4L2_MEMORY_MMAP:
+                       q->bufs[i]->boff  = bsize * i;
+                       break;
+               case V4L2_MEMORY_USERPTR:
+               case V4L2_MEMORY_OVERLAY:
+                       /* nothing */
+                       break;
+               }
+       }
+
+       if (!i)
+               return -ENOMEM;
+
+       dprintk(1, "mmap setup: %d buffers, %d bytes each\n",
+               i, bsize);
+
+       return i;
+}
+
+int videobuf_mmap_setup(struct videobuf_queue *q,
+                       unsigned int bcount, unsigned int bsize,
+                       enum v4l2_memory memory)
+{
+       int ret;
+       mutex_lock(&q->vb_lock);
+       ret = __videobuf_mmap_setup(q, bcount, bsize, memory);
+       mutex_unlock(&q->vb_lock);
+       return ret;
+}
+
 int videobuf_reqbufs(struct videobuf_queue *q,
                 struct v4l2_requestbuffers *req)
 {
-       unsigned int size,count;
+       unsigned int size, count;
        int retval;
 
-       if (req->type != q->type) {
-               dprintk(1,"reqbufs: queue type invalid\n");
-               return -EINVAL;
-       }
        if (req->count < 1) {
-               dprintk(1,"reqbufs: count invalid (%d)\n",req->count);
+               dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
                return -EINVAL;
        }
+
        if (req->memory != V4L2_MEMORY_MMAP     &&
            req->memory != V4L2_MEMORY_USERPTR  &&
            req->memory != V4L2_MEMORY_OVERLAY) {
-               dprintk(1,"reqbufs: memory type invalid\n");
+               dprintk(1, "reqbufs: memory type invalid\n");
                return -EINVAL;
        }
 
-       mutex_lock(&q->lock);
+       mutex_lock(&q->vb_lock);
+       if (req->type != q->type) {
+               dprintk(1, "reqbufs: queue type invalid\n");
+               retval = -EINVAL;
+               goto done;
+       }
+
        if (q->streaming) {
-               dprintk(1,"reqbufs: streaming already exists\n");
+               dprintk(1, "reqbufs: streaming already exists\n");
                retval = -EBUSY;
                goto done;
        }
        if (!list_empty(&q->stream)) {
-               dprintk(1,"reqbufs: stream running\n");
+               dprintk(1, "reqbufs: stream running\n");
                retval = -EBUSY;
                goto done;
        }
@@ -318,40 +429,49 @@ int videobuf_reqbufs(struct videobuf_queue *q,
        if (count > VIDEO_MAX_FRAME)
                count = VIDEO_MAX_FRAME;
        size = 0;
-       q->ops->buf_setup(q,&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",
+       dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
                count, size, (count*size)>>PAGE_SHIFT);
 
-       retval = videobuf_mmap_setup(q,count,size,req->memory);
+       retval = __videobuf_mmap_setup(q, count, size, req->memory);
        if (retval < 0) {
-               dprintk(1,"reqbufs: mmap setup returned %d\n",retval);
+               dprintk(1, "reqbufs: mmap setup returned %d\n", retval);
                goto done;
        }
 
-       req->count = count;
+       req->count = retval;
+       retval = 0;
 
  done:
-       mutex_unlock(&q->lock);
+       mutex_unlock(&q->vb_lock);
        return retval;
 }
 
 int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
 {
+       int ret = -EINVAL;
+
+       mutex_lock(&q->vb_lock);
        if (unlikely(b->type != q->type)) {
-               dprintk(1,"querybuf: Wrong type.\n");
-               return -EINVAL;
+               dprintk(1, "querybuf: Wrong type.\n");
+               goto done;
        }
-       if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) {
-               dprintk(1,"querybuf: index out of range.\n");
-               return -EINVAL;
+       if (unlikely(b->index >= VIDEO_MAX_FRAME)) {
+               dprintk(1, "querybuf: index out of range.\n");
+               goto done;
        }
        if (unlikely(NULL == q->bufs[b->index])) {
-               dprintk(1,"querybuf: buffer is null.\n");
-               return -EINVAL;
+               dprintk(1, "querybuf: buffer is null.\n");
+               goto done;
        }
-       videobuf_status(q,b,q->bufs[b->index],q->type);
-       return 0;
+
+       videobuf_status(q, b, q->bufs[b->index], q->type);
+
+       ret = 0;
+done:
+       mutex_unlock(&q->vb_lock);
+       return ret;
 }
 
 int videobuf_qbuf(struct videobuf_queue *q,
@@ -359,47 +479,47 @@ int videobuf_qbuf(struct videobuf_queue *q,
 {
        struct videobuf_buffer *buf;
        enum v4l2_field field;
-       unsigned long flags=0;
+       unsigned long flags = 0;
        int retval;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        if (b->memory == V4L2_MEMORY_MMAP)
                down_read(&current->mm->mmap_sem);
 
-       mutex_lock(&q->lock);
+       mutex_lock(&q->vb_lock);
        retval = -EBUSY;
        if (q->reading) {
-               dprintk(1,"qbuf: Reading running...\n");
+               dprintk(1, "qbuf: Reading running...\n");
                goto done;
        }
        retval = -EINVAL;
        if (b->type != q->type) {
-               dprintk(1,"qbuf: Wrong type.\n");
+               dprintk(1, "qbuf: Wrong type.\n");
                goto done;
        }
-       if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) {
-               dprintk(1,"qbuf: index out of range.\n");
+       if (b->index >= VIDEO_MAX_FRAME) {
+               dprintk(1, "qbuf: index out of range.\n");
                goto done;
        }
        buf = q->bufs[b->index];
        if (NULL == buf) {
-               dprintk(1,"qbuf: buffer is null.\n");
+               dprintk(1, "qbuf: buffer is null.\n");
                goto done;
        }
-       MAGIC_CHECK(buf->magic,MAGIC_BUFFER);
+       MAGIC_CHECK(buf->magic, MAGIC_BUFFER);
        if (buf->memory != b->memory) {
-               dprintk(1,"qbuf: memory type is wrong.\n");
+               dprintk(1, "qbuf: memory type is wrong.\n");
                goto done;
        }
-       if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) {
-               dprintk(1,"qbuf: buffer is already queued or active.\n");
+       if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) {
+               dprintk(1, "qbuf: buffer is already queued or active.\n");
                goto done;
        }
 
        if (b->flags & V4L2_BUF_FLAG_INPUT) {
                if (b->input >= q->inputs) {
-                       dprintk(1,"qbuf: wrong input.\n");
+                       dprintk(1, "qbuf: wrong input.\n");
                        goto done;
                }
                buf->input = b->input;
@@ -410,48 +530,49 @@ int videobuf_qbuf(struct videobuf_queue *q,
        switch (b->memory) {
        case V4L2_MEMORY_MMAP:
                if (0 == buf->baddr) {
-                       dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n");
+                       dprintk(1, "qbuf: mmap requested "
+                                  "but buffer addr is zero!\n");
                        goto done;
                }
                break;
        case V4L2_MEMORY_USERPTR:
                if (b->length < buf->bsize) {
-                       dprintk(1,"qbuf: buffer length is not enough\n");
+                       dprintk(1, "qbuf: buffer length is not enough\n");
                        goto done;
                }
-               if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr)
-                       q->ops->buf_release(q,buf);
+               if (VIDEOBUF_NEEDS_INIT != buf->state &&
+                   buf->baddr != b->m.userptr)
+                       q->ops->buf_release(q, buf);
                buf->baddr = b->m.userptr;
                break;
        case V4L2_MEMORY_OVERLAY:
                buf->boff = b->m.offset;
                break;
        default:
-               dprintk(1,"qbuf: wrong memory type\n");
+               dprintk(1, "qbuf: wrong memory type\n");
                goto done;
        }
 
-       dprintk(1,"qbuf: requesting next field\n");
+       dprintk(1, "qbuf: requesting next field\n");
        field = videobuf_next_field(q);
-       retval = q->ops->buf_prepare(q,buf,field);
+       retval = q->ops->buf_prepare(q, buf, field);
        if (0 != retval) {
-               dprintk(1,"qbuf: buffer_prepare returned %d\n",retval);
+               dprintk(1, "qbuf: buffer_prepare returned %d\n", retval);
                goto done;
        }
 
-       list_add_tail(&buf->stream,&q->stream);
+       list_add_tail(&buf->stream, &q->stream);
        if (q->streaming) {
-               if (q->irqlock)
-                       spin_lock_irqsave(q->irqlock,flags);
-               q->ops->buf_queue(q,buf);
-               if (q->irqlock)
-                       spin_unlock_irqrestore(q->irqlock,flags);
+               spin_lock_irqsave(q->irqlock, flags);
+               q->ops->buf_queue(q, buf);
+               spin_unlock_irqrestore(q->irqlock, flags);
        }
-       dprintk(1,"qbuf: succeded\n");
+       dprintk(1, "qbuf: succeded\n");
        retval = 0;
+       wake_up_interruptible_sync(&q->wait);
 
  done:
-       mutex_unlock(&q->lock);
+       mutex_unlock(&q->vb_lock);
 
        if (b->memory == V4L2_MEMORY_MMAP)
                up_read(&current->mm->mmap_sem);
@@ -459,69 +580,121 @@ int videobuf_qbuf(struct videobuf_queue *q,
        return retval;
 }
 
-int videobuf_dqbuf(struct videobuf_queue *q,
-              struct v4l2_buffer *b, int nonblocking)
+
+/* Locking: Caller holds q->vb_lock */
+static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock)
 {
-       struct videobuf_buffer *buf;
        int retval;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-
-       mutex_lock(&q->lock);
-       retval = -EBUSY;
-       if (q->reading) {
-               dprintk(1,"dqbuf: Reading running...\n");
-               goto done;
-       }
-       retval = -EINVAL;
-       if (b->type != q->type) {
-               dprintk(1,"dqbuf: Wrong type.\n");
+checks:
+       if (!q->streaming) {
+               dprintk(1, "next_buffer: Not streaming\n");
+               retval = -EINVAL;
                goto done;
        }
+
        if (list_empty(&q->stream)) {
-               dprintk(1,"dqbuf: stream running\n");
-               goto done;
+               if (noblock) {
+                       retval = -EAGAIN;
+                       dprintk(2, "next_buffer: no buffers to dequeue\n");
+                       goto done;
+               } else {
+                       dprintk(2, "next_buffer: waiting on buffer\n");
+
+                       /* Drop lock to avoid deadlock with qbuf */
+                       mutex_unlock(&q->vb_lock);
+
+                       /* Checking list_empty and streaming is safe without
+                        * locks because we goto checks to validate while
+                        * holding locks before proceeding */
+                       retval = wait_event_interruptible(q->wait,
+                               !list_empty(&q->stream) || !q->streaming);
+                       mutex_lock(&q->vb_lock);
+
+                       if (retval)
+                               goto done;
+
+                       goto checks;
+               }
        }
+
+       retval = 0;
+
+done:
+       return retval;
+}
+
+
+/* Locking: Caller holds q->vb_lock */
+static int stream_next_buffer(struct videobuf_queue *q,
+                       struct videobuf_buffer **vb, int nonblocking)
+{
+       int retval;
+       struct videobuf_buffer *buf = NULL;
+
+       retval = stream_next_buffer_check_queue(q, nonblocking);
+       if (retval)
+               goto done;
+
        buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
        retval = videobuf_waiton(buf, nonblocking, 1);
+       if (retval < 0)
+               goto done;
+
+       *vb = buf;
+done:
+       return retval;
+}
+
+int videobuf_dqbuf(struct videobuf_queue *q,
+              struct v4l2_buffer *b, int nonblocking)
+{
+       struct videobuf_buffer *buf = NULL;
+       int retval;
+
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+
+       mutex_lock(&q->vb_lock);
+
+       retval = stream_next_buffer(q, &buf, nonblocking);
        if (retval < 0) {
-               dprintk(1,"dqbuf: waiton returned %d\n",retval);
+               dprintk(1, "dqbuf: next_buffer error: %i\n", retval);
                goto done;
        }
+
        switch (buf->state) {
-       case STATE_ERROR:
-               dprintk(1,"dqbuf: state is error\n");
+       case VIDEOBUF_ERROR:
+               dprintk(1, "dqbuf: state is error\n");
                retval = -EIO;
-               CALL(q,sync,q, buf);
-               buf->state = STATE_IDLE;
+               CALL(q, sync, q, buf);
+               buf->state = VIDEOBUF_IDLE;
                break;
-       case STATE_DONE:
-               dprintk(1,"dqbuf: state is done\n");
-               CALL(q,sync,q, buf);
-               buf->state = STATE_IDLE;
+       case VIDEOBUF_DONE:
+               dprintk(1, "dqbuf: state is done\n");
+               CALL(q, sync, q, buf);
+               buf->state = VIDEOBUF_IDLE;
                break;
        default:
-               dprintk(1,"dqbuf: state invalid\n");
+               dprintk(1, "dqbuf: state invalid\n");
                retval = -EINVAL;
                goto done;
        }
        list_del(&buf->stream);
-       memset(b,0,sizeof(*b));
-       videobuf_status(q,b,buf,q->type);
+       memset(b, 0, sizeof(*b));
+       videobuf_status(q, b, buf, q->type);
 
  done:
-       mutex_unlock(&q->lock);
+       mutex_unlock(&q->vb_lock);
        return retval;
 }
 
 int videobuf_streamon(struct videobuf_queue *q)
 {
        struct videobuf_buffer *buf;
-       struct list_head *list;
-       unsigned long flags=0;
+       unsigned long flags = 0;
        int retval;
 
-       mutex_lock(&q->lock);
+       mutex_lock(&q->vb_lock);
        retval = -EBUSY;
        if (q->reading)
                goto done;
@@ -529,46 +702,50 @@ int videobuf_streamon(struct videobuf_queue *q)
        if (q->streaming)
                goto done;
        q->streaming = 1;
-       if (q->irqlock)
-               spin_lock_irqsave(q->irqlock,flags);
-       list_for_each(list,&q->stream) {
-               buf = list_entry(list, struct videobuf_buffer, stream);
-               if (buf->state == STATE_PREPARED)
-                       q->ops->buf_queue(q,buf);
-       }
-       if (q->irqlock)
-               spin_unlock_irqrestore(q->irqlock,flags);
+       spin_lock_irqsave(q->irqlock, flags);
+       list_for_each_entry(buf, &q->stream, stream)
+               if (buf->state == VIDEOBUF_PREPARED)
+                       q->ops->buf_queue(q, buf);
+       spin_unlock_irqrestore(q->irqlock, flags);
 
+       wake_up_interruptible_sync(&q->wait);
  done:
-       mutex_unlock(&q->lock);
+       mutex_unlock(&q->vb_lock);
        return retval;
 }
 
-int videobuf_streamoff(struct videobuf_queue *q)
+/* Locking: Caller holds q->vb_lock */
+static int __videobuf_streamoff(struct videobuf_queue *q)
 {
-       int retval = -EINVAL;
-
-       mutex_lock(&q->lock);
        if (!q->streaming)
-               goto done;
+               return -EINVAL;
+
        videobuf_queue_cancel(q);
-       q->streaming = 0;
-       retval = 0;
 
- done:
-       mutex_unlock(&q->lock);
+       return 0;
+}
+
+int videobuf_streamoff(struct videobuf_queue *q)
+{
+       int retval;
+
+       mutex_lock(&q->vb_lock);
+       retval = __videobuf_streamoff(q);
+       mutex_unlock(&q->vb_lock);
+
        return retval;
 }
 
+/* Locking: Caller holds q->vb_lock */
 static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
                                      char __user *data,
                                      size_t count, loff_t *ppos)
 {
        enum v4l2_field field;
-       unsigned long flags=0;
+       unsigned long flags = 0;
        int retval;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
        /* setup stuff */
        q->read_buf = videobuf_alloc(q);
@@ -580,20 +757,18 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
        q->read_buf->bsize  = count;
 
        field = videobuf_next_field(q);
-       retval = q->ops->buf_prepare(q,q->read_buf,field);
+       retval = q->ops->buf_prepare(q, q->read_buf, field);
        if (0 != retval)
                goto done;
 
        /* start capture & wait */
-       if (q->irqlock)
-               spin_lock_irqsave(q->irqlock,flags);
-       q->ops->buf_queue(q,q->read_buf);
-       if (q->irqlock)
-               spin_unlock_irqrestore(q->irqlock,flags);
-       retval = videobuf_waiton(q->read_buf,0,0);
+       spin_lock_irqsave(q->irqlock, flags);
+       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) {
-               CALL(q,sync,q,q->read_buf);
-               if (STATE_ERROR == q->read_buf->state)
+               CALL(q, sync, q, q->read_buf);
+               if (VIDEOBUF_ERROR == q->read_buf->state)
                        retval = -EIO;
                else
                        retval = q->read_buf->size;
@@ -601,7 +776,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
 
  done:
        /* cleanup */
-       q->ops->buf_release(q,q->read_buf);
+       q->ops->buf_release(q, q->read_buf);
        kfree(q->read_buf);
        q->read_buf = NULL;
        return retval;
@@ -612,21 +787,20 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
                          int nonblocking)
 {
        enum v4l2_field field;
-       unsigned long flags=0;
-       unsigned size, nbufs;
+       unsigned long flags = 0;
+       unsigned size = 0, nbufs = 1;
        int retval;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-       mutex_lock(&q->lock);
+       mutex_lock(&q->vb_lock);
 
-       nbufs = 1; size = 0;
-       q->ops->buf_setup(q,&nbufs,&size);
+       q->ops->buf_setup(q, &nbufs, &size);
 
        if (NULL == q->read_buf  &&
            count >= size        &&
            !nonblocking) {
-               retval = videobuf_read_zerocopy(q,data,count,ppos);
+               retval = videobuf_read_zerocopy(q, data, count, ppos);
                if (retval >= 0  ||  retval == -EIO)
                        /* ok, all done */
                        goto done;
@@ -638,25 +812,24 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
                retval = -ENOMEM;
                q->read_buf = videobuf_alloc(q);
 
-               dprintk(1,"video alloc=0x%p\n", q->read_buf);
+               dprintk(1, "video alloc=0x%p\n", q->read_buf);
                if (NULL == q->read_buf)
                        goto done;
                q->read_buf->memory = V4L2_MEMORY_USERPTR;
                q->read_buf->bsize = count; /* preferred size */
                field = videobuf_next_field(q);
-               retval = q->ops->buf_prepare(q,q->read_buf,field);
+               retval = q->ops->buf_prepare(q, q->read_buf, field);
 
                if (0 != retval) {
-                       kfree (q->read_buf);
+                       kfree(q->read_buf);
                        q->read_buf = NULL;
                        goto done;
                }
-               if (q->irqlock)
-                       spin_lock_irqsave(q->irqlock,flags);
 
-               q->ops->buf_queue(q,q->read_buf);
-               if (q->irqlock)
-                       spin_unlock_irqrestore(q->irqlock,flags);
+               spin_lock_irqsave(q->irqlock, flags);
+               q->ops->buf_queue(q, q->read_buf);
+               spin_unlock_irqrestore(q->irqlock, flags);
+
                q->read_off = 0;
        }
 
@@ -665,11 +838,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        if (0 != retval)
                goto done;
 
-       CALL(q,sync,q,q->read_buf);
+       CALL(q, sync, q, q->read_buf);
 
-       if (STATE_ERROR == q->read_buf->state) {
+       if (VIDEOBUF_ERROR == q->read_buf->state) {
                /* catch I/O errors */
-               q->ops->buf_release(q,q->read_buf);
+               q->ops->buf_release(q, q->read_buf);
                kfree(q->read_buf);
                q->read_buf = NULL;
                retval = -EIO;
@@ -677,64 +850,65 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        }
 
        /* Copy to userspace */
-       retval=CALL(q,copy_to_user,q,data,count,nonblocking);
-       if (retval<0)
+       retval = CALL(q, video_copy_to_user, q, data, count, nonblocking);
+       if (retval < 0)
                goto done;
 
        q->read_off += retval;
        if (q->read_off == q->read_buf->size) {
                /* all data copied, cleanup */
-               q->ops->buf_release(q,q->read_buf);
+               q->ops->buf_release(q, q->read_buf);
                kfree(q->read_buf);
                q->read_buf = NULL;
        }
 
  done:
-       mutex_unlock(&q->lock);
+       mutex_unlock(&q->vb_lock);
        return retval;
 }
 
-int videobuf_read_start(struct videobuf_queue *q)
+/* Locking: Caller holds q->vb_lock */
+static int __videobuf_read_start(struct videobuf_queue *q)
 {
        enum v4l2_field field;
-       unsigned long flags=0;
-       int count = 0, size = 0;
+       unsigned long flags = 0;
+       unsigned int count = 0, size = 0;
        int err, i;
 
-       q->ops->buf_setup(q,&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(q, count, size, V4L2_MEMORY_USERPTR);
-       if (err)
+       err = __videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR);
+       if (err < 0)
                return err;
 
+       count = err;
+
        for (i = 0; i < count; i++) {
                field = videobuf_next_field(q);
-               err = q->ops->buf_prepare(q,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);
        }
-       if (q->irqlock)
-               spin_lock_irqsave(q->irqlock,flags);
+       spin_lock_irqsave(q->irqlock, flags);
        for (i = 0; i < count; i++)
-               q->ops->buf_queue(q,q->bufs[i]);
-       if (q->irqlock)
-               spin_unlock_irqrestore(q->irqlock,flags);
+               q->ops->buf_queue(q, q->bufs[i]);
+       spin_unlock_irqrestore(q->irqlock, flags);
        q->reading = 1;
        return 0;
 }
 
-void videobuf_read_stop(struct videobuf_queue *q)
+static void __videobuf_read_stop(struct videobuf_queue *q)
 {
        int i;
 
        videobuf_queue_cancel(q);
-       videobuf_mmap_free(q);
+       __videobuf_mmap_free(q);
        INIT_LIST_HEAD(&q->stream);
        for (i = 0; i < VIDEO_MAX_FRAME; i++) {
                if (NULL == q->bufs[i])
@@ -743,25 +917,57 @@ void videobuf_read_stop(struct videobuf_queue *q)
                q->bufs[i] = NULL;
        }
        q->read_buf = NULL;
-       q->reading  = 0;
+
+}
+
+int videobuf_read_start(struct videobuf_queue *q)
+{
+       int rc;
+
+       mutex_lock(&q->vb_lock);
+       rc = __videobuf_read_start(q);
+       mutex_unlock(&q->vb_lock);
+
+       return rc;
+}
+
+void videobuf_read_stop(struct videobuf_queue *q)
+{
+       mutex_lock(&q->vb_lock);
+       __videobuf_read_stop(q);
+       mutex_unlock(&q->vb_lock);
+}
+
+void videobuf_stop(struct videobuf_queue *q)
+{
+       mutex_lock(&q->vb_lock);
+
+       if (q->streaming)
+               __videobuf_streamoff(q);
+
+       if (q->reading)
+               __videobuf_read_stop(q);
+
+       mutex_unlock(&q->vb_lock);
 }
 
+
 ssize_t videobuf_read_stream(struct videobuf_queue *q,
                             char __user *data, size_t count, loff_t *ppos,
                             int vbihack, int nonblocking)
 {
        int rc, retval;
-       unsigned long flags=0;
+       unsigned long flags = 0;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-       dprintk(2,"%s\n",__FUNCTION__);
-       mutex_lock(&q->lock);
+       dprintk(2, "%s\n", __func__);
+       mutex_lock(&q->vb_lock);
        retval = -EBUSY;
        if (q->streaming)
                goto done;
        if (!q->reading) {
-               retval = videobuf_read_start(q);
+               retval = __videobuf_read_start(q);
                if (retval < 0)
                        goto done;
        }
@@ -783,8 +989,8 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
                        break;
                }
 
-               if (q->read_buf->state == STATE_DONE) {
-                       rc = CALL (q,copy_stream, q, data + retval, count,
+               if (q->read_buf->state == VIDEOBUF_DONE) {
+                       rc = CALL(q, copy_stream, q, data + retval, count,
                                        retval, vbihack, nonblocking);
                        if (rc < 0) {
                                retval = rc;
@@ -804,11 +1010,9 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
                if (q->read_off == q->read_buf->size) {
                        list_add_tail(&q->read_buf->stream,
                                      &q->stream);
-                       if (q->irqlock)
-                               spin_lock_irqsave(q->irqlock,flags);
-                       q->ops->buf_queue(q,q->read_buf);
-                       if (q->irqlock)
-                               spin_unlock_irqrestore(q->irqlock,flags);
+                       spin_lock_irqsave(q->irqlock, flags);
+                       q->ops->buf_queue(q, q->read_buf);
+                       spin_unlock_irqrestore(q->irqlock, flags);
                        q->read_buf = NULL;
                }
                if (retval < 0)
@@ -816,7 +1020,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
        }
 
  done:
-       mutex_unlock(&q->lock);
+       mutex_unlock(&q->vb_lock);
        return retval;
 }
 
@@ -827,14 +1031,14 @@ unsigned int videobuf_poll_stream(struct file *file,
        struct videobuf_buffer *buf = NULL;
        unsigned int rc = 0;
 
-       mutex_lock(&q->lock);
+       mutex_lock(&q->vb_lock);
        if (q->streaming) {
                if (!list_empty(&q->stream))
                        buf = list_entry(q->stream.next,
                                         struct videobuf_buffer, stream);
        } else {
                if (!q->reading)
-                       videobuf_read_start(q);
+                       __videobuf_read_start(q);
                if (!q->reading) {
                        rc = POLLERR;
                } else if (NULL == q->read_buf) {
@@ -851,74 +1055,11 @@ unsigned int videobuf_poll_stream(struct file *file,
 
        if (0 == rc) {
                poll_wait(file, &buf->done, wait);
-               if (buf->state == STATE_DONE ||
-                   buf->state == STATE_ERROR)
+               if (buf->state == VIDEOBUF_DONE ||
+                   buf->state == VIDEOBUF_ERROR)
                        rc = POLLIN|POLLRDNORM;
        }
-       mutex_unlock(&q->lock);
-       return rc;
-}
-
-int videobuf_mmap_setup(struct videobuf_queue *q,
-                       unsigned int bcount, unsigned int bsize,
-                       enum v4l2_memory memory)
-{
-       unsigned int i;
-       int err;
-
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-
-       err = videobuf_mmap_free(q);
-       if (0 != err)
-               return err;
-
-       /* Allocate and initialize buffers */
-       for (i = 0; i < bcount; i++) {
-               q->bufs[i] = videobuf_alloc(q);
-
-               q->bufs[i]->i      = i;
-               q->bufs[i]->input  = UNSET;
-               q->bufs[i]->memory = memory;
-               q->bufs[i]->bsize  = bsize;
-               switch (memory) {
-               case V4L2_MEMORY_MMAP:
-                       q->bufs[i]->boff  = bsize * i;
-                       break;
-               case V4L2_MEMORY_USERPTR:
-               case V4L2_MEMORY_OVERLAY:
-                       /* nothing */
-                       break;
-               }
-       }
-
-       dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
-               bcount,bsize);
-
-       return 0;
-}
-
-int videobuf_mmap_free(struct videobuf_queue *q)
-{
-       int i;
-       int rc;
-
-       if (!q)
-               return 0;
-
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-
-       rc  = CALL(q,mmap_free,q);
-       if (rc<0)
-               return rc;
-
-       for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-               if (NULL == q->bufs[i])
-                       continue;
-               q->ops->buf_release(q,q->bufs[i]);
-               kfree(q->bufs[i]);
-               q->bufs[i] = NULL;
-       }
-
+       mutex_unlock(&q->vb_lock);
        return rc;
 }
 
@@ -927,11 +1068,12 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
 {
        int retval;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-       mutex_lock(&q->lock);
-       retval=CALL(q,mmap_mapper,q,vma);
-       mutex_unlock(&q->lock);
+       mutex_lock(&q->vb_lock);
+       retval = CALL(q, mmap_mapper, q, vma);
+       q->is_mmapped = 1;
+       mutex_unlock(&q->vb_lock);
 
        return retval;
 }
@@ -941,15 +1083,15 @@ int videobuf_cgmbuf(struct videobuf_queue *q,
                    struct video_mbuf *mbuf, int count)
 {
        struct v4l2_requestbuffers req;
-       int rc,i;
+       int rc, i;
 
-       MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-       memset(&req,0,sizeof(req));
+       memset(&req, 0, sizeof(req));
        req.type   = q->type;
        req.count  = count;
        req.memory = V4L2_MEMORY_MMAP;
-       rc = videobuf_reqbufs(q,&req);
+       rc = videobuf_reqbufs(q, &req);
        if (rc < 0)
                return rc;
 
@@ -962,6 +1104,7 @@ int videobuf_cgmbuf(struct videobuf_queue *q,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(videobuf_cgmbuf);
 #endif
 
 /* --------------------------------------------------------------------- */
@@ -980,22 +1123,17 @@ EXPORT_SYMBOL_GPL(videobuf_reqbufs);
 EXPORT_SYMBOL_GPL(videobuf_querybuf);
 EXPORT_SYMBOL_GPL(videobuf_qbuf);
 EXPORT_SYMBOL_GPL(videobuf_dqbuf);
-EXPORT_SYMBOL_GPL(videobuf_cgmbuf);
 EXPORT_SYMBOL_GPL(videobuf_streamon);
 EXPORT_SYMBOL_GPL(videobuf_streamoff);
 
 EXPORT_SYMBOL_GPL(videobuf_read_start);
 EXPORT_SYMBOL_GPL(videobuf_read_stop);
+EXPORT_SYMBOL_GPL(videobuf_stop);
 EXPORT_SYMBOL_GPL(videobuf_read_stream);
 EXPORT_SYMBOL_GPL(videobuf_read_one);
 EXPORT_SYMBOL_GPL(videobuf_poll_stream);
 
+EXPORT_SYMBOL_GPL(__videobuf_mmap_setup);
 EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
 EXPORT_SYMBOL_GPL(videobuf_mmap_free);
 EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */