All of lore.kernel.org
 help / color / mirror / Atom feed
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Bhupesh Sharma <bhupesh.sharma@st.com>
Cc: linux-usb@vger.kernel.org, balbi@ti.com,
	linux-media@vger.kernel.org, gregkh@linuxfoundation.org
Subject: Re: [PATCH 4/5] usb: gadget/uvc: Port UVC webcam gadget to use videobuf2 framework
Date: Tue, 19 Jun 2012 00:49:07 +0200	[thread overview]
Message-ID: <2099637.B2epIePqJp@avalon> (raw)
In-Reply-To: <243660e539dcccd868c641188faef26d83c2b894.1338543124.git.bhupesh.sharma@st.com>

Hi Bhupesh,

Thanks for the patch. It looks quite good, please see below for various small 
comments.

On Friday 01 June 2012 15:08:57 Bhupesh Sharma wrote:
> This patch reworks the videobuffer management logic present in the UVC
> webcam gadget and ports it to use the "more apt" videobuf2 framework for
> video buffer management.
> 
> To support routing video data captured from a real V4L2 video capture
> device with a "zero copy" operation on videobuffers (as they pass from the
> V4L2 domain to UVC domain via a user-space application), we need to support
> USER_PTR IO method at the UVC gadget side.
> 
> So the V4L2 capture device driver can still continue to use MMAO IO method

s/MMAO/MMAP/

> and now the user-space application can just pass a pointer to the video
> buffers being DeQueued from the V4L2 device side while Queueing them at the

I don't think dequeued and queueing need capitals :-)

> UVC gadget end. This ensures that we have a "zero-copy" design as the
> videobuffers pass from the V4L2 capture device to the UVC gadget.
> 
> Note that there will still be a need to apply UVC specific payload headers
> on top of each UVC payload data, which will still require a copy operation
> to be performed in the 'encode' routines of the UVC gadget.
> 
> Signed-off-by: Bhupesh Sharma <bhupesh.sharma@st.com>
> ---
>  drivers/usb/gadget/Kconfig     |    1 +
>  drivers/usb/gadget/uvc_queue.c |  524 ++++++++++---------------------------
>  drivers/usb/gadget/uvc_queue.h |   25 +--
>  drivers/usb/gadget/uvc_v4l2.c  |   35 ++--
>  drivers/usb/gadget/uvc_video.c |   17 +-
>  5 files changed, 184 insertions(+), 418 deletions(-)

[snip]

> diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c
> index 0cdf89d..907ece8 100644
> --- a/drivers/usb/gadget/uvc_queue.c
> +++ b/drivers/usb/gadget/uvc_queue.c

[snip]

This part is a bit difficult to review, as git tried too hard to create a 
universal diff where your patch really replaces the code. I'll remove the - 
lines to make the comments as readable as possible.

> +/*
> ---------------------------------------------------------------------------
> --
> + * videobuf2 queue operations
>   */
> +
> +static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format
> *fmt,
> +				unsigned int *nbuffers, unsigned int *nplanes,
> +				unsigned int sizes[], void *alloc_ctxs[])
>  {
> +	struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
> +	struct uvc_video *video =
> +			container_of(queue, struct uvc_video, queue);

No need for a line split.

> 
> +	if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
> +		*nbuffers = UVC_MAX_VIDEO_BUFFERS;
> 
> +	*nplanes = 1;
> +
> +	sizes[0] = video->imagesize;
> 
>  	return 0;
>  }
> 
> +static int uvc_buffer_prepare(struct vb2_buffer *vb)
>  {
> +	struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
> +	struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
> 
> +	if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
> +			vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {

Please align vb2 with the vb-> on the previous line.

Have you by any chance found some inspiration in 
drivers/media/video/uvc/uvc_queue.c ? :-) It would probably make sense to move 
this check to vb2 core, but that's outside of the scope of this patch.

> +		uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
> +		return -EINVAL;
> +	}
> 
> +	if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
> +		return -ENODEV;
> 
> +	buf->state = UVC_BUF_STATE_QUEUED;
> +	buf->mem = vb2_plane_vaddr(vb, 0);
> +	buf->length = vb2_plane_size(vb, 0);
> +	if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +		buf->bytesused = 0;
> +	else
> +		buf->bytesused = vb2_get_plane_payload(vb, 0);

