[media] V4L: Add mem2mem ioctl and file operation helpers
authorSylwester Nawrocki <s.nawrocki@samsung.com>
Sat, 14 Sep 2013 21:39:04 +0000 (18:39 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 4 Dec 2013 17:34:24 +0000 (15:34 -0200)
This patch adds ioctl helpers to the V4L2 mem-to-mem API, so we can avoid
several ioctl handlers in the mem-to-mem video node drivers that are simply
a pass-through to the v4l2_m2m_* calls. These helpers will only be useful
for drivers that use same mutex for both OUTPUT and CAPTURE queue, which
is the case for all currently in tree v4l2 m2m drivers. In order to use
the helpers the drivers are required to use struct v4l2_fh.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/v4l2-core/v4l2-mem2mem.c
include/media/v4l2-fh.h
include/media/v4l2-mem2mem.h

index 73035ee0f4def8c7425872dba6c1687419b1303f..178ce96556c6424432a9220295219ccd0dadf4e7 100644 (file)
@@ -558,6 +558,8 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 
        if (m2m_ctx->m2m_dev->m2m_ops->unlock)
                m2m_ctx->m2m_dev->m2m_ops->unlock(m2m_ctx->priv);
+       else if (m2m_ctx->q_lock)
+               mutex_unlock(m2m_ctx->q_lock);
 
        if (list_empty(&src_q->done_list))
                poll_wait(file, &src_q->done_wq, wait);
@@ -566,6 +568,8 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 
        if (m2m_ctx->m2m_dev->m2m_ops->lock)
                m2m_ctx->m2m_dev->m2m_ops->lock(m2m_ctx->priv);
+       else if (m2m_ctx->q_lock)
+               mutex_lock(m2m_ctx->q_lock);
 
        spin_lock_irqsave(&src_q->done_lock, flags);
        if (!list_empty(&src_q->done_list))
@@ -693,6 +697,13 @@ struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
 
        if (ret)
                goto err;
+       /*
+        * If both queues use same mutex assign it as the common buffer
+        * queues lock to the m2m context. This lock is used in the
+        * v4l2_m2m_ioctl_* helpers.
+        */
+       if (out_q_ctx->q.lock == cap_q_ctx->q.lock)
+               m2m_ctx->q_lock = out_q_ctx->q.lock;
 
        return m2m_ctx;
 err:
@@ -740,3 +751,118 @@ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_buffer *vb)
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue);
 
