diff mbox

[RFC,v4,8/8,media] videobuf2: Remove v4l2-dependencies from videobuf2-core

Message ID 1441797597-17389-9-git-send-email-jh1009.sung@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Junghak Sung Sept. 9, 2015, 11:19 a.m. UTC
Move v4l2-stuffs from videobuf2-core to videobuf2-v4l2. And make
wrappers that use the vb2_core_* functions.

Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
---
 drivers/media/v4l2-core/videobuf2-core.c     |  517 ++++++++++++++++----------
 drivers/media/v4l2-core/videobuf2-internal.h |   51 +--
 drivers/media/v4l2-core/videobuf2-v4l2.c     |  312 ++++++++++++----
 include/media/videobuf2-core.h               |   20 +-
 include/media/videobuf2-v4l2.h               |    3 +-
 5 files changed, 601 insertions(+), 302 deletions(-)

Comments

Hans Verkuil Sept. 11, 2015, 12:47 p.m. UTC | #1
Hi Junghak,

Patch 7/8 helped a lot in reducing the size of this one. But it is still difficult
to review so I would like to request one final (honest!) split for this patch:

Move all the code that does not depend on the new buf_ops into a separate patch.
So the new q->is_output and q->multiplanar field can be moved to that patch.
But also the changes to functions like vb2_expbuf() or streamon/off where some
checks are moved from core.c to v4l2.c can be done separately.

All such pretty easy to review modifications should be put in a separate patch,
leaving me with one remaining patch that I really need to study.

