Hi tech@,

I balled the copyright and license up a bit (thanks to deraadt@ and
bcallah@ for pointing this out).  I apologize to grange@ and mbalmer@
for not carrying along their copyright notices when I obviously
cribbed liberally from their code in uow.c and umbg.c, respectively.

Updated driver attached.  If anyone has one of these and can test
please let me know.  The only visible effect when you plug one in is
that Puffy's eyes in the sticker on my thinkpad glow a bit...  not
sure what's up with that, just going to go with it.

Feedback most welcome.

Pax, -A

/* -*- mode:c; tab-width:8; indent-tabs-mode:t; c-basic-offset:8 -*- */
/*
 * Copyright (c) 2006 Alexander Yurchenko <gra...@openbsd.org>
 * Copyright (c) 2007 Marc Balmer <mbal...@openbsd.org>
 * Copyright (C) 2015 attila <att...@stalphonsos.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Alea II TRNG.  Produces 100kbit/sec of entropy by black magic
 *
 * Product information in English can be found here:
 *     http://www.araneus.fi/products/alea2/en/
 *
 * I only have an Alea II to play with but the documentation says
 * that the Alea I is the same, so they should also work.
 *
 * I cribbed liberally from both the uow and umbg drivers, both of
 * which are similar to this situation in different ways.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/time.h>
#include <sys/timeout.h>

#include <dev/usb/usb.h>
#include <dev/usb/usbdevs.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>

#include <dev/rndvar.h>

#define ALEA_IFACE      0
#define ALEA_MSECS      10
#define ALEA_READ_TOUT  1100
#define ALEA_BUFSIZ     ((1024/8)*100)  /* 100 kbits */
/*#define ALEA_DEBUG    1*/             /* comment out */

#define OURNAME(x)      x->sc_dev.dv_xname

struct ualea_softc {
        struct  device sc_dev;
        struct  usbd_device *sc_udev;
        struct  usbd_interface *sc_iface;
        struct  usbd_pipe *sc_ibulk;
        struct  timeout sc_tout;
        struct  usb_task sc_task;
#ifdef ALEA_DEBUG
        struct  timespec sc_tattach;
        u_int32_t sc_nbits;
#endif
};

int ualea_match(struct device *, void *, void *);
void ualea_attach(struct device *, struct device *, void *);
int ualea_detach(struct device *, int);
void ualea_task(void *);
void ualea_intr(void *);

struct cfdriver ualea_cd = {
        NULL, "ualea", DV_DULL
};

const struct cfattach ualea_ca = {
        sizeof(struct ualea_softc),
        ualea_match,
        ualea_attach,
        ualea_detach
};

static const struct usb_devno ualea_devs[] = {
        { USB_VENDOR_ARANEUS,   USB_PRODUCT_ARANEUS_ALEA }
};

int
ualea_match(struct device *parent, void *match, void *aux)
{
        struct usb_attach_arg *uaa = aux;

        if (uaa->iface != NULL)
                return (UMATCH_NONE);
#ifdef ALEA_DEBUG
        if (uaa->vendor == USB_VENDOR_ARANEUS)
                printf("ualea: vendor 0x%x (%d) (ARANEUS) product 0x%x (%d)\n",
                    uaa->vendor, uaa->vendor, uaa->product, uaa->product);
#endif
        return ((usb_lookup(ualea_devs, uaa->vendor, uaa->product) != NULL) ?
            UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
}

void
ualea_attach(struct device *parent, struct device *self, void *aux)
{
        struct ualea_softc *sc = (struct ualea_softc *)self;
        struct usb_attach_arg *uaa = aux;
        usb_interface_descriptor_t *id;
        usb_endpoint_descriptor_t *ed;
        int ep_ibulk = -1;
        usbd_status error;
        int i;

        sc->sc_udev = uaa->device;
        error = usbd_set_config_index(sc->sc_udev, 0, 1);
        if (error != 0) {
                printf("%s: failed to set config: %s\n",
                       OURNAME(sc), usbd_errstr(error));
        }
        error = usbd_device2interface_handle(
                    sc->sc_udev, ALEA_IFACE, &sc->sc_iface);
        if (error != 0) {
                printf("%s: failed to get iface %d: %s\n",
                    OURNAME(sc), ALEA_IFACE, usbd_errstr(error));
                return;
        }
        /* Get endpoint (there can be only one) */
        id = usbd_get_interface_descriptor(sc->sc_iface);
        for (i = 0; i < id->bNumEndpoints; i++) {
                ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
                if (ed == NULL) {
                        printf("%s: failed to get endpoint %d descriptor\n",
                            OURNAME(sc), i);
                        return;
                }

#ifdef ALEA_DEBUG
                printf("%s: iface#%d endpoint#%d type %d\n",
                    OURNAME(sc), i, UE_GET_DIR(ed->bEndpointAddress),
                    UE_GET_XFERTYPE(ed->bmAttributes));
#endif /* ALEA_DEBUG */

                if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
                    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK &&
                    ep_ibulk == -1) {
                        ep_ibulk = ed->bEndpointAddress;
#ifdef ALEA_DEBUG
                        printf("%s: chosing ibulk endpoint#%d\n",
                            OURNAME(sc), ep_ibulk);
#else
                        break;
#endif /* ALEA_DEBUG */
                }
        }
        if (ep_ibulk == -1) {
                printf("%s: missing ibulk endpoint - cannot initialize\n",
                    OURNAME(sc));
                return;
        }
        /* Open pipe */
        error = usbd_open_pipe(sc->sc_iface, ep_ibulk, USBD_EXCLUSIVE_USE,
                    &sc->sc_ibulk);
        if (error) {
                printf("%s: failed to open bulk-in pipe: %s\n",
                    OURNAME(sc), usbd_errstr(error));
                return;
        }
        /* Get our task going */
        usb_init_task(&sc->sc_task, ualea_task, sc, USB_TASK_TYPE_GENERIC);
        timeout_set(&sc->sc_tout, ualea_intr, sc);
        timeout_add_msec(&sc->sc_tout, ALEA_MSECS);
#ifdef ALEA_DEBUG
        nanotime(&sc->sc_tattach);
        sc->sc_nbits = 0;
#endif /* ALEA_DEBUG */
}

