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