I recommend that you wait until 4.3-rc1 is released and merged back in our tree
since that will contain a number of vb2 changes (Jan Kara's work). So it makes
sense to rebase on top of that first before doing more work on this.

I did find a few things in this patch as well, see my comments below:

On 09/09/2015 01:19 PM, Junghak Sung wrote:
> Move v4l2-stuffs from videobuf2-core to videobuf2-v4l2. And make
> wrappers that use the vb2_core_* functions.
> 
> Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
> Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
> Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
> Acked-by: Inki Dae <inki.dae@samsung.com>
> ---
>  drivers/media/v4l2-core/videobuf2-core.c     |  517 ++++++++++++++++----------
>  drivers/media/v4l2-core/videobuf2-internal.h |   51 +--
>  drivers/media/v4l2-core/videobuf2-v4l2.c     |  312 ++++++++++++----
>  include/media/videobuf2-core.h               |   20 +-
>  include/media/videobuf2-v4l2.h               |    3 +-
>  5 files changed, 601 insertions(+), 302 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
> index 3e6ee0e..56d34f2 100644
> --- a/drivers/media/v4l2-core/videobuf2-core.c
> +++ b/drivers/media/v4l2-core/videobuf2-core.c

<snip>

> @@ -454,13 +426,34 @@ static bool __buffers_in_use(struct vb2_queue *q)
>  {
>  	unsigned int buffer;
>  	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
> -		if (__buffer_in_use(q, q->bufs[buffer]))
> +		if (vb2_buffer_in_use(q, q->bufs[buffer]))
>  			return true;
>  	}
>  	return false;
>  }
>  
>  /**
> + * vb2_core_querybuf() - query video buffer information
> + * @q:		videobuf queue
> + * @index:	id number of the buffer
> + * @pb:		buffer struct passed from userspace
> + *
> + * Should be called from vidioc_querybuf ioctl handler in driver.
> + * The passed buffer should have been verified.
> + * This function fills the relevant information for the userspace.
> + *
> + * The return values from this function are intended to be directly returned
> + * from vidioc_querybuf handler in driver.
> + */
> +int vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
> +{
> +	call_bufop(q, fill_user_buffer, q->bufs[index], pb);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(vb2_core_querybuf);

This should be a void function since it never returns an error.

But do we need it at all? It really doesn't do anything that is core-specific.
The querybuf ioctl is really pure V4L2 and has nothing to do with the vb2 core.

> +
> +/**
>   * __verify_userptr_ops() - verify that all memory operations required for
>   * USERPTR queue type have been provided
>   */
> @@ -1182,52 +1174,27 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
>  	call_void_vb_qop(vb, buf_queue, vb);
>  }
>  
> -int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
> +static int __buf_prepare(struct vb2_buffer *vb, void *pb)
>  {
> -	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>  	struct vb2_queue *q = vb->vb2_queue;
>  	int ret;
>  
> -	ret = __verify_length(vb, b);
> -	if (ret < 0) {
> -		dprintk(1, "plane parameters verification failed: %d\n", ret);
> -		return ret;
> -	}
> -	if (b->field == V4L2_FIELD_ALTERNATE && V4L2_TYPE_IS_OUTPUT(q->type)) {
> -		/*
> -		 * If the format's field is ALTERNATE, then the buffer's field
> -		 * should be either TOP or BOTTOM, not ALTERNATE since that
> -		 * makes no sense. The driver has to know whether the
> -		 * buffer represents a top or a bottom field in order to
> -		 * program any DMA correctly. Using ALTERNATE is wrong, since
> -		 * that just says that it is either a top or a bottom field,
> -		 * but not which of the two it is.
> -		 */
> -		dprintk(1, "the field is incorrectly set to ALTERNATE for an output buffer\n");
> -		return -EINVAL;
> -	}
> -
>  	if (q->error) {
>  		dprintk(1, "fatal error occurred on queue\n");
>  		return -EIO;
>  	}
>  
> -	vb->state = VB2_BUF_STATE_PREPARING;

Hmmm, this moved to v4l2.c. Why? This still belongs here as far as I can tell.
I suspect that was a copy-and-paste mistake.

> -	vbuf->timestamp.tv_sec = 0;
> -	vbuf->timestamp.tv_usec = 0;
> -	vbuf->sequence = 0;
> -
>  	switch (q->memory) {
>  	case VB2_MEMORY_MMAP:
> -		ret = __qbuf_mmap(vb, b);
> +		ret = __qbuf_mmap(vb, pb);
>  		break;
>  	case VB2_MEMORY_USERPTR:
>  		down_read(&current->mm->mmap_sem);
> -		ret = __qbuf_userptr(vb, b);
> +		ret = __qbuf_userptr(vb, pb);
>  		up_read(&current->mm->mmap_sem);
>  		break;
>  	case VB2_MEMORY_DMABUF:
> -		ret = __qbuf_dmabuf(vb, b);
> +		ret = __qbuf_dmabuf(vb, pb);
>  		break;
>  	default:
>  		WARN(1, "Invalid queue type\n");
> @@ -1241,32 +1208,94 @@ int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
>  	return ret;
>  }
>  
> -int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
> -				    const char *opname)
> +/**
> + * vb2_verify_buffer() - verify the buffer information passed from userspace
> + */
> +int vb2_verify_buffer(struct vb2_queue *q,
> +			enum vb2_memory memory, unsigned int type,
> +			unsigned int index, unsigned int nplanes,
> +			void *pplane, const char *opname)
>  {
> -	if (b->type != q->type) {
> +	if (type != q->type) {
>  		dprintk(1, "%s: invalid buffer type\n", opname);
>  		return -EINVAL;
>  	}
>  
> -	if (b->index >= q->num_buffers) {
> +	if (index >= q->num_buffers) {
>  		dprintk(1, "%s: buffer index out of range\n", opname);
>  		return -EINVAL;
>  	}
>  
> -	if (q->bufs[b->index] == NULL) {
> +	if (q->bufs[index] == NULL) {
>  		/* Should never happen */
>  		dprintk(1, "%s: buffer is NULL\n", opname);
>  		return -EINVAL;
>  	}
>  
> -	if (b->memory != q->memory) {
> +	if (memory != VB2_MEMORY_UNKNOWN && memory != q->memory) {
>  		dprintk(1, "%s: invalid memory type\n", opname);
>  		return -EINVAL;
>  	}
>  
> -	return __verify_planes_array(q->bufs[b->index], b);
> +	if (q->is_multiplanar) {
> +		struct vb2_buffer *vb = q->bufs[index];
> +
> +		/* Is memory for copying plane information present? */
> +		if (NULL == pplane) {
> +			dprintk(1, "%s: multi-planar buffer passed but "
> +				"planes array not provided\n", opname);
> +			return -EINVAL;
> +		}

This doesn't belong here. pplane is very much v4l2 specific and should be
tested there.

> +
> +		if (nplanes < vb->num_planes || nplanes > VB2_MAX_PLANES) {
> +			dprintk(1, "%s: incorrect planes array length, "
> +				"expected %d, got %d\n",
> +				opname, vb->num_planes, nplanes);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(vb2_verify_buffer);
> +
> +/**
> + * vb2_core_prepare_buf() - Pass ownership of a buffer from userspace to the kernel
> + * @q:		videobuf2 queue
> + * @index:	id number of the buffer
> + * @pb:		buffer structure passed from userspace to vidioc_prepare_buf
> + *		handler in driver
> + *
> + * Should be called from vidioc_prepare_buf ioctl handler of a driver.
> + * The passed buffer should have been verified.
> + * This function calls buf_prepare callback in the driver (if provided),
> + * in which driver-specific buffer initialization can be performed,
> + *
> + * The return values from this function are intended to be directly returned
> + * from vidioc_prepare_buf handler in driver.
> + */
> +int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
> +{
> +	struct vb2_buffer *vb;
> +	int ret;
> +
> +	vb = q->bufs[index];
> +	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
> +		dprintk(1, "invalid buffer state %d\n",
> +			vb->state);
> +		return -EINVAL;
> +	}
> +
> +	ret = __buf_prepare(vb, pb);
> +	if (!ret) {
> +		/* Fill buffer information for the userspace */
> +		call_bufop(q, fill_user_buffer, vb, pb);
> +
> +		dprintk(1, "prepare of buffer %d succeeded\n", vb->index);
> +	}
> +	return ret;
>  }
> +EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);
>  
>  /**
>   * vb2_start_streaming() - Attempt to start streaming.

Regards,

	Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Junghak Sung Sept. 14, 2015, 7:05 a.m. UTC | #2
On 09/11/2015 09:47 PM, Hans Verkuil wrote:
> Hi Junghak,
>
> Patch 7/8 helped a lot in reducing the size of this one. But it is still difficult
> to review so I would like to request one final (honest!) split for this patch:
>
> Move all the code that does not depend on the new buf_ops into a separate patch.
> So the new q->is_output and q->multiplanar field can be moved to that patch.
> But also the changes to functions like vb2_expbuf() or streamon/off where some
> checks are moved from core.c to v4l2.c can be done separately.
>
> All such pretty easy to review modifications should be put in a separate patch,
> leaving me with one remaining patch that I really need to study.
>
> I recommend that you wait until 4.3-rc1 is released and merged back in our tree
> since that will contain a number of vb2 changes (Jan Kara's work). So it makes
> sense to rebase on top of that first before doing more work on this.
>

I'll prepare to rebase on 4.3-rc1 and make it much easier to review.

> I did find a few things in this patch as well, see my comments below:
>
> On 09/09/2015 01:19 PM, Junghak Sung wrote:
>> Move v4l2-stuffs from videobuf2-core to videobuf2-v4l2. And make
>> wrappers that use the vb2_core_* functions.
>>
>> Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
>> Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
>> Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
>> Acked-by: Inki Dae <inki.dae@samsung.com>
>> ---
>>   drivers/media/v4l2-core/videobuf2-core.c     |  517 ++++++++++++++++----------
>>   drivers/media/v4l2-core/videobuf2-internal.h |   51 +--
>>   drivers/media/v4l2-core/videobuf2-v4l2.c     |  312 ++++++++++++----
>>   include/media/videobuf2-core.h               |   20 +-
>>   include/media/videobuf2-v4l2.h               |    3 +-
>>   5 files changed, 601 insertions(+), 302 deletions(-)
>>
>> diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
>> index 3e6ee0e..56d34f2 100644
>> --- a/drivers/media/v4l2-core/videobuf2-core.c
>> +++ b/drivers/media/v4l2-core/videobuf2-core.c
>
> <snip>
>
>> @@ -454,13 +426,34 @@ static bool __buffers_in_use(struct vb2_queue *q)
>>   {
>>   	unsigned int buffer;
>>   	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
>> -		if (__buffer_in_use(q, q->bufs[buffer]))
>> +		if (vb2_buffer_in_use(q, q->bufs[buffer]))
>>   			return true;
>>   	}
>>   	return false;
>>   }
>>
>>   /**
>> + * vb2_core_querybuf() - query video buffer information
>> + * @q:		videobuf queue
>> + * @index:	id number of the buffer
>> + * @pb:		buffer struct passed from userspace
>> + *
>> + * Should be called from vidioc_querybuf ioctl handler in driver.
>> + * The passed buffer should have been verified.
>> + * This function fills the relevant information for the userspace.
>> + *
>> + * The return values from this function are intended to be directly returned
>> + * from vidioc_querybuf handler in driver.
>> + */
>> +int vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
>> +{
>> +	call_bufop(q, fill_user_buffer, q->bufs[index], pb);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(vb2_core_querybuf);
>
> This should be a void function since it never returns an error.
>
> But do we need it at all? It really doesn't do anything that is core-specific.
> The querybuf ioctl is really pure V4L2 and has nothing to do with the vb2 core.
>

I think it would be better to keep this code, like other vb2_core 
functions. I do not want to call buf_ops callback function - i.e. 
full_user_buffer() - from the v4l2-side.
And return value is also needed because fill_user_buffer() can return 
error code.
But, this code should be modified like:

int vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
{
	return call_bufop(q, fill_user_buffer, q->bufs[index], pb);
}

>> +
>> +/**
>>    * __verify_userptr_ops() - verify that all memory operations required for
>>    * USERPTR queue type have been provided
>>    */
>> @@ -1182,52 +1174,27 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
>>   	call_void_vb_qop(vb, buf_queue, vb);
>>   }
>>
>> -int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
>> +static int __buf_prepare(struct vb2_buffer *vb, void *pb)
>>   {
>> -	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
>>   	struct vb2_queue *q = vb->vb2_queue;
>>   	int ret;
>>
>> -	ret = __verify_length(vb, b);
>> -	if (ret < 0) {
>> -		dprintk(1, "plane parameters verification failed: %d\n", ret);
>> -		return ret;
>> -	}
>> -	if (b->field == V4L2_FIELD_ALTERNATE && V4L2_TYPE_IS_OUTPUT(q->type)) {
>> -		/*
>> -		 * If the format's field is ALTERNATE, then the buffer's field
>> -		 * should be either TOP or BOTTOM, not ALTERNATE since that
>> -		 * makes no sense. The driver has to know whether the
>> -		 * buffer represents a top or a bottom field in order to
>> -		 * program any DMA correctly. Using ALTERNATE is wrong, since
>> -		 * that just says that it is either a top or a bottom field,
>> -		 * but not which of the two it is.
>> -		 */
>> -		dprintk(1, "the field is incorrectly set to ALTERNATE for an output buffer\n");
>> -		return -EINVAL;
>> -	}
>> -
>>   	if (q->error) {
>>   		dprintk(1, "fatal error occurred on queue\n");
>>   		return -EIO;
>>   	}
>>
>> -	vb->state = VB2_BUF_STATE_PREPARING;
>
> Hmmm, this moved to v4l2.c. Why? This still belongs here as far as I can tell.
> I suspect that was a copy-and-paste mistake.
>
Correct! I'll fix it.

>> -	vbuf->timestamp.tv_sec = 0;
>> -	vbuf->timestamp.tv_usec = 0;
>> -	vbuf->sequence = 0;
>> -
>>   	switch (q->memory) {
>>   	case VB2_MEMORY_MMAP:
>> -		ret = __qbuf_mmap(vb, b);
>> +		ret = __qbuf_mmap(vb, pb);
>>   		break;
>>   	case VB2_MEMORY_USERPTR:
>>   		down_read(&current->mm->mmap_sem);
>> -		ret = __qbuf_userptr(vb, b);
>> +		ret = __qbuf_userptr(vb, pb);
>>   		up_read(&current->mm->mmap_sem);
>>   		break;
>>   	case VB2_MEMORY_DMABUF:
>> -		ret = __qbuf_dmabuf(vb, b);
>> +		ret = __qbuf_dmabuf(vb, pb);
>>   		break;
>>   	default:
>>   		WARN(1, "Invalid queue type\n");
>> @@ -1241,32 +1208,94 @@ int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
>>   	return ret;
>>   }
>>
>> -int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
>> -				    const char *opname)
>> +/**
>> + * vb2_verify_buffer() - verify the buffer information passed from userspace
>> + */
>> +int vb2_verify_buffer(struct vb2_queue *q,
>> +			enum vb2_memory memory, unsigned int type,
>> +			unsigned int index, unsigned int nplanes,
>> +			void *pplane, const char *opname)
>>   {
>> -	if (b->type != q->type) {
>> +	if (type != q->type) {
>>   		dprintk(1, "%s: invalid buffer type\n", opname);
>>   		return -EINVAL;
>>   	}
>>
>> -	if (b->index >= q->num_buffers) {
>> +	if (index >= q->num_buffers) {
>>   		dprintk(1, "%s: buffer index out of range\n", opname);
>>   		return -EINVAL;
>>   	}
>>
>> -	if (q->bufs[b->index] == NULL) {
>> +	if (q->bufs[index] == NULL) {
>>   		/* Should never happen */
>>   		dprintk(1, "%s: buffer is NULL\n", opname);
>>   		return -EINVAL;
>>   	}
>>
>> -	if (b->memory != q->memory) {
>> +	if (memory != VB2_MEMORY_UNKNOWN && memory != q->memory) {
>>   		dprintk(1, "%s: invalid memory type\n", opname);
>>   		return -EINVAL;
>>   	}
>>
>> -	return __verify_planes_array(q->bufs[b->index], b);
>> +	if (q->is_multiplanar) {
>> +		struct vb2_buffer *vb = q->bufs[index];
>> +
>> +		/* Is memory for copying plane information present? */
>> +		if (NULL == pplane) {
>> +			dprintk(1, "%s: multi-planar buffer passed but "
>> +				"planes array not provided\n", opname);
>> +			return -EINVAL;
>> +		}
>
> This doesn't belong here. pplane is very much v4l2 specific and should be
> tested there.

Apparently, it should be checked on v4l2-side. I'll fix it.
Thank you.

Best regards,
Junghak

>
>> +
>> +		if (nplanes < vb->num_planes || nplanes > VB2_MAX_PLANES) {
>> +			dprintk(1, "%s: incorrect planes array length, "
>> +				"expected %d, got %d\n",
>> +				opname, vb->num_planes, nplanes);
>> +			return -EINVAL;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(vb2_verify_buffer);
>> +
>> +/**
>> + * vb2_core_prepare_buf() - Pass ownership of a buffer from userspace to the kernel
>> + * @q:		videobuf2 queue
>> + * @index:	id number of the buffer
>> + * @pb:		buffer structure passed from userspace to vidioc_prepare_buf
>> + *		handler in driver
>> + *
>> + * Should be called from vidioc_prepare_buf ioctl handler of a driver.
>> + * The passed buffer should have been verified.
>> + * This function calls buf_prepare callback in the driver (if provided),
>> + * in which driver-specific buffer initialization can be performed,
>> + *
>> + * The return values from this function are intended to be directly returned
>> + * from vidioc_prepare_buf handler in driver.
>> + */
>> +int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
>> +{
>> +	struct vb2_buffer *vb;
>> +	int ret;
>> +
>> +	vb = q->bufs[index];
>> +	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
>> +		dprintk(1, "invalid buffer state %d\n",
>> +			vb->state);
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = __buf_prepare(vb, pb);
>> +	if (!ret) {
>> +		/* Fill buffer information for the userspace */
>> +		call_bufop(q, fill_user_buffer, vb, pb);
>> +
>> +		dprintk(1, "prepare of buffer %d succeeded\n", vb->index);
>> +	}
>> +	return ret;
>>   }
>> +EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);
>>
>>   /**
>>    * vb2_start_streaming() - Attempt to start streaming.
>
> Regards,
>
> 	Hans
>
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index 3e6ee0e..56d34f2 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -24,20 +24,16 @@ 
 #include <linux/freezer.h>
 #include <linux/kthread.h>
 
-#include <media/v4l2-dev.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-common.h>
-#include <media/videobuf2-v4l2.h>
-
 #include <trace/events/v4l2.h>
 
+#include <media/videobuf2-core.h>
 #include "videobuf2-internal.h"
 
 int vb2_debug;
 EXPORT_SYMBOL_GPL(vb2_debug);
 module_param_named(debug, vb2_debug, int, 0644);
 
+static void __vb2_queue_cancel(struct vb2_queue *q);
 static void __enqueue_in_driver(struct vb2_buffer *vb);
 
 /**
@@ -47,7 +43,7 @@  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;
+			q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
 	void *mem_priv;
 	int plane;
 
@@ -289,7 +285,7 @@  static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
  * related information, if no buffers are left return the queue to an
  * uninitialized state. Might be called even if the queue has already been freed.
  */
-int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
+static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
 {
 	unsigned int buffer;
 
@@ -401,35 +397,10 @@  int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
 }
 
 /**
- * __verify_planes_array() - verify that the planes array passed in struct
- * v4l2_buffer from userspace can be safely used
- */
-int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b)
-{
-	if (!V4L2_TYPE_IS_MULTIPLANAR(b->type))
-		return 0;
-
-	/* Is memory for copying plane information present? */
-	if (NULL == b->m.planes) {
-		dprintk(1, "multi-planar buffer passed but "
-			   "planes array not provided\n");
-		return -EINVAL;
-	}
-
-	if (b->length < vb->num_planes || b->length > VB2_MAX_PLANES) {
-		dprintk(1, "incorrect planes array length, "
-			   "expected %d, got %d\n", vb->num_planes, b->length);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/**
- * __buffer_in_use() - return true if the buffer is in use and
+ * vb2_buffer_in_use() - return true if the buffer is in use and
  * the queue cannot be freed (by the means of REQBUFS(0)) call
  */
-bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
+bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
 {
 	unsigned int plane;
 	for (plane = 0; plane < vb->num_planes; ++plane) {
@@ -445,6 +416,7 @@  bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
 	}
 	return false;
 }
+EXPORT_SYMBOL_GPL(vb2_buffer_in_use);
 
 /**
  * __buffers_in_use() - return true if any buffers on the queue are in use and
@@ -454,13 +426,34 @@  static bool __buffers_in_use(struct vb2_queue *q)
 {
 	unsigned int buffer;
 	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
-		if (__buffer_in_use(q, q->bufs[buffer]))
+		if (vb2_buffer_in_use(q, q->bufs[buffer]))
 			return true;
 	}
 	return false;
 }
 
 /**
+ * vb2_core_querybuf() - query video buffer information
+ * @q:		videobuf queue
+ * @index:	id number of the buffer
+ * @pb:		buffer struct passed from userspace
+ *
+ * Should be called from vidioc_querybuf ioctl handler in driver.
+ * The passed buffer should have been verified.
+ * This function fills the relevant information for the userspace.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_querybuf handler in driver.
+ */
+int vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
+{
+	call_bufop(q, fill_user_buffer, q->bufs[index], pb);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_core_querybuf);
+
+/**
  * __verify_userptr_ops() - verify that all memory operations required for
  * USERPTR queue type have been provided
  */
@@ -501,10 +494,10 @@  static int __verify_dmabuf_ops(struct vb2_queue *q)
 }
 
 /**
- * __verify_memory_type() - Check whether the memory type and buffer type
+ * vb2_verify_memory_type() - Check whether the memory type and buffer type
  * passed to a buffer operation are compatible with the queue.
  */
-int __verify_memory_type(struct vb2_queue *q,
+int vb2_verify_memory_type(struct vb2_queue *q,
 		enum vb2_memory memory, unsigned int type)
 {
 	if (memory != VB2_MEMORY_MMAP && memory != VB2_MEMORY_USERPTR &&
@@ -537,22 +530,15 @@  int __verify_memory_type(struct vb2_queue *q,
 		return -EINVAL;
 	}
 
-	/*
-	 * Place the busy tests at the end: -EBUSY can be ignored when
-	 * create_bufs is called with count == 0, but count == 0 should still
-	 * do the memory and type validation.
-	 */
-	if (vb2_fileio_is_active(q)) {
-		dprintk(1, "file io in progress\n");
-		return -EBUSY;
-	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(vb2_verify_memory_type);
 
 /**
- * __reqbufs() - Initiate streaming
+ * vb2_core_reqbufs() - Initiate streaming
  * @q:		videobuf2 queue
- * @req:	struct passed from userspace to vidioc_reqbufs handler in driver
+ * @memory: memory type
+ * @count: requested buffer count
  *
  * Should be called from vidioc_reqbufs ioctl handler of a driver.
  * This function:
@@ -572,7 +558,8 @@  int __verify_memory_type(struct vb2_queue *q,
  * The return values from this function are intended to be directly returned
  * from vidioc_reqbufs handler in driver.
  */
-int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
+int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
+		unsigned int *count)
 {
 	unsigned int num_buffers, allocated_buffers, num_planes = 0;
 	int ret;
@@ -582,7 +569,7 @@  int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 		return -EBUSY;
 	}
 
-	if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
+	if (*count == 0 || q->num_buffers != 0 || q->memory != memory) {
 		/*
 		 * We already have buffers allocated, so first check if they
 		 * are not in use and can be freed.
@@ -609,18 +596,18 @@  int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 		 * In case of REQBUFS(0) return immediately without calling
 		 * driver's queue_setup() callback and allocating resources.
 		 */
-		if (req->count == 0)
+		if (*count == 0)
 			return 0;
 	}
 
 	/*
 	 * Make sure the requested values and current defaults are sane.
 	 */
-	num_buffers = min_t(unsigned int, req->count, VB2_MAX_FRAME);
+	num_buffers = min_t(unsigned int, *count, VB2_MAX_FRAME);
 	num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed);
 	memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
 	memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
-	q->memory = req->memory;
+	q->memory = memory;
 
 	/*
 	 * Ask the driver how many buffers and planes per buffer it requires.
@@ -632,7 +619,8 @@  int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 		return ret;
 
 	/* Finally, allocate buffers and video memory */
-	allocated_buffers = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes);
+	allocated_buffers =
+		__vb2_queue_alloc(q, memory, num_buffers, num_planes);
 	if (allocated_buffers == 0) {
 		dprintk(1, "memory allocation failed\n");
 		return -ENOMEM;
@@ -681,17 +669,19 @@  int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 	 * Return the number of successfully allocated buffers
 	 * to the userspace.
 	 */
-	req->count = allocated_buffers;
-	q->waiting_for_buffers = !V4L2_TYPE_IS_OUTPUT(q->type);
+	*count = allocated_buffers;
+	q->waiting_for_buffers = !q->is_output;
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(vb2_core_reqbufs);
 
 /**
- * __create_bufs() - Allocate buffers and any required auxiliary structs
+ * vb2_core_create_bufs() - Allocate buffers and any required auxiliary structs
  * @q:		videobuf2 queue
- * @create:	creation parameters, passed from userspace to vidioc_create_bufs
- *		handler in driver
+ * @memory: memory type
+ * @count: requested buffer count
+ * @parg: parameter passed to device driver
  *
  * Should be called from vidioc_create_bufs ioctl handler of a driver.
  * This function:
@@ -702,7 +692,8 @@  int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
  * The return values from this function are intended to be directly returned
  * from vidioc_create_bufs handler in driver.
  */
-int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
+int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
+		unsigned int *count, void *parg)
 {
 	unsigned int num_planes = 0, num_buffers, allocated_buffers;
 	int ret;
@@ -715,23 +706,23 @@  int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
 	if (!q->num_buffers) {
 		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);
+		q->memory = memory;
+		q->waiting_for_buffers = !q->is_output;
 	}
 
-	num_buffers = min(create->count, VB2_MAX_FRAME - q->num_buffers);
+	num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers);
 
 	/*
 	 * Ask the driver, whether the requested number of buffers, planes per
 	 * buffer and their sizes are acceptable
 	 */
-	ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
-		       &num_planes, q->plane_sizes, q->alloc_ctx);
+	ret = call_qop(q, queue_setup, q, parg, &num_buffers,
+			&num_planes, q->plane_sizes, q->alloc_ctx);
 	if (ret)
 		return ret;
 
 	/* Finally, allocate buffers and video memory */
-	allocated_buffers = __vb2_queue_alloc(q, create->memory, num_buffers,
+	allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers,
 				num_planes);
 	if (allocated_buffers == 0) {
 		dprintk(1, "memory allocation failed\n");
@@ -748,8 +739,8 @@  int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
 		 * q->num_buffers contains the total number of buffers, that the
 		 * queue driver has set up
 		 */
-		ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
-			       &num_planes, q->plane_sizes, q->alloc_ctx);
+		ret = call_qop(q, queue_setup, q, parg, &num_buffers,
+				&num_planes, q->plane_sizes, q->alloc_ctx);
 
 		if (!ret && allocated_buffers < num_buffers)
 			ret = -ENOMEM;
@@ -778,10 +769,11 @@  int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
 	 * Return the number of successfully allocated buffers
 	 * to the userspace.
 	 */
-	create->count = allocated_buffers;
+	*count = allocated_buffers;
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(vb2_core_create_bufs);
 
 /**
  * vb2_plane_vaddr() - Return a kernel virtual address of a given plane
@@ -917,16 +909,16 @@  EXPORT_SYMBOL_GPL(vb2_discard_done);
 /**
  * __qbuf_mmap() - handle qbuf of an MMAP buffer
  */
-static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+static int __qbuf_mmap(struct vb2_buffer *vb, void *pb)
 {
-	__fill_vb2_buffer(vb, b, vb->planes);
+	call_bufop(vb->vb2_queue, fill_vb2_buffer, vb, pb, vb->planes);
 	return call_vb_qop(vb, buf_prepare, vb);
 }
 
 /**
  * __qbuf_userptr() - handle qbuf of a USERPTR buffer
  */
-static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+static int __qbuf_userptr(struct vb2_buffer *vb, void *pb)
 {
 	struct vb2_plane planes[VB2_MAX_PLANES];
 	struct vb2_queue *q = vb->vb2_queue;
@@ -934,12 +926,12 @@  static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 	unsigned int plane;
 	int ret;
 	enum dma_data_direction dma_dir =
-		V4L2_TYPE_IS_OUTPUT(q->type) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+		q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
 	bool reacquired = vb->planes[0].mem_priv == NULL;
 
 	memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
 	/* Copy relevant information provided by the userspace */
-	__fill_vb2_buffer(vb, b, planes);
+	call_bufop(vb->vb2_queue, fill_vb2_buffer, vb, pb, planes);
 
 	for (plane = 0; plane < vb->num_planes; ++plane) {
 		/* Skip the plane if already verified */
@@ -1038,7 +1030,7 @@  err:
 /**
  * __qbuf_dmabuf() - handle qbuf of a DMABUF buffer
  */
-static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+static int __qbuf_dmabuf(struct vb2_buffer *vb, void *pb)
 {
 	struct vb2_plane planes[VB2_MAX_PLANES];
 	struct vb2_queue *q = vb->vb2_queue;
@@ -1046,12 +1038,12 @@  static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 	unsigned int plane;
 	int ret;
 	enum dma_data_direction dma_dir =
-		V4L2_TYPE_IS_OUTPUT(q->type) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+		q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
 	bool reacquired = vb->planes[0].mem_priv == NULL;
 
 	memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
 	/* Copy relevant information provided by the userspace */
-	__fill_vb2_buffer(vb, b, planes);
+	call_bufop(vb->vb2_queue, fill_vb2_buffer, vb, pb, planes);
 
 	for (plane = 0; plane < vb->num_planes; ++plane) {
 		struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd);
@@ -1182,52 +1174,27 @@  static void __enqueue_in_driver(struct vb2_buffer *vb)
 	call_void_vb_qop(vb, buf_queue, vb);
 }
 
-int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+static int __buf_prepare(struct vb2_buffer *vb, void *pb)
 {
-	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	struct vb2_queue *q = vb->vb2_queue;
 	int ret;
 
-	ret = __verify_length(vb, b);
-	if (ret < 0) {
-		dprintk(1, "plane parameters verification failed: %d\n", ret);
-		return ret;
-	}
-	if (b->field == V4L2_FIELD_ALTERNATE && V4L2_TYPE_IS_OUTPUT(q->type)) {
-		/*
-		 * If the format's field is ALTERNATE, then the buffer's field
-		 * should be either TOP or BOTTOM, not ALTERNATE since that
-		 * makes no sense. The driver has to know whether the
-		 * buffer represents a top or a bottom field in order to
-		 * program any DMA correctly. Using ALTERNATE is wrong, since
-		 * that just says that it is either a top or a bottom field,
-		 * but not which of the two it is.
-		 */
-		dprintk(1, "the field is incorrectly set to ALTERNATE for an output buffer\n");
-		return -EINVAL;
-	}
-
 	if (q->error) {
 		dprintk(1, "fatal error occurred on queue\n");
 		return -EIO;
 	}
 
-	vb->state = VB2_BUF_STATE_PREPARING;
-	vbuf->timestamp.tv_sec = 0;
-	vbuf->timestamp.tv_usec = 0;
-	vbuf->sequence = 0;
-
 	switch (q->memory) {
 	case VB2_MEMORY_MMAP:
-		ret = __qbuf_mmap(vb, b);
+		ret = __qbuf_mmap(vb, pb);
 		break;
 	case VB2_MEMORY_USERPTR:
 		down_read(&current->mm->mmap_sem);
-		ret = __qbuf_userptr(vb, b);
+		ret = __qbuf_userptr(vb, pb);
 		up_read(&current->mm->mmap_sem);
 		break;
 	case VB2_MEMORY_DMABUF:
-		ret = __qbuf_dmabuf(vb, b);
+		ret = __qbuf_dmabuf(vb, pb);
 		break;
 	default:
 		WARN(1, "Invalid queue type\n");
@@ -1241,32 +1208,94 @@  int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 	return ret;
 }
 
-int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
-				    const char *opname)
+/**
+ * vb2_verify_buffer() - verify the buffer information passed from userspace
+ */
+int vb2_verify_buffer(struct vb2_queue *q,
+			enum vb2_memory memory, unsigned int type,
+			unsigned int index, unsigned int nplanes,
+			void *pplane, const char *opname)
 {
-	if (b->type != q->type) {
+	if (type != q->type) {
 		dprintk(1, "%s: invalid buffer type\n", opname);
 		return -EINVAL;
 	}
 
-	if (b->index >= q->num_buffers) {
+	if (index >= q->num_buffers) {
 		dprintk(1, "%s: buffer index out of range\n", opname);
 		return -EINVAL;
 	}
 
-	if (q->bufs[b->index] == NULL) {
+	if (q->bufs[index] == NULL) {
 		/* Should never happen */
 		dprintk(1, "%s: buffer is NULL\n", opname);
 		return -EINVAL;
 	}
 
-	if (b->memory != q->memory) {
+	if (memory != VB2_MEMORY_UNKNOWN && memory != q->memory) {
 		dprintk(1, "%s: invalid memory type\n", opname);
 		return -EINVAL;
 	}
 
-	return __verify_planes_array(q->bufs[b->index], b);
+	if (q->is_multiplanar) {
+		struct vb2_buffer *vb = q->bufs[index];
+
+		/* Is memory for copying plane information present? */
+		if (NULL == pplane) {
+			dprintk(1, "%s: multi-planar buffer passed but "
+				"planes array not provided\n", opname);
+			return -EINVAL;
+		}
+
+		if (nplanes < vb->num_planes || nplanes > VB2_MAX_PLANES) {
+			dprintk(1, "%s: incorrect planes array length, "
+				"expected %d, got %d\n",
+				opname, vb->num_planes, nplanes);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_verify_buffer);
+
+/**
+ * vb2_core_prepare_buf() - Pass ownership of a buffer from userspace to the kernel
+ * @q:		videobuf2 queue
+ * @index:	id number of the buffer
+ * @pb:		buffer structure passed from userspace to vidioc_prepare_buf
+ *		handler in driver
+ *
+ * Should be called from vidioc_prepare_buf ioctl handler of a driver.
+ * The passed buffer should have been verified.
+ * This function calls buf_prepare callback in the driver (if provided),
+ * in which driver-specific buffer initialization can be performed,
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_prepare_buf handler in driver.
+ */
+int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
+{
+	struct vb2_buffer *vb;
+	int ret;
+
+	vb = q->bufs[index];
+	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+		dprintk(1, "invalid buffer state %d\n",
+			vb->state);
+		return -EINVAL;
+	}
+
+	ret = __buf_prepare(vb, pb);
+	if (!ret) {
+		/* Fill buffer information for the userspace */
+		call_bufop(q, fill_user_buffer, vb, pb);
+
+		dprintk(1, "prepare of buffer %d succeeded\n", vb->index);
+	}
+	return ret;
 }
+EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);
 
 /**
  * vb2_start_streaming() - Attempt to start streaming.
@@ -1331,21 +1360,34 @@  static int vb2_start_streaming(struct vb2_queue *q)
 	return ret;
 }
 
-int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+/**
+ * vb2_qbuf() - Queue a buffer from userspace
+ * @q:		videobuf2 queue
+ * @index:	id number of the buffer
+ * @pb:		buffer structure passed from userspace to vidioc_qbuf handler
+ *		in driver
+ *
+ * Should be called from vidioc_qbuf ioctl handler of a driver.
+ * The passed buffer should have been verified.
+ * This function:
+ * 1) if necessary, calls buf_prepare callback in the driver (if provided), in
+ *    which driver-specific buffer initialization can be performed,
+ * 2) if streaming is on, queues the buffer in driver by the means of buf_queue
+ *    callback for processing.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_qbuf handler in driver.
+ */
+int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
 {
-	int ret = vb2_queue_or_prepare_buf(q, b, "qbuf");
+	int ret;
 	struct vb2_buffer *vb;
-	struct vb2_v4l2_buffer *vbuf;
-
-	if (ret)
-		return ret;
 
-	vb = q->bufs[b->index];
-	vbuf = to_vb2_v4l2_buffer(vb);
+	vb = q->bufs[index];
 
 	switch (vb->state) {
 	case VB2_BUF_STATE_DEQUEUED:
-		ret = __buf_prepare(vb, b);
+		ret = __buf_prepare(vb, pb);
 		if (ret)
 			return ret;
 		break;
@@ -1367,18 +1409,13 @@  int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 	q->queued_count++;
 	q->waiting_for_buffers = false;
 	vb->state = VB2_BUF_STATE_QUEUED;
-	if (V4L2_TYPE_IS_OUTPUT(q->type)) {
-		/*
-		 * For output buffers copy the timestamp if needed,
-		 * and the timecode field and flag if needed.
-		 */
-		if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
-		    V4L2_BUF_FLAG_TIMESTAMP_COPY)
-			vbuf->timestamp = b->timestamp;
-		vbuf->flags |= b->flags & V4L2_BUF_FLAG_TIMECODE;
-		if (b->flags & V4L2_BUF_FLAG_TIMECODE)
-			vbuf->timecode = b->timecode;
-	}
+
+	/*
+	 * For output buffers copy the timestamp if needed,
+	 * and the timecode field and flag if needed.
+	 */
+	if (q->is_output)
+		call_bufop(q, fill_vb2_timestamp, vb, pb);
 
 	trace_vb2_qbuf(q, vb);
 
@@ -1390,7 +1427,7 @@  int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 		__enqueue_in_driver(vb);
 
 	/* Fill buffer information for the userspace */
-	__fill_v4l2_buffer(vb, b);
+	call_bufop(q, fill_user_buffer, vb, pb);
 
 	/*
 	 * If streamon has been called, and we haven't yet called
@@ -1408,6 +1445,7 @@  int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 	dprintk(1, "qbuf of buffer %d succeeded\n", vb->index);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(vb2_core_qbuf);
 
 /**
  * __vb2_wait_for_done_vb() - wait for a buffer to become available
@@ -1491,7 +1529,7 @@  static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
  * Will sleep if required for nonblocking == false.
  */
 static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
-				struct v4l2_buffer *b, int nonblocking)
+				int nonblocking)
 {
 	unsigned long flags;
 	int ret;
@@ -1512,10 +1550,11 @@  static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
 	/*
 	 * Only remove the buffer from done_list if v4l2_buffer can handle all
 	 * the planes.
+	 * ret = __verify_planes_array(*vb, pb);
+	 * But, actually that's unnecessary since this is checked already
+	 * before the buffer is queued/prepared. So it can never fails
 	 */
-	ret = __verify_planes_array(*vb, b);
-	if (!ret)
-		list_del(&(*vb)->done_entry);
+	list_del(&(*vb)->done_entry);
 	spin_unlock_irqrestore(&q->done_lock, flags);
 
 	return ret;
@@ -1567,18 +1606,33 @@  static void __vb2_dqbuf(struct vb2_buffer *vb)
 		}
 }
 
-int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
-		bool nonblocking)
+/**
+ * vb2_dqbuf() - Dequeue a buffer to the userspace
+ * @q:		videobuf2 queue
+ * @pb:		buffer structure passed from userspace to vidioc_dqbuf handler
+ *		in driver
+ * @nonblocking: if true, this call will not sleep waiting for a buffer if no
+ *		 buffers ready for dequeuing are present. Normally the driver
+ *		 would be passing (file->f_flags & O_NONBLOCK) here
+ *
+ * Should be called from vidioc_dqbuf ioctl handler of a driver.
+ * The passed buffer should have been verified.
+ * This function:
+ * 1) calls buf_finish callback in the driver (if provided), in which
+ *    driver can perform any additional operations that may be required before
+ *    returning the buffer to userspace, such as cache sync,
+ * 2) the buffer struct members are filled with relevant information for
+ *    the userspace.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_dqbuf handler in driver.
+ */
+int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking)
 {
 	struct vb2_buffer *vb = NULL;
-	struct vb2_v4l2_buffer *vbuf = NULL;
 	int ret;
 
-	if (b->type != q->type) {
-		dprintk(1, "invalid buffer type\n");
-		return -EINVAL;
-	}
-	ret = __vb2_get_done_vb(q, &vb, b, nonblocking);
+	ret = __vb2_get_done_vb(q, &vb, nonblocking);
 	if (ret < 0)
 		return ret;
 
@@ -1597,16 +1651,15 @@  int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
 	call_void_vb_qop(vb, buf_finish, vb);
 
 	/* Fill buffer information for the userspace */
-	__fill_v4l2_buffer(vb, b);
+	call_bufop(q, fill_user_buffer, vb, pb);
 	/* Remove from videobuf queue */
 	list_del(&vb->queued_entry);
 	q->queued_count--;
 
 	trace_vb2_dqbuf(q, vb);
 
-	vbuf = to_vb2_v4l2_buffer(vb);
-	if (!V4L2_TYPE_IS_OUTPUT(q->type) &&
-			vbuf->flags & V4L2_BUF_FLAG_LAST)
+	if (!q->is_output &&
+			call_bufop(q, is_last, vb))
 		q->last_buffer_dequeued = true;
 	/* go back to dequeued state */
 	__vb2_dqbuf(vb);
@@ -1616,6 +1669,7 @@  int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(vb2_core_dqbuf);
 
 /**
  * __vb2_queue_cancel() - cancel and stop (pause) streaming
@@ -1623,7 +1677,7 @@  int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
  * Removes all queued buffers from driver's queue and all buffers queued by
  * userspace from videobuf's queue. Returns to state after reqbufs.
  */
-void __vb2_queue_cancel(struct vb2_queue *q)
+static void __vb2_queue_cancel(struct vb2_queue *q)
 {
 	unsigned int i;
 
@@ -1685,15 +1739,22 @@  void __vb2_queue_cancel(struct vb2_queue *q)
 	}
 }
 
-int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
+/**
+ * vb2_streamon - start streaming
+ * @q:		videobuf2 queue
+ *
+ * Should be called from vidioc_streamon handler of a driver.
+ * This function :
+ * 1) verifies current state
+ * 2) passes any previously queued buffers to the driver and starts streaming
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_streamon handler in the driver.
+ */
+int vb2_core_streamon(struct vb2_queue *q)
 {
 	int ret;
 
-	if (type != q->type) {
-		dprintk(1, "invalid stream type\n");
-		return -EINVAL;
-	}
-
 	if (q->streaming) {
 		dprintk(3, "already streaming\n");
 		return 0;
@@ -1727,6 +1788,7 @@  int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
 	dprintk(3, "successful\n");
 	return 0;
 }
+EXPORT_SYMBOL_GPL(vb2_core_streamon);
 
 /**
  * vb2_queue_error() - signal a fatal error on the queue
@@ -1749,13 +1811,22 @@  void vb2_queue_error(struct vb2_queue *q)
 }
 EXPORT_SYMBOL_GPL(vb2_queue_error);
 
-int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
+/**
+ * vb2_streamoff - stop streaming
+ * @q:		videobuf2 queue
+ *
+ * Should be called from vidioc_streamoff handler of a driver.
+ * This function:
+ * 1) verifies current state,
+ * 2) stop streaming and dequeues any queued buffers, including those previously
+ *    passed to the driver (after waiting for the driver to finish).
+ *
+ * This call can be used for pausing playback.
+ * The return values from this function are intended to be directly returned
+ * from vidioc_streamoff handler in the driver
+ */
+int vb2_core_streamoff(struct vb2_queue *q)
 {
-	if (type != q->type) {
-		dprintk(1, "invalid stream type\n");
-		return -EINVAL;
-	}
-
 	/*
 	 * Cancel will pause streaming and remove all buffers from the driver
 	 * and videobuf, effectively returning control over them to userspace.
@@ -1766,12 +1837,13 @@  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);
+	q->waiting_for_buffers = !q->is_output;
 	q->last_buffer_dequeued = false;
 
 	dprintk(3, "successful\n");
 	return 0;
 }
+EXPORT_SYMBOL_GPL(vb2_core_streamoff);
 
 /**
  * __find_plane_by_offset() - find plane associated with the given offset off
@@ -1803,15 +1875,20 @@  static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
 }
 
 /**
- * vb2_expbuf() - Export a buffer as a file descriptor
+ * vb2_core_expbuf() - Export a buffer as a file descriptor
  * @q:		videobuf2 queue
- * @eb:		export buffer structure passed from userspace to vidioc_expbuf
- *		handler in driver
+ * @fd:		file descriptor associated with DMABUF (set by driver) *
+ * @type:	buffer type
+ * @index:	id number of the buffer
+ * @plane:	index of the plane to be exported, 0 for single plane queues
+ * @flags:	flags for newly created file, currently only O_CLOEXEC is
+ *		supported, refer to manual of open syscall for more details
  *
  * The return values from this function are intended to be directly returned
  * from vidioc_expbuf handler in driver.
  */
-int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb)
+int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
+		unsigned int index, unsigned int plane, unsigned int flags)
 {
 	struct vb2_buffer *vb = NULL;
 	struct vb2_plane *vb_plane;
@@ -1828,60 +1905,56 @@  int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb)
 		return -EINVAL;
 	}
 
-	if (eb->flags & ~(O_CLOEXEC | O_ACCMODE)) {
+	if (flags & ~(O_CLOEXEC | O_ACCMODE)) {
 		dprintk(1, "queue does support only O_CLOEXEC and access mode flags\n");
 		return -EINVAL;
 	}
 
-	if (eb->type != q->type) {
+	if (type != q->type) {
 		dprintk(1, "invalid buffer type\n");
 		return -EINVAL;
 	}
 
-	if (eb->index >= q->num_buffers) {
+	if (index >= q->num_buffers) {
 		dprintk(1, "buffer index out of range\n");
 		return -EINVAL;
 	}
 
-	vb = q->bufs[eb->index];
+	vb = q->bufs[index];
 
-	if (eb->plane >= vb->num_planes) {
+	if (plane >= vb->num_planes) {
 		dprintk(1, "buffer plane out of range\n");
 		return -EINVAL;
 	}
 
-	if (vb2_fileio_is_active(q)) {
-		dprintk(1, "expbuf: file io in progress\n");
-		return -EBUSY;
-	}
+	vb_plane = &vb->planes[plane];
 
-	vb_plane = &vb->planes[eb->plane];
-
-	dbuf = call_ptr_memop(vb, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE);
+	dbuf = call_ptr_memop(vb, get_dmabuf, vb_plane->mem_priv,
+				flags & O_ACCMODE);
 	if (IS_ERR_OR_NULL(dbuf)) {
 		dprintk(1, "failed to export buffer %d, plane %d\n",
-			eb->index, eb->plane);
+			index, plane);
 		return -EINVAL;
 	}
 
-	ret = dma_buf_fd(dbuf, eb->flags & ~O_ACCMODE);
+	ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE);
 	if (ret < 0) {
 		dprintk(3, "buffer %d, plane %d failed to export (%d)\n",
-			eb->index, eb->plane, ret);
+			index, plane, ret);
 		dma_buf_put(dbuf);
 		return ret;
 	}
 
 	dprintk(3, "buffer %d, plane %d exported as %d descriptor\n",
-		eb->index, eb->plane, ret);
-	eb->fd = ret;
+		index, plane, ret);
+	*fd = ret;
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(vb2_expbuf);
+EXPORT_SYMBOL_GPL(vb2_core_expbuf);
 
 /**
- * vb2_mmap() - map video buffers into application address space
+ * vb2_core_mmap() - map video buffers into application address space
  * @q:		videobuf2 queue
  * @vma:	vma passed to the mmap file operation handler in the driver
  *
@@ -1899,7 +1972,7 @@  EXPORT_SYMBOL_GPL(vb2_expbuf);
  * The return values from this function are intended to be directly returned
  * from the mmap handler in driver.
  */
-int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
+int vb2_core_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
 {
 	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
 	struct vb2_buffer *vb;
@@ -1919,7 +1992,7 @@  int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
 		dprintk(1, "invalid vma flags, VM_SHARED needed\n");
 		return -EINVAL;
 	}
-	if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+	if (q->is_output) {
 		if (!(vma->vm_flags & VM_WRITE)) {
 			dprintk(1, "invalid vma flags, VM_WRITE needed\n");
 			return -EINVAL;
@@ -1930,10 +2003,6 @@  int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
 			return -EINVAL;
 		}
 	}
-	if (vb2_fileio_is_active(q)) {
-		dprintk(1, "mmap: file io in progress\n");
-		return -EBUSY;
-	}
 
 	/*
 	 * Find the plane corresponding to the offset passed by userspace.
@@ -1965,7 +2034,7 @@  int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
 	dprintk(3, "buffer %d, plane %d successfully mapped\n", buffer, plane);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(vb2_mmap);
+EXPORT_SYMBOL_GPL(vb2_core_mmap);
 
 #ifndef CONFIG_MMU
 unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
@@ -2000,6 +2069,62 @@  unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
 EXPORT_SYMBOL_GPL(vb2_get_unmapped_area);
 #endif
 
+/**
+ * vb2_core_queue_init() - initialize a videobuf2 queue
+ * @q:		videobuf2 queue; this structure should be allocated in driver
+ *
+ * The vb2_queue structure should be allocated by the driver. The driver is
+ * responsible of clearing it's content and setting initial values for some
+ * required entries before calling this function.
+ * q->ops, q->mem_ops, q->type and q->io_modes are mandatory. Please refer
+ * to the struct vb2_queue description in include/media/videobuf2-core.h
+ * for more information.
+ */
+int vb2_core_queue_init(struct vb2_queue *q)
+{
+	/*
+	 * Sanity check
+	 */
+	if (WARN_ON(!q)				||
+		WARN_ON(!q->ops)		||
+		WARN_ON(!q->mem_ops)		||
+		WARN_ON(!q->buf_ops)		||
+		WARN_ON(!q->type)		||
+		WARN_ON(!q->io_modes)		||
+		WARN_ON(!q->ops->queue_setup)	||
+		WARN_ON(!q->ops->buf_queue))
+		return -EINVAL;
+
+	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)
+		q->buf_struct_size = sizeof(struct vb2_buffer);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_core_queue_init);
+
+/**
+ * vb2_core_queue_release() - stop streaming, release the queue and free memory
+ * @q:		videobuf2 queue
+ *
+ * This function stops streaming and performs necessary clean ups, including
+ * freeing video buffer memory. The driver is responsible for freeing
+ * the vb2_queue structure itself.
+ */
+void vb2_core_queue_release(struct vb2_queue *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_core_queue_release);
+
 MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
 MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/v4l2-core/videobuf2-internal.h b/drivers/media/v4l2-core/videobuf2-internal.h
index bf2339e..edde353 100644
--- a/drivers/media/v4l2-core/videobuf2-internal.h
+++ b/drivers/media/v4l2-core/videobuf2-internal.h
@@ -147,27 +147,36 @@  extern int vb2_debug;
 
 #endif
 
-bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb);
-int __verify_memory_type(struct vb2_queue *q,
+#define call_bufop(q, op, args...)					\
+({									\
+	int ret = 0;							\
+	if (q && q->buf_ops && q->buf_ops->op)				\
+		ret = q->buf_ops->op(args);				\
+	ret;								\
+})
+
+bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb);
+int vb2_verify_memory_type(struct vb2_queue *q,
 		enum vb2_memory memory, unsigned int type);
-int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req);
-int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create);
-int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b);
-int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b);
-int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b);
-void __vb2_queue_cancel(struct vb2_queue *q);
-int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers);
-void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b);
-void __fill_vb2_buffer(struct vb2_buffer *vb,
-		const struct v4l2_buffer *b, struct vb2_plane *planes);
-int __vb2_cleanup_fileio(struct vb2_queue *q);
-
-int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
-				    const char *opname);
-int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
-int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
-		bool nonblocking);
-int vb2_internal_streamon(struct vb2_queue *q, unsigned int type);
-int vb2_internal_streamoff(struct vb2_queue *q, unsigned int type);
+int vb2_verify_buffer(struct vb2_queue *q,
+			enum vb2_memory memory, unsigned int type,
+			unsigned int index, unsigned int nplanes,
+			void *pplane, const char *opname);
+int vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb);
+int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
+		unsigned int *count);
+int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
+		unsigned int *count, void *parg);
+int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb);
+int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb);
+int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblock);
+int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
+		unsigned int index, unsigned int plane, unsigned int flags);
+int vb2_core_streamon(struct vb2_queue *q);
+int vb2_core_streamoff(struct vb2_queue *q);
+int vb2_core_mmap(struct vb2_queue *q, struct vm_area_struct *vma);
+
+int __must_check vb2_core_queue_init(struct vb2_queue *q);
+void vb2_core_queue_release(struct vb2_queue *q);
 
 #endif /* _MEDIA_VIDEOBUF2_INTERNAL_H */
diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index 1a0526c..8690b91 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -102,8 +102,9 @@  static void vb2_warn_zero_bytesused(struct vb2_buffer *vb)
  * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
  * returned to userspace
  */
-void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
+static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 {
+	struct v4l2_buffer *b = pb;
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	struct vb2_queue *q = vb->vb2_queue;
 	unsigned int plane;
@@ -193,20 +194,34 @@  void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
 		break;
 	}
 
-	if (__buffer_in_use(q, vb))
+	if (vb2_buffer_in_use(q, vb))
 		b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+	return 0;
 }
 
 /**
  * __fill_vb2_buffer() - fill a vb2_buffer with information provided in a
- * v4l2_buffer by the userspace. The caller has already verified that struct
+ * v4l2_buffer by the userspace. It also verifies that struct
  * v4l2_buffer has a valid number of planes.
  */
-void __fill_vb2_buffer(struct vb2_buffer *vb,
-		const struct v4l2_buffer *b, struct vb2_plane *planes)
+static int __fill_vb2_buffer(struct vb2_buffer *vb,
+		void *pb, struct vb2_plane *planes)
 {
+	struct v4l2_buffer *b = pb;
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	unsigned int plane;
+	int ret;
+
+	ret = __verify_length(vb, b);
+	if (ret < 0) {
+		dprintk(1, "plane parameters verification failed: %d\n", ret);
+		return ret;
+	}
+	vb->state = VB2_BUF_STATE_PREPARING;
+	vbuf->timestamp.tv_sec = 0;
+	vbuf->timestamp.tv_usec = 0;
+	vbuf->sequence = 0;
 
 	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
 		if (b->memory == V4L2_MEMORY_USERPTR) {
@@ -323,8 +338,44 @@  void __fill_vb2_buffer(struct vb2_buffer *vb,
 		/* Zero any output buffer flags as this is a capture buffer */
 		vbuf->flags &= ~V4L2_BUFFER_OUT_FLAGS;
 	}
+
+	return 0;
+}
+
+static int __fill_vb2_timestamp(struct vb2_buffer *vb, void *pb)
+{
+	struct v4l2_buffer *b = pb;
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct vb2_queue *q = vb->vb2_queue;
+
+	/*
+	 * For output buffers copy the timestamp if needed,
+	 * and the timecode field and flag if needed.
+	 */
+	if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
+			V4L2_BUF_FLAG_TIMESTAMP_COPY)
+		vbuf->timestamp = b->timestamp;
+	vbuf->flags |= b->flags & V4L2_BUF_FLAG_TIMECODE;
+	if (b->flags & V4L2_BUF_FLAG_TIMECODE)
+		vbuf->timecode = b->timecode;
+
+	return 0;
+};
+
+static int __is_last(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+	return (vbuf->flags & V4L2_BUF_FLAG_LAST);
 }
 