The driver doesn't support the capture type at the moment so this might be a 
bit overkill, but I think it's a good idea to support capture in the queue 
imeplementation. I plan to try and merge the uvcvideo and uvcgadget queue 
implementations at some point.

> 
> +	return 0;
> +}
> 
> +static void uvc_buffer_queue(struct vb2_buffer *vb)
> +{
> +	struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
> +	struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
> +	unsigned long flags;
> 
> +	spin_lock_irqsave(&queue->irqlock, flags);
> 
> +	if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
> +		list_add_tail(&buf->queue, &queue->irqqueue);
> +	} else {
> +		/* If the device is disconnected return the buffer to userspace
> +		 * directly. The next QBUF call will fail with -ENODEV.
> +		 */
> +		buf->state = UVC_BUF_STATE_ERROR;
> +		vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
>  	}
> 
> +	spin_unlock_irqrestore(&queue->irqlock, flags);
>  }
> 
> +static struct vb2_ops uvc_queue_qops = {
> +	.queue_setup = uvc_queue_setup,
> +	.buf_prepare = uvc_buffer_prepare,
> +	.buf_queue = uvc_buffer_queue,
> +};
> +
> +static
> +void uvc_queue_init(struct uvc_video_queue *queue,
> +				enum v4l2_buf_type type)

This can fit on two lines. Please align enum with struct.

>  {
> +	mutex_init(&queue->mutex);
> +	spin_lock_init(&queue->irqlock);
> +	INIT_LIST_HEAD(&queue->irqqueue);

Please add a blank line here.

> +	queue->queue.type = type;
> +	queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
> +	queue->queue.drv_priv = queue;
> +	queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
> +	queue->queue.ops = &uvc_queue_qops;
> +	queue->queue.mem_ops = &vb2_vmalloc_memops;
> +	vb2_queue_init(&queue->queue);
>  }

[snip]

>  /*
> + * Allocate the video buffers.
>   */
> +static int uvc_alloc_buffers(struct uvc_video_queue *queue,
> +				struct v4l2_requestbuffers *rb)

Please align struct with struct (same for the rest of the file).

>  {
> +	int ret;
> 
> +	/*
> +	 * we can support a max of UVC_MAX_VIDEO_BUFFERS video buffers
> +	 */
> +	if (rb->count > UVC_MAX_VIDEO_BUFFERS)
> +		rb->count = UVC_MAX_VIDEO_BUFFERS;
> 

The check is already present in uvc_queue_setup(), you can remove it here.

>  	mutex_lock(&queue->mutex);
> +	ret = vb2_reqbufs(&queue->queue, rb);
> +	mutex_unlock(&queue->mutex);
> 
> +	return ret ? ret : rb->count;
> +}

[snip]

> @@ -481,10 +250,10 @@ static void uvc_queue_cancel(struct uvc_video_queue
> *queue, int disconnect) spin_lock_irqsave(&queue->irqlock, flags);
>  	while (!list_empty(&queue->irqqueue)) {
>  		buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
> -				       queue);
> +					queue);

No need to change indentation here.

