Module Name: src Committed By: riastradh Date: Sat Jul 15 05:46:09 UTC 2017
Modified Files: src/sys/dev/usb: ualea.c Log Message: Tidy up a bit. Fulfil requests completely. To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/sys/dev/usb/ualea.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/ualea.c diff -u src/sys/dev/usb/ualea.c:1.6 src/sys/dev/usb/ualea.c:1.7 --- src/sys/dev/usb/ualea.c:1.6 Wed Apr 19 00:01:38 2017 +++ src/sys/dev/usb/ualea.c Sat Jul 15 05:46:09 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ualea.c,v 1.6 2017/04/19 00:01:38 riastradh Exp $ */ +/* $NetBSD: ualea.c,v 1.7 2017/07/15 05:46:09 riastradh Exp $ */ /*- * Copyright (c) 2017 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ualea.c,v 1.6 2017/04/19 00:01:38 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ualea.c,v 1.7 2017/07/15 05:46:09 riastradh Exp $"); #include <sys/types.h> #include <sys/atomic.h> @@ -47,16 +47,21 @@ __KERNEL_RCSID(0, "$NetBSD: ualea.c,v 1. struct ualea_softc { device_t sc_dev; - struct usbd_device *sc_udev; - struct usbd_interface *sc_uif; kmutex_t sc_lock; krndsource_t sc_rnd; uint16_t sc_maxpktsize; struct usbd_pipe *sc_pipe; + /* + * Lock covers: + * - sc_needed + * - sc_attached + * - sc_inflight + * - usbd_transfer(sc_xfer) + */ struct usbd_xfer *sc_xfer; + size_t sc_needed; bool sc_attached:1; bool sc_inflight:1; - /* lock covers sc_attached, sc_inflight, and usbd_transfer(sc_xfer) */ }; static int ualea_match(device_t, cfdata_t, void *); @@ -88,28 +93,26 @@ ualea_attach(device_t parent, device_t s { struct usbif_attach_arg *uiaa = aux; struct ualea_softc *sc = device_private(self); - struct usbd_device *udev = uiaa->uiaa_device; - struct usbd_interface *uif = uiaa->uiaa_iface; const usb_endpoint_descriptor_t *ed; char *devinfop; usbd_status status; + /* Print the device info. */ aprint_naive("\n"); aprint_normal("\n"); - - devinfop = usbd_devinfo_alloc(udev, 0); + devinfop = usbd_devinfo_alloc(uiaa->uiaa_device, 0); aprint_normal_dev(self, "%s\n", devinfop); usbd_devinfo_free(devinfop); + /* Initialize the softc. */ sc->sc_dev = self; - sc->sc_udev = udev; - sc->sc_uif = uif; mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); rndsource_setcb(&sc->sc_rnd, ualea_get, sc); rnd_attach_source(&sc->sc_rnd, device_xname(self), RND_TYPE_RNG, RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB); - ed = usbd_interface2endpoint_descriptor(uif, 0); + /* Get endpoint descriptor 0. Make sure it's bulk-in. */ + ed = usbd_interface2endpoint_descriptor(uiaa->uiaa_iface, 0); if (ed == NULL) { aprint_error_dev(sc->sc_dev, "failed to read endpoint 0\n"); return; @@ -120,9 +123,11 @@ ualea_attach(device_t parent, device_t s return; } + /* Remember the maximum packet size. */ sc->sc_maxpktsize = UGETW(ed->wMaxPacketSize); - status = usbd_open_pipe(uif, ed->bEndpointAddress, + /* Open an exclusive MP-safe pipe for endpoint 0. */ + status = usbd_open_pipe(uiaa->uiaa_iface, ed->bEndpointAddress, USBD_EXCLUSIVE_USE|USBD_MPSAFE, &sc->sc_pipe); if (status) { aprint_error_dev(sc->sc_dev, "failed to open pipe: %d\n", @@ -130,6 +135,7 @@ ualea_attach(device_t parent, device_t s return; } + /* Create an xfer of maximum packet size, short OK, on the pipe. */ status = usbd_create_xfer(sc->sc_pipe, sc->sc_maxpktsize, USBD_SHORT_XFER_OK, 0, &sc->sc_xfer); if (status) { @@ -138,6 +144,7 @@ ualea_attach(device_t parent, device_t s return; } + /* Setup the xfer to call ualea_xfer_done with sc. */ usbd_setup_xfer(sc->sc_xfer, sc, usbd_get_buffer(sc->sc_xfer), sc->sc_maxpktsize, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, ualea_xfer_done); @@ -178,24 +185,56 @@ ualea_detach(device_t self, int flags) } static void -ualea_get(size_t nbytes, void *cookie) +ualea_xfer(struct ualea_softc *sc) { - struct ualea_softc *sc = cookie; usbd_status status; - mutex_enter(&sc->sc_lock); - if (!sc->sc_attached) - goto out; - if (sc->sc_inflight) - goto out; - sc->sc_inflight = true; + KASSERT(mutex_owned(&sc->sc_lock)); + KASSERT(sc->sc_attached); + KASSERT(!sc->sc_inflight); + + /* Do nothing if we need nothing. */ + if (sc->sc_needed == 0) + return; + + /* Issue xfer or complain if we can't. */ + /* + * XXX Does USBD_NORMAL_COMPLETION (= 0) make sense here? The + * xfer can't complete synchronously because of the lock. + */ status = usbd_transfer(sc->sc_xfer); if (status && status != USBD_IN_PROGRESS) { aprint_error_dev(sc->sc_dev, "failed to issue xfer: %d\n", status); /* We failed -- let someone else have a go. */ - sc->sc_inflight = false; + return; } + + /* Mark xfer in-flight. */ + sc->sc_inflight = true; +} + +static void +ualea_get(size_t nbytes, void *cookie) +{ + struct ualea_softc *sc = cookie; + + mutex_enter(&sc->sc_lock); + + /* Do nothing if not yet attached. */ + if (!sc->sc_attached) + goto out; + + /* Update how many bytes we need. */ + sc->sc_needed = MAX(sc->sc_needed, nbytes); + + /* Do nothing if xfer is already in flight. */ + if (sc->sc_inflight) + goto out; + + /* Issue xfer. */ + ualea_xfer(sc); + out: mutex_exit(&sc->sc_lock); } @@ -226,9 +265,17 @@ ualea_xfer_done(struct usbd_xfer *xfer, rnd_add_data(&sc->sc_rnd, pkt, pktsize, NBBY*pktsize); out: - /* Allow subsequent transfers. */ mutex_enter(&sc->sc_lock); + + /* Debit what we contributed from what we need. */ + sc->sc_needed -= MIN(sc->sc_needed, pktsize); + + /* Mark xfer done. */ sc->sc_inflight = false; + + /* Reissue xfer if we still need more. */ + ualea_xfer(sc); + mutex_exit(&sc->sc_lock); }