/* 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; int retval; MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); /* setup stuff */ q->read_buf = videobuf_alloc_vb(q); if (NULL == q->read_buf) return -ENOMEM; q->read_buf->memory = V4L2_MEMORY_USERPTR; q->read_buf->baddr = (unsigned long)data; q->read_buf->bsize = count; field = videobuf_next_field(q); 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(q, q->read_buf); spin_unlock_irqrestore(q->irqlock, flags); retval = videobuf_waiton(q, q->read_buf, 0, 0); if (0 == retval) { CALL(q, sync, q, q->read_buf); if (VIDEOBUF_ERROR == q->read_buf->state) retval = -EIO; else retval = q->read_buf->size; } done: /* cleanup */ q->ops->buf_release(q, q->read_buf); kfree(q->read_buf); q->read_buf = NULL; return retval; }
/* 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_free(q); if (0 != err) return err; /* Allocate and initialize buffers */ for (i = 0; i < bcount; i++) { q->bufs[i] = videobuf_alloc_vb(q); if (NULL == q->bufs[i]) 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 = PAGE_ALIGN(bsize) * i; break; case V4L2_MEMORY_USERPTR: case V4L2_MEMORY_OVERLAY: case V4L2_MEMORY_DMABUF: /* nothing */ break; } } if (!i) return -ENOMEM; dprintk(1, "mmap setup: %d buffers, %d bytes each\n", i, bsize); return i; }
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 = 0; unsigned size = 0, nbufs = 1; int retval; MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); videobuf_queue_lock(q); q->ops->buf_setup(q, &nbufs, &size); if (NULL == q->read_buf && count >= size && !nonblocking) { retval = videobuf_read_zerocopy(q, data, count, ppos); if (retval >= 0 || retval == -EIO) /* ok, all done */ goto done; /* fallback to kernel bounce buffer on failures */ } if (NULL == q->read_buf) { /* need to capture a new frame */ retval = -ENOMEM; q->read_buf = videobuf_alloc_vb(q); 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); if (0 != retval) { kfree(q->read_buf); q->read_buf = NULL; goto done; } spin_lock_irqsave(q->irqlock, flags); 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, q->read_buf, nonblocking, 1); if (0 != retval) goto done; CALL(q, sync, q, q->read_buf); if (VIDEOBUF_ERROR == q->read_buf->state) { /* catch I/O errors */ q->ops->buf_release(q, q->read_buf); kfree(q->read_buf); q->read_buf = NULL; retval = -EIO; goto done; } /* Copy to userspace */ retval = __videobuf_copy_to_user(q, q->read_buf, 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); kfree(q->read_buf); q->read_buf = NULL; } done: videobuf_queue_unlock(q); return retval; }