>  		list_del(&buf->queue);
>  		buf->state = UVC_BUF_STATE_ERROR;
> -		wake_up(&buf->wait);
> +		vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
>  	}
>  	/* This must be protected by the irqlock spinlock to avoid race
>  	 * conditions between uvc_queue_buffer and the disconnection event that
> @@ -516,26 +285,28 @@ static void uvc_queue_cancel(struct uvc_video_queue
> *queue, int disconnect) */
>  static int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
>  {
> +	unsigned long flags;
>  	int ret = 0;
> 
>  	mutex_lock(&queue->mutex);
>  	if (enable) {
> +		ret = vb2_streamon(&queue->queue, queue->queue.type);
> +		if (ret < 0)
>  			goto done;
> +
>  		queue->buf_used = 0;
> +		queue->flags |= UVC_QUEUE_STREAMING;

I think UVC_QUEUE_STREAMING isn't used anymore.

>  	} else {
> +		if (uvc_queue_streaming(queue)) {

The uvcvideo driver doesn't have this check. It thus returns -EINVAL if 
VIDIOC_STREAMOFF is called on a stream that is already stopped. I'm not sure 
what the right behaviour is, so let's keep the check here until we figure it 
out.

> +			ret = vb2_streamoff(&queue->queue, queue->queue.type);
> +			if (ret < 0)
> +				goto done;
> +
> +			spin_lock_irqsave(&queue->irqlock, flags);
> +			INIT_LIST_HEAD(&queue->irqqueue);
> +			queue->flags &= ~UVC_QUEUE_STREAMING;
> +			spin_unlock_irqrestore(&queue->irqlock, flags);
> +		}
>  	}
> 
>  done:
> @@ -543,30 +314,29 @@ done:
>  	return ret;
>  }
> 
> -/* called with queue->irqlock held.. */
> +/* called with &queue_irqlock held.. */
>  static struct uvc_buffer *
>  uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer
> *buf) {
>  	struct uvc_buffer *nextbuf;
> 
>  	if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
> -	    buf->buf.length != buf->buf.bytesused) {
> +			buf->length != buf->bytesused) {

Please keep the indentation.

>  		buf->state = UVC_BUF_STATE_QUEUED;
> -		buf->buf.bytesused = 0;
> +		vb2_set_plane_payload(&buf->buf, 0, 0);
>  		return buf;
>  	}
> 
>  	list_del(&buf->queue);
>  	if (!list_empty(&queue->irqqueue))
>  		nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
> -					   queue);
> +						queue);

Same here.

>  	else
>  		nextbuf = NULL;
> 
> -	buf->buf.sequence = queue->sequence++;
> -	do_gettimeofday(&buf->buf.timestamp);

videobuf2 doesn't fill the sequence number or timestamp fields, so you either 
need to keep this here or move it to the caller.

> +	vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
> +	vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
> 
> -	wake_up(&buf->wait);
>  	return nextbuf;
>  }
> 
> @@ -576,7 +346,7 @@ static struct uvc_buffer *uvc_queue_head(struct
> uvc_video_queue *queue)
> 
>  	if (!list_empty(&queue->irqqueue))
>  		buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
> -				       queue);
> +					queue);

Please keep the indentation.

>  	else
>  		queue->flags |= UVC_QUEUE_PAUSED;
> 

[snip]

> diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c
> index f6e083b..9c2b45b 100644
> --- a/drivers/usb/gadget/uvc_v4l2.c
> +++ b/drivers/usb/gadget/uvc_v4l2.c
> @@ -144,20 +144,23 @@ uvc_v4l2_release(struct file *file)
>  	struct uvc_device *uvc = video_get_drvdata(vdev);
>  	struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
>  	struct uvc_video *video = handle->device;
> +	int ret;
> 
>  	uvc_function_disconnect(uvc);
> 
> -	uvc_video_enable(video, 0);
> -	mutex_lock(&video->queue.mutex);
> -	if (uvc_free_buffers(&video->queue) < 0)
> -		printk(KERN_ERR "uvc_v4l2_release: Unable to free "
> -				"buffers.\n");
> -	mutex_unlock(&video->queue.mutex);
> +	ret = uvc_video_enable(video, 0);
> +	if (ret < 0) {
> +		printk(KERN_ERR "uvc_v4l2_release: uvc video disable failed\n");
> +		return ret;
> +	}

This shouldn't prevent uvc_v4l2_release() from succeeding. In practive 
uvc_video_enable(0) will never fail, so you can remove the error check.

> +
> +	uvc_free_buffers(&video->queue);
> 
>  	file->private_data = NULL;
>  	v4l2_fh_del(&handle->vfh);
>  	v4l2_fh_exit(&handle->vfh);
>  	kfree(handle);
> +
>  	return 0;
>  }

