summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/gadget/function/uvc.h5
-rw-r--r--drivers/usb/gadget/function/uvc_video.c17
2 files changed, 21 insertions, 1 deletions
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index cb35687b11e7..55d796f5f5e8 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -71,6 +71,9 @@ extern unsigned int uvc_gadget_trace_param;
#define UVCG_REQUEST_HEADER_LEN 12
+#define UVCG_REQ_MAX_INT_COUNT 16
+#define UVCG_REQ_MAX_ZERO_COUNT (2 * UVCG_REQ_MAX_INT_COUNT)
+
/* ------------------------------------------------------------------------
* Structures
*/
@@ -91,6 +94,8 @@ struct uvc_video {
struct work_struct pump;
struct workqueue_struct *async_wq;
+ atomic_t queued;
+
/* Frame parameters */
u8 bpp;
u32 fcc;
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index 002bf724d802..c041873cf856 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -269,6 +269,8 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
}
}
+ atomic_inc(&video->queued);
+
return ret;
}
@@ -304,7 +306,7 @@ static int uvcg_video_usb_req_queue(struct uvc_video *video,
*/
if (list_empty(&video->req_free) || ureq->last_buf ||
!(video->req_int_count %
- DIV_ROUND_UP(video->uvc_num_requests, 4))) {
+ min(DIV_ROUND_UP(video->uvc_num_requests, 4), UVCG_REQ_MAX_INT_COUNT))) {
video->req_int_count = 0;
req->no_interrupt = 0;
} else {
@@ -379,6 +381,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
int ret = 0;
spin_lock_irqsave(&video->req_lock, flags);
+ atomic_dec(&video->queued);
if (!video->is_enabled) {
/*
* When is_enabled is false, uvcg_video_disable() ensures
@@ -466,6 +469,16 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
* happen.
*/
queue_work(video->async_wq, &video->pump);
+ } else if (atomic_read(&video->queued) > UVCG_REQ_MAX_ZERO_COUNT) {
+ list_add_tail(&to_queue->list, &video->req_free);
+ /*
+ * There is a new free request - wake up the pump.
+ */
+ queue_work(video->async_wq, &video->pump);
+
+ spin_unlock_irqrestore(&video->req_lock, flags);
+
+ return;
}
/*
* Queue to the endpoint. The actual queueing to ep will
@@ -756,6 +769,8 @@ int uvcg_video_enable(struct uvc_video *video)
video->req_int_count = 0;
+ atomic_set(&video->queued, 0);
+
uvc_video_ep_queue_initial_requests(video);
queue_work(video->async_wq, &video->pump);