1 1.19 riastrad /* $NetBSD: ualea.c,v 1.19 2022/03/20 13:18:30 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /*- 4 1.1 riastrad * Copyright (c) 2017 The NetBSD Foundation, Inc. 5 1.1 riastrad * All rights reserved. 6 1.1 riastrad * 7 1.1 riastrad * This code is derived from software contributed to The NetBSD Foundation 8 1.1 riastrad * by Taylor R. Campbell. 9 1.1 riastrad * 10 1.1 riastrad * Redistribution and use in source and binary forms, with or without 11 1.1 riastrad * modification, are permitted provided that the following conditions 12 1.1 riastrad * are met: 13 1.1 riastrad * 1. Redistributions of source code must retain the above copyright 14 1.1 riastrad * notice, this list of conditions and the following disclaimer. 15 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 riastrad * notice, this list of conditions and the following disclaimer in the 17 1.1 riastrad * documentation and/or other materials provided with the distribution. 18 1.1 riastrad * 19 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE. 30 1.1 riastrad */ 31 1.1 riastrad 32 1.1 riastrad #include <sys/cdefs.h> 33 1.19 riastrad __KERNEL_RCSID(0, "$NetBSD: ualea.c,v 1.19 2022/03/20 13:18:30 riastradh Exp $"); 34 1.1 riastrad 35 1.1 riastrad #include <sys/types.h> 36 1.1 riastrad #include <sys/atomic.h> 37 1.1 riastrad #include <sys/device_if.h> 38 1.1 riastrad #include <sys/kmem.h> 39 1.6 riastrad #include <sys/module.h> 40 1.1 riastrad #include <sys/rndsource.h> 41 1.1 riastrad 42 1.1 riastrad #include <dev/usb/usb.h> 43 1.1 riastrad #include <dev/usb/usbdevs.h> 44 1.1 riastrad #include <dev/usb/usbdi.h> 45 1.1 riastrad #include <dev/usb/usbdi_util.h> 46 1.1 riastrad 47 1.1 riastrad struct ualea_softc { 48 1.1 riastrad device_t sc_dev; 49 1.1 riastrad kmutex_t sc_lock; 50 1.1 riastrad krndsource_t sc_rnd; 51 1.1 riastrad uint16_t sc_maxpktsize; 52 1.1 riastrad struct usbd_pipe *sc_pipe; 53 1.7 riastrad /* 54 1.7 riastrad * Lock covers: 55 1.7 riastrad * - sc_needed 56 1.7 riastrad * - sc_inflight 57 1.7 riastrad * - usbd_transfer(sc_xfer) 58 1.7 riastrad */ 59 1.1 riastrad struct usbd_xfer *sc_xfer; 60 1.7 riastrad size_t sc_needed; 61 1.1 riastrad bool sc_attached:1; 62 1.1 riastrad bool sc_inflight:1; 63 1.1 riastrad }; 64 1.1 riastrad 65 1.1 riastrad static int ualea_match(device_t, cfdata_t, void *); 66 1.1 riastrad static void ualea_attach(device_t, device_t, void *); 67 1.1 riastrad static int ualea_detach(device_t, int); 68 1.1 riastrad static void ualea_get(size_t, void *); 69 1.1 riastrad static void ualea_xfer_done(struct usbd_xfer *, void *, usbd_status); 70 1.1 riastrad 71 1.1 riastrad CFATTACH_DECL_NEW(ualea, sizeof(struct ualea_softc), 72 1.1 riastrad ualea_match, ualea_attach, ualea_detach, NULL); 73 1.1 riastrad 74 1.1 riastrad static const struct usb_devno ualea_devs[] = { 75 1.5 riastrad { USB_VENDOR_ARANEUS, USB_PRODUCT_ARANEUS_ALEA }, 76 1.1 riastrad }; 77 1.1 riastrad 78 1.1 riastrad static int 79 1.1 riastrad ualea_match(device_t parent, cfdata_t match, void *aux) 80 1.1 riastrad { 81 1.1 riastrad struct usbif_attach_arg *uiaa = aux; 82 1.1 riastrad 83 1.1 riastrad if (usb_lookup(ualea_devs, uiaa->uiaa_vendor, uiaa->uiaa_product)) 84 1.1 riastrad return UMATCH_VENDOR_PRODUCT; 85 1.1 riastrad 86 1.1 riastrad return UMATCH_NONE; 87 1.1 riastrad } 88 1.1 riastrad 89 1.1 riastrad static void 90 1.1 riastrad ualea_attach(device_t parent, device_t self, void *aux) 91 1.1 riastrad { 92 1.1 riastrad struct usbif_attach_arg *uiaa = aux; 93 1.1 riastrad struct ualea_softc *sc = device_private(self); 94 1.1 riastrad const usb_endpoint_descriptor_t *ed; 95 1.1 riastrad char *devinfop; 96 1.1 riastrad usbd_status status; 97 1.1 riastrad 98 1.7 riastrad /* Print the device info. */ 99 1.1 riastrad aprint_naive("\n"); 100 1.1 riastrad aprint_normal("\n"); 101 1.7 riastrad devinfop = usbd_devinfo_alloc(uiaa->uiaa_device, 0); 102 1.1 riastrad aprint_normal_dev(self, "%s\n", devinfop); 103 1.1 riastrad usbd_devinfo_free(devinfop); 104 1.1 riastrad 105 1.7 riastrad /* Initialize the softc. */ 106 1.1 riastrad sc->sc_dev = self; 107 1.16 riastrad mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTSERIAL); 108 1.1 riastrad 109 1.7 riastrad /* Get endpoint descriptor 0. Make sure it's bulk-in. */ 110 1.7 riastrad ed = usbd_interface2endpoint_descriptor(uiaa->uiaa_iface, 0); 111 1.1 riastrad if (ed == NULL) { 112 1.1 riastrad aprint_error_dev(sc->sc_dev, "failed to read endpoint 0\n"); 113 1.1 riastrad return; 114 1.1 riastrad } 115 1.1 riastrad if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || 116 1.1 riastrad UE_GET_XFERTYPE(ed->bmAttributes) != UE_BULK) { 117 1.1 riastrad aprint_error_dev(sc->sc_dev, "invalid endpoint\n"); 118 1.1 riastrad return; 119 1.1 riastrad } 120 1.1 riastrad 121 1.7 riastrad /* Remember the maximum packet size. */ 122 1.1 riastrad sc->sc_maxpktsize = UGETW(ed->wMaxPacketSize); 123 1.1 riastrad 124 1.7 riastrad /* Open an exclusive MP-safe pipe for endpoint 0. */ 125 1.7 riastrad status = usbd_open_pipe(uiaa->uiaa_iface, ed->bEndpointAddress, 126 1.1 riastrad USBD_EXCLUSIVE_USE|USBD_MPSAFE, &sc->sc_pipe); 127 1.1 riastrad if (status) { 128 1.1 riastrad aprint_error_dev(sc->sc_dev, "failed to open pipe: %d\n", 129 1.1 riastrad status); 130 1.1 riastrad return; 131 1.1 riastrad } 132 1.1 riastrad 133 1.9 skrll /* Create an xfer of maximum packet size on the pipe. */ 134 1.1 riastrad status = usbd_create_xfer(sc->sc_pipe, sc->sc_maxpktsize, 135 1.9 skrll 0, 0, &sc->sc_xfer); 136 1.1 riastrad if (status) { 137 1.1 riastrad aprint_error_dev(sc->sc_dev, "failed to create xfer: %d\n", 138 1.1 riastrad status); 139 1.1 riastrad return; 140 1.1 riastrad } 141 1.1 riastrad 142 1.13 riastrad if (!pmf_device_register(self, NULL, NULL)) 143 1.13 riastrad aprint_error_dev(sc->sc_dev, "failed to register power handler" 144 1.13 riastrad "\n"); 145 1.13 riastrad 146 1.1 riastrad /* Success! We are ready to run. */ 147 1.1 riastrad sc->sc_attached = true; 148 1.11 riastrad rndsource_setcb(&sc->sc_rnd, ualea_get, sc); 149 1.11 riastrad rnd_attach_source(&sc->sc_rnd, device_xname(self), RND_TYPE_RNG, 150 1.11 riastrad RND_FLAG_COLLECT_VALUE|RND_FLAG_HASCB); 151 1.1 riastrad } 152 1.1 riastrad 153 1.1 riastrad static int 154 1.1 riastrad ualea_detach(device_t self, int flags) 155 1.1 riastrad { 156 1.1 riastrad struct ualea_softc *sc = device_private(self); 157 1.1 riastrad 158 1.1 riastrad /* Prevent new use of xfer. */ 159 1.11 riastrad if (sc->sc_attached) 160 1.11 riastrad rnd_detach_source(&sc->sc_rnd); 161 1.1 riastrad 162 1.17 riastrad /* Prevent xfer from rescheduling itself, if still pending. */ 163 1.17 riastrad mutex_enter(&sc->sc_lock); 164 1.17 riastrad sc->sc_needed = 0; 165 1.17 riastrad mutex_exit(&sc->sc_lock); 166 1.17 riastrad 167 1.1 riastrad /* Cancel pending xfer. */ 168 1.1 riastrad if (sc->sc_pipe) 169 1.14 riastrad usbd_abort_pipe(sc->sc_pipe); 170 1.1 riastrad KASSERT(!sc->sc_inflight); 171 1.1 riastrad 172 1.1 riastrad /* All users have drained. Tear it all down. */ 173 1.1 riastrad if (sc->sc_xfer) 174 1.1 riastrad usbd_destroy_xfer(sc->sc_xfer); 175 1.1 riastrad if (sc->sc_pipe) 176 1.15 riastrad usbd_close_pipe(sc->sc_pipe); 177 1.1 riastrad mutex_destroy(&sc->sc_lock); 178 1.1 riastrad 179 1.1 riastrad return 0; 180 1.1 riastrad } 181 1.1 riastrad 182 1.1 riastrad static void 183 1.7 riastrad ualea_xfer(struct ualea_softc *sc) 184 1.7 riastrad { 185 1.7 riastrad usbd_status status; 186 1.7 riastrad 187 1.7 riastrad KASSERT(mutex_owned(&sc->sc_lock)); 188 1.7 riastrad KASSERT(sc->sc_attached); 189 1.7 riastrad KASSERT(!sc->sc_inflight); 190 1.7 riastrad 191 1.7 riastrad /* Do nothing if we need nothing. */ 192 1.7 riastrad if (sc->sc_needed == 0) 193 1.7 riastrad return; 194 1.7 riastrad 195 1.12 simonb /* Setup the xfer to call ualea_xfer_done with sc. */ 196 1.12 simonb usbd_setup_xfer(sc->sc_xfer, sc, usbd_get_buffer(sc->sc_xfer), 197 1.12 simonb sc->sc_maxpktsize, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, 198 1.12 simonb ualea_xfer_done); 199 1.12 simonb 200 1.7 riastrad /* Issue xfer or complain if we can't. */ 201 1.7 riastrad status = usbd_transfer(sc->sc_xfer); 202 1.10 riastrad KASSERT(status != USBD_NORMAL_COMPLETION); /* asynchronous xfer */ 203 1.10 riastrad if (status != USBD_IN_PROGRESS) { 204 1.17 riastrad device_printf(sc->sc_dev, "failed to issue xfer: %s\n", 205 1.17 riastrad usbd_errstr(status)); 206 1.7 riastrad /* We failed -- let someone else have a go. */ 207 1.7 riastrad return; 208 1.7 riastrad } 209 1.7 riastrad 210 1.7 riastrad /* Mark xfer in-flight. */ 211 1.7 riastrad sc->sc_inflight = true; 212 1.7 riastrad } 213 1.7 riastrad 214 1.7 riastrad static void 215 1.1 riastrad ualea_get(size_t nbytes, void *cookie) 216 1.1 riastrad { 217 1.1 riastrad struct ualea_softc *sc = cookie; 218 1.1 riastrad 219 1.1 riastrad mutex_enter(&sc->sc_lock); 220 1.7 riastrad sc->sc_needed = MAX(sc->sc_needed, nbytes); 221 1.11 riastrad if (!sc->sc_inflight) 222 1.11 riastrad ualea_xfer(sc); 223 1.11 riastrad mutex_exit(&sc->sc_lock); 224 1.1 riastrad } 225 1.1 riastrad 226 1.1 riastrad static void 227 1.1 riastrad ualea_xfer_done(struct usbd_xfer *xfer, void *cookie, usbd_status status) 228 1.1 riastrad { 229 1.1 riastrad struct ualea_softc *sc = cookie; 230 1.1 riastrad void *pkt; 231 1.1 riastrad uint32_t pktsize; 232 1.1 riastrad 233 1.18 riastrad /* 234 1.18 riastrad * If the transfer failed, give up -- forget what we need and 235 1.18 riastrad * don't reschedule ourselves. 236 1.18 riastrad */ 237 1.1 riastrad if (status) { 238 1.17 riastrad device_printf(sc->sc_dev, "xfer failed: %s\n", 239 1.17 riastrad usbd_errstr(status)); 240 1.18 riastrad mutex_enter(&sc->sc_lock); 241 1.18 riastrad sc->sc_needed = 0; 242 1.18 riastrad sc->sc_inflight = false; 243 1.18 riastrad mutex_exit(&sc->sc_lock); 244 1.18 riastrad return; 245 1.1 riastrad } 246 1.1 riastrad 247 1.18 riastrad /* Get the transferred size. */ 248 1.1 riastrad usbd_get_xfer_status(xfer, NULL, &pkt, &pktsize, NULL); 249 1.18 riastrad KASSERTMSG(pktsize <= sc->sc_maxpktsize, 250 1.18 riastrad "pktsize %"PRIu32" > %"PRIu16" (max)", 251 1.18 riastrad pktsize, sc->sc_maxpktsize); 252 1.1 riastrad 253 1.18 riastrad /* 254 1.19 riastrad * Enter the data, debit what we contributed from what we need, 255 1.19 riastrad * mark the xfer as done, and reschedule the xfer if we still 256 1.19 riastrad * need more. 257 1.19 riastrad * 258 1.19 riastrad * Must enter the data under the lock so it happens atomically 259 1.19 riastrad * with updating sc_needed -- otherwise we might hang needing 260 1.19 riastrad * entropy and not scheduling xfer. Must not touch pkt after 261 1.19 riastrad * clearing sc_inflight and possibly rescheduling the xfer. 262 1.18 riastrad */ 263 1.2 riastrad mutex_enter(&sc->sc_lock); 264 1.19 riastrad rnd_add_data(&sc->sc_rnd, pkt, pktsize, NBBY*pktsize); 265 1.7 riastrad sc->sc_needed -= MIN(sc->sc_needed, pktsize); 266 1.1 riastrad sc->sc_inflight = false; 267 1.7 riastrad ualea_xfer(sc); 268 1.2 riastrad mutex_exit(&sc->sc_lock); 269 1.1 riastrad } 270 1.6 riastrad 271 1.6 riastrad MODULE(MODULE_CLASS_DRIVER, ualea, NULL); 272 1.6 riastrad 273 1.6 riastrad #ifdef _MODULE 274 1.6 riastrad #include "ioconf.c" 275 1.6 riastrad #endif 276 1.6 riastrad 277 1.6 riastrad static int 278 1.6 riastrad ualea_modcmd(modcmd_t cmd, void *aux) 279 1.6 riastrad { 280 1.6 riastrad int error = 0; 281 1.6 riastrad 282 1.6 riastrad switch (cmd) { 283 1.6 riastrad case MODULE_CMD_INIT: 284 1.6 riastrad #ifdef _MODULE 285 1.6 riastrad error = config_init_component(cfdriver_ioconf_ualea, 286 1.6 riastrad cfattach_ioconf_ualea, cfdata_ioconf_ualea); 287 1.6 riastrad #endif 288 1.6 riastrad return error; 289 1.6 riastrad case MODULE_CMD_FINI: 290 1.6 riastrad #ifdef _MODULE 291 1.6 riastrad error = config_fini_component(cfdriver_ioconf_ualea, 292 1.6 riastrad cfattach_ioconf_ualea, cfdata_ioconf_ualea); 293 1.6 riastrad #endif 294 1.6 riastrad return error; 295 1.6 riastrad default: 296 1.6 riastrad return ENOTTY; 297 1.6 riastrad } 298 1.6 riastrad } 299