diff options
author | Liu Ying <Ying.Liu@freescale.com> | 2011-12-27 10:35:38 +0800 |
---|---|---|
committer | Liu Ying <Ying.Liu@freescale.com> | 2011-12-27 13:34:57 +0800 |
commit | f3952d2b4c53ee537648c0838c66839b03f07995 (patch) | |
tree | 4d6e8b0454913e74c4b7d1f141551630fea319a2 | |
parent | cd642710096176aa777bea3e40418570a8fd1ec4 (diff) |
ENGR00170756 MXC v4l2 output:Support user buffer
This patch supports buffers allocated by user to
be passed into MXC v4l2 output. The user should
call VIDIOC_REQBUFS ioctrl to specify the total
user buffer number before qbuf.
Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
(cherry picked from commit 4f35f9587b2c71de492aa96256a7c17a39672ea4)
-rw-r--r-- | drivers/media/video/mxc/output/mxc_v4l2_output.c | 90 |
1 files changed, 69 insertions, 21 deletions
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.c b/drivers/media/video/mxc/output/mxc_v4l2_output.c index 0efece1bfc01..dee717636e84 100644 --- a/drivers/media/video/mxc/output/mxc_v4l2_output.c +++ b/drivers/media/video/mxc/output/mxc_v4l2_output.c @@ -2162,7 +2162,8 @@ mxc_v4l2out_do_ioctl(struct file *file, { struct v4l2_requestbuffers *req = arg; if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || - (req->memory != V4L2_MEMORY_MMAP)) { + (req->memory != V4L2_MEMORY_MMAP && + req->memory != V4L2_MEMORY_USERPTR)) { dev_dbg(&vdev->dev, "VIDIOC_REQBUFS: incorrect buffer type\n"); retval = -EINVAL; @@ -2173,7 +2174,8 @@ mxc_v4l2out_do_ioctl(struct file *file, mxc_v4l2out_streamoff(vout); if (vout->state == STATE_STREAM_OFF) { - if (vout->queue_buf_paddr[0] != 0) { + if (vout->queue_buf_paddr[0] != 0 && + req->memory == V4L2_MEMORY_MMAP) { mxc_free_buffers(vout->queue_buf_paddr, vout->queue_buf_vaddr, vout->buffer_cnt, @@ -2198,15 +2200,18 @@ mxc_v4l2out_do_ioctl(struct file *file, req->count = MAX_FRAME_NUM; } vout->buffer_cnt = req->count; - vout->queue_buf_size = - PAGE_ALIGN(vout->v2f.fmt.pix.sizeimage); - - retval = mxc_allocate_buffers(vout->queue_buf_paddr, - vout->queue_buf_vaddr, - vout->buffer_cnt, - vout->queue_buf_size); - if (retval < 0) - break; + + if (req->memory == V4L2_MEMORY_MMAP) { + vout->queue_buf_size = + PAGE_ALIGN(vout->v2f.fmt.pix.sizeimage); + + retval = mxc_allocate_buffers(vout->queue_buf_paddr, + vout->queue_buf_vaddr, + vout->buffer_cnt, + vout->queue_buf_size); + if (retval < 0) + break; + } /* Init buffer queues */ vout->done_q.head = 0; @@ -2218,14 +2223,15 @@ mxc_v4l2out_do_ioctl(struct file *file, memset(&(vout->v4l2_bufs[i]), 0, sizeof(vout->v4l2_bufs[i])); vout->v4l2_bufs[i].flags = 0; - vout->v4l2_bufs[i].memory = V4L2_MEMORY_MMAP; + vout->v4l2_bufs[i].memory = req->memory; vout->v4l2_bufs[i].index = i; vout->v4l2_bufs[i].type = V4L2_BUF_TYPE_VIDEO_OUTPUT; vout->v4l2_bufs[i].length = PAGE_ALIGN(vout->v2f.fmt.pix.sizeimage); - vout->v4l2_bufs[i].m.offset = - (unsigned long)vout->queue_buf_paddr[i]; + if (req->memory == V4L2_MEMORY_MMAP) + vout->v4l2_bufs[i].m.offset = + (unsigned long)vout->queue_buf_paddr[i]; vout->v4l2_bufs[i].timestamp.tv_sec = 0; vout->v4l2_bufs[i].timestamp.tv_usec = 0; } @@ -2252,26 +2258,68 @@ mxc_v4l2out_do_ioctl(struct file *file, case VIDIOC_QBUF: { struct v4l2_buffer *buf = arg; - int index = buf->index; + int index = 0, i = 0; unsigned long lock_flags; int param[5][3]; - if ((buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || - (index >= vout->buffer_cnt)) { + if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + dev_err(&vdev->dev, + "VIDIOC_QBUF: wrong buf type\n"); retval = -EINVAL; break; } - dev_dbg(&vdev->dev, "VIDIOC_QBUF: %d field = %d\n", buf->index, buf->field); + if (buf->memory == V4L2_MEMORY_MMAP) { + index = buf->index; + if (index >= vout->buffer_cnt) { + dev_err(&vdev->dev, "VIDIOC_QBUF: " + "too big mmap buf index %d\n", + index); + retval = -EINVAL; + break; + } + + dev_dbg(&vdev->dev, "VIDIOC_QBUF: MMAP buf %d " + "field = %d\n", buf->index, buf->field); - /* mmapped buffers are L1 WB cached, - * so we need to clean them */ - if (buf->memory & V4L2_MEMORY_MMAP) { + /* mmapped buffers are L1 WB cached, + * so we need to clean them */ flush_cache_all(); } spin_lock_irqsave(&g_lock, lock_flags); + if (buf->memory == V4L2_MEMORY_USERPTR) { + if (buf->m.userptr == 0) { + dev_err(&vdev->dev, "VIDIOC_QBUF: " + "user buffer wrong ptr\n"); + retval = -EINVAL; + spin_unlock_irqrestore(&g_lock, + lock_flags); + break; + } + + for (i = 0; i < vout->buffer_cnt; i++) { + index = i; + if (vout->v4l2_bufs[i].m.userptr == + buf->m.userptr || + vout->v4l2_bufs[i].m.userptr == 0) + break; + } + + if (i == vout->buffer_cnt) { + dev_err(&vdev->dev, "VIDIOC_QBUF: " + "user buffer num overflows\n"); + spin_unlock_irqrestore(&g_lock, + lock_flags); + retval = -EINVAL; + break; + } + + dev_dbg(&vdev->dev, "VIDIOC_QBUF: USER buf %d " + "field = %d\n", index, buf->field); + } + memcpy(&(vout->v4l2_bufs[index]), buf, sizeof(*buf)); vout->v4l2_bufs[index].flags |= V4L2_BUF_FLAG_QUEUED; |