Commit 58da4e57 authored by Michael Grzeschik's avatar Michael Grzeschik Committed by Greg Kroah-Hartman

usb: gadget: uvc: rework complete handler

We refactor the complete handler since the return path with the
locking are really difficult to follow. Just simplify the function by
switching the logic return it on an disabled endpoint early. This way
the second level of indentation can be removed.
Signed-off-by: default avatarMichael Grzeschik <m.grzeschik@pengutronix.de>
Link: https://lore.kernel.org/r/20240214-uvc-gadget-cleanup-v1-3-de6d78780459@pengutronix.deSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5e7ea65d
...@@ -370,6 +370,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -370,6 +370,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
struct uvc_video *video = ureq->video; struct uvc_video *video = ureq->video;
struct uvc_video_queue *queue = &video->queue; struct uvc_video_queue *queue = &video->queue;
struct uvc_buffer *last_buf; struct uvc_buffer *last_buf;
struct usb_request *to_queue = req;
unsigned long flags; unsigned long flags;
bool is_bulk = video->max_payload_size; bool is_bulk = video->max_payload_size;
int ret = 0; int ret = 0;
...@@ -425,59 +426,59 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -425,59 +426,59 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
* we're still streaming before queueing the usb_request * we're still streaming before queueing the usb_request
* back to req_free * back to req_free
*/ */
if (video->is_enabled) { if (!video->is_enabled) {
uvc_video_free_request(ureq, ep);
spin_unlock_irqrestore(&video->req_lock, flags);
uvcg_queue_cancel(queue, 0);
return;
}
/*
* Here we check whether any request is available in the ready
* list. If it is, queue it to the ep and add the current
* usb_request to the req_free list - for video_pump to fill in.
* Otherwise, just use the current usb_request to queue a 0
* length request to the ep. Since we always add to the req_free
* list if we dequeue from the ready list, there will never
* be a situation where the req_free list is completely out of
* requests and cannot recover.
*/
to_queue->length = 0;
if (!list_empty(&video->req_ready)) {
to_queue = list_first_entry(&video->req_ready,
struct usb_request, list);
list_del(&to_queue->list);
list_add_tail(&req->list, &video->req_free);
/* /*
* Here we check whether any request is available in the ready * Queue work to the wq as well since it is possible that a
* list. If it is, queue it to the ep and add the current * buffer may not have been completely encoded with the set of
* usb_request to the req_free list - for video_pump to fill in. * in-flight usb requests for whih the complete callbacks are
* Otherwise, just use the current usb_request to queue a 0 * firing.
* length request to the ep. Since we always add to the req_free * In that case, if we do not queue work to the worker thread,
* list if we dequeue from the ready list, there will never * the buffer will never be marked as complete - and therefore
* be a situation where the req_free list is completely out of * not be returned to userpsace. As a result,
* requests and cannot recover. * dequeue -> queue -> dequeue flow of uvc buffers will not
* happen.
*/ */
struct usb_request *to_queue = req; queue_work(video->async_wq, &video->pump);
}
to_queue->length = 0; /*
if (!list_empty(&video->req_ready)) { * Queue to the endpoint. The actual queueing to ep will
to_queue = list_first_entry(&video->req_ready, * only happen on one thread - the async_wq for bulk endpoints
struct usb_request, list); * and this thread for isoc endpoints.
list_del(&to_queue->list); */
list_add_tail(&req->list, &video->req_free); ret = uvcg_video_usb_req_queue(video, to_queue, !is_bulk);
/* if (ret < 0) {
* Queue work to the wq as well since it is possible that a
* buffer may not have been completely encoded with the set of
* in-flight usb requests for whih the complete callbacks are
* firing.
* In that case, if we do not queue work to the worker thread,
* the buffer will never be marked as complete - and therefore
* not be returned to userpsace. As a result,
* dequeue -> queue -> dequeue flow of uvc buffers will not
* happen.
*/
queue_work(video->async_wq, &video->pump);
}
/* /*
* Queue to the endpoint. The actual queueing to ep will * Endpoint error, but the stream is still enabled.
* only happen on one thread - the async_wq for bulk endpoints * Put request back in req_free for it to be cleaned
* and this thread for isoc endpoints. * up later.
*/ */
ret = uvcg_video_usb_req_queue(video, to_queue, !is_bulk); list_add_tail(&to_queue->list, &video->req_free);
if (ret < 0) {
/*
* Endpoint error, but the stream is still enabled.
* Put request back in req_free for it to be cleaned
* up later.
*/
list_add_tail(&to_queue->list, &video->req_free);
}
} else {
uvc_video_free_request(ureq, ep);
ret = 0;
} }
spin_unlock_irqrestore(&video->req_lock, flags); spin_unlock_irqrestore(&video->req_lock, flags);
if (ret < 0)
uvcg_queue_cancel(queue, 0);
} }
static int static int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment