From 4f731aad272daa2f3d9eb51ecdfabce8b1271b49 Mon Sep 17 00:00:00 2001 From: mpi Date: Thu, 22 Jan 2015 10:27:47 +0000 Subject: [PATCH] Reduce the number of intermediate buffers by pre-allocating DMA buffers in the report functions instead of letting the stack do it magically for us. Reviewed and tested by David Higgs, thanks! --- sys/dev/usb/uhidev.c | 73 +++++++++++++++++++++++++------------------- sys/dev/usb/usbdi.c | 32 ++++++++++--------- sys/dev/usb/usbdi.h | 6 ++-- 3 files changed, 61 insertions(+), 50 deletions(-) diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c index 46ca3e52b02..27e1e60de68 100644 --- a/sys/dev/usb/uhidev.c +++ b/sys/dev/usb/uhidev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uhidev.c,v 1.68 2015/01/09 12:09:51 mpi Exp $ */ +/* $OpenBSD: uhidev.c,v 1.69 2015/01/22 10:27:47 mpi Exp $ */ /* $NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $ */ /* @@ -671,18 +671,30 @@ int uhidev_set_report_async(struct uhidev_softc *sc, int type, int id, void *data, int len) { + struct usbd_xfer *xfer; usb_device_request_t req; - char *buf = data; int actlen = len; + char *buf; + + xfer = usbd_alloc_xfer(sc->sc_udev); + if (xfer == NULL) + return (-1); + + if (id > 0) + len++; + + buf = usbd_alloc_buffer(xfer, len); + if (buf == NULL) { + usbd_free_xfer(xfer); + return (-1); + } /* Prepend the reportID. */ if (id > 0) { - len++; - buf = malloc(len, M_TEMP, M_NOWAIT); - if (buf == NULL) - return (-1); buf[0] = id; memcpy(buf + 1, data, len - 1); + } else { + memcpy(buf, data, len); } req.bmRequestType = UT_WRITE_CLASS_INTERFACE; @@ -691,17 +703,9 @@ uhidev_set_report_async(struct uhidev_softc *sc, int type, int id, void *data, USETW(req.wIndex, sc->sc_ifaceno); USETW(req.wLength, len); - if (usbd_do_request_async(sc->sc_udev, &req, buf, NULL, NULL)) + if (usbd_request_async(xfer, &req, NULL, NULL)) actlen = -1; - /* - * Since report requests are write-only it is safe to free - * the buffer right after submitting the transfer because - * it won't be used afterward. - */ - if (id > 0) - free(buf, M_TEMP, len); - return (actlen); } @@ -750,11 +754,11 @@ uhidev_get_report_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status err) if (info->id > 0) { len--; memcpy(info->data, xfer->buffer + 1, len); + } else { + memcpy(info->data, xfer->buffer, len); } } info->callback(info->priv, info->id, info->data, len); - if (info->id > 0) - free(xfer->buffer, M_TEMP, xfer->length); free(info, M_TEMP, sizeof(*info)); usbd_free_xfer(xfer); } @@ -763,42 +767,47 @@ int uhidev_get_report_async(struct uhidev_softc *sc, int type, int id, void *data, int len, void *priv, void (*callback)(void *, int, void *, int)) { + struct usbd_xfer *xfer; usb_device_request_t req; struct uhidev_async_info *info; - char *buf = data; int actlen = len; + char *buf; + + xfer = usbd_alloc_xfer(sc->sc_udev); + if (xfer == NULL) + return (-1); + + if (id > 0) + len++; + + buf = usbd_alloc_buffer(xfer, len); + if (buf == NULL) { + usbd_free_xfer(xfer); + return (-1); + } info = malloc(sizeof(*info), M_TEMP, M_NOWAIT); - if (info == NULL) + if (info == NULL) { + usbd_free_xfer(xfer); return (-1); + } info->callback = callback; info->priv = priv; info->data = data; info->id = id; - if (id > 0) { - len++; - buf = malloc(len, M_TEMP, M_NOWAIT|M_ZERO); - if (buf == NULL) { - free(info, M_TEMP, sizeof(*info)); - return (-1); - } - } - req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UR_GET_REPORT; USETW2(req.wValue, type, id); USETW(req.wIndex, sc->sc_ifaceno); USETW(req.wLength, len); - if (usbd_do_request_async(sc->sc_udev, &req, buf, priv, - uhidev_get_report_async_cb)) { + if (usbd_request_async(xfer, &req, priv, uhidev_get_report_async_cb)) { free(info, M_TEMP, sizeof(*info)); - if (id > 0) - free(buf, M_TEMP, len); actlen = -1; } + return (actlen); } diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c index 7db61f201c0..e203b7e742d 100644 --- a/sys/dev/usb/usbdi.c +++ b/sys/dev/usb/usbdi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: usbdi.c,v 1.78 2015/01/11 15:41:16 mpi Exp $ */ +/* $OpenBSD: usbdi.c,v 1.79 2015/01/22 10:27:47 mpi Exp $ */ /* $NetBSD: usbdi.c,v 1.103 2002/09/27 15:37:38 provos Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbdi.c,v 1.28 1999/11/17 22:33:49 n_hibma Exp $ */ @@ -55,8 +55,7 @@ extern int usbdebug; #define DPRINTFN(n,x) #endif -void usbd_do_request_async_cb(struct usbd_xfer *, void *, - usbd_status); +void usbd_request_async_cb(struct usbd_xfer *, void *, usbd_status); void usbd_start_next(struct usbd_pipe *pipe); usbd_status usbd_open_pipe_ival(struct usbd_interface *, u_int8_t, u_int8_t, struct usbd_pipe **, int); @@ -586,6 +585,7 @@ usbd_status usbd_clear_endpoint_stall_async(struct usbd_pipe *pipe) { struct usbd_device *dev = pipe->device; + struct usbd_xfer *xfer; usb_device_request_t req; usbd_status err; @@ -596,7 +596,12 @@ usbd_clear_endpoint_stall_async(struct usbd_pipe *pipe) USETW(req.wValue, UF_ENDPOINT_HALT); USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); USETW(req.wLength, 0); - err = usbd_do_request_async(dev, &req, 0, 0, 0); + + xfer = usbd_alloc_xfer(dev); + if (xfer == NULL) + return (USBD_NOMEM); + + err = usbd_request_async(xfer, &req, NULL, NULL); return (err); } @@ -949,8 +954,7 @@ usbd_do_request_flags(struct usbd_device *dev, usb_device_request_t *req, } void -usbd_do_request_async_cb(struct usbd_xfer *xfer, void *priv, - usbd_status status) +usbd_request_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status status) { usbd_free_xfer(xfer); } @@ -960,19 +964,17 @@ usbd_do_request_async_cb(struct usbd_xfer *xfer, void *priv, * Can be used from interrupt context. */ usbd_status -usbd_do_request_async(struct usbd_device *dev, usb_device_request_t *req, - void *data, void *priv, usbd_callback callback) +usbd_request_async(struct usbd_xfer *xfer, usb_device_request_t *req, + void *priv, usbd_callback callback) { - struct usbd_xfer *xfer; usbd_status err; - xfer = usbd_alloc_xfer(dev); - if (xfer == NULL) - return (USBD_NOMEM); if (callback == NULL) - callback = usbd_do_request_async_cb; - usbd_setup_default_xfer(xfer, dev, priv, USBD_DEFAULT_TIMEOUT, req, - data, UGETW(req->wLength), 0, callback); + callback = usbd_request_async_cb; + + usbd_setup_default_xfer(xfer, xfer->device, priv, + USBD_DEFAULT_TIMEOUT, req, NULL, UGETW(req->wLength), + USBD_NO_COPY, callback); err = usbd_transfer(xfer); if (err != USBD_IN_PROGRESS) { usbd_free_xfer(xfer); diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index b91697b2fc8..336191da5be 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usbdi.h,v 1.64 2015/01/09 12:07:50 mpi Exp $ */ +/* $OpenBSD: usbdi.h,v 1.65 2015/01/22 10:27:47 mpi Exp $ */ /* $NetBSD: usbdi.h,v 1.62 2002/07/11 21:14:35 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $ */ @@ -121,8 +121,8 @@ usbd_status usbd_open_pipe_intr(struct usbd_interface *iface, u_int8_t address, void *buffer, u_int32_t length, usbd_callback, int); usbd_status usbd_do_request(struct usbd_device *pipe, usb_device_request_t *req, void *data); -usbd_status usbd_do_request_async(struct usbd_device *pipe, - usb_device_request_t *req, void *data, void *priv, usbd_callback callback); +usbd_status usbd_request_async(struct usbd_xfer *xfer, + usb_device_request_t *req, void *priv, usbd_callback callback); usbd_status usbd_do_request_flags(struct usbd_device *pipe, usb_device_request_t *req, void *data, u_int16_t flags, int*, u_int32_t); usb_interface_descriptor_t *usbd_get_interface_descriptor( -- 2.20.1