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);
 
        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))
 
        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:
 }
 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);
+
 
 };
 
 struct v4l2_m2m_ctx {
+       /* optional cap/out vb2 queues lock */
+       struct mutex                    *q_lock;
+
 /* private: internal use only */
        struct v4l2_m2m_dev             *m2m_dev;
 
        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 */