int
ualea_detach(struct device *self, int flags)
{
        struct ualea_softc *sc = (struct ualea_softc *)self;

        if (timeout_initialized(&sc->sc_tout))
                timeout_del(&sc->sc_tout);
        if (sc->sc_ibulk != NULL) {
                usbd_abort_pipe(sc->sc_ibulk);
                usbd_close_pipe(sc->sc_ibulk);
                sc->sc_ibulk = NULL;
        }

        return 0;
}

void
ualea_task(void *arg)
{
        struct ualea_softc *sc = (struct ualea_softc *)arg;
        usbd_status error;
        u_int32_t n, i;
        int *buf;
        struct usbd_xfer *xfer;
#ifdef ALEA_DEBUG
        u_int32_t kbps, dt, nbits;
        struct timespec now;
#endif /* ALEA_DEBUG */

        xfer = usbd_alloc_xfer(sc->sc_udev);
        if (xfer == NULL) {
                printf("%s: could not alloc xfer\n", OURNAME(sc));
                goto bail;
        }
        /* Is there any chance this buffer is not at least int-aligned? */
        buf = usbd_alloc_buffer(xfer, ALEA_BUFSIZ);
        usbd_setup_xfer(xfer, sc->sc_ibulk, NULL, (void *)buf,
            ALEA_BUFSIZ, USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS,
            ALEA_READ_TOUT, NULL);
        error = usbd_transfer(xfer);
        if (error) {
                printf("%s: xfer failed: %s\n", OURNAME(sc),
                    usbd_errstr(error));
                goto bail;
        }
        usbd_get_xfer_status(xfer, NULL, NULL, &n, NULL);
        if (n < sizeof(int)) {
                printf("%s: xfer too short (%u bytes) - dropping\n",
                    OURNAME(sc), n);
                goto bail;
        }
#ifdef ALEA_DEBUG
        else if (n != ALEA_BUFSIZ)
                printf("%s: short read got %u bytes (exp. %u)\n", OURNAME(sc),
                    n, ALEA_BUFSIZ);
#endif /* ALEA_DEBUG */
        n /= sizeof(int);
        /*
         * A random(|ness) koan:
         *   children chug entropy like thirsty rhinos
         *     surfing at the mall
         *    privacy died in their hands
         */
        for (i = 0; i < n; i++)
                add_true_randomness(buf[i]);
#ifdef ALEA_DEBUG
        nanotime(&now);
        dt = now.tv_sec - sc->sc_tattach.tv_sec;
        nbits = n * sizeof(int) * 8;
        sc->sc_nbits += nbits;
        kbps = dt ? ((sc->sc_nbits / 1024) / dt) : 0;
        printf("%s: added %d bits: %dkbit/sec\n", OURNAME(sc), nbits, kbps);
#endif /* ALEA_DEBUG */
bail:
        if (xfer)
                usbd_free_xfer(xfer);
        timeout_add_msec(&sc->sc_tout, ALEA_MSECS);
}

void
ualea_intr(void *arg)
{
        struct ualea_softc *sc = arg;

        usb_add_task(sc->sc_udev, &sc->sc_task);
}

Reply via email to