Re: [PATCH V2 1/2] usb: gadget/uvc: Port UVC webcam gadget to use videobuf2 framework

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Bhupesh,

Thank you for the patch.

On Tuesday 31 July 2012 06:24:51 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 MMAP IO
> method 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 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.
> 
> This patch also addresses two issues found out while porting the UVC
> gadget to videobuf2 framework:
> 	- In case the usb requests queued by the gadget get completed
> 	  with a status of -ESHUTDOWN (disconnected from host), the
> 	  queue of videobuf2 should be cancelled to ensure that the
> 	  application space daemon is not left in a state waiting for
> 	  a vb2 to be successfully absorbed at the USB side.
> 
> 	- In case the underlying UDC has already returned -ESHUTDOWN
> 	  as status of a queued request, it means that the video
> 	  streaming endpoint is going to be disabled and hence the
> 	  underlying UDC will giveback all queued requests with a status
> 	  of -ESHUTDOWN. In such a case, the requests are not longer
> 	  queued at the UDC end and it doesn't make sense to dequeue
> 	  them again in uvc_video_enable(0).
> 
> Signed-off-by: Bhupesh Sharma <bhupesh.sharma@xxxxxx>
> ---
>  drivers/usb/gadget/uvc_queue.c |  531 ++++++++++++-------------------------
>  drivers/usb/gadget/uvc_queue.h |   25 +--
>  drivers/usb/gadget/uvc_v4l2.c  |   27 +--
>  drivers/usb/gadget/uvc_video.c |   28 ++-
>  4 files changed, 190 insertions(+), 421 deletions(-)

Shouldn't you select VIDEOBUF2_VMALLOC in Kconfig ? That was done in v1 but 
you seem to have dropped it here.

> diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c
> index 104ae9c..bf6621b 100644
> --- a/drivers/usb/gadget/uvc_queue.c
> +++ b/drivers/usb/gadget/uvc_queue.c

[snip]

> @@ -484,9 +243,10 @@ static void uvc_queue_cancel(struct uvc_video_queue
> *queue, int disconnect) queue);
>  		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
> +	/*
> +	 * This must be protected by the irqlock spinlock to avoid race
>  	 * conditions between uvc_queue_buffer and the disconnection event that
>  	 * could result in an interruptible wait in uvc_dequeue_buffer. Do not
>  	 * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED
> @@ -516,26 +276,34 @@ 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 int i;
> +	unsigned long flags;
>  	int ret = 0;
> 
>  	mutex_lock(&queue->mutex);
>  	if (enable) {
> -		if (uvc_queue_streaming(queue)) {
> -			ret = -EBUSY;
> +		ret = vb2_streamon(&queue->queue, queue->queue.type);
> +		if (ret < 0)
>  			goto done;
> -		}
> -		queue->sequence = 0;
> -		queue->flags |= UVC_QUEUE_STREAMING;
> +
>  		queue->buf_used = 0;
>  	} else {
> -		uvc_queue_cancel(queue, 0);
> -		INIT_LIST_HEAD(&queue->mainqueue);
> +		ret = vb2_streamoff(&queue->queue, queue->queue.type);
> +		if (ret < 0)
> +			goto done;
> +
> +		spin_lock_irqsave(&queue->irqlock, flags);
> +
> +		INIT_LIST_HEAD(&queue->irqqueue);
> 
> -		for (i = 0; i < queue->count; ++i)
> -			queue->buffer[i].state = UVC_BUF_STATE_IDLE;
> +		/*
> +		 * as the uvc queue is being disabled, clear any
> +		 * DISCONNECTED flag which was set earlier, so that the
> +		 * next qbuf from userspace does not fail with ENODEV.
> +		 */

Please start the comment with a capital letter, spell UVC in capital, and fill 
the space up to 80 columns.

> +		if (queue->flags & UVC_QUEUE_DISCONNECTED)
> +			queue->flags &= ~UVC_QUEUE_DISCONNECTED;

You can clear the flag unconditionally. What about moving this to the enable 
branch of the if ?

> -		queue->flags &= ~UVC_QUEUE_STREAMING;
> +		spin_unlock_irqrestore(&queue->irqlock, flags);
>  	}
> 
>  done:

[snip]

> @@ -563,10 +331,18 @@ uvc_queue_next_buffer(struct uvc_video_queue *queue,
> struct uvc_buffer *buf) else
>  		nextbuf = NULL;
> 
> -	buf->buf.sequence = queue->sequence++;
> -	do_gettimeofday(&buf->buf.timestamp);
> +	/*
> +	 * FIXME: with videobuf2, the sequence number or timestamp fields
> +	 * are valid only for video capture devices and the UVC gadget
> +	 * usually is a video output device. Keeping these until the
> +	 * specs are clear on this aspect.
> +	 */

Please fill the space up to 80 columns.

> +	buf->buf.v4l2_buf.sequence = queue->sequence++;
> +	do_gettimeofday(&buf->buf.v4l2_buf.timestamp);
> +
> +	vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
> +	vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
> 
> -	wake_up(&buf->wait);
>  	return nextbuf;
>  }
> 

[snip]

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

[snip]

> @@ -332,6 +335,7 @@ uvc_video_enable(struct uvc_video *video, int enable)
>  {
>  	unsigned int i;
>  	int ret;
> +	struct uvc_video_queue *queue = &video->queue;
> 
>  	if (video->ep == NULL) {
>  		printk(KERN_INFO "Video enable failed, device is "
> @@ -340,8 +344,13 @@ uvc_video_enable(struct uvc_video *video, int enable)
>  	}
> 
>  	if (!enable) {
> -		for (i = 0; i < UVC_NUM_REQUESTS; ++i)
> -			usb_ep_dequeue(video->ep, video->req[i]);
> +		/*
> +		 * dequeue requests on underlying UDC only if
> +		 * -ESHUTDOWN was not asserted by UDC earlier
> +		 */
> +		if (!(queue->flags & UVC_QUEUE_DISCONNECTED))
> +			for (i = 0; i < UVC_NUM_REQUESTS; ++i)
> +				usb_ep_dequeue(video->ep, video->req[i]);

What happens if you omit this check ?

>  		uvc_video_free_requests(video);
>  		uvc_queue_enable(&video->queue, 0);
> @@ -382,4 +391,3 @@ uvc_video_init(struct uvc_video *video)
>  	uvc_queue_init(&video->queue, V4L2_BUF_TYPE_VIDEO_OUTPUT);
>  	return 0;
>  }
> -
-- 
Regards,

Laurent Pinchart

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux