int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) { int ret = -EINVAL; videobuf_queue_lock(q); if (unlikely(b->type != q->type)) { dprintk(1, "querybuf: Wrong type.\n"); goto done; } 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"); goto done; } videobuf_status(q, b, q->bufs[b->index], q->type); ret = 0; done: videobuf_queue_unlock(q); return ret; }
static void videobuf_vm_close(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_queue *q = map->q; struct videobuf_dma_sg_memory *mem; int i; dprintk(2, "vm_close %p [count=%d,vma=%08lx-%08lx]\n", map, map->count, vma->vm_start, vma->vm_end); map->count--; if (0 == map->count) { dprintk(1, "munmap %p q=%p\n", map, q); videobuf_queue_lock(q); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; mem = q->bufs[i]->priv; if (!mem) continue; MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); if (q->bufs[i]->map != map) continue; q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; q->ops->buf_release(q, q->bufs[i]); } videobuf_queue_unlock(q); kfree(map); } return; }
int videobuf_streamon(struct videobuf_queue *q) { struct videobuf_buffer *buf; unsigned long flags = 0; int retval; videobuf_queue_lock(q); retval = -EBUSY; if (q->reading) goto done; retval = 0; if (q->streaming) goto done; q->streaming = 1; 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: videobuf_queue_unlock(q); return retval; }
int videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req) { unsigned int size, count; int retval; if (req->memory != V4L2_MEMORY_MMAP && req->memory != V4L2_MEMORY_USERPTR && req->memory != V4L2_MEMORY_OVERLAY) { dprintk(1, "reqbufs: memory type invalid\n"); return -EINVAL; } videobuf_queue_lock(q); 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"); retval = -EBUSY; goto done; } if (!list_empty(&q->stream)) { dprintk(1, "reqbufs: stream running\n"); retval = -EBUSY; goto done; } if (req->count == 0) { dprintk(1, "reqbufs: count invalid (%d)\n", req->count); retval = __videobuf_free(q); goto done; } count = req->count; if (count > VIDEO_MAX_FRAME) count = VIDEO_MAX_FRAME; size = 0; q->ops->buf_setup(q, &count, &size); dprintk(1, "reqbufs: bufs=%d, size=0x%x [%u pages total]\n", count, size, (unsigned int)((count * PAGE_ALIGN(size)) >> PAGE_SHIFT)); retval = __videobuf_mmap_setup(q, count, size, req->memory); if (retval < 0) { dprintk(1, "reqbufs: mmap setup returned %d\n", retval); goto done; } req->count = retval; retval = 0; done: videobuf_queue_unlock(q); return retval; }
int videobuf_mmap_free(struct videobuf_queue *q) { int ret; videobuf_queue_lock(q); ret = __videobuf_free(q); videobuf_queue_unlock(q); return ret; }
static void videobuf_vm_close(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_queue *q = map->q; int i; dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, map->count, vma->vm_start, vma->vm_end); map->count--; if (0 == map->count) { struct videobuf_vmalloc_memory *mem; dprintk(1, "munmap %p q=%p\n", map, q); videobuf_queue_lock(q); /* */ if (q->streaming) videobuf_queue_cancel(q); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; if (q->bufs[i]->map != map) continue; mem = q->bufs[i]->priv; if (mem) { /* */ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); /* */ dprintk(1, "%s: buf[%d] freeing (%p)\n", __func__, i, mem->vaddr); vfree(mem->vaddr); mem->vaddr = NULL; } q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; } kfree(map); videobuf_queue_unlock(q); } return; }
static void videobuf_vm_close(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_queue *q = map->q; int i; dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, map->count, vma->vm_start, vma->vm_end); map->count--; if (0 == map->count) { struct videobuf_vmalloc_memory *mem; dprintk(1, "munmap %p q=%p\n", map, q); videobuf_queue_lock(q); /* We need first to cancel streams, before unmapping */ if (q->streaming) videobuf_queue_cancel(q); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; if (q->bufs[i]->map != map) continue; mem = q->bufs[i]->priv; if (mem) { /* This callback is called only if kernel has allocated memory and this memory is mmapped. In this case, memory should be freed, in order to do memory unmap. */ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); /* vfree is not atomic - can't be called with IRQ's disabled */ dprintk(1, "%s: buf[%d] freeing (%p)\n", __func__, i, mem->vaddr); vfree(mem->vaddr); mem->vaddr = NULL; } q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; } kfree(map); videobuf_queue_unlock(q); } return; }
int videobuf_streamoff(struct videobuf_queue *q) { int retval; videobuf_queue_lock(q); retval = __videobuf_streamoff(q); videobuf_queue_unlock(q); return retval; }
int videobuf_mmap_setup(struct videobuf_queue *q, unsigned int bcount, unsigned int bsize, enum v4l2_memory memory) { int ret; videobuf_queue_lock(q); ret = __videobuf_mmap_setup(q, bcount, bsize, memory); videobuf_queue_unlock(q); return ret; }
int videobuf_read_start(struct videobuf_queue *q) { int rc; videobuf_queue_lock(q); rc = __videobuf_read_start(q); videobuf_queue_unlock(q); return rc; }
/* Locking: Caller holds q->vb_lock */ static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock) { int retval; bool is_ext_locked; checks: if (!q->streaming) { dprintk(1, "next_buffer: Not streaming\n"); retval = -EINVAL; goto done; } if (list_empty(&q->stream)) { 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 */ videobuf_queue_unlock(q); /*[email protected] */ is_ext_locked = q->ext_lock && mutex_is_locked(q->ext_lock); /* Release vdev lock to prevent this wait from blocking outside access to the device. */ if (is_ext_locked) mutex_unlock(q->ext_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); videobuf_queue_lock(q); /*[email protected] */ if (is_ext_locked) mutex_lock(q->ext_lock); if (retval) goto done; goto checks; } } retval = 0; done: return retval; }
void videobuf_stop(struct videobuf_queue *q) { videobuf_queue_lock(q); if (q->streaming) __videobuf_streamoff(q); if (q->reading) __videobuf_read_stop(q); videobuf_queue_unlock(q); }
/* Locking: Caller holds q->vb_lock */ static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock) { int retval; checks: if (!q->streaming) { dprintk(1, "next_buffer: Not streaming\n"); retval = -EINVAL; goto done; } if (list_empty(&q->stream)) { 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 */ videobuf_queue_unlock(q); /* 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); videobuf_queue_lock(q); if (retval) goto done; goto checks; } } retval = 0; 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); memset(b, 0, sizeof(*b)); videobuf_queue_lock(q); retval = stream_next_buffer(q, &buf, nonblocking); if (retval < 0) { dprintk(1, "dqbuf: next_buffer error: %i\n", retval); goto done; } switch (buf->state) { case VIDEOBUF_ERROR: dprintk(1, "dqbuf: state is error\n"); break; case VIDEOBUF_DONE: dprintk(1, "dqbuf: state is done\n"); break; default: dprintk(1, "dqbuf: state invalid\n"); retval = -EINVAL; goto done; } CALL(q, sync, q, buf); videobuf_status(q, b, buf, q->type); list_del(&buf->stream); buf->state = VIDEOBUF_IDLE; b->flags &= ~V4L2_BUF_FLAG_DONE; done: videobuf_queue_unlock(q); 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 = 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; }
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; }
void videobuf_read_stop(struct videobuf_queue *q) { videobuf_queue_lock(q); __videobuf_read_stop(q); videobuf_queue_unlock(q); }