]> err.no Git - linux-2.6/blobdiff - drivers/media/video/videobuf-core.c
Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/cooloney...
[linux-2.6] / drivers / media / video / videobuf-core.c
index ca67f80184bdfb69fd9e44a6e420036793dd58c4..89a44f16f0ba50892be204f19f66c576cf46a2e1 100644 (file)
@@ -94,29 +94,39 @@ int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
        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.
+
+          However, this way is just too dirty! Better to wait for some event.
+        */
+       schedule_timeout(HZ);
+
        return CALL(q,iolock,q,vb,fbuf);
 }
 
 /* --------------------------------------------------------------------- */
 
 
-void videobuf_queue_init(struct videobuf_queue* q,
+void videobuf_queue_core_init(struct videobuf_queue* q,
                         struct videobuf_queue_ops *ops,
                         void *dev,
                         spinlock_t *irqlock,
                         enum v4l2_buf_type type,
                         enum v4l2_field field,
                         unsigned int msize,
-                        void *priv)
+                        void *priv,
+                        struct videobuf_qtype_ops *int_ops)
 {
        memset(q,0,sizeof(*q));
-       q->irqlock = irqlock;
-       q->dev     = dev;
-       q->type    = type;
-       q->field   = field;
-       q->msize   = msize;
-       q->ops     = ops;
+       q->irqlock   = irqlock;
+       q->dev       = dev;
+       q->type      = type;
+       q->field     = field;
+       q->msize     = msize;
+       q->ops       = ops;
        q->priv_data = priv;
+       q->int_ops   = int_ops;
 
        /* All buffer operations are mandatory */
        BUG_ON (!q->ops->buf_setup);
@@ -124,6 +134,9 @@ void videobuf_queue_init(struct videobuf_queue* q,
        BUG_ON (!q->ops->buf_queue);
        BUG_ON (!q->ops->buf_release);
 
+       /* Having implementations for abstract methods are mandatory */
+       BUG_ON (!q->int_ops);
+
        mutex_init(&q->lock);
        INIT_LIST_HEAD(&q->stream);
 }
@@ -316,7 +329,7 @@ int videobuf_reqbufs(struct videobuf_queue *q,
                goto done;
        }
 
-       req->count = count;
+       req->count = retval;
 
  done:
        mutex_unlock(&q->lock);
@@ -504,7 +517,6 @@ int videobuf_dqbuf(struct videobuf_queue *q,
 int videobuf_streamon(struct videobuf_queue *q)
 {
        struct videobuf_buffer *buf;
-       struct list_head *list;
        unsigned long flags=0;
        int retval;
 
@@ -518,11 +530,9 @@ int videobuf_streamon(struct videobuf_queue *q)
        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);
+       list_for_each_entry(buf, &q->stream, stream)
                if (buf->state == STATE_PREPARED)
                        q->ops->buf_queue(q,buf);
-       }
        if (q->irqlock)
                spin_unlock_irqrestore(q->irqlock,flags);
 
@@ -664,7 +674,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        }
 
        /* Copy to userspace */
-       retval=CALL(q,copy_to_user,q,data,count,nonblocking);
+       retval=CALL(q,video_copy_to_user,q,data,count,nonblocking);
        if (retval<0)
                goto done;
 
@@ -685,7 +695,7 @@ int videobuf_read_start(struct videobuf_queue *q)
 {
        enum v4l2_field field;
        unsigned long flags=0;
-       int count = 0, size = 0;
+       unsigned int count = 0, size = 0;
        int err, i;
 
        q->ops->buf_setup(q,&count,&size);
@@ -696,9 +706,11 @@ int videobuf_read_start(struct videobuf_queue *q)
        size = PAGE_ALIGN(size);
 
        err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR);
-       if (err)
+       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);
@@ -771,7 +783,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
                }
 
                if (q->read_buf->state == STATE_DONE) {
-                       rc = CALL (q,copy_stream, q, data, count,
+                       rc = CALL (q,copy_stream, q, data + retval, count,
                                        retval, vbihack, nonblocking);
                        if (rc < 0) {
                                retval = rc;
@@ -863,6 +875,9 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
        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;
@@ -878,10 +893,13 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
                }
        }
 
+       if (!i)
+               return -ENOMEM;
+
        dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
-               bcount,bsize);
+               i, bsize);
 
-       return 0;
+       return i;
 }
 
 int videobuf_mmap_free(struct videobuf_queue *q)
@@ -949,6 +967,7 @@ int videobuf_cgmbuf(struct videobuf_queue *q,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(videobuf_cgmbuf);
 #endif
 
 /* --------------------------------------------------------------------- */
@@ -958,7 +977,7 @@ EXPORT_SYMBOL_GPL(videobuf_iolock);
 
 EXPORT_SYMBOL_GPL(videobuf_alloc);
 
-EXPORT_SYMBOL_GPL(videobuf_queue_init);
+EXPORT_SYMBOL_GPL(videobuf_queue_core_init);
 EXPORT_SYMBOL_GPL(videobuf_queue_cancel);
 EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
 
@@ -967,7 +986,6 @@ 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);