summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2005-04-16 14:55:11 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2005-04-16 14:55:11 +0000
commit291c8f565a8265a970ea5c13f4fd28c60b35c9ab (patch)
tree5dd7e68ab8f9c2532e8cc46c496251654e30adf1 /sys/dev/usb
parent134ff4e75d9718004af8606850074df5a52017a4 (diff)
Driver for Analog Devices Eagle chipset.
ok deraadt@
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/files.usb7
-rw-r--r--sys/dev/usb/ueagle.c1466
-rw-r--r--sys/dev/usb/ueaglereg.h123
-rw-r--r--sys/dev/usb/ueaglevar.h191
-rw-r--r--sys/dev/usb/usbdevs21
5 files changed, 1806 insertions, 2 deletions
diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb
index 70fdfbb726f..1b6328eadb1 100644
--- a/sys/dev/usb/files.usb
+++ b/sys/dev/usb/files.usb
@@ -1,4 +1,4 @@
-# $OpenBSD: files.usb,v 1.46 2005/03/16 23:28:59 deraadt Exp $
+# $OpenBSD: files.usb,v 1.47 2005/04/16 14:55:10 damien Exp $
# $NetBSD: files.usb,v 1.16 2000/02/14 20:29:54 augustss Exp $
#
# Config file and device description for machine-independent USB code.
@@ -222,3 +222,8 @@ file dev/usb/if_ubt.c ubt
device ural: ether, ifnet, ifmedia, wlan
attach ural at uhub
file dev/usb/if_ral.c ural
+
+# Analog Devices Eagle driver
+device ueagle: atm, ifnet, ezload, firmload
+attach ueagle at uhub
+file dev/usb/ueagle.c ueagle
diff --git a/sys/dev/usb/ueagle.c b/sys/dev/usb/ueagle.c
new file mode 100644
index 00000000000..da4dcb9d8dd
--- /dev/null
+++ b/sys/dev/usb/ueagle.c
@@ -0,0 +1,1466 @@
+/* $OpenBSD: ueagle.c,v 1.1 2005/04/16 14:55:10 damien Exp $ */
+
+/*-
+ * Copyright (c) 2003-2005
+ * Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+/*-
+ * Analog Devices Eagle chipset driver
+ * http://www.analog.com/
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/kthread.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_atm.h>
+#include <net/if_media.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_atm.h>
+#endif
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/ezload.h>
+#include <dev/usb/usbdevs.h>
+
+#include <dev/usb/ueaglereg.h>
+#include <dev/usb/ueaglevar.h>
+
+#ifdef USB_DEBUG
+#define DPRINTF(x) do { if (ueagledebug > 0) logprintf x; } while (0)
+#define DPRINTFN(n, x) do { if (ueagledebug >= (n)) logprintf x; } while (0)
+int ueagledebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n, x)
+#endif
+
+/* various supported device vendors/products */
+static const struct ueagle_type {
+ struct usb_devno dev;
+ const char *fw;
+} ueagle_devs[] = {
+ { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEI }, NULL },
+ { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEI_NF }, "ueagleI" },
+ { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEII }, NULL },
+ { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEII_NF }, "ueagleII" },
+ { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIIC }, NULL },
+ { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIIC_NF }, "ueagleII" },
+ { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIII }, NULL },
+ { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIII_NF }, "ueagleIII" },
+ { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_A }, NULL },
+ { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_A_NF }, "ueagleI" },
+ { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_B }, NULL },
+ { { USB_VENDOR_USR, USB_PRODUCT_USR_HEINEKEN_B_NF }, "ueagleI" },
+ { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_A }, NULL },
+ { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_A_NF }, "ueagleI" },
+ { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_B }, NULL },
+ { { USB_VENDOR_USR, USB_PRODUCT_USR_MILLER_B_NF }, "ueagleI" }
+};
+#define ueagle_lookup(v, p) \
+ ((struct ueagle_type *)usb_lookup(ueagle_devs, v, p))
+
+Static void ueagle_attachhook(void *);
+Static int ueagle_getesi(struct ueagle_softc *, uint8_t *);
+Static void ueagle_loadpage(void *);
+Static void ueagle_request(struct ueagle_softc *, uint16_t, uint16_t,
+ void *, int);
+#ifdef USB_DEBUG
+Static void ueagle_dump_cmv(struct ueagle_softc *, struct ueagle_cmv *);
+#endif
+Static int ueagle_cr(struct ueagle_softc *, uint32_t, uint16_t,
+ uint32_t *);
+Static int ueagle_cw(struct ueagle_softc *, uint32_t, uint16_t, uint32_t);
+Static int ueagle_stat(struct ueagle_softc *);
+Static void ueagle_stat_thread(void *);
+Static int ueagle_boot(struct ueagle_softc *);
+Static void ueagle_swap_intr(struct ueagle_softc *, struct ueagle_swap *);
+Static void ueagle_cmv_intr(struct ueagle_softc *, struct ueagle_cmv *);
+Static void ueagle_intr(usbd_xfer_handle, usbd_private_handle,
+ usbd_status);
+Static uint32_t ueagle_crc_update(uint32_t, uint8_t *, int);
+Static void ueagle_push_cell(struct ueagle_softc *, uint8_t *);
+Static void ueagle_rxeof(usbd_xfer_handle, usbd_private_handle,
+ usbd_status);
+Static void ueagle_txeof(usbd_xfer_handle, usbd_private_handle,
+ usbd_status);
+Static int ueagle_encap(struct ueagle_softc *, struct mbuf *);
+Static void ueagle_start(struct ifnet *);
+Static int ueagle_open_vcc(struct ueagle_softc *,
+ struct atm_pseudoioctl *);
+Static int ueagle_close_vcc(struct ueagle_softc *,
+ struct atm_pseudoioctl *);
+Static int ueagle_ioctl(struct ifnet *, u_long, caddr_t);
+Static int ueagle_open_pipes(struct ueagle_softc *);
+Static void ueagle_close_pipes(struct ueagle_softc *);
+Static int ueagle_init(struct ifnet *);
+Static void ueagle_stop(struct ifnet *, int);
+
+USB_DECLARE_DRIVER(ueagle);
+
+USB_MATCH(ueagle)
+{
+ USB_MATCH_START(ueagle, uaa);
+
+ if (uaa->iface != NULL)
+ return UMATCH_NONE;
+
+ return (ueagle_lookup(uaa->vendor, uaa->product) != NULL) ?
+ UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
+}
+
+Static void
+ueagle_attachhook(void *xsc)
+{
+ char *firmwares[2];
+ struct ueagle_softc *sc = xsc;
+
+ firmwares[0] = (char *)sc->fw;
+ firmwares[1] = NULL;
+
+ if (ezload_downloads_and_reset(sc->sc_udev, firmwares) != 0) {
+ printf("%s: could not download firmware\n",
+ USBDEVNAME(sc->sc_dev));
+ return;
+ }
+}
+
+USB_ATTACH(ueagle)
+{
+ USB_ATTACH_START(ueagle, sc, uaa);
+ struct ifnet *ifp = &sc->sc_if;
+ char devinfo[1024];
+ uint8_t addr[6];
+
+ sc->sc_udev = uaa->device;
+
+ /*
+ * Pre-firmware modems must be flashed and reset first. They will
+ * automatically detach themselves from the bus and reattach later
+ * with a new product Id.
+ */
+ sc->fw = ueagle_lookup(uaa->vendor, uaa->product)->fw;
+ if (sc->fw != NULL) {
+ if (rootvp == NULL)
+ mountroothook_establish(ueagle_attachhook, sc);
+ else
+ ueagle_attachhook(sc);
+
+ /* processing of pre-firmware modems ends here */
+ USB_ATTACH_SUCCESS_RETURN;
+ }
+
+ usbd_devinfo(sc->sc_udev, 0, devinfo, sizeof devinfo);
+ USB_ATTACH_SETUP;
+ printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
+
+ if (usbd_set_config_no(sc->sc_udev, UEAGLE_CONFIG_NO, 0) != 0) {
+ printf("%s: could not set configuration no\n",
+ USBDEVNAME(sc->sc_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ if (ueagle_getesi(sc, addr) != 0) {
+ printf("%s: could not read end system identifier\n",
+ USBDEVNAME(sc->sc_dev));
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ printf("%s: address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ USBDEVNAME(sc->sc_dev), addr[0], addr[1], addr[2], addr[3],
+ addr[4], addr[5]);
+
+ usb_init_task(&sc->sc_swap_task, ueagle_loadpage, sc);
+
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_SIMPLEX;
+ ifp->if_init = ueagle_init;
+ ifp->if_ioctl = ueagle_ioctl;
+ ifp->if_start = ueagle_start;
+ IFQ_SET_READY(&ifp->if_snd);
+ memcpy(ifp->if_xname, USBDEVNAME(sc->sc_dev), IFNAMSIZ);
+
+ if_attach(ifp);
+ atm_ifattach(ifp);
+
+ /* override default MTU value (9180 is too large for us) */
+ ifp->if_mtu = UEAGLE_IFMTU;
+
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_RAW, 0);
+#endif
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ USB_ATTACH_SUCCESS_RETURN;
+}
+
+USB_DETACH(ueagle)
+{
+ USB_DETACH_START(ueagle, sc);
+ struct ifnet *ifp = &sc->sc_if;
+
+ if (sc->fw != NULL)
+ return 0; /* shortcut for pre-firmware devices */
+
+ sc->gone = 1;
+ ueagle_stop(ifp, 1);
+
+ /* wait for stat thread to exit properly */
+ if (sc->stat_thread != NULL) {
+ DPRINTFN(3, ("%s: waiting for stat thread to exit\n",
+ USBDEVNAME(sc->sc_dev)));
+
+ tsleep(sc->stat_thread, PZERO, "ueaglestat", 0);
+
+ DPRINTFN(3, ("%s: stat thread exited properly\n",
+ USBDEVNAME(sc->sc_dev)));
+ }
+
+#if NBPFILTER > 0
+ bpfdetach(ifp);
+#endif
+ if_detach(ifp);
+
+ usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
+ USBDEV(sc->sc_dev));
+
+ return 0;
+}
+
+/*
+ * Retrieve the device End System Identifier (MAC address).
+ */
+Static int
+ueagle_getesi(struct ueagle_softc *sc, uint8_t *addr)
+{
+ usb_string_descriptor_t us;
+ usbd_status error;
+ uint16_t c;
+ int i, len;
+
+ error = usbd_get_string_desc(sc->sc_udev, UEAGLE_ESISTR, 0, &us, &len);
+ if (error != 0)
+ return error;
+
+ if (us.bLength < (6 + 1) * 2)
+ return 1;
+
+ for (i = 0; i < 6 * 2; i++) {
+ if ((c = UGETW(us.bString[i])) & 0xff00)
+ return 1; /* not 8-bit clean */
+
+ if (i & 1)
+ addr[i / 2] <<= 4;
+ else
+ addr[i / 2] = 0;
+
+ if (c >= '0' && c <= '9')
+ addr[i / 2] |= c - '0';
+ else if (c >= 'a' && c <= 'f')
+ addr[i / 2] |= c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ addr[i / 2] |= c - 'A' + 10;
+ else
+ return 1;
+ }
+
+ return 0;
+}
+
+Static void
+ueagle_loadpage(void *xsc)
+{
+ struct ueagle_softc *sc = xsc;
+ usbd_xfer_handle xfer;
+ struct ueagle_block_info bi;
+ uint16_t pageno = sc->pageno;
+ uint16_t ovl = sc->ovl;
+ uint8_t pagecount, blockcount;
+ uint16_t blockaddr, blocksize;
+ uint32_t pageoffset;
+ uint8_t *p;
+ int i;
+
+ p = sc->dsp;
+ pagecount = *p++;
+
+ if (pageno >= pagecount) {
+ printf("%s: invalid page number %u requested\n",
+ USBDEVNAME(sc->sc_dev), pageno);
+ return;
+ }
+
+ p += 4 * pageno;
+ pageoffset = UGETDW(p);
+ if (pageoffset == 0)
+ return;
+
+ p = sc->dsp + pageoffset;
+ blockcount = *p++;
+
+ DPRINTF(("%s: sending %u blocks for fw page %u\n",
+ USBDEVNAME(sc->sc_dev), blockcount, pageno));
+
+ if ((xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) {
+ printf("%s: could not allocate xfer\n",
+ USBDEVNAME(sc->sc_dev));
+ return;
+ }
+
+ USETW(bi.wHdr, UEAGLE_BLOCK_INFO_HDR);
+ USETW(bi.wOvl, ovl);
+ USETW(bi.wOvlOffset, ovl | 0x8000);
+
+ for (i = 0; i < blockcount; i++) {
+ blockaddr = UGETW(p); p += 2;
+ blocksize = UGETW(p); p += 2;
+
+ USETW(bi.wSize, blocksize);
+ USETW(bi.wAddress, blockaddr);
+ USETW(bi.wLast, (i == blockcount - 1) ? 1 : 0);
+
+ /* send block info through the IDMA pipe */
+ usbd_setup_xfer(xfer, sc->pipeh_idma, sc, &bi, sizeof bi, 0,
+ UEAGLE_IDMA_TIMEOUT, NULL);
+ if (usbd_sync_transfer(xfer) != 0) {
+ printf("%s: could not transfer block info\n",
+ USBDEVNAME(sc->sc_dev));
+ break;
+ }
+
+ /* send block data through the IDMA pipe */
+ usbd_setup_xfer(xfer, sc->pipeh_idma, sc, p, blocksize, 0,
+ UEAGLE_IDMA_TIMEOUT, NULL);
+ if (usbd_sync_transfer(xfer) != 0) {
+ printf("%s: could not transfer block data\n",
+ USBDEVNAME(sc->sc_dev));
+ break;
+ }
+
+ p += blocksize;
+ }
+
+ usbd_free_xfer(xfer);
+}
+
+Static void
+ueagle_request(struct ueagle_softc *sc, uint16_t val, uint16_t index,
+ void *data, int len)
+{
+ usb_device_request_t req;
+ usbd_status error;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = UEAGLE_REQUEST;
+ USETW(req.wValue, val);
+ USETW(req.wIndex, index);
+ USETW(req.wLength, len);
+
+ error = usbd_do_request_async(sc->sc_udev, &req, data);
+ if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
+ printf("%s: could not send request\n", USBDEVNAME(sc->sc_dev));
+}
+
+#ifdef USB_DEBUG
+Static void
+ueagle_dump_cmv(struct ueagle_softc *sc, struct ueagle_cmv *cmv)
+{
+ printf(" Preamble: 0x%04x\n", UGETW(cmv->wPreamble));
+ printf(" Destination: %s (0x%02x)\n",
+ (cmv->bDst == UEAGLE_HOST) ? "Host" : "Modem", cmv->bDst);
+ printf(" Type: %u\n", cmv->bFunction >> 4);
+ printf(" Subtype: %u\n", cmv->bFunction & 0xf);
+ printf(" Index: %u\n", UGETW(cmv->wIndex));
+ printf(" Address: %c%c%c%c.%u\n",
+ cmv->dwSymbolicAddress[1], cmv->dwSymbolicAddress[0],
+ cmv->dwSymbolicAddress[3], cmv->dwSymbolicAddress[2],
+ UGETW(cmv->wOffsetAddress));
+ printf(" Data: 0x%08x\n", UGETDATA(cmv->dwData));
+}
+#endif
+
+Static int
+ueagle_cr(struct ueagle_softc *sc, uint32_t address, uint16_t offset,
+ uint32_t *data)
+{
+ struct ueagle_cmv cmv;
+ usbd_status error;
+ int s;
+
+ USETW(cmv.wPreamble, UEAGLE_CMV_PREAMBLE);
+ cmv.bDst = UEAGLE_MODEM;
+ cmv.bFunction = UEAGLE_CR;
+ USETW(cmv.wIndex, sc->index);
+ USETW(cmv.wOffsetAddress, offset);
+ USETDW(cmv.dwSymbolicAddress, address);
+ USETDATA(cmv.dwData, 0);
+
+#ifdef USB_DEBUG
+ if (ueagledebug >= 15) {
+ printf("%s: reading CMV\n", USBDEVNAME(sc->sc_dev));
+ ueagle_dump_cmv(sc, &cmv);
+ }
+#endif
+
+ s = splusb();
+
+ ueagle_request(sc, UEAGLE_SETBLOCK, UEAGLE_MPTXSTART, &cmv, sizeof cmv);
+
+ /* wait at most 2 seconds for an answer */
+ error = tsleep(UEAGLE_COND_CMV(sc), PZERO, "cmv", 2 * hz);
+ if (error != 0) {
+ printf("%s: timeout waiting for CMV ack\n",
+ USBDEVNAME(sc->sc_dev));
+ splx(s);
+ return error;
+ }
+
+ *data = sc->data;
+ splx(s);
+
+ return 0;
+}
+
+Static int
+ueagle_cw(struct ueagle_softc *sc, uint32_t address, uint16_t offset,
+ uint32_t data)
+{
+ struct ueagle_cmv cmv;
+ usbd_status error;
+ int s;
+
+ USETW(cmv.wPreamble, UEAGLE_CMV_PREAMBLE);
+ cmv.bDst = UEAGLE_MODEM;
+ cmv.bFunction = UEAGLE_CW;
+ USETW(cmv.wIndex, sc->index);
+ USETW(cmv.wOffsetAddress, offset);
+ USETDW(cmv.dwSymbolicAddress, address);
+ USETDATA(cmv.dwData, data);
+
+#ifdef USB_DEBUG
+ if (ueagledebug >= 15) {
+ printf("%s: writing CMV\n", USBDEVNAME(sc->sc_dev));
+ ueagle_dump_cmv(sc, &cmv);
+ }
+#endif
+
+ s = splusb();
+
+ ueagle_request(sc, UEAGLE_SETBLOCK, UEAGLE_MPTXSTART, &cmv, sizeof cmv);
+
+ /* wait at most 2 seconds for an answer */
+ error = tsleep(UEAGLE_COND_CMV(sc), PZERO, "cmv", 2 * hz);
+ if (error != 0) {
+ printf("%s: timeout waiting for CMV ack\n",
+ USBDEVNAME(sc->sc_dev));
+ splx(s);
+ return error;
+ }
+
+ splx(s);
+
+ return 0;
+}
+
+Static int
+ueagle_stat(struct ueagle_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_if;
+ uint32_t data;
+ usbd_status error;
+#define CR(sc, address, offset, data) do { \
+ if ((error = ueagle_cr(sc, address, offset, data)) != 0) \
+ return error; \
+} while (0)
+
+ CR(sc, UEAGLE_CMV_STAT, 0, &sc->stats.phy.status);
+ switch ((sc->stats.phy.status >> 8) & 0xf) {
+ case 0: /* idle */
+ DPRINTFN(3, ("%s: waiting for synchronization\n",
+ USBDEVNAME(sc->sc_dev)));
+ return ueagle_cw(sc, UEAGLE_CMV_CNTL, 0, 2);
+
+ case 1: /* initialization */
+ DPRINTFN(3, ("%s: initializing\n", USBDEVNAME(sc->sc_dev)));
+ return ueagle_cw(sc, UEAGLE_CMV_CNTL, 0, 2);
+
+ case 2: /* operational */
+ DPRINTFN(4, ("%s: operational\n", USBDEVNAME(sc->sc_dev)));
+ break;
+
+ default: /* fail ... */
+ DPRINTFN(3, ("%s: synchronization failed\n",
+ USBDEVNAME(sc->sc_dev)));
+ ueagle_init(ifp);
+ return 1;
+ }
+
+ CR(sc, UEAGLE_CMV_DIAG, 1, &sc->stats.phy.flags);
+ if (sc->stats.phy.flags & 0x10) {
+ DPRINTF(("%s: delineation LOSS\n", USBDEVNAME(sc->sc_dev)));
+ sc->stats.phy.status = 0;
+ ueagle_init(ifp);
+ return 1;
+ }
+
+ CR(sc, UEAGLE_CMV_RATE, 0, &data);
+ sc->stats.phy.dsrate = ((data >> 16) & 0x1ff) * 32;
+ sc->stats.phy.usrate = (data & 0xff) * 32;
+
+ CR(sc, UEAGLE_CMV_DIAG, 23, &data);
+ sc->stats.phy.attenuation = (data & 0xff) / 2;
+
+ CR(sc, UEAGLE_CMV_DIAG, 3, &sc->stats.atm.cells_crc_errors);
+ CR(sc, UEAGLE_CMV_DIAG, 22, &sc->stats.phy.dserror);
+ CR(sc, UEAGLE_CMV_DIAG, 25, &sc->stats.phy.dsmargin);
+ CR(sc, UEAGLE_CMV_DIAG, 46, &sc->stats.phy.userror);
+ CR(sc, UEAGLE_CMV_DIAG, 49, &sc->stats.phy.usmargin);
+ CR(sc, UEAGLE_CMV_DIAG, 51, &sc->stats.phy.rxflow);
+ CR(sc, UEAGLE_CMV_DIAG, 52, &sc->stats.phy.txflow);
+ CR(sc, UEAGLE_CMV_DIAG, 54, &sc->stats.phy.dsunc);
+ CR(sc, UEAGLE_CMV_DIAG, 58, &sc->stats.phy.usunc);
+ CR(sc, UEAGLE_CMV_INFO, 8, &sc->stats.phy.vidco);
+ CR(sc, UEAGLE_CMV_INFO, 14, &sc->stats.phy.vidcpe);
+
+ if (sc->pipeh_tx != NULL)
+ return 0;
+
+ return ueagle_open_pipes(sc);
+#undef CR
+}
+
+Static void
+ueagle_stat_thread(void *arg)
+{
+ struct ueagle_softc *sc = arg;
+
+ for (;;) {
+ if (ueagle_stat(sc) != 0)
+ break;
+
+ usbd_delay_ms(sc->sc_udev, 5000);
+ }
+
+ wakeup(sc->stat_thread);
+
+ kthread_exit(0);
+}
+
+Static int
+ueagle_boot(struct ueagle_softc *sc)
+{
+ uint16_t zero = 0; /* ;-) */
+ usbd_status error;
+#define CW(sc, address, offset, data) do { \
+ if ((error = ueagle_cw(sc, address, offset, data)) != 0) \
+ return error; \
+} while (0)
+
+ ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_BOOTIDMA, NULL, 0);
+ ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_STARTRESET, NULL, 0);
+
+ usbd_delay_ms(sc->sc_udev, 200);
+
+ ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_ENDRESET, NULL, 0);
+ ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_MPTXMAILBOX, &zero, 2);
+ ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_MPRXMAILBOX, &zero, 2);
+ ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_SWAPMAILBOX, &zero, 2);
+
+ usbd_delay_ms(sc->sc_udev, 1000);
+
+ sc->pageno = 0;
+ sc->ovl = 0;
+ ueagle_loadpage(sc);
+
+ /* wait until modem reaches operationnal state */
+ error = tsleep(UEAGLE_COND_READY(sc), PZERO | PCATCH, "boot", 10 * hz);
+ if (error != 0) {
+ printf("%s: timeout waiting for operationnal state\n",
+ USBDEVNAME(sc->sc_dev));
+ return error;
+ }
+
+ CW(sc, UEAGLE_CMV_CNTL, 0, 1);
+
+ /* send configuration options */
+ CW(sc, UEAGLE_CMV_OPTN, 0, UEAGLE_OPTN0);
+ CW(sc, UEAGLE_CMV_OPTN, 2, UEAGLE_OPTN2);
+ CW(sc, UEAGLE_CMV_OPTN, 7, UEAGLE_OPTN7);
+
+ /* continue with synchronization */
+ CW(sc, UEAGLE_CMV_CNTL, 0, 2);
+
+ return kthread_create(ueagle_stat_thread, sc, &sc->stat_thread,
+ USBDEVNAME(sc->sc_dev));
+#undef CW
+}
+
+Static void
+ueagle_swap_intr(struct ueagle_softc *sc, struct ueagle_swap *swap)
+{
+#define rotbr(v, n) ((v) >> (n) | (v) << (8 - (n)))
+ sc->pageno = swap->bPageNo;
+ sc->ovl = rotbr(swap->bOvl, 4);
+
+ usb_add_task(sc->sc_udev, &sc->sc_swap_task);
+#undef rotbr
+}
+
+/*
+ * This function handles spontaneous CMVs and CMV acknowledgements sent by the
+ * modem on the interrupt pipe.
+ */
+Static void
+ueagle_cmv_intr(struct ueagle_softc *sc, struct ueagle_cmv *cmv)
+{
+#ifdef USB_DEBUG
+ if (ueagledebug >= 15) {
+ printf("%s: receiving CMV\n", USBDEVNAME(sc->sc_dev));
+ ueagle_dump_cmv(sc, cmv);
+ }
+#endif
+
+ if (UGETW(cmv->wPreamble) != UEAGLE_CMV_PREAMBLE) {
+ printf("%s: received CMV with invalid preamble\n",
+ USBDEVNAME(sc->sc_dev));
+ return;
+ }
+
+ if (cmv->bDst != UEAGLE_HOST) {
+ printf("%s: received CMV with bad direction\n",
+ USBDEVNAME(sc->sc_dev));
+ return;
+ }
+
+ /* synchronize our current CMV index with the modem */
+ sc->index = UGETW(cmv->wIndex) + 1;
+
+ /* handle spontaneous CMVs */
+ if (cmv->bFunction == UEAGLE_MODEMREADY) {
+ wakeup(UEAGLE_COND_READY(sc));
+ return;
+ }
+
+ /* if it is the ack of a previous CR, save the data field */
+ if (cmv->bFunction == UEAGLE_CR_ACK)
+ sc->data = UGETDATA(cmv->dwData);
+
+ wakeup(UEAGLE_COND_CMV(sc));
+}
+
+Static void
+ueagle_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
+{
+ struct ueagle_softc *sc = priv;
+ struct ueagle_intr *intr;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
+ return;
+
+ printf("%s: abnormal interrupt status: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(status));
+
+ if (status == USBD_STALLED)
+ usbd_clear_endpoint_stall_async(sc->pipeh_intr);
+
+ return;
+ }
+
+ intr = (struct ueagle_intr *)sc->ibuf;
+ switch (UGETW(intr->wInterrupt)) {
+ case UEAGLE_INTR_SWAP:
+ ueagle_swap_intr(sc, (struct ueagle_swap *)(intr + 1));
+ break;
+
+ case UEAGLE_INTR_CMV:
+ ueagle_cmv_intr(sc, (struct ueagle_cmv *)(intr + 1));
+ break;
+
+ default:
+ printf("%s: caught unknown interrupt\n",
+ USBDEVNAME(sc->sc_dev));
+ }
+}
+
+static const uint32_t ueagle_crc32_table[256] = {
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc,
+ 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f,
+ 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a,
+ 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+ 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8,
+ 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
+ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e,
+ 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+ 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84,
+ 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027,
+ 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022,
+ 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077,
+ 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c,
+ 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1,
+ 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+ 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb,
+ 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
+ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d,
+ 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+ 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f,
+ 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044,
+ 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689,
+ 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683,
+ 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59,
+ 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c,
+ 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+ 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e,
+ 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
+ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48,
+ 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+ 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2,
+ 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601,
+ 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604,
+ 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6,
+ 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad,
+ 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7,
+ 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+ 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd,
+ 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
+ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b,
+ 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+ 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679,
+ 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12,
+ 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af,
+ 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5,
+ 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06,
+ 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03,
+ 0xb1f740b4
+};
+
+Static uint32_t
+ueagle_crc_update(uint32_t crc, uint8_t *buf, int len)
+{
+ for (; len != 0; len--, buf++)
+ crc = ueagle_crc32_table[(crc >> 24) ^ *buf] ^ (crc << 8);
+
+ return crc;
+}
+
+/*
+ * Reassembly part of the software ATM AAL5 SAR.
+ */
+Static void
+ueagle_push_cell(struct ueagle_softc *sc, uint8_t *cell)
+{
+ struct ueagle_vcc *vcc = &sc->vcc;
+ struct ifnet *ifp;
+ struct mbuf *m;
+ uint32_t crc;
+ uint16_t pdulen, totlen;
+ int s;
+
+ sc->stats.atm.cells_received++;
+
+ if (!(vcc->flags & UEAGLE_VCC_ACTIVE) ||
+ ATM_CH_GETVPI(cell) != vcc->vpi ||
+ ATM_CH_GETVCI(cell) != vcc->vci) {
+ sc->stats.atm.vcc_no_conn++;
+ return;
+ }
+
+ if (vcc->flags & UEAGLE_VCC_DROP) {
+ if (ATM_CH_ISLASTCELL(cell)) {
+ vcc->flags &= ~UEAGLE_VCC_DROP;
+ sc->stats.atm.cspdus_dropped++;
+ }
+
+ sc->stats.atm.cells_dropped++;
+ return;
+ }
+
+ if (vcc->m == NULL) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ vcc->flags |= UEAGLE_VCC_DROP;
+ return;
+ }
+
+ MCLGET(m, M_DONTWAIT);
+ if (!(m->m_flags & M_EXT)) {
+ vcc->flags |= UEAGLE_VCC_DROP;
+ m_freem(m);
+ return;
+ }
+
+ vcc->m = m;
+ vcc->dst = mtod(m, uint8_t *);
+ vcc->limit = vcc->dst + MCLBYTES - ATM_CELL_PAYLOAD_SIZE;
+ }
+
+ if (vcc->dst > vcc->limit) {
+ vcc->flags |= UEAGLE_VCC_DROP;
+ sc->stats.atm.cells_dropped++;
+ goto fail;
+ }
+
+ memcpy(vcc->dst, cell + ATM_CELL_HEADER_SIZE, ATM_CELL_PAYLOAD_SIZE);
+ vcc->dst += ATM_CELL_PAYLOAD_SIZE;
+
+ if (!ATM_CH_ISLASTCELL(cell))
+ return;
+
+ /*
+ * Handle the last cell of the AAL5 CPCS-PDU.
+ */
+ m = vcc->m;
+
+ totlen = vcc->dst - mtod(m, uint8_t *);
+ pdulen = AAL5_TR_GETPDULEN(cell);
+
+ if (totlen < pdulen + AAL5_TRAILER_SIZE) {
+ sc->stats.atm.cspdus_dropped++;
+ goto fail;
+ }
+
+ if (totlen >= pdulen + ATM_CELL_PAYLOAD_SIZE + AAL5_TRAILER_SIZE) {
+ sc->stats.atm.cspdus_dropped++;
+ goto fail;
+ }
+
+ crc = ueagle_crc_update(CRC_INITIAL, mtod(m, uint8_t *), totlen);
+ if (crc != CRC_MAGIC) {
+ sc->stats.atm.cspdus_crc_errors++;
+ goto fail;
+ }
+
+ /* finalize mbuf */
+ ifp = &sc->sc_if;
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = pdulen;
+
+ sc->stats.atm.cspdus_received++;
+
+ s = splnet();
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf != NULL)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+
+ /* send the AAL5 CPCS-PDU to the ATM layer */
+ ifp->if_ipackets++;
+ atm_input(ifp, &vcc->aph, m, vcc->rxhand);
+ vcc->m = NULL;
+
+ splx(s);
+
+ return;
+
+fail: m_freem(vcc->m);
+ vcc->m = NULL;
+}
+
+Static void
+ueagle_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv,
+ usbd_status status)
+{
+ struct ueagle_isoreq *req = priv;
+ struct ueagle_softc *sc = req->sc;
+ uint32_t count;
+ uint8_t *p;
+ int i;
+
+ if (status == USBD_CANCELLED)
+ return;
+
+ for (i = 0; i < UEAGLE_NISOFRMS; i++) {
+ count = req->frlengths[i];
+ p = req->offsets[i];
+
+ while (count >= ATM_CELL_SIZE) {
+ ueagle_push_cell(sc, p);
+ p += ATM_CELL_SIZE;
+ count -= ATM_CELL_SIZE;
+ }
+#ifdef DIAGNOSTIC
+ if (count > 0) {
+ printf("%s: truncated cell (%u bytes)\n", count,
+ USBDEVNAME(sc->sc_dev));
+ }
+#endif
+ req->frlengths[i] = sc->isize;
+ }
+
+ usbd_setup_isoc_xfer(req->xfer, sc->pipeh_rx, req, req->frlengths,
+ UEAGLE_NISOFRMS, USBD_NO_COPY, ueagle_rxeof);
+ usbd_transfer(xfer);
+}
+
+Static void
+ueagle_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
+ usbd_status status)
+{
+ struct ueagle_txreq *req = priv;
+ struct ueagle_softc *sc = req->sc;
+ struct ifnet *ifp = &sc->sc_if;
+ int s;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
+ return;
+
+ printf("%s: could not transmit buffer: %s\n",
+ USBDEVNAME(sc->sc_dev), usbd_errstr(status));
+
+ if (status == USBD_STALLED)
+ usbd_clear_endpoint_stall(sc->pipeh_tx);
+
+ ifp->if_oerrors++;
+ return;
+ }
+
+ s = splnet();
+
+ ifp->if_opackets++;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ ueagle_start(ifp);
+
+ splx(s);
+}
+
+/*
+ * Segmentation part of the software ATM AAL5 SAR.
+ */
+Static int
+ueagle_encap(struct ueagle_softc *sc, struct mbuf *m0)
+{
+ struct ueagle_vcc *vcc = &sc->vcc;
+ struct ueagle_txreq *req;
+ struct mbuf *m;
+ uint8_t *src, *dst;
+ uint32_t crc;
+ int n, cellleft, mleft;
+ usbd_status error;
+
+ req = &sc->txreqs[0];
+
+ m_adj(m0, sizeof (struct atm_pseudohdr));
+
+ dst = req->buf;
+ cellleft = 0;
+ crc = CRC_INITIAL;
+
+ for (m = m0; m != NULL; m = m->m_next) {
+ src = mtod(m, uint8_t *);
+ mleft = m->m_len;
+
+ crc = ueagle_crc_update(crc, src, mleft);
+
+ if (cellleft != 0) {
+ n = min(mleft, cellleft);
+
+ memcpy(dst, src, n);
+ dst += n;
+ src += n;
+ cellleft -= n;
+ mleft -= n;
+ }
+
+ while (mleft >= ATM_CELL_PAYLOAD_SIZE) {
+ memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
+ dst += ATM_CELL_HEADER_SIZE;
+ memcpy(dst, src, ATM_CELL_PAYLOAD_SIZE);
+ dst += ATM_CELL_PAYLOAD_SIZE;
+ src += ATM_CELL_PAYLOAD_SIZE;
+ mleft -= ATM_CELL_PAYLOAD_SIZE;
+ sc->stats.atm.cells_transmitted++;
+ }
+
+ if (mleft != 0) {
+ memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
+ dst += ATM_CELL_HEADER_SIZE;
+ memcpy(dst, src, mleft);
+ dst += mleft;
+ cellleft = ATM_CELL_PAYLOAD_SIZE - mleft;
+ sc->stats.atm.cells_transmitted++;
+ }
+ }
+
+ /*
+ * If there is not enough space to put the AAL5 trailer into this cell,
+ * pad the content of this cell with zeros and create a new cell which
+ * will contain no data except the AAL5 trailer itself.
+ */
+ if (cellleft < AAL5_TRAILER_SIZE) {
+ memset(dst, 0, cellleft);
+ crc = ueagle_crc_update(crc, dst, cellleft);
+ dst += cellleft;
+
+ memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
+ dst += ATM_CELL_HEADER_SIZE;
+ cellleft = ATM_CELL_PAYLOAD_SIZE;
+ sc->stats.atm.cells_transmitted++;
+ }
+
+ /*
+ * Fill the AAL5 CPCS-PDU trailer.
+ */
+ memset(dst, 0, cellleft - AAL5_TRAILER_SIZE);
+
+ /* src now points to the beginning of the last cell */
+ src = dst + cellleft - ATM_CELL_SIZE;
+ ATM_CH_SETPTFLAGS(src, 1);
+
+ AAL5_TR_SETCPSUU(src, 0);
+ AAL5_TR_SETCPI(src, 0);
+ AAL5_TR_SETPDULEN(src, m0->m_pkthdr.len);
+
+ crc = ~ueagle_crc_update(crc, dst, cellleft - 4);
+ AAL5_TR_SETCRC(src, crc);
+
+ usbd_setup_xfer(req->xfer, sc->pipeh_tx, req, req->buf,
+ dst + cellleft - req->buf, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
+ UEAGLE_TX_TIMEOUT, ueagle_txeof);
+
+ error = usbd_transfer(req->xfer);
+ if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
+ return error;
+
+ sc->stats.atm.cspdus_transmitted++;
+
+ return 0;
+}
+
+Static void
+ueagle_start(struct ifnet *ifp)
+{
+ struct ueagle_softc *sc = ifp->if_softc;
+ struct mbuf *m0;
+
+ /* nothing goes out until modem is synchronized and VCC is opened */
+ if (!(sc->vcc.flags & UEAGLE_VCC_ACTIVE))
+ return;
+
+ IFQ_POLL(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ return;
+
+ if (ueagle_encap(sc, m0) != 0) {
+ m_freem(m0);
+ return;
+ }
+
+ IFQ_DEQUEUE(&ifp->if_snd, m0);
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf != NULL)
+ bpf_mtap(ifp->if_bpf, m0);
+#endif
+
+ m_freem(m0);
+
+ ifp->if_flags |= IFF_OACTIVE;
+}
+
+Static int
+ueagle_open_vcc(struct ueagle_softc *sc, struct atm_pseudoioctl *api)
+{
+ struct ueagle_vcc *vcc = &sc->vcc;
+
+ DPRINTF(("%s: opening ATM VCC\n", USBDEVNAME(sc->sc_dev)));
+
+ vcc->vpi = ATM_PH_VPI(&api->aph);
+ vcc->vci = ATM_PH_VCI(&api->aph);
+ vcc->rxhand = api->rxhand;
+ vcc->m = NULL;
+ vcc->aph = api->aph;
+ vcc->flags = UEAGLE_VCC_ACTIVE;
+
+ /* pre-calculate cell headers (HEC field is set by hardware) */
+ ATM_CH_FILL(vcc->ch, 0, vcc->vpi, vcc->vci, 0, 0, 0);
+
+ return 0;
+}
+
+Static int
+ueagle_close_vcc(struct ueagle_softc *sc, struct atm_pseudoioctl *api)
+{
+ DPRINTF(("%s: closing ATM VCC\n", USBDEVNAME(sc->sc_dev)));
+
+ sc->vcc.flags &= ~UEAGLE_VCC_ACTIVE;
+
+ return 0;
+}
+
+Static int
+ueagle_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct ueagle_softc *sc = ifp->if_softc;
+ struct atm_pseudoioctl *api;
+ struct ifaddr *ifa;
+ struct ifreq *ifr;
+ int s, error = 0;
+
+ s = splnet();
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifa = (struct ifaddr *)data;
+ ifp->if_flags |= IFF_UP;
+
+ ueagle_init(ifp);
+#ifdef INET
+ ifa->ifa_rtrequest = atm_rtrequest;
+#endif
+ break;
+
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (!(ifp->if_flags & IFF_RUNNING))
+ ueagle_init(ifp);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ ueagle_stop(ifp, 1);
+ }
+ break;
+
+ case SIOCSIFMTU:
+ ifr = (struct ifreq *)data;
+
+ if (ifr->ifr_mtu > UEAGLE_IFMTU)
+ error = EINVAL;
+ else
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+
+ case SIOCATMENA:
+ api = (struct atm_pseudoioctl *)data;
+ error = ueagle_open_vcc(sc, api);
+ break;
+
+ case SIOCATMDIS:
+ api = (struct atm_pseudoioctl *)data;
+ error = ueagle_close_vcc(sc, api);
+ break;
+
+ default:
+ error = EINVAL;
+ }
+
+ splx(s);
+
+ return error;
+}
+
+Static int
+ueagle_open_pipes(struct ueagle_softc *sc)
+{
+ usb_endpoint_descriptor_t *edesc;
+ usbd_interface_handle iface;
+ struct ueagle_txreq *txreq;
+ struct ueagle_isoreq *isoreq;
+ usbd_status error;
+ uint8_t *buf;
+ int i, j;
+
+ error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_US_IFACE_NO,
+ &iface);
+ if (error != 0) {
+ printf("%s: could not get tx interface handle\n",
+ USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ error = usbd_open_pipe(iface, UEAGLE_TX_PIPE, USBD_EXCLUSIVE_USE,
+ &sc->pipeh_tx);
+ if (error != 0) {
+ printf("%s: could not open tx pipe\n", USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ for (i = 0; i < UEAGLE_TX_LIST_CNT; i++) {
+ txreq = &sc->txreqs[i];
+
+ txreq->sc = sc;
+
+ txreq->xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (txreq->xfer == NULL) {
+ printf("%s: could not allocate tx xfer\n",
+ USBDEVNAME(sc->sc_dev));
+ error = ENOMEM;
+ goto fail;
+ }
+
+ txreq->buf = usbd_alloc_buffer(txreq->xfer, UEAGLE_TXBUFLEN);
+ if (txreq->buf == NULL) {
+ printf("%s: could not allocate tx buffer\n",
+ USBDEVNAME(sc->sc_dev));
+ error = ENOMEM;
+ goto fail;
+ }
+ }
+
+ error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_DS_IFACE_NO,
+ &iface);
+ if (error != 0) {
+ printf("%s: could not get rx interface handle\n",
+ USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ /* XXX: alternative interface number sould depend on downrate */
+ error = usbd_set_interface(iface, 8);
+ if (error != 0) {
+ printf("%s: could not set rx alternative interface\n",
+ USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ edesc = usbd_get_endpoint_descriptor(iface, UEAGLE_RX_PIPE);
+ if (edesc == NULL) {
+ printf("%s: could not get rx endpoint descriptor\n",
+ USBDEVNAME(sc->sc_dev));
+ error = EIO;
+ goto fail;
+ }
+
+ sc->isize = UGETW(edesc->wMaxPacketSize);
+
+ error = usbd_open_pipe(iface, UEAGLE_RX_PIPE, USBD_EXCLUSIVE_USE,
+ &sc->pipeh_rx);
+ if (error != 0) {
+ printf("%s: could not open rx pipe\n", USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ for (i = 0; i < UEAGLE_NISOREQS; i++) {
+ isoreq = &sc->isoreqs[i];
+
+ isoreq->sc = sc;
+
+ isoreq->xfer = usbd_alloc_xfer(sc->sc_udev);
+ if (isoreq->xfer == NULL) {
+ printf("%s: could not allocate rx xfer\n",
+ USBDEVNAME(sc->sc_dev));
+ error = ENOMEM;
+ goto fail;
+ }
+
+ buf = usbd_alloc_buffer(isoreq->xfer,
+ sc->isize * UEAGLE_NISOFRMS);
+ if (buf == NULL) {
+ printf("%s: could not allocate rx buffer\n",
+ USBDEVNAME(sc->sc_dev));
+ error = ENOMEM;
+ goto fail;
+ }
+
+ for (j = 0; j < UEAGLE_NISOFRMS; j++) {
+ isoreq->frlengths[j] = sc->isize;
+ isoreq->offsets[j] = buf + j * sc->isize;
+ }
+
+ usbd_setup_isoc_xfer(isoreq->xfer, sc->pipeh_rx, isoreq,
+ isoreq->frlengths, UEAGLE_NISOFRMS, USBD_NO_COPY,
+ ueagle_rxeof);
+ usbd_transfer(isoreq->xfer);
+ }
+
+ ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_LOOPBACKOFF, NULL, 0);
+
+ return 0;
+
+fail: ueagle_close_pipes(sc);
+ return error;
+}
+
+Static void
+ueagle_close_pipes(struct ueagle_softc *sc)
+{
+ int i;
+
+ ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_LOOPBACKON, NULL, 0);
+
+ /* free Tx resources */
+ if (sc->pipeh_tx != NULL) {
+ usbd_abort_pipe(sc->pipeh_tx);
+ usbd_close_pipe(sc->pipeh_tx);
+ sc->pipeh_tx = NULL;
+ }
+
+ for (i = 0; i < UEAGLE_TX_LIST_CNT; i++) {
+ if (sc->txreqs[i].xfer != NULL) {
+ usbd_free_xfer(sc->txreqs[i].xfer);
+ sc->txreqs[i].xfer = NULL;
+ }
+ }
+
+ /* free Rx resources */
+ if (sc->pipeh_rx != NULL) {
+ usbd_abort_pipe(sc->pipeh_rx);
+ usbd_close_pipe(sc->pipeh_rx);
+ sc->pipeh_rx = NULL;
+ }
+
+ for (i = 0; i < UEAGLE_NISOREQS; i++) {
+ if (sc->isoreqs[i].xfer != NULL) {
+ usbd_free_xfer(sc->isoreqs[i].xfer);
+ sc->isoreqs[i].xfer = NULL;
+ }
+ }
+}
+
+Static int
+ueagle_init(struct ifnet *ifp)
+{
+ struct ueagle_softc *sc = ifp->if_softc;
+ usbd_interface_handle iface;
+ usbd_status error;
+ int len;
+
+ ueagle_stop(ifp, 0);
+
+ error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_US_IFACE_NO,
+ &iface);
+ if (error != 0) {
+ printf("%s: could not get idma interface handle\n",
+ USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ error = usbd_open_pipe(iface, UEAGLE_IDMA_PIPE, USBD_EXCLUSIVE_USE,
+ &sc->pipeh_idma);
+ if (error != 0) {
+ printf("%s: could not open idma pipe\n",
+ USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_INTR_IFACE_NO,
+ &iface);
+ if (error != 0) {
+ printf("%s: could not get interrupt interface handle\n",
+ USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ error = loadfirmware("ueagle-dsp", &sc->dsp, &len);
+ if (error != 0) {
+ printf("%s: could not load firmware\n", USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ error = usbd_open_pipe_intr(iface, UEAGLE_INTR_PIPE, USBD_SHORT_XFER_OK,
+ &sc->pipeh_intr, sc, sc->ibuf, UEAGLE_INTR_MAXSIZE, ueagle_intr,
+ UEAGLE_INTR_INTERVAL);
+ if (error != 0) {
+ printf("%s: could not open interrupt pipe\n",
+ USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ error = ueagle_boot(sc);
+ if (error != 0) {
+ printf("%s: could not boot modem\n", USBDEVNAME(sc->sc_dev));
+ goto fail;
+ }
+
+ /*
+ * Opening of tx and rx pipes if deferred after synchronization is
+ * established.
+ */
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return 0;
+
+fail: ueagle_stop(ifp, 1);
+ return error;
+}
+
+Static void
+ueagle_stop(struct ifnet *ifp, int disable)
+{
+ struct ueagle_softc *sc = ifp->if_softc;
+
+ /* stop any pending task */
+ usb_rem_task(sc->sc_udev, &sc->sc_swap_task);
+
+ /* free Tx and Rx resources */
+ ueagle_close_pipes(sc);
+
+ /* free firmware */
+ if (sc->dsp != NULL) {
+ free(sc->dsp, M_DEVBUF);
+ sc->dsp = NULL;
+ }
+
+ /* free interrupt resources */
+ if (sc->pipeh_intr != NULL) {
+ usbd_abort_pipe(sc->pipeh_intr);
+ usbd_close_pipe(sc->pipeh_intr);
+ sc->pipeh_intr = NULL;
+ }
+
+ /* free IDMA resources */
+ if (sc->pipeh_idma != NULL) {
+ usbd_abort_pipe(sc->pipeh_idma);
+ usbd_close_pipe(sc->pipeh_idma);
+ sc->pipeh_idma = NULL;
+ }
+
+ /* reset statistics */
+ memset(&sc->stats, 0, sizeof (struct ueagle_stats));
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+}
+
+Static int
+ueagle_activate(device_ptr_t self, enum devact act)
+{
+ struct ueagle_softc *sc = (struct ueagle_softc *)self;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ return EOPNOTSUPP;
+
+ case DVACT_DEACTIVATE:
+ if_deactivate(&sc->sc_if);
+ sc->gone = 1;
+ break;
+ }
+
+ return 0;
+}
diff --git a/sys/dev/usb/ueaglereg.h b/sys/dev/usb/ueaglereg.h
new file mode 100644
index 00000000000..f6e2ed8b843
--- /dev/null
+++ b/sys/dev/usb/ueaglereg.h
@@ -0,0 +1,123 @@
+/* $OpenBSD: ueaglereg.h,v 1.1 2005/04/16 14:55:10 damien Exp $ */
+
+/*-
+ * Copyright (c) 2003-2005
+ * Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+/* OPTN: default values from analog devices */
+#ifndef UEAGLE_OPTN0
+#define UEAGLE_OPTN0 0x80020066
+#endif
+#ifndef UEAGLE_OPTN2
+#define UEAGLE_OPTN2 0x23700000
+#endif
+#ifndef UEAGLE_OPTN7
+#define UEAGLE_OPTN7 0x02cd8044
+#endif
+
+#define UEAGLE_CONFIG_NO 1
+
+#define UEAGLE_INTR_IFACE_NO 0
+#define UEAGLE_US_IFACE_NO 1
+#define UEAGLE_DS_IFACE_NO 2
+
+#define UEAGLE_ESISTR 4
+
+#define UEAGLE_TX_PIPE 0x02
+#define UEAGLE_IDMA_PIPE 0x04
+#define UEAGLE_INTR_PIPE 0x84
+#define UEAGLE_RX_PIPE 0x88
+
+#define UEAGLE_REQUEST 0
+
+#define UEAGLE_SETBLOCK 0x0001
+#define UEAGLE_SETMODE 0x0003
+#define UEAGLE_SET2183DATA 0x0004
+
+#define UEAGLE_LOOPBACKOFF 0x0002
+#define UEAGLE_LOOPBACKON 0x0003
+#define UEAGLE_BOOTIDMA 0x0006
+#define UEAGLE_STARTRESET 0x0007
+#define UEAGLE_ENDRESET 0x0008
+#define UEAGLE_SWAPMAILBOX 0x7fcd
+#define UEAGLE_MPTXSTART 0x7fce
+#define UEAGLE_MPTXMAILBOX 0x7fd6
+#define UEAGLE_MPRXMAILBOX 0x7fdf
+
+/* block within a firmware page */
+struct ueagle_block_info {
+ uWord wHdr;
+#define UEAGLE_BLOCK_INFO_HDR 0xabcd
+
+ uWord wAddress;
+ uWord wSize;
+ uWord wOvlOffset;
+ uWord wOvl; /* overlay */
+ uWord wLast;
+} UPACKED;
+
+/* CMV (Configuration and Management Variable) */
+struct ueagle_cmv {
+ uWord wPreamble;
+#define UEAGLE_CMV_PREAMBLE 0x535c
+
+ uByte bDst;
+#define UEAGLE_HOST 0x01
+#define UEAGLE_MODEM 0x10
+
+ uByte bFunction;
+#define UEAGLE_CR 0x10
+#define UEAGLE_CW 0x11
+#define UEAGLE_CR_ACK 0x12
+#define UEAGLE_MODEMREADY 0x71
+
+ uWord wIndex;
+ uDWord dwSymbolicAddress;
+#define UEAGLE_MAKESA(a, b, c, d) ((c) << 24 | (d) << 16 | (a) << 8 | (b))
+#define UEAGLE_CMV_CNTL UEAGLE_MAKESA('C', 'N', 'T', 'L')
+#define UEAGLE_CMV_DIAG UEAGLE_MAKESA('D', 'I', 'A', 'G')
+#define UEAGLE_CMV_INFO UEAGLE_MAKESA('I', 'N', 'F', 'O')
+#define UEAGLE_CMV_OPTN UEAGLE_MAKESA('O', 'P', 'T', 'N')
+#define UEAGLE_CMV_RATE UEAGLE_MAKESA('R', 'A', 'T', 'E')
+#define UEAGLE_CMV_STAT UEAGLE_MAKESA('S', 'T', 'A', 'T')
+
+ uWord wOffsetAddress;
+ uDWord dwData;
+#define UGETDATA(w) ((w)[2] | (w)[3] << 8 | (w)[0] << 16 | (w)[1] << 24)
+#define USETDATA(w, v) \
+ ((w)[2] = (uint8_t)(v), \
+ (w)[3] = (uint8_t)((v) >> 8), \
+ (w)[0] = (uint8_t)((v) >> 16), \
+ (w)[1] = (uint8_t)((v) >> 24))
+} UPACKED;
+
+struct ueagle_swap {
+ uByte bPageNo;
+ uByte bOvl; /* overlay */
+} UPACKED;
+
+struct ueagle_intr {
+ uByte bType;
+ uByte bNotification;
+ uWord wValue;
+ uWord wIndex;
+ uWord wLength;
+ uWord wInterrupt;
+#define UEAGLE_INTR_SWAP 1
+#define UEAGLE_INTR_CMV 2
+} UPACKED;
+
+#define UEAGLE_INTR_MAXSIZE 28
diff --git a/sys/dev/usb/ueaglevar.h b/sys/dev/usb/ueaglevar.h
new file mode 100644
index 00000000000..ec41efc45f0
--- /dev/null
+++ b/sys/dev/usb/ueaglevar.h
@@ -0,0 +1,191 @@
+/* $OpenBSD: ueaglevar.h,v 1.1 2005/04/16 14:55:10 damien Exp $ */
+
+/*-
+ * Copyright (c) 2003-2005
+ * Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * 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.
+ */
+
+#define UEAGLE_NISOREQS 6
+#define UEAGLE_NISOFRMS 4
+
+#ifndef UEAGLE_INTR_INTERVAL
+#define UEAGLE_INTR_INTERVAL 10 /* ms */
+#endif
+
+#define UEAGLE_TX_LIST_CNT 1
+
+#define UEAGLE_IDMA_TIMEOUT 1000
+#define UEAGLE_TX_TIMEOUT 10000
+
+#define CRC_INITIAL 0xffffffff
+#define CRC_MAGIC 0xc704dd7b
+
+#define ATM_CELL_SIZE 53
+#define ATM_CELL_HEADER_SIZE 5
+#define ATM_CELL_PAYLOAD_SIZE (ATM_CELL_SIZE - ATM_CELL_HEADER_SIZE)
+
+#define AAL5_TRAILER_SIZE 8
+
+/*-
+ * ATM cell header:
+ *
+ * 0 4 8
+ * +-----------------+-----------------+
+ * | GFC | VPI |
+ * +-----------------+-----------------+
+ * | VPI | VCI |
+ * +-----------------+-----------------+
+ * | VCI |
+ * +-----------------+-----------+-----+
+ * | VCI | PT (3) | CLP |
+ * +-----------------+-----------+-----+
+ * | HEC |
+ * +-----------------------------------+
+ */
+#define ATM_CH_FILL(x, gfc, vpi, vci, pt, clp, hec) do { \
+ (x)[0] = ((gfc) & 0xf) << 4 | ((vpi) & 0xf0) >> 4; \
+ (x)[1] = ((vpi) & 0xf) << 4 | ((vci) & 0xf000) >> 12; \
+ (x)[2] = ((vci) & 0xff0) >> 4; \
+ (x)[3] = ((vci) & 0xf) << 4 | ((pt) & 0x7) << 1 | ((clp) & 0x1);\
+ (x)[4] = (uint8_t)(hec); \
+} while (/* CONSTCOND */0)
+
+#define ATM_CH_SETPTFLAGS(x, v) ((x)[3] |= ((v) & 0x7) << 1)
+#define ATM_CH_GETPTFLAGS(x) (((x)[3] >> 1) & 0x7)
+#define ATM_CH_GETVPI(x) ((x)[0] << 4 | (x)[1] >> 4)
+#define ATM_CH_GETVCI(x) \
+ (((x)[1] & 0xf) << 12 | (x)[2] << 4 | ((x)[3] & 0xf0) >> 4)
+
+/* optimized shortcut for (ATM_CH_GETPTFLAGS(x) & 1) */
+#define ATM_CH_ISLASTCELL(x) ((x)[3] & 0x2)
+
+#define AAL5_TR_SETCPSUU(x, v) ((x)[45] = (uint8_t)(v))
+#define AAL5_TR_SETCPI(x, v) ((x)[46] = (uint8_t)(v))
+#define AAL5_TR_SETPDULEN(x, v) do { \
+ (x)[47] = (uint8_t)((v) >> 8); \
+ (x)[48] = (uint8_t)(v); \
+} while (/* CONSTCOND */0)
+
+#define AAL5_TR_GETPDULEN(x) (uint16_t)((x)[47] << 8 | (x)[48])
+#define AAL5_TR_SETCRC(x, v) do { \
+ (x)[49] = (uint8_t)((v) >> 24); \
+ (x)[50] = (uint8_t)((v) >> 16); \
+ (x)[51] = (uint8_t)((v) >> 8); \
+ (x)[52] = (uint8_t)(v); \
+} while (/* CONSTCOND */0)
+
+#define UEAGLE_IFMTU 1500
+#define UEAGLE_TXBUFLEN \
+ (((UEAGLE_IFMTU / ATM_CELL_PAYLOAD_SIZE) + 2) * ATM_CELL_SIZE)
+
+struct ueagle_vcc {
+ uint16_t vci;
+ uint8_t vpi;
+ uint8_t ch[ATM_CELL_HEADER_SIZE];
+ void *rxhand;
+ struct mbuf *m;
+ uint8_t *dst;
+ uint8_t *limit;
+ struct atm_pseudohdr aph;
+ int flags;
+#define UEAGLE_VCC_ACTIVE (1 << 0)
+#define UEAGLE_VCC_DROP (1 << 1)
+};
+
+struct ueagle_softc;
+
+struct ueagle_isoreq {
+ struct ueagle_softc *sc;
+ usbd_xfer_handle xfer;
+ uint16_t frlengths[UEAGLE_NISOFRMS];
+ uint8_t *offsets[UEAGLE_NISOFRMS];
+};
+
+struct ueagle_txreq {
+ struct ueagle_softc *sc;
+ usbd_xfer_handle xfer;
+ uint8_t *buf;
+};
+
+struct ueagle_stats {
+ struct {
+ uint32_t status;
+ uint32_t flags;
+ uint32_t vidcpe;
+ uint32_t vidco;
+ uint32_t dsrate;
+ uint32_t usrate;
+ uint32_t dserror;
+ uint32_t userror;
+ uint32_t dsunc;
+ uint32_t usunc;
+ uint32_t txflow;
+ uint32_t rxflow;
+ uint32_t attenuation;
+ uint32_t dsmargin;
+ uint32_t usmargin;
+ } phy;
+
+ struct {
+ uint32_t cells_transmitted;
+ uint32_t cells_received;
+ uint32_t cells_crc_errors;
+ uint32_t cells_dropped;
+ uint32_t vcc_no_conn;
+ uint32_t cspdus_transmitted;
+ uint32_t cspdus_received;
+ uint32_t cspdus_crc_errors;
+ uint32_t cspdus_dropped;
+ } atm;
+};
+
+#define UEAGLE_COND_CMV(sc) ((char *)(sc) + 1)
+#define UEAGLE_COND_READY(sc) ((char *)(sc) + 2)
+#define UEAGLE_COND_SYNC(sc) ((char *)(sc) + 3)
+
+struct ueagle_softc {
+ USBBASEDEVICE sc_dev;
+ struct ifnet sc_if;
+
+ usbd_device_handle sc_udev;
+
+ struct proc *stat_thread;
+ struct usb_task sc_swap_task;
+ uint16_t pageno;
+ uint16_t ovl;
+
+ const char *fw;
+ uint8_t *dsp;
+
+ struct usb_task sc_init_task;
+
+ usbd_pipe_handle pipeh_tx;
+ usbd_pipe_handle pipeh_rx;
+ usbd_pipe_handle pipeh_idma;
+ usbd_pipe_handle pipeh_intr;
+
+ struct ueagle_isoreq isoreqs[UEAGLE_NISOREQS];
+ struct ueagle_txreq txreqs[UEAGLE_TX_LIST_CNT];
+ struct ueagle_vcc vcc;
+ struct ueagle_stats stats;
+
+ uint16_t isize;
+ char ibuf[32];
+
+ int gone;
+
+ uint16_t index;
+ uint32_t data;
+};
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index 8540e0f7032..05bc3424277 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -1,4 +1,4 @@
-$OpenBSD: usbdevs,v 1.151 2005/04/15 13:44:40 jakob Exp $
+$OpenBSD: usbdevs,v 1.152 2005/04/16 14:55:10 damien Exp $
/* $NetBSD: usbdevs,v 1.322 2003/05/10 17:47:14 hamajima Exp $ */
/*
@@ -386,6 +386,7 @@ vendor MOTOROLA 0x1063 Motorola
vendor CCYU 0x1065 CCYU Technology
vendor PLX 0x10b5 PLX
vendor ASANTE 0x10bd Asante
+vendor ANALOG 0x1110 Analog Devices, Inc.
vendor JRC 0x1145 Japan Radio Company
vendor SERVERWORKS 0x1166 ServerWorks
vendor ACERCM 0x1189 Acer Communications & Multimedia
@@ -565,6 +566,16 @@ product AMBIT WLAN 0x0302 WLAN
/* American Power Conversion products */
product APC UPSPRO500 0x0002 Back-UPS Pro 500
+/* Analog Devices, Inc. products */
+product ANALOG EAGLEI 0x900f Eagle I
+product ANALOG EAGLEI_NF 0x9010 Eagle I
+product ANALOG EAGLEII 0x9021 Eagle II
+product ANALOG EAGLEII_NF 0x9022 Eagle II
+product ANALOG EAGLEIIC 0x9023 Eagle IIC
+product ANALOG EAGLEIIC_NF 0x9024 Eagle IIC
+product ANALOG EAGLEIII 0x9031 Eagle III
+product ANALOG EAGLEIII_NF 0x9032 Eagle III
+
/* Anchor products */
product ANCHOR EZUSB 0x2131 EZUSB
product ANCHOR EZLINK 0x2720 EZLINK
@@ -1787,6 +1798,14 @@ product UNIACCESS PANACHE 0x0101 Panache Surf ISDN
/* U.S. Robotics products */
product USR USR1120 0x00eb USR1120 WLAN
+product USR MILLER_A 0x00f1 USR9000 SureConnect ADSL
+product USR MILLER_A_NF 0x00f2 USR9000 SureConnect ADSL
+product USR HEINEKEN_A 0x00f5 USR9000 SureConnect ADSL
+product USR HEINEKEN_A_NF 0x00f6 USR9000 SureConnect ADSL
+product USR HEINEKEN_B 0x00f7 USR9000 SureConnect ADSL
+product USR HEINEKEN_B_NF 0x00f8 USR9000 SureConnect ADSL
+product USR MILLER_B 0x00f9 USR9000 SureConnect ADSL
+product USR MILLER_B_NF 0x00fa USR9000 SureConnect ADSL
/* ViewSonic products */
product VIEWSONIC G773HUB 0x00fe G773 Monitor Hub