With this patch, the dummy_hcd gains first support for isoc transfers. It will complete the whole urb with all packages. Even if the gadget side did not enqueue any request, the urb will be handled. Signed-off-by: Michael Grzeschik <m.grzeschik@xxxxxxxxxxxxxx> --- With this patch it is possible to test the series [1] on any device using the uvc-gadget code [2]. I added some patches on top of uvc-gadget to prove that it is now possible to completely remove the configfs parsing and DATA/SETUP event handling from userspace [3]. To test the gadget, just fill the uvc configfs setup with some script [4] or even use the modern (but optional) way with gt (gadget-tool) [5] including libusbgx (uvc/configfs) [6] support and a scheme file describing the gadget. [1] https://lore.kernel.org/linux-usb/20220105115527.3592860-1-m.grzeschik@xxxxxxxxxxxxxx/ [2] https://git.ideasonboard.org/uvc-gadget.git [3] https://git.pengutronix.de/cgit/mgr/uvc-gadget/log/?h=ml [4] https://git.ideasonboard.org/uvc-gadget.git/blob/HEAD:/scripts/uvc-gadget.sh [5] https://github.com/linux-usb-gadgets/libusbgx [6] https://github.com/linux-usb-gadgets/gt drivers/usb/gadget/udc/dummy_hcd.c | 34 +++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index a2d956af42a23c..aff5f1fa4feef9 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -147,36 +147,30 @@ static const struct { USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), EP_INFO("ep2out-bulk", USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), -/* EP_INFO("ep3in-iso", USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), EP_INFO("ep4out-iso", USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), -*/ EP_INFO("ep5in-int", USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), EP_INFO("ep6in-bulk", USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), EP_INFO("ep7out-bulk", USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), -/* EP_INFO("ep8in-iso", USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), EP_INFO("ep9out-iso", USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), -*/ EP_INFO("ep10in-int", USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), EP_INFO("ep11in-bulk", USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), EP_INFO("ep12out-bulk", USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), -/* EP_INFO("ep13in-iso", USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), EP_INFO("ep14out-iso", USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), -*/ EP_INFO("ep15in-int", USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), @@ -1402,6 +1396,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, struct dummy *dum = dum_hcd->dum; struct dummy_request *req; int sent = 0; + int count = 0; top: /* if there's no request queued, the device is NAKing; return */ @@ -1459,6 +1454,13 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, sent += len; urb->actual_length += len; req->req.actual += len; + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + if (count <= urb->number_of_packets) { + urb->iso_frame_desc[count].actual_length = len; + urb->iso_frame_desc[count].status = 0; + count++; + } + } } } @@ -1527,6 +1529,17 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, if (rescan) goto top; } + + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + int i; + + for (i = count; i < urb->number_of_packets; ++i) { + urb->iso_frame_desc[i].actual_length = 0; + urb->iso_frame_desc[i].status = 0; + } + *status = 0; + } + return sent; } @@ -1950,13 +1963,14 @@ static void dummy_timer(struct timer_list *t) * here are some of the issues we'd have to face: * * Is it urb->interval since the last xfer? - * Use urb->iso_frame_desc[i]. - * Complete whether or not ep has requests queued. * Report random errors, to debug drivers. */ limit = max(limit, periodic_bytes(dum, ep)); - status = -EINVAL; /* fail all xfers */ - break; + ep->last_io = jiffies; + total -= transfer(dum_hcd, urb, ep, limit, &status); + if (status == -EINPROGRESS) + continue; + goto return_urb; case PIPE_INTERRUPT: /* FIXME is it urb->interval since the last xfer? -- 2.30.2