+const struct vb2_buf_ops v4l2_buf_ops = {
+	.fill_user_buffer	= __fill_v4l2_buffer,
+	.fill_vb2_buffer	= __fill_vb2_buffer,
+	.fill_vb2_timestamp	= __fill_vb2_timestamp,
+	.is_last		= __is_last,
+};
+
 /**
  * vb2_querybuf() - query video buffer information
  * @q:		videobuf queue
@@ -340,55 +391,55 @@  void __fill_vb2_buffer(struct vb2_buffer *vb,
  */
 int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
 {
-	struct vb2_buffer *vb;
-	int ret;
-
-	if (b->type != q->type) {
-		dprintk(1, "wrong buffer type\n");
-		return -EINVAL;
-	}
+	int ret = vb2_verify_buffer(q, b->memory, b->type, b->index,
+			b->length, b->m.planes, "querybuf");
 
-	if (b->index >= q->num_buffers) {
-		dprintk(1, "buffer index out of range\n");
-		return -EINVAL;
-	}
-	vb = q->bufs[b->index];
-	ret = __verify_planes_array(vb, b);
-	if (!ret)
-		__fill_v4l2_buffer(vb, b);
-	return ret;
+	return ret ? ret : vb2_core_querybuf(q, b->index, b);
 }
 EXPORT_SYMBOL(vb2_querybuf);
 
 /**
- * vb2_reqbufs() - Wrapper for __reqbufs() that also verifies the memory and
- * type values.
+ * vb2_reqbufs() - Wrapper for vb2_core_reqbufs() that also verifies
+ * the memory and type values.
  * @q:		videobuf2 queue
- * @req:	struct passed from userspace to vidioc_reqbufs handler in driver
+ * @req:	struct passed from userspace to vidioc_reqbufs handler
+ *		in driver
  */
 int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 {
-	int ret = __verify_memory_type(q, req->memory, req->type);
+	int ret = vb2_verify_memory_type(q, req->memory, req->type);
 
-	return ret ? ret : __reqbufs(q, req);
+	if (ret)
+		return ret;
+	if (vb2_fileio_is_active(q)) {
+		dprintk(1, "file io in progress\n");
+		return -EBUSY;
+	}
+
+	return vb2_core_reqbufs(q, req->memory, &req->count);
 }
 EXPORT_SYMBOL_GPL(vb2_reqbufs);
 
 /**
- * vb2_create_bufs() - Wrapper for __create_bufs() that also verifies the
- * memory and type values.
+ * vb2_create_bufs() - Wrapper for vb2_core_create_bufs() that also verifies
+ * the memory and type values.
  * @q:		videobuf2 queue
  * @create:	creation parameters, passed from userspace to vidioc_create_bufs
  *		handler in driver
  */
 int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
 {
-	int ret = __verify_memory_type(q, create->memory, create->format.type);
+	int ret = vb2_verify_memory_type(q, create->memory, create->format.type);
 
 	create->index = q->num_buffers;
-	if (create->count == 0)
-		return ret != -EBUSY ? ret : 0;
-	return ret ? ret : __create_bufs(q, create);
+	if (ret || create->count == 0)
+		return ret;
+	if (vb2_fileio_is_active(q)) {
+		dprintk(1, "file io in progress\n");
+		return -EBUSY;
+	}
+
+	return vb2_core_create_bufs(q, create->memory, &create->count, &create->format);
 }
 EXPORT_SYMBOL_GPL(vb2_create_bufs);
 
@@ -409,7 +460,6 @@  EXPORT_SYMBOL_GPL(vb2_create_bufs);
  */
 int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
 {
-	struct vb2_buffer *vb;
 	int ret;
 
 	if (vb2_fileio_is_active(q)) {
@@ -417,27 +467,50 @@  int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
 		return -EBUSY;
 	}
 
-	ret = vb2_queue_or_prepare_buf(q, b, "prepare_buf");
+	ret = vb2_verify_buffer(q, b->memory, b->type, b->index,
+			b->length, b->m.planes, "prepare_buf");
 	if (ret)
 		return ret;
 
-	vb = q->bufs[b->index];
-	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
-		dprintk(1, "invalid buffer state %d\n",
-			vb->state);
+	if (b->field == V4L2_FIELD_ALTERNATE && q->is_output) {
+		/*
+		 * If the format's field is ALTERNATE, then the buffer's field
+		 * should be either TOP or BOTTOM, not ALTERNATE since that
+		 * makes no sense. The driver has to know whether the
+		 * buffer represents a top or a bottom field in order to
+		 * program any DMA correctly. Using ALTERNATE is wrong, since
+		 * that just says that it is either a top or a bottom field,
+		 * but not which of the two it is.
+		 */
+		dprintk(1, "the field is incorrectly set to ALTERNATE "
+				"for an output buffer\n");
 		return -EINVAL;
 	}
 
-	ret = __buf_prepare(vb, b);
-	if (!ret) {
-		/* Fill buffer information for the userspace */
-		__fill_v4l2_buffer(vb, b);
+	return vb2_core_prepare_buf(q, b->index, b);
+}
+EXPORT_SYMBOL_GPL(vb2_prepare_buf);
 
-		dprintk(1, "prepare of buffer %d succeeded\n", vb->index);
+static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+	int ret = vb2_verify_buffer(q, b->memory, b->type, b->index,
+			b->length, b->m.planes, "qbuf");
+	struct vb2_buffer *vb;
+
+	if (ret)
+		return ret;
+
+	vb = q->bufs[b->index];
+
+	if (vb->state == VB2_BUF_STATE_DEQUEUED
+			&& b->field == V4L2_FIELD_ALTERNATE && q->is_output) {
+		dprintk(1, "the field is incorrectly set to ALTERNATE "
+				"for an output buffer\n");
+		return -EINVAL;
 	}
-	return ret;
+
+	return ret ? ret : vb2_core_qbuf(q, b->index, b);
 }
