diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2018-05-16 08:20:01 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2018-05-16 08:20:01 +0000 |
commit | e21428954dd958af48f88b8678d0564c32bd8541 (patch) | |
tree | 377508e361f3bcbf3bb4b5abcbe5bb84f013a124 /sys/dev/usb | |
parent | 60489abfc15051f9141be0abff32d05c384f9ebf (diff) |
Implement a BCDC control packet mechanism based on the command request
ids. So far we were only able to have one command in flight at a time
and race conditions could easily lead to unexpected behaviour, especia-
lly combined with a slow bus and timeouts. With this rework we send or
enqueue a control packet command and wait for replies to happen. Thus
we can have multiple control packets in flight and a reply with the
correct id will wake us up.
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/if_bwfm_usb.c | 112 |
1 files changed, 65 insertions, 47 deletions
diff --git a/sys/dev/usb/if_bwfm_usb.c b/sys/dev/usb/if_bwfm_usb.c index 42e5623d9d8..99b1f0122cc 100644 --- a/sys/dev/usb/if_bwfm_usb.c +++ b/sys/dev/usb/if_bwfm_usb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bwfm_usb.c,v 1.11 2018/02/11 05:13:07 patrick Exp $ */ +/* $OpenBSD: if_bwfm_usb.c,v 1.12 2018/05/16 08:20:00 patrick Exp $ */ /* * Copyright (c) 2010-2016 Broadcom Corporation * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se> @@ -45,6 +45,7 @@ #include <dev/usb/usbdi.h> #include <dev/usb/usbdi_util.h> #include <dev/usb/usbdivar.h> +#include <dev/usb/usb_mem.h> #include <dev/usb/usbdevs.h> #include <dev/ic/bwfmvar.h> @@ -198,8 +199,8 @@ void bwfm_usb_free_tx_list(struct bwfm_usb_softc *); int bwfm_usb_txcheck(struct bwfm_softc *); int bwfm_usb_txdata(struct bwfm_softc *, struct mbuf *); -int bwfm_usb_txctl(struct bwfm_softc *, char *, size_t); -int bwfm_usb_rxctl(struct bwfm_softc *, char *, size_t *); +int bwfm_usb_txctl(struct bwfm_softc *); +void bwfm_usb_txctl_cb(struct usbd_xfer *, void *, usbd_status); struct mbuf * bwfm_usb_newbuf(void); void bwfm_usb_rxeof(struct usbd_xfer *, void *, usbd_status); @@ -211,7 +212,6 @@ struct bwfm_bus_ops bwfm_usb_bus_ops = { .bs_txcheck = bwfm_usb_txcheck, .bs_txdata = bwfm_usb_txdata, .bs_txctl = bwfm_usb_txctl, - .bs_rxctl = bwfm_usb_rxctl, }; struct cfattach bwfm_usb_ca = { @@ -779,67 +779,85 @@ bwfm_usb_txdata(struct bwfm_softc *bwfm, struct mbuf *m) } int -bwfm_usb_txctl(struct bwfm_softc *bwfm, char *buf, size_t len) +bwfm_usb_txctl(struct bwfm_softc *bwfm) { struct bwfm_usb_softc *sc = (void *)bwfm; + struct bwfm_proto_bcdc_ctl *ctl, *tmp; usb_device_request_t req; + struct usbd_xfer *xfer; usbd_status error; - int ret = 1; + char *buf; DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); - req.bmRequestType = UT_WRITE_CLASS_INTERFACE; - req.bRequest = 0; + TAILQ_FOREACH_SAFE(ctl, &sc->sc_sc.sc_bcdc_txctlq, next, tmp) { + TAILQ_REMOVE(&sc->sc_sc.sc_bcdc_txctlq, ctl, next); - USETW(req.wValue, 0); - USETW(req.wIndex, sc->sc_ifaceno); - USETW(req.wLength, len); + /* Send out control packet. */ + req.bmRequestType = UT_WRITE_CLASS_INTERFACE; + req.bRequest = 0; + USETW(req.wValue, 0); + USETW(req.wIndex, sc->sc_ifaceno); + USETW(req.wLength, ctl->len); - error = usbd_do_request(sc->sc_udev, &req, buf); - if (error != 0) { - printf("%s: could not read ctl packet: %s\n", - DEVNAME(sc), usbd_errstr(error)); - goto err; - } + error = usbd_do_request(sc->sc_udev, &req, ctl->buf); + if (error != 0) { + printf("%s: could not write ctl packet: %s\n", + DEVNAME(sc), usbd_errstr(error)); + free(ctl->buf, M_TEMP, ctl->len); + free(ctl, M_TEMP, sizeof(*ctl)); + return 1; + } - ret = 0; -err: - return ret; -} + /* Setup asynchronous receive. */ + if ((xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) { + free(ctl->buf, M_TEMP, ctl->len); + free(ctl, M_TEMP, sizeof(*ctl)); + return 1; + } + if ((buf = usbd_alloc_buffer(xfer, ctl->len)) == NULL) { + free(ctl, M_TEMP, sizeof(*ctl)); + free(ctl->buf, M_TEMP, ctl->len); + usbd_free_xfer(xfer); + return 1; + } -int -bwfm_usb_rxctl(struct bwfm_softc *bwfm, char *buf, size_t *len) -{ - struct bwfm_usb_softc *sc = (void *)bwfm; - usb_device_request_t req; - usbd_status error; - uint32_t len32; - int ret = 1; + memset(buf, 0, ctl->len); + req.bmRequestType = UT_READ_CLASS_INTERFACE; + req.bRequest = 1; + USETW(req.wValue, 0); + USETW(req.wIndex, sc->sc_ifaceno); + USETW(req.wLength, ctl->len); - DPRINTFN(2, ("%s: %s\n", DEVNAME(sc), __func__)); + error = usbd_request_async(xfer, &req, sc, bwfm_usb_txctl_cb); + if (error != 0) { + printf("%s: could not read ctl packet: %s\n", + DEVNAME(sc), usbd_errstr(error)); + free(ctl->buf, M_TEMP, ctl->len); + free(ctl, M_TEMP, sizeof(*ctl)); + usbd_free_xfer(xfer); + return 1; + } - req.bmRequestType = UT_READ_CLASS_INTERFACE; - req.bRequest = 1; + TAILQ_INSERT_TAIL(&sc->sc_sc.sc_bcdc_rxctlq, ctl, next); + } - USETW(req.wValue, 0); - USETW(req.wIndex, sc->sc_ifaceno); - USETW(req.wLength, *len); + return 0; +} - error = usbd_do_request_flags(sc->sc_udev, &req, buf, 0, - &len32, USBD_DEFAULT_TIMEOUT); - if (error != 0) { - printf("%s: could not read ctl packet: %s\n", - DEVNAME(sc), usbd_errstr(error)); - goto err; - } +void +bwfm_usb_txctl_cb(struct usbd_xfer *xfer, void *priv, usbd_status err) +{ + struct bwfm_usb_softc *sc = priv; - if (len32 > *len) { - printf("%s: broken length\n", DEVNAME(sc)); + if (usbd_is_dying(xfer->pipe->device)) goto err; + + if (err == USBD_NORMAL_COMPLETION || err == USBD_SHORT_XFER) { + sc->sc_sc.sc_proto_ops->proto_rxctl(&sc->sc_sc, + KERNADDR(&xfer->dmabuf, 0), xfer->actlen); } - *len = len32; - ret = 0; err: - return ret; + usbd_free_xfer(xfer); } |