static int
uvc_video_pump(struct uvc_video *video)
{
	struct usb_request *req;
	struct uvc_buffer *buf;
	unsigned long flags;
	int ret;

	/*                                                               
               
  */

	while (1) {
		/*                                                           
                  
   */
		spin_lock_irqsave(&video->req_lock, flags);
		if (list_empty(&video->req_free)) {
			spin_unlock_irqrestore(&video->req_lock, flags);
			return 0;
		}
		req = list_first_entry(&video->req_free, struct usb_request,
					list);
		list_del(&req->list);
		spin_unlock_irqrestore(&video->req_lock, flags);

		/*                                                       
                                                   
   */
		spin_lock_irqsave(&video->queue.irqlock, flags);
		buf = uvc_queue_head(&video->queue);
		if (buf == NULL) {
			spin_unlock_irqrestore(&video->queue.irqlock, flags);
			break;
		}

		video->encode(req, video, buf);

		/*                       */
		if ((ret = usb_ep_queue(video->ep, req, GFP_KERNEL)) < 0) {
			printk(KERN_INFO "Failed to queue request (%d)\n", ret);
			usb_ep_set_halt(video->ep);
			spin_unlock_irqrestore(&video->queue.irqlock, flags);
			break;
		}
		spin_unlock_irqrestore(&video->queue.irqlock, flags);
	}

	spin_lock_irqsave(&video->req_lock, flags);
	list_add_tail(&req->list, &video->req_free);
	spin_unlock_irqrestore(&video->req_lock, flags);
	return 0;
}
/*
 * uvc_video_pump - Pump video data into the USB requests
 *
 * This function fills the available USB requests (listed in req_free) with
 * video data from the queued buffers.
 */
static int
uvc_video_pump(struct uvc_video *video)
{
	struct usb_request *req;
	struct uvc_buffer *buf;
	unsigned long flags;
	int ret;

	/* FIXME TODO Race between uvc_video_pump and requests completion
	 * handler ???
	 */

	while (1) {
		/* Retrieve the first available USB request, protected by the
		 * request lock.
		 */
		spin_lock_irqsave(&video->req_lock, flags);
		if (list_empty(&video->req_free)) {
			spin_unlock_irqrestore(&video->req_lock, flags);
			return 0;
		}
		req = list_first_entry(&video->req_free, struct usb_request,
					list);
		list_del(&req->list);
		spin_unlock_irqrestore(&video->req_lock, flags);

		/* Retrieve the first available video buffer and fill the
		 * request, protected by the video queue irqlock.
		 */
		spin_lock_irqsave(&video->queue.irqlock, flags);
		buf = uvc_queue_head(&video->queue);
		if (buf == NULL) {
			spin_unlock_irqrestore(&video->queue.irqlock, flags);
			break;
		}

		video->encode(req, video, buf);

		/* Queue the USB request */
		if ((ret = usb_ep_queue(video->ep, req, GFP_KERNEL)) < 0) {
			printk(KERN_INFO "Failed to queue request (%d)\n", ret);
			usb_ep_set_halt(video->ep);
			spin_unlock_irqrestore(&video->queue.irqlock, flags);
			break;
		}
		spin_unlock_irqrestore(&video->queue.irqlock, flags);
	}

	spin_lock_irqsave(&video->req_lock, flags);
	list_add_tail(&req->list, &video->req_free);
	spin_unlock_irqrestore(&video->req_lock, flags);
	return 0;
}
static void
uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
{
	struct uvc_video *video = req->context;
	struct uvc_buffer *buf;
	unsigned long flags;
	int ret;

	switch (req->status) {
	case 0:
		break;

	case -ESHUTDOWN:
		printk(KERN_INFO "VS request cancelled.\n");
		goto requeue;

	default:
		printk(KERN_INFO "VS request completed with status %d.\n",
			req->status);
		goto requeue;
	}

	spin_lock_irqsave(&video->queue.irqlock, flags);
	buf = uvc_queue_head(&video->queue);
	if (buf == NULL) {
		spin_unlock_irqrestore(&video->queue.irqlock, flags);
		goto requeue;
	}

	video->encode(req, video, buf);

	if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) {
		printk(KERN_INFO "Failed to queue request (%d).\n", ret);
		usb_ep_set_halt(ep);
		spin_unlock_irqrestore(&video->queue.irqlock, flags);
		goto requeue;
	}
	spin_unlock_irqrestore(&video->queue.irqlock, flags);

	return;

requeue:
	spin_lock_irqsave(&video->req_lock, flags);
	list_add_tail(&req->list, &video->req_free);
	spin_unlock_irqrestore(&video->req_lock, flags);
}