-EXPORT_SYMBOL_GPL(vb2_prepare_buf);
 
 /**
  * vb2_qbuf() - Queue a buffer from userspace
@@ -467,6 +540,16 @@  int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 }
 EXPORT_SYMBOL_GPL(vb2_qbuf);
 
+static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
+			bool nonblocking)
+{
+	if (b->type != q->type) {
+		dprintk(1, "invalid buffer type\n");
+		return -EINVAL;
+	}
+	return vb2_core_dqbuf(q, b, nonblocking);
+}
+
 /**
  * vb2_dqbuf() - Dequeue a buffer to the userspace
  * @q:		videobuf2 queue
@@ -499,6 +582,36 @@  int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
 EXPORT_SYMBOL_GPL(vb2_dqbuf);
 
 /**
+ * vb2_expbuf() - Export a buffer as a file descriptor
+ * @q:		videobuf2 queue
+ * @eb:		export buffer structure passed from userspace to vidioc_expbuf
+ *		handler in driver
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_expbuf handler in driver.
+ */
+int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb)
+{
+	if (vb2_fileio_is_active(q)) {
+		dprintk(1, "file io in progress\n");
+		return -EBUSY;
+	}
+
+	return vb2_core_expbuf(q, &eb->fd, eb->type, eb->index,
+				eb->plane, eb->flags);
+}
+EXPORT_SYMBOL_GPL(vb2_expbuf);
+
+static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
+{
+	if (type != q->type) {
+		dprintk(1, "invalid stream type\n");
+		return -EINVAL;
+	}
+	return vb2_core_streamon(q);
+}
+
+/**
  * vb2_streamon - start streaming
  * @q:		videobuf2 queue
  * @type:	type argument passed from userspace to vidioc_streamon handler
@@ -521,6 +634,15 @@  int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
 }
 EXPORT_SYMBOL_GPL(vb2_streamon);
 
+static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
+{
+	if (type != q->type) {
+		dprintk(1, "invalid stream type\n");
+		return -EINVAL;
+	}
+	return vb2_core_streamoff(q);
+}
+
 /**
  * vb2_streamoff - stop streaming
  * @q:		videobuf2 queue
@@ -547,6 +669,36 @@  int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
 EXPORT_SYMBOL_GPL(vb2_streamoff);
 
 /**
+ * vb2_mmap() - map video buffers into application address space
+ * @q:		videobuf2 queue
+ * @vma:	vma passed to the mmap file operation handler in the driver
+ *
+ * Should be called from mmap file operation handler of a driver.
+ * This function maps one plane of one of the available video buffers to
+ * userspace. To map whole video memory allocated on reqbufs, this function
+ * has to be called once per each plane per each buffer previously allocated.
+ *
+ * When the userspace application calls mmap, it passes to it an offset returned
+ * to it earlier by the means of vidioc_querybuf handler. That offset acts as
+ * a "cookie", which is then used to identify the plane to be mapped.
+ * This function finds a plane with a matching offset and a mapping is performed
+ * by the means of a provided memory operation.
+ *
+ * The return values from this function are intended to be directly returned
+ * from the mmap handler in driver.
+ */
+int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
+{
+	if (vb2_fileio_is_active(q)) {
+		dprintk(1, "mmap: file io in progress\n");
+		return -EBUSY;
+	}
+
+	return vb2_core_mmap(q, vma);
+}
+EXPORT_SYMBOL_GPL(vb2_mmap);
+
+/**
  * vb2_queue_init() - initialize a videobuf2 queue
  * @q:		videobuf2 queue; this structure should be allocated in driver
  *
@@ -559,17 +711,17 @@  EXPORT_SYMBOL_GPL(vb2_streamoff);
  */
 int vb2_queue_init(struct vb2_queue *q)
 {
+	if (WARN_ON(VB2_MEMORY_MMAP != (int)V4L2_MEMORY_MMAP)
+		|| WARN_ON(VB2_MEMORY_USERPTR != (int)V4L2_MEMORY_USERPTR)
+		|| WARN_ON(VB2_MEMORY_DMABUF != (int)V4L2_MEMORY_DMABUF))
+		return -EINVAL;
 	/*
 	 * Sanity check
 	 */
-	if (WARN_ON(!q)			  ||
-	    WARN_ON(!q->ops)		  ||
-	    WARN_ON(!q->mem_ops)	  ||
-	    WARN_ON(!q->type)		  ||
-	    WARN_ON(!q->io_modes)	  ||
-	    WARN_ON(!q->ops->queue_setup) ||
-	    WARN_ON(!q->ops->buf_queue)   ||
-	    WARN_ON(q->timestamp_flags &
+	if (WARN_ON(!q)	|| WARN_ON(!q->type))
+		return -EINVAL;
+
+	if (WARN_ON(q->timestamp_flags &
 		    ~(V4L2_BUF_FLAG_TIMESTAMP_MASK |
 		      V4L2_BUF_FLAG_TSTAMP_SRC_MASK)))
 		return -EINVAL;
@@ -578,19 +730,18 @@  int vb2_queue_init(struct vb2_queue *q)
 	WARN_ON((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
 		V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN);
 
-	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)
-		q->buf_struct_size = sizeof(struct vb2_buffer);
+		q->buf_struct_size = sizeof(struct vb2_v4l2_buffer);
 
-	return 0;
+	q->buf_ops = &v4l2_buf_ops;
+	q->is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type);
+	q->is_output = V4L2_TYPE_IS_OUTPUT(q->type);
+
+	return vb2_core_queue_init(q);
 }
 EXPORT_SYMBOL_GPL(vb2_queue_init);
 
+static int __vb2_cleanup_fileio(struct vb2_queue *q);
 /**
  * vb2_queue_release() - stop streaming, release the queue and free memory
  * @q:		videobuf2 queue
@@ -602,10 +753,7 @@  EXPORT_SYMBOL_GPL(vb2_queue_init);
 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);
+	vb2_core_queue_release(q);
 }
 EXPORT_SYMBOL_GPL(vb2_queue_release);
 
@@ -714,7 +862,7 @@  static int __vb2_init_fileio(struct vb2_queue *q, int read)
 	fileio->req.memory = V4L2_MEMORY_MMAP;
 	fileio->req.type = q->type;
 	q->fileio = fileio;
-	ret = __reqbufs(q, &fileio->req);
+	ret = vb2_core_reqbufs(q, fileio->req.memory, &fileio->req.count);
 	if (ret)
 		goto err_kfree;
 
@@ -743,7 +891,7 @@  static int __vb2_init_fileio(struct vb2_queue *q, int read)
 	 * Read mode requires pre queuing of all buffers.
 	 */
 	if (read) {
-		bool is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type);
+		bool is_multiplanar = q->is_multiplanar;
 
 		/*
 		 * Queue all buffers.
@@ -784,7 +932,7 @@  static int __vb2_init_fileio(struct vb2_queue *q, int read)
 
 err_reqbufs:
 	fileio->req.count = 0;
-	__reqbufs(q, &fileio->req);
+	vb2_core_reqbufs(q, fileio->req.memory, &fileio->req.count);
 
 err_kfree:
 	q->fileio = NULL;
@@ -796,7 +944,7 @@  err_kfree:
  * __vb2_cleanup_fileio() - free resourced used by file io emulator
  * @q:		videobuf2 queue
  */
-int __vb2_cleanup_fileio(struct vb2_queue *q)
+static int __vb2_cleanup_fileio(struct vb2_queue *q)
 {
 	struct vb2_fileio_data *fileio = q->fileio;
 
@@ -820,12 +968,12 @@  int __vb2_cleanup_fileio(struct vb2_queue *q)
  * @nonblock:	mode selector (1 means blocking calls, 0 means nonblocking)
  * @read:	access mode selector (1 means read, 0 means write)
  */
-static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
-		loff_t *ppos, int nonblock, int read)
+static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data,
+		size_t count, loff_t *ppos, int nonblock, int read)
 {
 	struct vb2_fileio_data *fileio;
 	struct vb2_fileio_buf *buf;
-	bool is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type);
+	bool is_multiplanar = q->is_multiplanar;
 	/*
 	 * When using write() to write data to an output video node the vb2 core
 	 * should set timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody
@@ -1132,7 +1280,7 @@  static int vb2_thread(void *data)
 	int index = 0;
 	int ret = 0;
 
-	if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+	if (q->is_output) {
 		prequeue = q->num_buffers;
 		set_timestamp =
 			(q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
@@ -1210,7 +1358,7 @@  int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
 	threadio->fnc = fnc;
 	threadio->priv = priv;
 
-	ret = __vb2_init_fileio(q, !V4L2_TYPE_IS_OUTPUT(q->type));
+	ret = __vb2_init_fileio(q, !q->is_output);
 	dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
 	if (ret)
 		goto nomem;
@@ -1270,13 +1418,15 @@  int vb2_ioctl_reqbufs(struct file *file, void *priv,
 			  struct v4l2_requestbuffers *p)
 {
 	struct video_device *vdev = video_devdata(file);
-	int res = __verify_memory_type(vdev->queue, p->memory, p->type);
+	int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type);
 
 	if (res)
 		return res;
+	if (vb2_fileio_is_active(vdev->queue))
+		return -EBUSY;
 	if (vb2_queue_is_busy(vdev, file))
 		return -EBUSY;
-	res = __reqbufs(vdev->queue, p);
+	res = vb2_core_reqbufs(vdev->queue, p->memory, &p->count);
 	/* If count == 0, then the owner has released all buffers and he
 	   is no longer owner of the queue. Otherwise we have a new owner. */
 	if (res == 0)