+/* Videobuf2 ioctl helpers */
+
+int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv,
+                               struct v4l2_requestbuffers *rb)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_reqbufs(file, fh->m2m_ctx, rb);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_reqbufs);
+
+int v4l2_m2m_ioctl_create_bufs(struct file *file, void *priv,
+                               struct v4l2_create_buffers *create)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_create_bufs(file, fh->m2m_ctx, create);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_create_bufs);
+
+int v4l2_m2m_ioctl_querybuf(struct file *file, void *priv,
+                               struct v4l2_buffer *buf)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_querybuf(file, fh->m2m_ctx, buf);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_querybuf);
+
+int v4l2_m2m_ioctl_qbuf(struct file *file, void *priv,
+                               struct v4l2_buffer *buf)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_qbuf);
+
+int v4l2_m2m_ioctl_dqbuf(struct file *file, void *priv,
+                               struct v4l2_buffer *buf)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_dqbuf);
+
+int v4l2_m2m_ioctl_expbuf(struct file *file, void *priv,
+                               struct v4l2_exportbuffer *eb)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_expbuf(file, fh->m2m_ctx, eb);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_expbuf);
+
+int v4l2_m2m_ioctl_streamon(struct file *file, void *priv,
+                               enum v4l2_buf_type type)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_streamon(file, fh->m2m_ctx, type);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamon);
+
+int v4l2_m2m_ioctl_streamoff(struct file *file, void *priv,
+                               enum v4l2_buf_type type)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_streamoff(file, fh->m2m_ctx, type);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamoff);
+
+/*
+ * v4l2_file_operations helpers. It is assumed here same lock is used
+ * for the output and the capture buffer queue.
+ */
+
+int v4l2_m2m_fop_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct v4l2_fh *fh = file->private_data;
+       struct v4l2_m2m_ctx *m2m_ctx = fh->m2m_ctx;
+       int ret;
+
+       if (m2m_ctx->q_lock && mutex_lock_interruptible(m2m_ctx->q_lock))
+               return -ERESTARTSYS;
+
+       ret = v4l2_m2m_mmap(file, m2m_ctx, vma);
+
+       if (m2m_ctx->q_lock)
+               mutex_unlock(m2m_ctx->q_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_fop_mmap);
+
+unsigned int v4l2_m2m_fop_poll(struct file *file, poll_table *wait)
+{
+       struct v4l2_fh *fh = file->private_data;
+       struct v4l2_m2m_ctx *m2m_ctx = fh->m2m_ctx;
+       unsigned int ret;
+
+       if (m2m_ctx->q_lock)
+               mutex_lock(m2m_ctx->q_lock);
+
+       ret = v4l2_m2m_poll(file, m2m_ctx, wait);
+
+       if (m2m_ctx->q_lock)
+               mutex_unlock(m2m_ctx->q_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_fop_poll);
+
index 528cdaf622e192aa572ade990b60acf949e74109..803516775162d184d4dbe8cf78e427ec3452e23c 100644 (file)
@@ -45,6 +45,10 @@ struct v4l2_fh {
        struct list_head        available; /* Dequeueable event */
        unsigned int            navailable;
        u32                     sequence;
+
+#if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV)
+       struct v4l2_m2m_ctx     *m2m_ctx;
+#endif
 };
 
 /*
index 44542a20ab8126cdcd851a3d369f2b2b956c96ac..12ea5a6a4331c7036341f6bc0ff4cbe48d767a01 100644 (file)
@@ -64,6 +64,9 @@ struct v4l2_m2m_queue_ctx {
 };
 
 struct v4l2_m2m_ctx {
+       /* optional cap/out vb2 queues lock */
+       struct mutex                    *q_lock;
+
 /* private: internal use only */
        struct v4l2_m2m_dev             *m2m_dev;
 
@@ -229,5 +232,26 @@ static inline void *v4l2_m2m_dst_buf_remove(struct v4l2_m2m_ctx *m2m_ctx)
        return v4l2_m2m_buf_remove(&m2m_ctx->cap_q_ctx);
 }
 
+/* v4l2 ioctl helpers */
+
+int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv,
+                               struct v4l2_requestbuffers *rb);
+int v4l2_m2m_ioctl_create_bufs(struct file *file, void *fh,
+                               struct v4l2_create_buffers *create);
+int v4l2_m2m_ioctl_querybuf(struct file *file, void *fh,
+                               struct v4l2_buffer *buf);
+int v4l2_m2m_ioctl_expbuf(struct file *file, void *fh,
+                               struct v4l2_exportbuffer *eb);
+int v4l2_m2m_ioctl_qbuf(struct file *file, void *fh,
+                               struct v4l2_buffer *buf);
+int v4l2_m2m_ioctl_dqbuf(struct file *file, void *fh,
+                               struct v4l2_buffer *buf);
+int v4l2_m2m_ioctl_streamon(struct file *file, void *fh,
+                               enum v4l2_buf_type type);
+int v4l2_m2m_ioctl_streamoff(struct file *file, void *fh,
+                               enum v4l2_buf_type type);
+int v4l2_m2m_fop_mmap(struct file *file, struct vm_area_struct *vma);
+unsigned int v4l2_m2m_fop_poll(struct file *file, poll_table *wait);
+
 #endif /* _MEDIA_V4L2_MEM2MEM_H */