diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-02-10 11:35:36 -0800 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-02-10 11:35:36 -0800 |
commit | 4ba24fef3eb3b142197135223b90ced2f319cd53 (patch) | |
tree | a20c125b27740ec7b4c761b11d801108e1b316b2 /drivers/media/v4l2-core/videobuf2-core.c | |
parent | 47c1ffb2b6b630894e9a16442611c056ab21c057 (diff) | |
parent | 98a4a59ee31a12105a2b84f5b8b515ac2cb208ef (diff) |
Merge branch 'next' into for-linus
Prepare first round of input updates for 3.20.
Diffstat (limited to 'drivers/media/v4l2-core/videobuf2-core.c')
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-core.c | 115 |
1 files changed, 49 insertions, 66 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 25d3ae2188c..d09a8916e94 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 @@ -189,6 +189,8 @@ static void __vb2_queue_cancel(struct vb2_queue *q); static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) { struct vb2_queue *q = vb->vb2_queue; + enum dma_data_direction dma_dir = + V4L2_TYPE_IS_OUTPUT(q->type) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; void *mem_priv; int plane; @@ -200,7 +202,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]); mem_priv = call_ptr_memop(vb, alloc, q->alloc_ctx[plane], - size, q->gfp_flags); + size, dma_dir, q->gfp_flags); if (IS_ERR_OR_NULL(mem_priv)) goto free; @@ -882,7 +884,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 +898,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 +960,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,8 +969,10 @@ 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 @@ -1063,6 +1071,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) { @@ -1071,8 +1080,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 @@ -1349,7 +1360,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) void *mem_priv; unsigned int plane; int ret; - int write = !V4L2_TYPE_IS_OUTPUT(q->type); + enum dma_data_direction dma_dir = + V4L2_TYPE_IS_OUTPUT(q->type) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; bool reacquired = vb->planes[0].mem_priv == NULL; memset(planes, 0, sizeof(planes[0]) * vb->num_planes); @@ -1391,7 +1403,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) /* Acquire each plane's memory */ mem_priv = call_ptr_memop(vb, get_userptr, q->alloc_ctx[plane], planes[plane].m.userptr, - planes[plane].length, write); + planes[plane].length, dma_dir); if (IS_ERR_OR_NULL(mem_priv)) { dprintk(1, "failed acquiring userspace " "memory for plane %d\n", plane); @@ -1452,7 +1464,8 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) void *mem_priv; unsigned int plane; int ret; - int write = !V4L2_TYPE_IS_OUTPUT(q->type); + enum dma_data_direction dma_dir = + V4L2_TYPE_IS_OUTPUT(q->type) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; bool reacquired = vb->planes[0].mem_priv == NULL; memset(planes, 0, sizeof(planes[0]) * vb->num_planes); @@ -1500,7 +1513,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) /* Acquire each plane's memory */ mem_priv = call_ptr_memop(vb, attach_dmabuf, q->alloc_ctx[plane], - dbuf, planes[plane].length, write); + dbuf, planes[plane].length, dma_dir); if (IS_ERR(mem_priv)) { dprintk(1, "failed to attach dmabuf\n"); ret = PTR_ERR(mem_priv); @@ -1581,7 +1594,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); @@ -1618,26 +1630,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); @@ -2504,7 +2499,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; @@ -2523,6 +2520,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) { @@ -2539,7 +2537,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 @@ -2686,6 +2685,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) @@ -2707,7 +2707,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); @@ -2985,6 +2987,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]; } @@ -3372,15 +3380,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); @@ -3388,14 +3389,14 @@ int _vb2_fop_release(struct file *file, struct mutex *lock) { struct video_device *vdev = video_devdata(file); + if (lock) + mutex_lock(lock); if (file->private_data == vdev->queue->owner) { - if (lock) - mutex_lock(lock); vb2_queue_release(vdev->queue); vdev->queue->owner = NULL; - if (lock) - mutex_unlock(lock); } + if (lock) + mutex_unlock(lock); return v4l2_fh_release(file); } EXPORT_SYMBOL_GPL(_vb2_fop_release); @@ -3458,27 +3459,16 @@ unsigned int vb2_fop_poll(struct file *file, poll_table *wait) struct video_device *vdev = video_devdata(file); struct vb2_queue *q = vdev->queue; struct mutex *lock = q->lock ? q->lock : vdev->lock; - unsigned long req_events = poll_requested_events(wait); unsigned res; void *fileio; - bool must_lock = false; - /* Try to be smart: only lock if polling might start fileio, - otherwise locking will only introduce unwanted delays. */ - if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) { - if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) && - (req_events & (POLLIN | POLLRDNORM))) - must_lock = true; - else if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) && - (req_events & (POLLOUT | POLLWRNORM))) - must_lock = true; - } - - /* If locking is needed, but this helper doesn't know how, then you - shouldn't be using this helper but you should write your own. */ - WARN_ON(must_lock && !lock); + /* + * If this helper doesn't know how to lock, then you shouldn't be using + * it but you should write your own. + */ + WARN_ON(!lock); - if (must_lock && lock && mutex_lock_interruptible(lock)) + if (lock && mutex_lock_interruptible(lock)) return POLLERR; fileio = q->fileio; @@ -3486,9 +3476,9 @@ unsigned int vb2_fop_poll(struct file *file, poll_table *wait) res = vb2_poll(vdev->queue, file, wait); /* If fileio was started, then we have a new queue owner. */ - if (must_lock && !fileio && q->fileio) + if (!fileio && q->fileio) q->owner = file->private_data; - if (must_lock && lock) + if (lock) mutex_unlock(lock); return res; } @@ -3499,15 +3489,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 |