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: