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); }