summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2018-05-16 08:20:01 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2018-05-16 08:20:01 +0000
commite21428954dd958af48f88b8678d0564c32bd8541 (patch)
tree377508e361f3bcbf3bb4b5abcbe5bb84f013a124 /sys/dev/usb
parent60489abfc15051f9141be0abff32d05c384f9ebf (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.c112
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);
}