Hi,

In ugen(4), bulk reads of length > UGEN_BBSIZE are split into
multiple transfers.  This patch instead sends a single
transfer utilizing USBD_NO_COPY.

Grant

Index: ugen.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ugen.c,v
retrieving revision 1.85
diff -u -p -d -r1.85 ugen.c
--- ugen.c      10 Jul 2015 15:45:57 -0000      1.85
+++ ugen.c      1 Sep 2015 22:22:37 -0000
@@ -469,7 +469,7 @@ ugen_do_read(struct ugen_softc *sc, int 
 {
        struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
        u_int32_t n, tn;
-       char buf[UGEN_BBSIZE];
+       void *buf = 0;
        struct usbd_xfer *xfer;
        usbd_status err;
        int s;
@@ -541,14 +541,19 @@ ugen_do_read(struct ugen_softc *sc, int 
                xfer = usbd_alloc_xfer(sc->sc_udev);
                if (xfer == 0)
                        return (ENOMEM);
-               flags = USBD_SYNCHRONOUS;
+               flags = USBD_SYNCHRONOUS | USBD_NO_COPY;
                if (sce->state & UGEN_SHORT_OK)
                        flags |= USBD_SHORT_XFER_OK;
                if (sce->timeout == 0)
                        flags |= USBD_CATCH;
-               while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
+               if ((n = uio->uio_resid) != 0) {
+                       buf = usbd_alloc_buffer(xfer, n);
+                       if (buf == 0) {
+                               error = ENOMEM;
+                               goto end;
+                       }
                        DPRINTFN(1, ("ugenread: start transfer %d bytes\n",n));
-                       usbd_setup_xfer(xfer, sce->pipeh, 0, buf, n,
+                       usbd_setup_xfer(xfer, sce->pipeh, 0, NULL, n,
                            flags, sce->timeout, NULL);
                        err = usbd_transfer(xfer);
                        if (err) {
@@ -559,14 +564,13 @@ ugen_do_read(struct ugen_softc *sc, int 
                                        error = ETIMEDOUT;
                                else
                                        error = EIO;
-                               break;
+                               goto end;
                        }
                        usbd_get_xfer_status(xfer, NULL, NULL, &tn, NULL);
                        DPRINTFN(1, ("ugenread: got %d bytes\n", tn));
                        error = uiomovei(buf, tn, uio);
-                       if (error || tn < n)
-                               break;
                }
+       end:
                usbd_free_xfer(xfer);
                break;
        case UE_ISOCHRONOUS:

Reply via email to