Message ID | 20230508231103.1621375-1-arakesh@google.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp2508491vqo; Mon, 8 May 2023 16:56:59 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6BlzFKotLU132Fix9VQP5tvC3vCaZfkbEqqd0MXqz+NY3XFYXPP8vqdViawJ6ba9xIARmw X-Received: by 2002:a17:90b:4c8d:b0:250:9d96:9999 with SMTP id my13-20020a17090b4c8d00b002509d969999mr2647790pjb.27.1683590219421; Mon, 08 May 2023 16:56:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683590219; cv=none; d=google.com; s=arc-20160816; b=zHG7CIKx08tMW8l/Et/RhvKYIS+L2sxP80wWTr+AFJ2rEMV1jllAXO2B44OGuFTlJx ZbF5GrF/4Hqtfxkjir301llMyoa9NBpdYnhsa7Z6OlRjaqbW2fzSh57rmPbk+thUCiI7 e+oXJ1yNfC8PxRnAgG2L2TJrJr+Ok462+g16GpGzLOTfrIwkFa+trxiwWEpwZy/StIHt 0TY+fQFuJv95WZ2uF/uK06SCMdJK9AYi5FlXfWrPAnS3+VrGTjqcqPdhsmhP90GzT/Gl dPafY/EdPg5dMxcGgbizWMr28vhAOcjxfDWU6vIfhWw+HVvcLlGUMP5z1YK1XVUSZD6z 4YxA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:mime-version:date :dkim-signature; bh=+KHbWW8aLhrRbwJSnBa+NaTRCZqDMugAVxqQ48a5vrA=; b=mtBnDPZ7teSEycUtLyJUn4SVyIesCZ2M3HarhszM737ifZ+Lvj5m/4bvDmFVR6+Y5/ LeO0rCCWqvqXsD1qW9Y0rB10S+IKxMW6L3MvGDQyfLc+u416NtAweicDuCFptGmq9CcE DJDhg3mttd1u04oSTGeeOtkSEJGf3nvQoobWbYw7y8C5cD7V3Aek+CVPNazXMUOLSok+ D4jCMiQHcZTVwh7WZeTpz6ztLf2gK7xz5hvaQXwSHkVaJ1pxXklyuEg13nc7I3drSY61 1EMG3Nsgk72EI8pBbWMQotYFSmicX4W0aR/cnMf7w8pd21qGx8Z7b59egWJUvoo6Cw1J rD4g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=Ckjnqpvo; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id em13-20020a17090b014d00b0023a177c4951si15835713pjb.39.2023.05.08.16.56.46; Mon, 08 May 2023 16:56:59 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b=Ckjnqpvo; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233900AbjEHXLL (ORCPT <rfc822;jeantsuru.cumc.mandola@gmail.com> + 99 others); Mon, 8 May 2023 19:11:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42200 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234016AbjEHXLJ (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Mon, 8 May 2023 19:11:09 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2056C46AC for <linux-kernel@vger.kernel.org>; Mon, 8 May 2023 16:11:08 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-b9a6eeea78cso37489827276.0 for <linux-kernel@vger.kernel.org>; Mon, 08 May 2023 16:11:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1683587467; x=1686179467; h=cc:to:from:subject:message-id:mime-version:date:from:to:cc:subject :date:message-id:reply-to; bh=+KHbWW8aLhrRbwJSnBa+NaTRCZqDMugAVxqQ48a5vrA=; b=CkjnqpvoEfZTwHBSM/0dyupsDIBPF7IPLz0ISI7PYOrxbb5YGCHqcS8N0v1ZYLos5s ZtWoMSyGyNck58xxb4MlM7D9oeMpY0FMBEc1BB4KSMsLYewZ4bdbEkD4livoTWc5PyMn O6B6HPkIRROawPcob38VSK47JQ4hFYCRXn3/HKfzTm2sErrjX47RdPpxKRFPiEamuWVj dY0PNzDtDuNp4y+ZdO9x1a1jm8PI7Jl4Z50tbqGybTBauo0Ds/fKCExzX4fsh1G9Ky3M zud9d1MI+NzDEjmYLQsAx7fV9bJWoybJ0h2w+RKsLj2WC3dKJRNmET+kWSdQCNy3pj45 NCwQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683587467; x=1686179467; h=cc:to:from:subject:message-id:mime-version:date:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=+KHbWW8aLhrRbwJSnBa+NaTRCZqDMugAVxqQ48a5vrA=; b=GWegMLi5ZrrndnbSWHahaB+9Th3Ju0coVXgM7BmXAS0Ok8CTg3sF2mWxixNUj5XSSw TRXCjhiFPYU5gtg/o63+LTX59+d2e160WXgrHkVkw89ym7FJFYODsRFv9PYJQExloW+y hd9goy5WgcCPc81dgSC/LwjPiOKjnv6CzGDrpOk4g+y8/jc7eK3+efs/vMByWbm9nzmP H96V0qxmraWuPVsKeHFnPuS8+xvRqNlFGgAJlkAJ+yMD9rVqihIhx7ZMzN80lOtOpciF Vr6Zhvk/46na4obiZGd2Re1K/HGyvmBDdZ5Jq2yTW2x6W0UGrY0SXZDYD/EGE6lj0cId yGJQ== X-Gm-Message-State: AC+VfDxbRp0F/egqTGkzcY1AELfOfCNILEORYO2901jMH0f1jQ8Ymntn lfoH61cZstn2A1IeoSdFdm33tJF1+1Py X-Received: from hi-h2o-specialist.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:3cef]) (user=arakesh job=sendgmr) by 2002:a25:1283:0:b0:b9a:672d:23c9 with SMTP id 125-20020a251283000000b00b9a672d23c9mr7400472ybs.0.1683587467239; Mon, 08 May 2023 16:11:07 -0700 (PDT) Date: Mon, 8 May 2023 16:11:03 -0700 Mime-Version: 1.0 X-Mailer: git-send-email 2.40.1.521.gf1e218fcd8-goog Message-ID: <20230508231103.1621375-1-arakesh@google.com> Subject: [PATCH] usb: gadget: uvc: queue empty isoc requests if no video buffer is available From: Avichal Rakesh <arakesh@google.com> To: Laurent Pinchart <laurent.pinchart@ideasonboard.com>, Daniel Scally <dan.scally@ideasonboard.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: "Eino-Ville Talvala (Eddy)" <etalvala@google.com>, Jayant Chowdhary <jchowdhary@google.com>, Thinh Nguyen <Thinh.Nguyen@synopsys.com>, Alan Stern <stern@rowland.harvard.edu>, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Avichal Rakesh <arakesh@google.com> Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1765372297776090775?= X-GMAIL-MSGID: =?utf-8?q?1765372297776090775?= |
Series |
usb: gadget: uvc: queue empty isoc requests if no video buffer is available
|
|
Commit Message
Avichal Rakesh
May 8, 2023, 11:11 p.m. UTC
ISOC transfers expect a certain cadence of requests being queued. Not
keeping up with the expected rate of requests results in missed ISOC
transfers (EXDEV). The application layer may or may not produce video
frames to match this expectation, so uvc gadget driver must handle cases
where the application is not queuing up buffers fast enough to fulfill
ISOC requirements.
Currently, uvc gadget driver waits for new video buffer to become available
before queuing up usb requests. With this patch the gadget driver queues up
0 length usb requests whenever there are no video buffers available. The
USB controller's complete callback is used as the limiter for how quickly
the 0 length packets will be queued. Video buffers are still queued as
soon as they become available.
Link: https://lore.kernel.org/CAMHf4WKbi6KBPQztj9FA4kPvESc1fVKrC8G73-cs6tTeQby9=w@mail.gmail.com/
Signed-off-by: Avichal Rakesh <arakesh@google.com>
---
drivers/usb/gadget/function/uvc_video.c | 32 ++++++++++++++++++-------
1 file changed, 24 insertions(+), 8 deletions(-)
Comments
Hi Avichal, Thank you for the patch. On Mon, May 08, 2023 at 04:11:03PM -0700, Avichal Rakesh wrote: > ISOC transfers expect a certain cadence of requests being queued. Not > keeping up with the expected rate of requests results in missed ISOC > transfers (EXDEV). The application layer may or may not produce video > frames to match this expectation, so uvc gadget driver must handle cases > where the application is not queuing up buffers fast enough to fulfill > ISOC requirements. I think the application *must* not produce video frames to match the expectations. If it did, it would mean that it would either have to use more than the available ISOC bandwidth (which is obviously bad), or use *exactly* the ISOC bandwidth. Unless the application performs rate matching (which would require information about the USB timings that isn't available to userspace as far as I can tell), that's not possible. > Currently, uvc gadget driver waits for new video buffer to become available > before queuing up usb requests. With this patch the gadget driver queues up > 0 length usb requests whenever there are no video buffers available. The > USB controller's complete callback is used as the limiter for how quickly > the 0 length packets will be queued. Video buffers are still queued as > soon as they become available. > > Link: https://lore.kernel.org/CAMHf4WKbi6KBPQztj9FA4kPvESc1fVKrC8G73-cs6tTeQby9=w@mail.gmail.com/ > Signed-off-by: Avichal Rakesh <arakesh@google.com> > --- > drivers/usb/gadget/function/uvc_video.c | 32 ++++++++++++++++++------- > 1 file changed, 24 insertions(+), 8 deletions(-) > > diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c > index dd1c6b2ca7c6..e81865978299 100644 > --- a/drivers/usb/gadget/function/uvc_video.c > +++ b/drivers/usb/gadget/function/uvc_video.c > @@ -386,6 +386,9 @@ static void uvcg_video_pump(struct work_struct *work) > struct uvc_buffer *buf; > unsigned long flags; > int ret; > + bool buf_int; > + /* video->max_payload_size is only set when using bulk transfer */ > + bool is_bulk = video->max_payload_size; Let's rename buf_int to buf_done, that matches the intent of the code better. Could you reorder the fields by line length ? struct uvc_video *video = container_of(work, struct uvc_video, pump); struct uvc_video_queue *queue = &video->queue; /* video->max_payload_size is only set when using bulk transfer */ bool is_bulk = video->max_payload_size; struct usb_request *req = NULL; struct uvc_buffer *buf; unsigned long flags; bool buf_done; int ret; > > while (video->ep->enabled) { > /* > @@ -408,20 +411,35 @@ static void uvcg_video_pump(struct work_struct *work) > */ > spin_lock_irqsave(&queue->irqlock, flags); > buf = uvcg_queue_head(queue); > - if (buf == NULL) { > + > + if (buf != NULL) { > + video->encode(req, video, buf); > + /* Always interrupt for the last request of a video buffer */ I would drop this comment, and ... (see below) > + buf_int = buf->state == UVC_BUF_STATE_DONE; > + } else if (!(queue->flags & UVC_QUEUE_DISCONNECTED) && !is_bulk) { > + /* > + * No video buffer available; the queue is still connected and > + * we're traferring over ISOC. Queue a 0 length request to s/traferring/transferring/ > + * prevent missed ISOC transfers. > + */ > + req->length = 0; > + buf_int = false; > + } else { > + /* > + * Either queue has been disconnected or no video buffer s/Either queue/Either the queue/ > + * available to bulk transfer. Either way, stop processing s/to bulk/for bulk/ > + * further. > + */ > spin_unlock_irqrestore(&queue->irqlock, flags); > break; > } > > - video->encode(req, video, buf); > - > /* > * With usb3 we have more requests. This will decrease the > * interrupt load to a quarter but also catches the corner > * cases, which needs to be handled. > */ ... and expand this: /* * With USB3 handling more requests at a higher speed, we can't * afford to generate an interrupt for every request. Decide to * interrupt: * * - When no more requests are available in the free queue, as * this may be our last chance to refill the endpoint's * request queue. * * - When this is request is the last request for the video * buffer, as we want to start sending the next video buffer * ASAP in case it doesn't get started already in the next * iteration of this loop. * * - Four times over the length of the requests queue (as * indicated by video->uvc_num_requests), as a trade-off * between latency and interrupt load. */ And now that I've written this, I wonder if we could drop the second case. Now that we have a guarantee we will queue 0-length requests after the current buffer if no other buffer is available, I don't think we need to make the last request of a buffer a special case. It even seems to me that we could drop the first case too, and just interrupt 4 times over the length of the requests queue. What do you think ? > - if (list_empty(&video->req_free) || > - buf->state == UVC_BUF_STATE_DONE || > + if (list_empty(&video->req_free) || buf_int || > !(video->req_int_count % > DIV_ROUND_UP(video->uvc_num_requests, 4))) { > video->req_int_count = 0; > @@ -441,8 +459,7 @@ static void uvcg_video_pump(struct work_struct *work) > > /* Endpoint now owns the request */ > req = NULL; > - if (buf->state != UVC_BUF_STATE_DONE) > - video->req_int_count++; > + video->req_int_count++; > } > > if (!req) > @@ -527,4 +544,3 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) > V4L2_BUF_TYPE_VIDEO_OUTPUT, &video->mutex); > return 0; > } > -
On 6/2/23 08:19, Laurent Pinchart wrote: > Hi Avichal, > > Thank you for the patch. > > On Mon, May 08, 2023 at 04:11:03PM -0700, Avichal Rakesh wrote: >> ISOC transfers expect a certain cadence of requests being queued. Not >> keeping up with the expected rate of requests results in missed ISOC >> transfers (EXDEV). The application layer may or may not produce video >> frames to match this expectation, so uvc gadget driver must handle cases >> where the application is not queuing up buffers fast enough to fulfill >> ISOC requirements. > > I think the application *must* not produce video frames to match the > expectations. If it did, it would mean that it would either have to use > more than the available ISOC bandwidth (which is obviously bad), or use > *exactly* the ISOC bandwidth. Unless the application performs rate > matching (which would require information about the USB timings that > isn't available to userspace as far as I can tell), that's not possible. Ah, that is a good point. This makes it sound like the userspace application is responsible for maintaining the cadence, which is false. Tweaked the language to (hopefully) sound less blame-y. > >> Currently, uvc gadget driver waits for new video buffer to become available >> before queuing up usb requests. With this patch the gadget driver queues up >> 0 length usb requests whenever there are no video buffers available. The >> USB controller's complete callback is used as the limiter for how quickly >> the 0 length packets will be queued. Video buffers are still queued as >> soon as they become available. >> >> Link: https://lore.kernel.org/CAMHf4WKbi6KBPQztj9FA4kPvESc1fVKrC8G73-cs6tTeQby9=w@mail.gmail.com/ >> Signed-off-by: Avichal Rakesh <arakesh@google.com> >> --- >> drivers/usb/gadget/function/uvc_video.c | 32 ++++++++++++++++++------- >> 1 file changed, 24 insertions(+), 8 deletions(-) >> >> diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c >> index dd1c6b2ca7c6..e81865978299 100644 >> --- a/drivers/usb/gadget/function/uvc_video.c >> +++ b/drivers/usb/gadget/function/uvc_video.c >> @@ -386,6 +386,9 @@ static void uvcg_video_pump(struct work_struct *work) >> struct uvc_buffer *buf; >> unsigned long flags; >> int ret; >> + bool buf_int; >> + /* video->max_payload_size is only set when using bulk transfer */ >> + bool is_bulk = video->max_payload_size; > > Let's rename buf_int to buf_done, that matches the intent of the code > better. > > Could you reorder the fields by line length ? > > struct uvc_video *video = container_of(work, struct uvc_video, pump); > struct uvc_video_queue *queue = &video->queue; > /* video->max_payload_size is only set when using bulk transfer */ > bool is_bulk = video->max_payload_size; > struct usb_request *req = NULL; > struct uvc_buffer *buf; > unsigned long flags; > bool buf_done; > int ret; > >> >> while (video->ep->enabled) { >> /* >> @@ -408,20 +411,35 @@ static void uvcg_video_pump(struct work_struct *work) >> */ >> spin_lock_irqsave(&queue->irqlock, flags); >> buf = uvcg_queue_head(queue); >> - if (buf == NULL) { >> + >> + if (buf != NULL) { >> + video->encode(req, video, buf); >> + /* Always interrupt for the last request of a video buffer */ > > I would drop this comment, and ... (see below) > >> + buf_int = buf->state == UVC_BUF_STATE_DONE; >> + } else if (!(queue->flags & UVC_QUEUE_DISCONNECTED) && !is_bulk) { >> + /* >> + * No video buffer available; the queue is still connected and >> + * we're traferring over ISOC. Queue a 0 length request to > > s/traferring/transferring/ > >> + * prevent missed ISOC transfers. >> + */ >> + req->length = 0; >> + buf_int = false; >> + } else { >> + /* >> + * Either queue has been disconnected or no video buffer > > s/Either queue/Either the queue/ > >> + * available to bulk transfer. Either way, stop processing > > s/to bulk/for bulk/ > >> + * further. >> + */ >> spin_unlock_irqrestore(&queue->irqlock, flags); >> break; >> } >> >> - video->encode(req, video, buf); >> - >> /* >> * With usb3 we have more requests. This will decrease the >> * interrupt load to a quarter but also catches the corner >> * cases, which needs to be handled. >> */ > > ... and expand this: > > /* > * With USB3 handling more requests at a higher speed, we can't > * afford to generate an interrupt for every request. Decide to > * interrupt: > * > * - When no more requests are available in the free queue, as > * this may be our last chance to refill the endpoint's > * request queue. > * > * - When this is request is the last request for the video > * buffer, as we want to start sending the next video buffer > * ASAP in case it doesn't get started already in the next > * iteration of this loop. > * > * - Four times over the length of the requests queue (as > * indicated by video->uvc_num_requests), as a trade-off > * between latency and interrupt load. > */ > > And now that I've written this, I wonder if we could drop the second > case. Now that we have a guarantee we will queue 0-length requests after > the current buffer if no other buffer is available, I don't think we > need to make the last request of a buffer a special case. It even seems > to me that we could drop the first case too, and just interrupt 4 times > over the length of the requests queue. What do you think ? The complete callback of the last request for a buffer is used to return the buffer back to the vb2 framework, which could in the worst case get delayed by 15 requests. This is probably not a functional issue, as we already see system latencies far greater than the 2ms that would occur from those 15 requests, but I think it is a good invariant to have to try and minimize any latency jitters when interacting with the userspace application. On the other hand, removing it does make the code much simpler, so if you feel strongly about it, I am happy to drop the second case. > >> - if (list_empty(&video->req_free) || >> - buf->state == UVC_BUF_STATE_DONE || >> + if (list_empty(&video->req_free) || buf_int || >> !(video->req_int_count % >> DIV_ROUND_UP(video->uvc_num_requests, 4))) { >> video->req_int_count = 0; >> @@ -441,8 +459,7 @@ static void uvcg_video_pump(struct work_struct *work) >> >> /* Endpoint now owns the request */ >> req = NULL; >> - if (buf->state != UVC_BUF_STATE_DONE) >> - video->req_int_count++; >> + video->req_int_count++; >> } >> >> if (!req) >> @@ -527,4 +544,3 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) >> V4L2_BUF_TYPE_VIDEO_OUTPUT, &video->mutex); >> return 0; >> } >> - > Thank you for the review, sent out a v2 with the comments addressed! - Avi.
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index dd1c6b2ca7c6..e81865978299 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -386,6 +386,9 @@ static void uvcg_video_pump(struct work_struct *work) struct uvc_buffer *buf; unsigned long flags; int ret; + bool buf_int; + /* video->max_payload_size is only set when using bulk transfer */ + bool is_bulk = video->max_payload_size; while (video->ep->enabled) { /* @@ -408,20 +411,35 @@ static void uvcg_video_pump(struct work_struct *work) */ spin_lock_irqsave(&queue->irqlock, flags); buf = uvcg_queue_head(queue); - if (buf == NULL) { + + if (buf != NULL) { + video->encode(req, video, buf); + /* Always interrupt for the last request of a video buffer */ + buf_int = buf->state == UVC_BUF_STATE_DONE; + } else if (!(queue->flags & UVC_QUEUE_DISCONNECTED) && !is_bulk) { + /* + * No video buffer available; the queue is still connected and + * we're traferring over ISOC. Queue a 0 length request to + * prevent missed ISOC transfers. + */ + req->length = 0; + buf_int = false; + } else { + /* + * Either queue has been disconnected or no video buffer + * available to bulk transfer. Either way, stop processing + * further. + */ spin_unlock_irqrestore(&queue->irqlock, flags); break; } - video->encode(req, video, buf); - /* * With usb3 we have more requests. This will decrease the * interrupt load to a quarter but also catches the corner * cases, which needs to be handled. */ - if (list_empty(&video->req_free) || - buf->state == UVC_BUF_STATE_DONE || + if (list_empty(&video->req_free) || buf_int || !(video->req_int_count % DIV_ROUND_UP(video->uvc_num_requests, 4))) { video->req_int_count = 0; @@ -441,8 +459,7 @@ static void uvcg_video_pump(struct work_struct *work) /* Endpoint now owns the request */ req = NULL; - if (buf->state != UVC_BUF_STATE_DONE) - video->req_int_count++; + video->req_int_count++; } if (!req) @@ -527,4 +544,3 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) V4L2_BUF_TYPE_VIDEO_OUTPUT, &video->mutex); return 0; } -