Re: [PATCH V4 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,

Thanks for the patch. Please see below for a couple of small comments.

On Thursday 21 March 2013 13:56:08 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 one issue 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.
> 
> Signed-off-by: Bhupesh Sharma <bhupesh.sharma@xxxxxx>
> ---
>  drivers/usb/gadget/Kconfig     |    1 +
>  drivers/usb/gadget/uvc_queue.c |  533 ++++++++++++-------------------------
>  drivers/usb/gadget/uvc_queue.h |   25 +--
>  drivers/usb/gadget/uvc_v4l2.c  |   37 +--
>  drivers/usb/gadget/uvc_video.c |   17 +-
>  5 files changed, 188 insertions(+), 425 deletions(-)

[snip]

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

[snip]

> +static int uvc_queue_init(struct uvc_video_queue *queue,
> +			  enum v4l2_buf_type type)
>  {
> +	int ret;
> 
> +	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;
> +	ret = vb2_queue_init(&queue->queue);
> +	if (ret)
> +		return ret;
> 
> +	mutex_init(&queue->mutex);
> +	spin_lock_init(&queue->irqlock);
> +	INIT_LIST_HEAD(&queue->irqqueue);

I think you should initialize queue->flags to 0 here.

> 
> +	return 0;
>  }

[snip]

> +static int uvc_queue_buffer(struct uvc_video_queue *queue,
> +			    struct v4l2_buffer *buf)
>  {
> +	int ret;
> +
> +	mutex_lock(&queue->mutex);
> +	ret = vb2_qbuf(&queue->queue, buf);
> +	ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
> +	queue->flags &= ~UVC_QUEUE_PAUSED;

Access to the queue flags need to be protected by the irqlock spinlock here 
(in addition to the queue mutex).

> +	mutex_unlock(&queue->mutex);
> 
> +	return ret;
>  }

[snip]

> @@ -516,26 +283,32 @@ 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;

Shouldn't you keep this line ?

> -		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;
> 
> -		for (i = 0; i < queue->count; ++i)
> -			queue->buffer[i].state = UVC_BUF_STATE_IDLE;
> +		spin_lock_irqsave(&queue->irqlock, flags);
> +		INIT_LIST_HEAD(&queue->irqqueue);
> 
> -		queue->flags &= ~UVC_QUEUE_STREAMING;
> +		/*
> +		 * FIXME: We need to clear the DISCONNECTED flag to ensure that
> +		 * applications will be able to queue buffers for the next
> +		 * streaming run. However, clearing it here doesn't guarantee
> +		 * that the device will be reconnected in the meantime.
> +		 */
> +		queue->flags &= ~UVC_QUEUE_DISCONNECTED;
> +		spin_unlock_irqrestore(&queue->irqlock, flags);
>  	}
> 
>  done:

[snip]

> diff --git a/drivers/usb/gadget/uvc_queue.h b/drivers/usb/gadget/uvc_queue.h
> index 1812a8e..47ad0b8 100644
> --- a/drivers/usb/gadget/uvc_queue.h
> +++ b/drivers/usb/gadget/uvc_queue.h

[snip]

> @@ -25,14 +26,13 @@ enum uvc_buffer_state {
>  };
> 
>  struct uvc_buffer {
> -	unsigned long vma_use_count;
> -	struct list_head stream;
> -
> -	/* Touched by interrupt handler. */
> -	struct v4l2_buffer buf;
> +	struct vb2_buffer buf;
>  	struct list_head queue;
> -	wait_queue_head_t wait;
> +
>  	enum uvc_buffer_state state;
> +	void *mem;
> +	unsigned int length;
> +	unsigned int bytesused;
>  };
> 
>  #define UVC_QUEUE_STREAMING		(1 << 0)

You can remove the UVC_QUEUE_STREAMIN flag, it's not used anymore.

> @@ -41,26 +41,21 @@ struct uvc_buffer {
>  #define UVC_QUEUE_PAUSED		(1 << 3)
> 
>  struct uvc_video_queue {
> -	enum v4l2_buf_type type;
> +	struct vb2_queue queue;
> +	struct mutex mutex;	/* Protects queue */
> 
> -	void *mem;
>  	unsigned int flags;
>  	__u32 sequence;
> 
> -	unsigned int count;
> -	unsigned int buf_size;
>  	unsigned int buf_used;
> -	struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
> -	struct mutex mutex;	/* protects buffers and mainqueue */
> -	spinlock_t irqlock;	/* protects irqqueue */
> 
> -	struct list_head mainqueue;
> +	spinlock_t irqlock;	/* Protects irqqueue */

The comment is incorrect, it should be "Protects flags and irqqueue" (it's my 
fault, but let's fix it :-)).

>  	struct list_head irqqueue;
>  };
> 
>  static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
>  {
> -	return queue->flags & UVC_QUEUE_STREAMING;
> +	return vb2_is_streaming(&queue->queue);
>  }
> 
>  #endif /* __KERNEL__ */

[snip]

-- 
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