@@ -1289,18 +1439,22 @@  int vb2_ioctl_create_bufs(struct file *file, void *priv,
 			  struct v4l2_create_buffers *p)
 {
 	struct video_device *vdev = video_devdata(file);
-	int res = __verify_memory_type(vdev->queue, p->memory, p->format.type);
+	int res = vb2_verify_memory_type(vdev->queue,
+				p->memory, p->format.type);
 
+	if (vb2_fileio_is_active(vdev->queue))
+		return -EBUSY;
 	p->index = vdev->queue->num_buffers;
 	/* If count == 0, then just check if memory and type are valid.
-	   Any -EBUSY result from __verify_memory_type can be mapped to 0. */
+	   Any -EBUSY result from vb2_verify_memory_type can be mapped to 0. */
 	if (p->count == 0)
 		return res != -EBUSY ? res : 0;
 	if (res)
 		return res;
 	if (vb2_queue_is_busy(vdev, file))
 		return -EBUSY;
-	res = __create_bufs(vdev->queue, p);
+	res = vb2_core_create_bufs(vdev->queue,
+				p->memory, &p->count, &p->format);
 	if (res == 0)
 		vdev->queue->owner = file->private_data;
 	return res;
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 3894e1e..89c7982 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -15,7 +15,6 @@ 
 #include <linux/mm_types.h>
 #include <linux/mutex.h>
 #include <linux/poll.h>
-#include <linux/videodev2.h>
 #include <linux/dma-buf.h>
 
 #define VB2_MAX_FRAME	(32)
@@ -355,6 +354,13 @@  struct vb2_ops {
 	void (*buf_queue)(struct vb2_buffer *vb);
 };
 
+struct vb2_buf_ops {
+	int (*fill_user_buffer)(struct vb2_buffer *vb, void *pb);
+	int (*fill_vb2_buffer)(struct vb2_buffer *vb, void *pb,
+				struct vb2_plane *planes);
+	int (*fill_vb2_timestamp)(struct vb2_buffer *vb, void *pb);
+	int (*is_last)(struct vb2_buffer *vb);
+};
 
 /**
  * struct vb2_queue - a videobuf queue
@@ -377,6 +383,8 @@  struct vb2_ops {
  *		drivers to easily associate an owner filehandle with the queue.
  * @ops:	driver-specific callbacks
  * @mem_ops:	memory allocator specific callbacks
+ * @buf_ops:	callbacks to deliver buffer information
+ *		between user-space and kernel-space
  * @drv_priv:	driver private data
  * @buf_struct_size: size of the driver-specific buffer structure;
  *		"0" indicates the driver doesn't want to use a custom buffer
@@ -412,6 +420,8 @@  struct vb2_ops {
  * @waiting_for_buffers: used in poll() to check if vb2 is still waiting for
  *		buffers. Only set for capture queues if qbuf has not yet been
  *		called since poll() needs to return POLLERR in that situation.
+ * @is_multiplanar: set if buffer type is multiplanar
+ * @is_output:	set if buffer type is output
  * @last_buffer_dequeued: used in poll() and DQBUF to immediately return if the
  *		last decoded buffer was already dequeued. Set for capture queues
  *		when a buffer with the V4L2_BUF_FLAG_LAST is dequeued.
@@ -430,6 +440,8 @@  struct vb2_queue {
 
 	const struct vb2_ops		*ops;
 	const struct vb2_mem_ops	*mem_ops;
+	const struct vb2_buf_ops	*buf_ops;
+
 	void				*drv_priv;
 	unsigned int			buf_struct_size;
 	u32				timestamp_flags;
@@ -457,6 +469,8 @@  struct vb2_queue {
 	unsigned int			start_streaming_called:1;
 	unsigned int			error:1;
 	unsigned int			waiting_for_buffers:1;
+	unsigned int			is_multiplanar:1;
+	unsigned int			is_output:1;
 	unsigned int			last_buffer_dequeued:1;
 
 	struct vb2_fileio_data		*fileio;
@@ -483,10 +497,6 @@  void vb2_discard_done(struct vb2_queue *q);
 int vb2_wait_for_all_buffers(struct vb2_queue *q);
 
 void vb2_queue_error(struct vb2_queue *q);
-
-int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb);
-
-int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma);
 #ifndef CONFIG_MMU
 unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
 				    unsigned long addr,
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 255727c..420e7ae 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -53,11 +53,12 @@  int __must_check vb2_queue_init(struct vb2_queue *q);
 void vb2_queue_release(struct vb2_queue *q);
 
 int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb);
 int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking);
 
 int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type);
 int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type);
-
+int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma);
 unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait);
 size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
 		loff_t *ppos, int nonblock);