/* Locking: Caller holds q->vb_lock */ static int __videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; unsigned long flags = 0; unsigned int count = 0, size = 0; int err, i; 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 < 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); 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(q, q->bufs[i]); spin_unlock_irqrestore(q->irqlock, flags); q->reading = 1; return 0; }
/* Locking: Caller holds q->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(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 */ 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); if (0 == retval) { CALL(q,sync,q,q->read_buf); if (STATE_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; }
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, nbufs; int retval; MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); mutex_lock(&q->lock); nbufs = 1; size = 0; 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(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; } 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); q->read_off = 0; } /* wait until capture is done */ retval = videobuf_waiton(q->read_buf, nonblocking, 1); if (0 != retval) goto done; CALL(q,sync,q,q->read_buf); if (STATE_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=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); kfree(q->read_buf); q->read_buf = NULL; } done: mutex_unlock(&q->lock); return retval; }
int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b) { struct videobuf_buffer *buf; enum v4l2_field field; unsigned long flags=0; int retval; MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); if (b->memory == V4L2_MEMORY_MMAP) down_read(¤t->mm->mmap_sem); mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) { dprintk(1,"qbuf: Reading running...\n"); goto done; } retval = -EINVAL; if (b->type != q->type) { 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"); goto done; } buf = q->bufs[b->index]; if (NULL == buf) { dprintk(1,"qbuf: buffer is null.\n"); goto done; } MAGIC_CHECK(buf->magic,MAGIC_BUFFER); if (buf->memory != b->memory) { 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"); goto done; } if (b->flags & V4L2_BUF_FLAG_INPUT) { if (b->input >= q->inputs) { dprintk(1,"qbuf: wrong input.\n"); goto done; } buf->input = b->input; } else { buf->input = UNSET; } switch (b->memory) { case V4L2_MEMORY_MMAP: if (0 == buf->baddr) { 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"); goto done; } if (STATE_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"); goto done; } dprintk(1,"qbuf: requesting next field\n"); field = videobuf_next_field(q); retval = q->ops->buf_prepare(q,buf,field); if (0 != retval) { dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); goto done; } 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); } dprintk(1,"qbuf: succeded\n"); retval = 0; done: mutex_unlock(&q->lock); if (b->memory == V4L2_MEMORY_MMAP) up_read(¤t->mm->mmap_sem); return retval; }
int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b) { struct videobuf_buffer *buf; enum v4l2_field field; unsigned long flags = 0; int retval; MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); if (b->memory == V4L2_MEMORY_MMAP) down_read(¤t->mm->mmap_sem); videobuf_queue_lock(q); retval = -EBUSY; if (q->reading) { dprintk(1, "qbuf: Reading running...\n"); goto done; } retval = -EINVAL; if (b->type != q->type) { dprintk(1, "qbuf: Wrong type.\n"); goto done; } 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"); goto done; } MAGIC_CHECK(buf->magic, MAGIC_BUFFER); if (buf->memory != b->memory) { dprintk(1, "qbuf: memory type is wrong.\n"); goto done; } if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) { dprintk(1, "qbuf: buffer is already queued or active.\n"); goto done; } switch (b->memory) { case V4L2_MEMORY_MMAP: if (0 == buf->baddr) { dprintk(1, "qbuf: mmap requested but buffer addr is zero!\n"); goto done; } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT || q->type == V4L2_BUF_TYPE_VBI_OUTPUT || q->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT || q->type == V4L2_BUF_TYPE_SDR_OUTPUT) { buf->size = b->bytesused; buf->field = b->field; buf->ts = v4l2_timeval_to_ns(&b->timestamp); } break; case V4L2_MEMORY_USERPTR: if (b->length < buf->bsize) { dprintk(1, "qbuf: buffer length is not enough\n"); goto done; } 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"); goto done; } dprintk(1, "qbuf: requesting next field\n"); field = videobuf_next_field(q); retval = q->ops->buf_prepare(q, buf, field); if (0 != retval) { dprintk(1, "qbuf: buffer_prepare returned %d\n", retval); goto done; } list_add_tail(&buf->stream, &q->stream); if (q->streaming) { spin_lock_irqsave(q->irqlock, flags); q->ops->buf_queue(q, buf); spin_unlock_irqrestore(q->irqlock, flags); } dprintk(1, "qbuf: succeeded\n"); retval = 0; wake_up_interruptible_sync(&q->wait); done: videobuf_queue_unlock(q); if (b->memory == V4L2_MEMORY_MMAP) up_read(¤t->mm->mmap_sem); return retval; }