[snip]

> diff --git a/drivers/usb/gadget/uvc_video.c b/drivers/usb/gadget/uvc_video.c
> index b0e53a8..195bbb6 100644
> --- a/drivers/usb/gadget/uvc_video.c
> +++ b/drivers/usb/gadget/uvc_video.c

[snip]

> @@ -161,6 +161,7 @@ static void
>  uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
>  {
>  	struct uvc_video *video = req->context;
> +	struct uvc_video_queue *queue = &video->queue;
>  	struct uvc_buffer *buf;
>  	unsigned long flags;
>  	int ret;
> @@ -169,13 +170,15 @@ uvc_video_complete(struct usb_ep *ep, struct
> usb_request *req) case 0:
>  		break;
> 
> -	case -ESHUTDOWN:
> +	case -ESHUTDOWN:	/* disconnect from host. */
>  		printk(KERN_INFO "VS request cancelled.\n");
> +		uvc_queue_cancel(queue, 1);
>  		goto requeue;
> 
>  	default:
>  		printk(KERN_INFO "VS request completed with status %d.\n",
>  			req->status);
> +		uvc_queue_cancel(queue, 0);

I wonder why there was no uvc_queue_cancel() here already, it makes me a bit 
suspicious :-) Have you double-checked this ?

>  		goto requeue;
>  	}

-- 
Regards,

Laurent Pinchart


  parent reply	other threads:[~2012-06-18 22:48 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-06-01  9:37 [PATCH 0/5] UVC webcam gadget related changes Bhupesh Sharma
2012-06-01  9:38 ` [PATCH 1/5] usb: gadget/uvc: Fix string descriptor STALL issue when multiple uvc functions are added to a configuration Bhupesh Sharma
2012-06-01  9:38 ` [PATCH 2/5] usb: gadget/uvc: Use macro for interrupt endpoint status size instead of using a MAGIC number Bhupesh Sharma
2012-06-01  9:38 ` [PATCH 3/5] usb: gadget/uvc: Add super-speed support to UVC webcam gadget Bhupesh Sharma
2012-06-08 15:52   ` Laurent Pinchart
2012-06-09  5:39     ` Bhupesh SHARMA
2012-06-11  7:25       ` Laurent Pinchart
2012-06-15 10:24         ` Bhupesh SHARMA
2012-06-01  9:38 ` [PATCH 4/5] usb: gadget/uvc: Port UVC webcam gadget to use videobuf2 framework Bhupesh Sharma
2012-06-04 15:13   ` Felipe Balbi
2012-06-04 15:21     ` Bhupesh SHARMA
2012-06-04 15:28       ` Felipe Balbi
2012-06-04 15:37         ` Bhupesh SHARMA
2012-06-04 15:40           ` Felipe Balbi
2012-06-04 15:43             ` Bhupesh SHARMA
2012-06-04 16:40         ` Laurent Pinchart
2012-06-04 16:41           ` Felipe Balbi
2012-06-18 10:14   ` Bhupesh SHARMA
2012-06-18 22:50     ` Laurent Pinchart
2012-06-18 22:49   ` Laurent Pinchart [this message]
2012-07-03 15:42     ` Bhupesh SHARMA
2012-07-07 11:58       ` Laurent Pinchart
2012-07-25 18:18         ` Bhupesh SHARMA
2012-06-01  9:38 ` [PATCH 5/5] usb: gadget/uvc: Add support for 'USB_GADGET_DELAYED_STATUS' response for a set_intf(alt-set 1) command Bhupesh Sharma
2012-06-18 10:14   ` Bhupesh SHARMA
2012-06-19 21:49   ` Laurent Pinchart
2012-07-03 15:47     ` Bhupesh SHARMA
2012-07-07 13:06       ` Laurent Pinchart
2012-07-25 18:14         ` Bhupesh SHARMA

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2099637.B2epIePqJp@avalon \
    --to=laurent.pinchart@ideasonboard.com \
    --cc=balbi@ti.com \
    --cc=bhupesh.sharma@st.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.