diff options
Diffstat (limited to 'drivers/media/v4l2-core/videobuf2-core.c')
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-core.c | 114 |
1 files changed, 65 insertions, 49 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index c359006074a..f2e43de3dd8 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -36,7 +36,7 @@ module_param(debug, int, 0644); #define dprintk(level, fmt, arg...) \ do { \ if (debug >= level) \ - pr_debug("vb2: %s: " fmt, __func__, ## arg); \ + pr_info("vb2: %s: " fmt, __func__, ## arg); \ } while (0) #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -882,7 +882,9 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * We already have buffers allocated, so first check if they * are not in use and can be freed. */ + mutex_lock(&q->mmap_lock); if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) { + mutex_unlock(&q->mmap_lock); dprintk(1, "memory in use, cannot free\n"); return -EBUSY; } @@ -894,6 +896,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) */ __vb2_queue_cancel(q); ret = __vb2_queue_free(q, q->num_buffers); + mutex_unlock(&q->mmap_lock); if (ret) return ret; @@ -955,6 +958,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) */ } + mutex_lock(&q->mmap_lock); q->num_buffers = allocated_buffers; if (ret < 0) { @@ -963,14 +967,17 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) * from q->num_buffers. */ __vb2_queue_free(q, allocated_buffers); + mutex_unlock(&q->mmap_lock); return ret; } + mutex_unlock(&q->mmap_lock); /* * Return the number of successfully allocated buffers * to the userspace. */ req->count = allocated_buffers; + q->waiting_for_buffers = !V4L2_TYPE_IS_OUTPUT(q->type); return 0; } @@ -1018,6 +1025,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); q->memory = create->memory; + q->waiting_for_buffers = !V4L2_TYPE_IS_OUTPUT(q->type); } num_buffers = min(create->count, VIDEO_MAX_FRAME - q->num_buffers); @@ -1061,6 +1069,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create */ } + mutex_lock(&q->mmap_lock); q->num_buffers += allocated_buffers; if (ret < 0) { @@ -1069,8 +1078,10 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create * from q->num_buffers. */ __vb2_queue_free(q, allocated_buffers); + mutex_unlock(&q->mmap_lock); return -ENOMEM; } + mutex_unlock(&q->mmap_lock); /* * Return the number of successfully allocated buffers @@ -1130,7 +1141,7 @@ EXPORT_SYMBOL_GPL(vb2_plane_vaddr); */ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) { - if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) + if (plane_no >= vb->num_planes || !vb->planes[plane_no].mem_priv) return NULL; return call_ptr_memop(vb, cookie, vb->planes[plane_no].mem_priv); @@ -1165,13 +1176,10 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) if (WARN_ON(vb->state != VB2_BUF_STATE_ACTIVE)) return; - if (!q->start_streaming_called) { - if (WARN_ON(state != VB2_BUF_STATE_QUEUED)) - state = VB2_BUF_STATE_QUEUED; - } else if (WARN_ON(state != VB2_BUF_STATE_DONE && - state != VB2_BUF_STATE_ERROR)) { - state = VB2_BUF_STATE_ERROR; - } + if (WARN_ON(state != VB2_BUF_STATE_DONE && + state != VB2_BUF_STATE_ERROR && + state != VB2_BUF_STATE_QUEUED)) + state = VB2_BUF_STATE_ERROR; #ifdef CONFIG_VIDEO_ADV_DEBUG /* @@ -1582,7 +1590,6 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) { struct vb2_queue *q = vb->vb2_queue; - struct rw_semaphore *mmap_sem; int ret; ret = __verify_length(vb, b); @@ -1619,26 +1626,9 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) ret = __qbuf_mmap(vb, b); break; case V4L2_MEMORY_USERPTR: - /* - * In case of user pointer buffers vb2 allocators need to get - * direct access to userspace pages. This requires getting - * the mmap semaphore for read access in the current process - * structure. The same semaphore is taken before calling mmap - * operation, while both qbuf/prepare_buf and mmap are called - * by the driver or v4l2 core with the driver's lock held. - * To avoid an AB-BA deadlock (mmap_sem then driver's lock in - * mmap and driver's lock then mmap_sem in qbuf/prepare_buf), - * the videobuf2 core releases the driver's lock, takes - * mmap_sem and then takes the driver's lock again. - */ - mmap_sem = ¤t->mm->mmap_sem; - call_void_qop(q, wait_prepare, q); - down_read(mmap_sem); - call_void_qop(q, wait_finish, q); - + down_read(¤t->mm->mmap_sem); ret = __qbuf_userptr(vb, b); - - up_read(mmap_sem); + up_read(¤t->mm->mmap_sem); break; case V4L2_MEMORY_DMABUF: ret = __qbuf_dmabuf(vb, b); @@ -1762,6 +1752,12 @@ static int vb2_start_streaming(struct vb2_queue *q) q->start_streaming_called = 0; dprintk(1, "driver refused to start streaming\n"); + /* + * If you see this warning, then the driver isn't cleaning up properly + * after a failed start_streaming(). See the start_streaming() + * documentation in videobuf2-core.h for more information how buffers + * should be returned to vb2 in start_streaming(). + */ if (WARN_ON(atomic_read(&q->owned_by_drv_count))) { unsigned i; @@ -1777,6 +1773,12 @@ static int vb2_start_streaming(struct vb2_queue *q) /* Must be zero now */ WARN_ON(atomic_read(&q->owned_by_drv_count)); } + /* + * If done_list is not empty, then start_streaming() didn't call + * vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED) but STATE_ERROR or + * STATE_DONE. + */ + WARN_ON(!list_empty(&q->done_list)); return ret; } @@ -1812,6 +1814,7 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) */ list_add_tail(&vb->queued_entry, &q->queued_list); q->queued_count++; + q->waiting_for_buffers = false; vb->state = VB2_BUF_STATE_QUEUED; if (V4L2_TYPE_IS_OUTPUT(q->type)) { /* @@ -2123,6 +2126,12 @@ static void __vb2_queue_cancel(struct vb2_queue *q) if (q->start_streaming_called) call_void_qop(q, stop_streaming, q); + /* + * If you see this warning, then the driver isn't cleaning up properly + * in stop_streaming(). See the stop_streaming() documentation in + * videobuf2-core.h for more information how buffers should be returned + * to vb2 in stop_streaming(). + */ if (WARN_ON(atomic_read(&q->owned_by_drv_count))) { for (i = 0; i < q->num_buffers; ++i) if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) @@ -2272,6 +2281,7 @@ static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) * their normal dequeued state. */ __vb2_queue_cancel(q); + q->waiting_for_buffers = !V4L2_TYPE_IS_OUTPUT(q->type); dprintk(3, "successful\n"); return 0; @@ -2485,7 +2495,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) return -EINVAL; } + mutex_lock(&q->mmap_lock); ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma); + mutex_unlock(&q->mmap_lock); if (ret) return ret; @@ -2504,6 +2516,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, unsigned long off = pgoff << PAGE_SHIFT; struct vb2_buffer *vb; unsigned int buffer, plane; + void *vaddr; int ret; if (q->memory != V4L2_MEMORY_MMAP) { @@ -2520,7 +2533,8 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, vb = q->bufs[buffer]; - return (unsigned long)vb2_plane_vaddr(vb, plane); + vaddr = vb2_plane_vaddr(vb, plane); + return vaddr ? (unsigned long)vaddr : -EINVAL; } EXPORT_SYMBOL_GPL(vb2_get_unmapped_area); #endif @@ -2590,10 +2604,17 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) } /* - * There is nothing to wait for if no buffer has been queued and the - * queue isn't streaming, or if the error flag is set. + * There is nothing to wait for if the queue isn't streaming, or if the + * error flag is set. */ - if ((list_empty(&q->queued_list) && !vb2_is_streaming(q)) || q->error) + if (!vb2_is_streaming(q) || q->error) + return res | POLLERR; + /* + * For compatibility with vb1: if QBUF hasn't been called yet, then + * return POLLERR as well. This only affects capture queues, output + * queues will always initialize waiting_for_buffers to false. + */ + if (q->waiting_for_buffers) return res | POLLERR; /* @@ -2660,6 +2681,7 @@ int vb2_queue_init(struct vb2_queue *q) INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); + mutex_init(&q->mmap_lock); init_waitqueue_head(&q->done_wq); if (q->buf_struct_size == 0) @@ -2681,7 +2703,9 @@ void vb2_queue_release(struct vb2_queue *q) { __vb2_cleanup_fileio(q); __vb2_queue_cancel(q); + mutex_lock(&q->mmap_lock); __vb2_queue_free(q, q->num_buffers); + mutex_unlock(&q->mmap_lock); } EXPORT_SYMBOL_GPL(vb2_queue_release); @@ -2959,6 +2983,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ buf->queued = 0; buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0) : vb2_plane_size(q->bufs[index], 0); + /* Compensate for data_offset on read in the multiplanar case. */ + if (is_multiplanar && read && + fileio->b.m.planes[0].data_offset < buf->size) { + buf->pos = fileio->b.m.planes[0].data_offset; + buf->size -= buf->pos; + } } else { buf = &fileio->bufs[index]; } @@ -3346,15 +3376,8 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_expbuf); int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma) { struct video_device *vdev = video_devdata(file); - struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; - int err; - if (lock && mutex_lock_interruptible(lock)) - return -ERESTARTSYS; - err = vb2_mmap(vdev->queue, vma); - if (lock) - mutex_unlock(lock); - return err; + return vb2_mmap(vdev->queue, vma); } EXPORT_SYMBOL_GPL(vb2_fop_mmap); @@ -3473,15 +3496,8 @@ unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct video_device *vdev = video_devdata(file); - struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; - int ret; - if (lock && mutex_lock_interruptible(lock)) - return -ERESTARTSYS; - ret = vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags); - if (lock) - mutex_unlock(lock); - return ret; + return vb2_get_unmapped_area(vdev->queue, addr, len, pgoff, flags); } EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area); #endif |