root/dev/usb/ueagle.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ueagle_match
  2. ueagle_attachhook
  3. ueagle_attach
  4. ueagle_detach
  5. ueagle_getesi
  6. ueagle_loadpage
  7. ueagle_request
  8. ueagle_dump_cmv
  9. ueagle_cr
  10. ueagle_cw
  11. ueagle_stat
  12. ueagle_stat_thread
  13. ueagle_boot
  14. ueagle_swap_intr
  15. ueagle_cmv_intr
  16. ueagle_intr
  17. ueagle_crc_update
  18. ueagle_push_cell
  19. ueagle_rxeof
  20. ueagle_txeof
  21. ueagle_encap
  22. ueagle_start
  23. ueagle_open_vcc
  24. ueagle_close_vcc
  25. ueagle_ioctl
  26. ueagle_open_pipes
  27. ueagle_close_pipes
  28. ueagle_init
  29. ueagle_stop
  30. ueagle_activate

    1 /*      $OpenBSD: ueagle.c,v 1.21 2007/06/14 10:11:15 mbalmer Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 2003-2006
    5  *      Damien Bergamini <damien.bergamini@free.fr>
    6  *
    7  * Permission to use, copy, modify, and distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 
   20 /*-
   21  * Driver for Analog Devices Eagle chipset.
   22  * http://www.analog.com/
   23  */
   24 
   25 #include "bpfilter.h"
   26 
   27 #include <sys/param.h>
   28 #include <sys/sysctl.h>
   29 #include <sys/sockio.h>
   30 #include <sys/mbuf.h>
   31 #include <sys/kernel.h>
   32 #include <sys/socket.h>
   33 #include <sys/systm.h>
   34 #include <sys/malloc.h>
   35 #include <sys/device.h>
   36 #include <sys/kthread.h>
   37 
   38 #include <net/bpf.h>
   39 #include <net/if.h>
   40 #include <net/if_atm.h>
   41 #include <net/if_media.h>
   42 
   43 #ifdef INET
   44 #include <netinet/in.h>
   45 #include <netinet/if_atm.h>
   46 #include <netinet/if_ether.h>
   47 #endif
   48 
   49 #include <dev/usb/usb.h>
   50 #include <dev/usb/usbdi.h>
   51 #include <dev/usb/usbdi_util.h>
   52 #include <dev/usb/ezload.h>
   53 #include <dev/usb/usbdevs.h>
   54 
   55 #include <dev/usb/ueaglereg.h>
   56 #include <dev/usb/ueaglevar.h>
   57 
   58 #ifdef USB_DEBUG
   59 #define DPRINTF(x)      do { if (ueagledebug > 0) printf x; } while (0)
   60 #define DPRINTFN(n, x)  do { if (ueagledebug >= (n)) printf x; } while (0)
   61 int ueagledebug = 0;
   62 #else
   63 #define DPRINTF(x)
   64 #define DPRINTFN(n, x)
   65 #endif
   66 
   67 /* various supported device vendors/products */
   68 static const struct ueagle_type {
   69         struct usb_devno        dev;
   70         const char              *fw;
   71 } ueagle_devs[] = {
   72   { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEI },      NULL },
   73   { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEI_NF },   "ueagleI" },
   74   { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEII },     NULL },
   75   { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEII_NF },  "ueagleII" },
   76   { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIIC },    NULL },
   77   { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIIC_NF }, "ueagleII" },
   78   { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIII },    NULL },
   79   { { USB_VENDOR_ANALOG, USB_PRODUCT_ANALOG_EAGLEIII_NF }, "ueagleIII" },
   80   { { USB_VENDOR_USR,    USB_PRODUCT_USR_HEINEKEN_A },     NULL },
   81   { { USB_VENDOR_USR,    USB_PRODUCT_USR_HEINEKEN_A_NF },  "ueagleI" },
   82   { { USB_VENDOR_USR,    USB_PRODUCT_USR_HEINEKEN_B },     NULL },
   83   { { USB_VENDOR_USR,    USB_PRODUCT_USR_HEINEKEN_B_NF },  "ueagleI" },
   84   { { USB_VENDOR_USR,    USB_PRODUCT_USR_MILLER_A },       NULL },
   85   { { USB_VENDOR_USR,    USB_PRODUCT_USR_MILLER_A_NF },    "ueagleI" },
   86   { { USB_VENDOR_USR,    USB_PRODUCT_USR_MILLER_B },       NULL },
   87   { { USB_VENDOR_USR,    USB_PRODUCT_USR_MILLER_B_NF },    "ueagleI" }
   88 };
   89 #define ueagle_lookup(v, p)     \
   90         ((struct ueagle_type *)usb_lookup(ueagle_devs, v, p))
   91 
   92 void            ueagle_attachhook(void *);
   93 int             ueagle_getesi(struct ueagle_softc *, uint8_t *);
   94 void            ueagle_loadpage(void *);
   95 void            ueagle_request(struct ueagle_softc *, uint16_t, uint16_t,
   96                     void *, int);
   97 #ifdef USB_DEBUG
   98 void            ueagle_dump_cmv(struct ueagle_softc *, struct ueagle_cmv *);
   99 #endif
  100 int             ueagle_cr(struct ueagle_softc *, uint32_t, uint16_t,
  101                     uint32_t *);
  102 int             ueagle_cw(struct ueagle_softc *, uint32_t, uint16_t, uint32_t);
  103 int             ueagle_stat(struct ueagle_softc *);
  104 void            ueagle_stat_thread(void *);
  105 int             ueagle_boot(struct ueagle_softc *);
  106 void            ueagle_swap_intr(struct ueagle_softc *, struct ueagle_swap *);
  107 void            ueagle_cmv_intr(struct ueagle_softc *, struct ueagle_cmv *);
  108 void            ueagle_intr(usbd_xfer_handle, usbd_private_handle,
  109                     usbd_status);
  110 uint32_t        ueagle_crc_update(uint32_t, uint8_t *, int);
  111 void            ueagle_push_cell(struct ueagle_softc *, uint8_t *);
  112 void            ueagle_rxeof(usbd_xfer_handle, usbd_private_handle,
  113                     usbd_status);
  114 void            ueagle_txeof(usbd_xfer_handle, usbd_private_handle,
  115                     usbd_status);
  116 int             ueagle_encap(struct ueagle_softc *, struct mbuf *);
  117 void            ueagle_start(struct ifnet *);
  118 int             ueagle_open_vcc(struct ueagle_softc *,
  119                     struct atm_pseudoioctl *);
  120 int             ueagle_close_vcc(struct ueagle_softc *,
  121                     struct atm_pseudoioctl *);
  122 int             ueagle_ioctl(struct ifnet *, u_long, caddr_t);
  123 int             ueagle_open_pipes(struct ueagle_softc *);
  124 void            ueagle_close_pipes(struct ueagle_softc *);
  125 int             ueagle_init(struct ifnet *);
  126 void            ueagle_stop(struct ifnet *, int);
  127 
  128 int ueagle_match(struct device *, void *, void *); 
  129 void ueagle_attach(struct device *, struct device *, void *); 
  130 int ueagle_detach(struct device *, int); 
  131 int ueagle_activate(struct device *, enum devact); 
  132 
  133 struct cfdriver ueagle_cd = { 
  134         NULL, "ueagle", DV_DULL 
  135 }; 
  136 
  137 const struct cfattach ueagle_ca = { 
  138         sizeof(struct ueagle_softc), 
  139         ueagle_match, 
  140         ueagle_attach, 
  141         ueagle_detach, 
  142         ueagle_activate, 
  143 };
  144 
  145 int
  146 ueagle_match(struct device *parent, void *match, void *aux)
  147 {
  148         struct usb_attach_arg *uaa = aux;
  149 
  150         if (uaa->iface != NULL)
  151                 return UMATCH_NONE;
  152 
  153         return (ueagle_lookup(uaa->vendor, uaa->product) != NULL) ?
  154             UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
  155 }
  156 
  157 void
  158 ueagle_attachhook(void *xsc)
  159 {
  160         char *firmwares[2];
  161         struct ueagle_softc *sc = xsc;
  162 
  163         firmwares[0] = (char *)sc->fw;
  164         firmwares[1] = NULL;
  165 
  166         if (ezload_downloads_and_reset(sc->sc_udev, firmwares) != 0) {
  167                 printf("%s: could not download firmware\n",
  168                     sc->sc_dev.dv_xname);
  169                 return;
  170         }
  171 }
  172 
  173 void
  174 ueagle_attach(struct device *parent, struct device *self, void *aux)
  175 {
  176         struct ueagle_softc *sc = (struct ueagle_softc *)self;
  177         struct usb_attach_arg *uaa = aux;
  178         struct ifnet *ifp = &sc->sc_if;
  179         char *devinfop;
  180         uint8_t addr[ETHER_ADDR_LEN];
  181 
  182         sc->sc_udev = uaa->device;
  183         printf("\n");
  184 
  185         /*
  186          * Pre-firmware modems must be flashed and reset first.  They will
  187          * automatically detach themselves from the bus and reattach later
  188          * with a new product Id.
  189          */
  190         sc->fw = ueagle_lookup(uaa->vendor, uaa->product)->fw;
  191         if (sc->fw != NULL) {
  192                 if (rootvp == NULL)
  193                         mountroothook_establish(ueagle_attachhook, sc);
  194                 else
  195                         ueagle_attachhook(sc);
  196 
  197                 /* processing of pre-firmware modems ends here */
  198                 return;
  199         }
  200 
  201         devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
  202         printf("%s: %s\n", sc->sc_dev.dv_xname, devinfop);
  203         usbd_devinfo_free(devinfop);
  204 
  205         if (usbd_set_config_no(sc->sc_udev, UEAGLE_CONFIG_NO, 0) != 0) {
  206                 printf("%s: could not set configuration no\n",
  207                     sc->sc_dev.dv_xname);
  208                 return;
  209         }
  210 
  211         if (ueagle_getesi(sc, addr) != 0) {
  212                 printf("%s: could not read end system identifier\n",
  213                     sc->sc_dev.dv_xname);
  214                 return;
  215         }
  216 
  217         printf("%s: address: %02x:%02x:%02x:%02x:%02x:%02x\n",
  218             sc->sc_dev.dv_xname, addr[0], addr[1], addr[2], addr[3],
  219             addr[4], addr[5]);
  220 
  221         usb_init_task(&sc->sc_swap_task, ueagle_loadpage, sc);
  222 
  223         ifp->if_softc = sc;
  224         ifp->if_flags = IFF_SIMPLEX;
  225         ifp->if_init = ueagle_init;
  226         ifp->if_ioctl = ueagle_ioctl;
  227         ifp->if_start = ueagle_start;
  228         IFQ_SET_READY(&ifp->if_snd);
  229         memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
  230 
  231         if_attach(ifp);
  232         atm_ifattach(ifp);
  233 
  234         /* override default MTU value (9180 is too large for us) */
  235         ifp->if_mtu = UEAGLE_IFMTU;
  236 
  237 #if NBPFILTER > 0
  238         bpfattach(&ifp->if_bpf, ifp, DLT_RAW, 0);
  239 #endif
  240 
  241         usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
  242             &sc->sc_dev);
  243 }
  244 
  245 int
  246 ueagle_detach(struct device *self, int flags)
  247 {
  248         struct ueagle_softc *sc = (struct ueagle_softc *)self;
  249         struct ifnet *ifp = &sc->sc_if;
  250 
  251         if (sc->fw != NULL)
  252                 return 0; /* shortcut for pre-firmware devices */
  253 
  254         sc->gone = 1;
  255         ueagle_stop(ifp, 1);
  256 
  257         /* wait for stat thread to exit properly */
  258         if (sc->stat_thread != NULL) {
  259                 DPRINTFN(3, ("%s: waiting for stat thread to exit\n",
  260                     sc->sc_dev.dv_xname));
  261 
  262                 tsleep(sc->stat_thread, PZERO, "ueaglestat", 0);
  263 
  264                 DPRINTFN(3, ("%s: stat thread exited properly\n",
  265                     sc->sc_dev.dv_xname));
  266         }
  267 
  268         if_detach(ifp);
  269 
  270         usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
  271             &sc->sc_dev);
  272 
  273         return 0;
  274 }
  275 
  276 /*
  277  * Retrieve the device End System Identifier (MAC address).
  278  */
  279 int
  280 ueagle_getesi(struct ueagle_softc *sc, uint8_t *addr)
  281 {
  282         usb_string_descriptor_t us;
  283         usbd_status error;
  284         uint16_t c;
  285         int i, len;
  286 
  287         error = usbd_get_string_desc(sc->sc_udev, UEAGLE_ESISTR, 0, &us, &len);
  288         if (error != 0)
  289                 return error;
  290 
  291         if (us.bLength < (6 + 1) * 2)
  292                 return 1;
  293 
  294         for (i = 0; i < 6 * 2; i++) {
  295                 if ((c = UGETW(us.bString[i])) & 0xff00)
  296                         return 1;       /* not 8-bit clean */
  297 
  298                 if (i & 1)
  299                         addr[i / 2] <<= 4;
  300                 else
  301                         addr[i / 2] = 0;
  302 
  303                 if (c >= '0' && c <= '9')
  304                         addr[i / 2] |= c - '0';
  305                 else if (c >= 'a' && c <= 'f')
  306                         addr[i / 2] |= c - 'a' + 10;
  307                 else if (c >= 'A' && c <= 'F')
  308                         addr[i / 2] |= c - 'A' + 10;
  309                 else
  310                         return 1;
  311         }
  312 
  313         return 0;
  314 }
  315 
  316 void
  317 ueagle_loadpage(void *xsc)
  318 {
  319         struct ueagle_softc *sc = xsc;
  320         usbd_xfer_handle xfer;
  321         struct ueagle_block_info bi;
  322         uint16_t pageno = sc->pageno;
  323         uint16_t ovl = sc->ovl;
  324         uint8_t pagecount, blockcount;
  325         uint16_t blockaddr, blocksize;
  326         uint32_t pageoffset;
  327         uint8_t *p;
  328         int i;
  329 
  330         p = sc->dsp;
  331         pagecount = *p++;
  332 
  333         if (pageno >= pagecount) {
  334                 printf("%s: invalid page number %u requested\n",
  335                     sc->sc_dev.dv_xname, pageno);
  336                 return;
  337         }
  338 
  339         p += 4 * pageno;
  340         pageoffset = UGETDW(p);
  341         if (pageoffset == 0)
  342                 return;
  343 
  344         p = sc->dsp + pageoffset;
  345         blockcount = *p++;
  346 
  347         DPRINTF(("%s: sending %u blocks for fw page %u\n",
  348             sc->sc_dev.dv_xname, blockcount, pageno));
  349 
  350         if ((xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) {
  351                 printf("%s: could not allocate xfer\n",
  352                     sc->sc_dev.dv_xname);
  353                 return;
  354         }
  355 
  356         USETW(bi.wHdr, UEAGLE_BLOCK_INFO_HDR);
  357         USETW(bi.wOvl, ovl);
  358         USETW(bi.wOvlOffset, ovl | 0x8000);
  359 
  360         for (i = 0; i < blockcount; i++) {
  361                 blockaddr = UGETW(p); p += 2;
  362                 blocksize = UGETW(p); p += 2;
  363 
  364                 USETW(bi.wSize, blocksize);
  365                 USETW(bi.wAddress, blockaddr);
  366                 USETW(bi.wLast, (i == blockcount - 1) ? 1 : 0);
  367 
  368                 /* send block info through the IDMA pipe */
  369                 usbd_setup_xfer(xfer, sc->pipeh_idma, sc, &bi, sizeof bi, 0,
  370                     UEAGLE_IDMA_TIMEOUT, NULL);
  371                 if (usbd_sync_transfer(xfer) != 0) {
  372                         printf("%s: could not transfer block info\n",
  373                             sc->sc_dev.dv_xname);
  374                         break;
  375                 }
  376 
  377                 /* send block data through the IDMA pipe */
  378                 usbd_setup_xfer(xfer, sc->pipeh_idma, sc, p, blocksize, 0,
  379                     UEAGLE_IDMA_TIMEOUT, NULL);
  380                 if (usbd_sync_transfer(xfer) != 0) {
  381                         printf("%s: could not transfer block data\n",
  382                             sc->sc_dev.dv_xname);
  383                         break;
  384                 }
  385 
  386                 p += blocksize;
  387         }
  388 
  389         usbd_free_xfer(xfer);
  390 }
  391 
  392 void
  393 ueagle_request(struct ueagle_softc *sc, uint16_t val, uint16_t index,
  394     void *data, int len)
  395 {
  396         usb_device_request_t req;
  397         usbd_status error;
  398 
  399         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  400         req.bRequest = UEAGLE_REQUEST;
  401         USETW(req.wValue, val);
  402         USETW(req.wIndex, index);
  403         USETW(req.wLength, len);
  404 
  405         error = usbd_do_request_async(sc->sc_udev, &req, data);
  406         if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
  407                 printf("%s: could not send request\n", sc->sc_dev.dv_xname);
  408 }
  409 
  410 #ifdef USB_DEBUG
  411 void
  412 ueagle_dump_cmv(struct ueagle_softc *sc, struct ueagle_cmv *cmv)
  413 {
  414         printf("    Preamble:    0x%04x\n", UGETW(cmv->wPreamble));
  415         printf("    Destination: %s (0x%02x)\n",
  416             (cmv->bDst == UEAGLE_HOST) ? "Host" : "Modem", cmv->bDst);
  417         printf("    Type:        %u\n", cmv->bFunction >> 4);
  418         printf("    Subtype:     %u\n", cmv->bFunction & 0xf);
  419         printf("    Index:       %u\n", UGETW(cmv->wIndex));
  420         printf("    Address:     %c%c%c%c.%u\n",
  421             cmv->dwSymbolicAddress[1], cmv->dwSymbolicAddress[0],
  422             cmv->dwSymbolicAddress[3], cmv->dwSymbolicAddress[2],
  423             UGETW(cmv->wOffsetAddress));
  424         printf("    Data:        0x%08x\n", UGETDATA(cmv->dwData));
  425 }
  426 #endif
  427 
  428 int
  429 ueagle_cr(struct ueagle_softc *sc, uint32_t address, uint16_t offset,
  430     uint32_t *data)
  431 {
  432         struct ueagle_cmv cmv;
  433         usbd_status error;
  434         int s;
  435 
  436         USETW(cmv.wPreamble, UEAGLE_CMV_PREAMBLE);
  437         cmv.bDst = UEAGLE_MODEM;
  438         cmv.bFunction = UEAGLE_CR;
  439         USETW(cmv.wIndex, sc->index);
  440         USETW(cmv.wOffsetAddress, offset);
  441         USETDW(cmv.dwSymbolicAddress, address);
  442         USETDATA(cmv.dwData, 0);
  443 
  444 #ifdef USB_DEBUG
  445         if (ueagledebug >= 15) {
  446                 printf("%s: reading CMV\n", sc->sc_dev.dv_xname);
  447                 ueagle_dump_cmv(sc, &cmv);
  448         }
  449 #endif
  450 
  451         s = splusb();
  452 
  453         ueagle_request(sc, UEAGLE_SETBLOCK, UEAGLE_MPTXSTART, &cmv, sizeof cmv);
  454 
  455         /* wait at most 2 seconds for an answer */
  456         error = tsleep(UEAGLE_COND_CMV(sc), PZERO, "cmv", 2 * hz);
  457         if (error != 0) {
  458                 printf("%s: timeout waiting for CMV ack\n",
  459                     sc->sc_dev.dv_xname);
  460                 splx(s);
  461                 return error;
  462         }
  463 
  464         *data = sc->data;
  465         splx(s);
  466 
  467         return 0;
  468 }
  469 
  470 int
  471 ueagle_cw(struct ueagle_softc *sc, uint32_t address, uint16_t offset,
  472     uint32_t data)
  473 {
  474         struct ueagle_cmv cmv;
  475         usbd_status error;
  476         int s;
  477 
  478         USETW(cmv.wPreamble, UEAGLE_CMV_PREAMBLE);
  479         cmv.bDst = UEAGLE_MODEM;
  480         cmv.bFunction = UEAGLE_CW;
  481         USETW(cmv.wIndex, sc->index);
  482         USETW(cmv.wOffsetAddress, offset);
  483         USETDW(cmv.dwSymbolicAddress, address);
  484         USETDATA(cmv.dwData, data);
  485 
  486 #ifdef USB_DEBUG
  487         if (ueagledebug >= 15) {
  488                 printf("%s: writing CMV\n", sc->sc_dev.dv_xname);
  489                 ueagle_dump_cmv(sc, &cmv);
  490         }
  491 #endif
  492 
  493         s = splusb();
  494 
  495         ueagle_request(sc, UEAGLE_SETBLOCK, UEAGLE_MPTXSTART, &cmv, sizeof cmv);
  496 
  497         /* wait at most 2 seconds for an answer */
  498         error = tsleep(UEAGLE_COND_CMV(sc), PZERO, "cmv", 2 * hz);
  499         if (error != 0) {
  500                 printf("%s: timeout waiting for CMV ack\n",
  501                     sc->sc_dev.dv_xname);
  502                 splx(s);
  503                 return error;
  504         }
  505 
  506         splx(s);
  507 
  508         return 0;
  509 }
  510 
  511 int
  512 ueagle_stat(struct ueagle_softc *sc)
  513 {
  514         struct ifnet *ifp = &sc->sc_if;
  515         uint32_t data;
  516         usbd_status error;
  517 #define CR(sc, address, offset, data) do {                              \
  518         if ((error = ueagle_cr(sc, address, offset, data)) != 0)        \
  519                 return error;                                           \
  520 } while (0)
  521 
  522         CR(sc, UEAGLE_CMV_STAT, 0, &sc->stats.phy.status);
  523         switch ((sc->stats.phy.status >> 8) & 0xf) {
  524         case 0: /* idle */
  525                 DPRINTFN(3, ("%s: waiting for synchronization\n",
  526                     sc->sc_dev.dv_xname));
  527                 return ueagle_cw(sc, UEAGLE_CMV_CNTL, 0, 2);
  528 
  529         case 1: /* initialization */
  530                 DPRINTFN(3, ("%s: initializing\n", sc->sc_dev.dv_xname));
  531                 return ueagle_cw(sc, UEAGLE_CMV_CNTL, 0, 2);
  532 
  533         case 2: /* operational */
  534                 DPRINTFN(4, ("%s: operational\n", sc->sc_dev.dv_xname));
  535                 break;
  536 
  537         default: /* fail ... */
  538                 DPRINTFN(3, ("%s: synchronization failed\n",
  539                     sc->sc_dev.dv_xname));
  540                 ueagle_init(ifp);
  541                 return 1;
  542         }
  543 
  544         CR(sc, UEAGLE_CMV_DIAG, 1, &sc->stats.phy.flags);
  545         if (sc->stats.phy.flags & 0x10) {
  546                 DPRINTF(("%s: delineation LOSS\n", sc->sc_dev.dv_xname));
  547                 sc->stats.phy.status = 0;
  548                 ueagle_init(ifp);
  549                 return 1;
  550         }
  551 
  552         CR(sc, UEAGLE_CMV_RATE, 0, &data);
  553         sc->stats.phy.dsrate = ((data >> 16) & 0x1ff) * 32;
  554         sc->stats.phy.usrate = (data & 0xff) * 32;
  555 
  556         CR(sc, UEAGLE_CMV_DIAG, 23, &data);
  557         sc->stats.phy.attenuation = (data & 0xff) / 2;
  558 
  559         CR(sc, UEAGLE_CMV_DIAG,  3, &sc->stats.atm.cells_crc_errors);
  560         CR(sc, UEAGLE_CMV_DIAG, 22, &sc->stats.phy.dserror);
  561         CR(sc, UEAGLE_CMV_DIAG, 25, &sc->stats.phy.dsmargin);
  562         CR(sc, UEAGLE_CMV_DIAG, 46, &sc->stats.phy.userror);
  563         CR(sc, UEAGLE_CMV_DIAG, 49, &sc->stats.phy.usmargin);
  564         CR(sc, UEAGLE_CMV_DIAG, 51, &sc->stats.phy.rxflow);
  565         CR(sc, UEAGLE_CMV_DIAG, 52, &sc->stats.phy.txflow);
  566         CR(sc, UEAGLE_CMV_DIAG, 54, &sc->stats.phy.dsunc);
  567         CR(sc, UEAGLE_CMV_DIAG, 58, &sc->stats.phy.usunc);
  568         CR(sc, UEAGLE_CMV_INFO,  8, &sc->stats.phy.vidco);
  569         CR(sc, UEAGLE_CMV_INFO, 14, &sc->stats.phy.vidcpe);
  570 
  571         if (sc->pipeh_tx != NULL)
  572                 return 0;
  573 
  574         return ueagle_open_pipes(sc);
  575 #undef CR
  576 }
  577 
  578 void
  579 ueagle_stat_thread(void *arg)
  580 {
  581         struct ueagle_softc *sc = arg;
  582 
  583         for (;;) {
  584                 if (ueagle_stat(sc) != 0)
  585                         break;
  586 
  587                 usbd_delay_ms(sc->sc_udev, 5000);
  588         }
  589 
  590         wakeup(sc->stat_thread);
  591 
  592         kthread_exit(0);
  593 }
  594 
  595 int
  596 ueagle_boot(struct ueagle_softc *sc)
  597 {
  598         uint16_t zero = 0; /* ;-) */
  599         usbd_status error;
  600 #define CW(sc, address, offset, data) do {                              \
  601         if ((error = ueagle_cw(sc, address, offset, data)) != 0)        \
  602                 return error;                                           \
  603 } while (0)
  604 
  605         ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_BOOTIDMA, NULL, 0);
  606         ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_STARTRESET, NULL, 0);
  607 
  608         usbd_delay_ms(sc->sc_udev, 200);
  609 
  610         ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_ENDRESET, NULL, 0);
  611         ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_MPTXMAILBOX, &zero, 2);
  612         ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_MPRXMAILBOX, &zero, 2);
  613         ueagle_request(sc, UEAGLE_SET2183DATA, UEAGLE_SWAPMAILBOX, &zero, 2);
  614 
  615         usbd_delay_ms(sc->sc_udev, 1000);
  616 
  617         sc->pageno = 0;
  618         sc->ovl = 0;
  619         ueagle_loadpage(sc);
  620 
  621         /* wait until modem reaches operationnal state */
  622         error = tsleep(UEAGLE_COND_READY(sc), PZERO | PCATCH, "boot", 10 * hz);
  623         if (error != 0) {
  624                 printf("%s: timeout waiting for operationnal state\n",
  625                     sc->sc_dev.dv_xname);
  626                 return error;
  627         }
  628 
  629         CW(sc, UEAGLE_CMV_CNTL, 0, 1);
  630 
  631         /* send configuration options */
  632         CW(sc, UEAGLE_CMV_OPTN, 0, UEAGLE_OPTN0);
  633         CW(sc, UEAGLE_CMV_OPTN, 2, UEAGLE_OPTN2);
  634         CW(sc, UEAGLE_CMV_OPTN, 7, UEAGLE_OPTN7);
  635 
  636         /* continue with synchronization */
  637         CW(sc, UEAGLE_CMV_CNTL, 0, 2);
  638 
  639         return kthread_create(ueagle_stat_thread, sc, &sc->stat_thread,
  640             sc->sc_dev.dv_xname);
  641 #undef CW
  642 }
  643 
  644 void
  645 ueagle_swap_intr(struct ueagle_softc *sc, struct ueagle_swap *swap)
  646 {
  647 #define rotbr(v, n)     ((v) >> (n) | (v) << (8 - (n)))
  648         sc->pageno = swap->bPageNo;
  649         sc->ovl = rotbr(swap->bOvl, 4);
  650 
  651         usb_add_task(sc->sc_udev, &sc->sc_swap_task);
  652 #undef rotbr
  653 }
  654 
  655 /*
  656  * This function handles spontaneous CMVs and CMV acknowledgements sent by the
  657  * modem on the interrupt pipe.
  658  */
  659 void
  660 ueagle_cmv_intr(struct ueagle_softc *sc, struct ueagle_cmv *cmv)
  661 {
  662 #ifdef USB_DEBUG
  663         if (ueagledebug >= 15) {
  664                 printf("%s: receiving CMV\n", sc->sc_dev.dv_xname);
  665                 ueagle_dump_cmv(sc, cmv);
  666         }
  667 #endif
  668 
  669         if (UGETW(cmv->wPreamble) != UEAGLE_CMV_PREAMBLE) {
  670                 printf("%s: received CMV with invalid preamble\n",
  671                     sc->sc_dev.dv_xname);
  672                 return;
  673         }
  674 
  675         if (cmv->bDst != UEAGLE_HOST) {
  676                 printf("%s: received CMV with bad direction\n",
  677                     sc->sc_dev.dv_xname);
  678                 return;
  679         }
  680 
  681         /* synchronize our current CMV index with the modem */
  682         sc->index = UGETW(cmv->wIndex) + 1;
  683 
  684         switch (cmv->bFunction) {
  685         case UEAGLE_MODEMREADY:
  686                 wakeup(UEAGLE_COND_READY(sc));
  687                 break;
  688 
  689         case UEAGLE_CR_ACK:
  690                 sc->data = UGETDATA(cmv->dwData);
  691                 /* FALLTHROUGH */
  692         case UEAGLE_CW_ACK:
  693                 wakeup(UEAGLE_COND_CMV(sc));
  694                 break;
  695         }
  696 }
  697 
  698 void
  699 ueagle_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
  700 {
  701         struct ueagle_softc *sc = priv;
  702         struct ueagle_intr *intr;
  703 
  704         if (status != USBD_NORMAL_COMPLETION) {
  705                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
  706                         return;
  707 
  708                 printf("%s: abnormal interrupt status: %s\n",
  709                     sc->sc_dev.dv_xname, usbd_errstr(status));
  710 
  711                 if (status == USBD_STALLED)
  712                         usbd_clear_endpoint_stall_async(sc->pipeh_intr);
  713 
  714                 return;
  715         }
  716 
  717         intr = (struct ueagle_intr *)sc->ibuf;
  718         switch (UGETW(intr->wInterrupt)) {
  719         case UEAGLE_INTR_SWAP:
  720                 ueagle_swap_intr(sc, (struct ueagle_swap *)(intr + 1));
  721                 break;
  722 
  723         case UEAGLE_INTR_CMV:
  724                 ueagle_cmv_intr(sc, (struct ueagle_cmv *)(intr + 1));
  725                 break;
  726 
  727         default:
  728                 printf("%s: caught unknown interrupt\n",
  729                     sc->sc_dev.dv_xname);
  730         }
  731 }
  732 
  733 static const uint32_t ueagle_crc32_table[256] = {
  734         0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc,
  735         0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f,
  736         0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a,
  737         0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
  738         0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8,
  739         0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
  740         0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e,
  741         0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
  742         0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84,
  743         0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027,
  744         0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022,
  745         0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
  746         0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077,
  747         0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c,
  748         0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1,
  749         0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
  750         0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb,
  751         0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
  752         0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d,
  753         0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
  754         0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f,
  755         0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044,
  756         0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689,
  757         0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
  758         0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683,
  759         0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59,
  760         0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c,
  761         0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
  762         0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e,
  763         0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
  764         0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48,
  765         0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
  766         0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2,
  767         0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601,
  768         0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604,
  769         0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
  770         0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6,
  771         0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad,
  772         0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7,
  773         0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
  774         0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd,
  775         0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
  776         0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b,
  777         0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
  778         0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679,
  779         0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12,
  780         0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af,
  781         0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
  782         0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5,
  783         0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06,
  784         0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03,
  785         0xb1f740b4
  786 };
  787 
  788 uint32_t
  789 ueagle_crc_update(uint32_t crc, uint8_t *buf, int len)
  790 {
  791         for (; len != 0; len--, buf++)
  792                 crc = ueagle_crc32_table[(crc >> 24) ^ *buf] ^ (crc << 8);
  793 
  794         return crc;
  795 }
  796 
  797 /*
  798  * Reassembly part of the software ATM AAL5 SAR.
  799  */
  800 void
  801 ueagle_push_cell(struct ueagle_softc *sc, uint8_t *cell)
  802 {
  803         struct ueagle_vcc *vcc = &sc->vcc;
  804         struct ifnet *ifp;
  805         struct mbuf *m;
  806         uint32_t crc;
  807         uint16_t pdulen, totlen;
  808         int s;
  809 
  810         sc->stats.atm.cells_received++;
  811 
  812         if (!(vcc->flags & UEAGLE_VCC_ACTIVE) ||
  813             ATM_CH_GETVPI(cell) != vcc->vpi ||
  814             ATM_CH_GETVCI(cell) != vcc->vci) {
  815                 sc->stats.atm.vcc_no_conn++;
  816                 return;
  817         }
  818 
  819         if (vcc->flags & UEAGLE_VCC_DROP) {
  820                 if (ATM_CH_ISLASTCELL(cell)) {
  821                         vcc->flags &= ~UEAGLE_VCC_DROP;
  822                         sc->stats.atm.cspdus_dropped++;
  823                 }
  824 
  825                 sc->stats.atm.cells_dropped++;
  826                 return;
  827         }
  828 
  829         if (vcc->m == NULL) {
  830                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  831                 if (m == NULL) {
  832                         vcc->flags |= UEAGLE_VCC_DROP;
  833                         return;
  834                 }
  835 
  836                 MCLGET(m, M_DONTWAIT);
  837                 if (!(m->m_flags & M_EXT)) {
  838                         vcc->flags |= UEAGLE_VCC_DROP;
  839                         m_freem(m);
  840                         return;
  841                 }
  842 
  843                 vcc->m = m;
  844                 vcc->dst = mtod(m, uint8_t *);
  845                 vcc->limit = vcc->dst + MCLBYTES - ATM_CELL_PAYLOAD_SIZE;
  846         }
  847 
  848         if (vcc->dst > vcc->limit) {
  849                 vcc->flags |= UEAGLE_VCC_DROP;
  850                 sc->stats.atm.cells_dropped++;
  851                 goto fail;
  852         }
  853 
  854         memcpy(vcc->dst, cell + ATM_CELL_HEADER_SIZE, ATM_CELL_PAYLOAD_SIZE);
  855         vcc->dst += ATM_CELL_PAYLOAD_SIZE;
  856 
  857         if (!ATM_CH_ISLASTCELL(cell))
  858                 return;
  859 
  860         /*
  861          * Handle the last cell of the AAL5 CPCS-PDU.
  862          */
  863         m = vcc->m;
  864 
  865         totlen = vcc->dst - mtod(m, uint8_t *);
  866         pdulen = AAL5_TR_GETPDULEN(cell);
  867 
  868         if (totlen < pdulen + AAL5_TRAILER_SIZE) {
  869                 sc->stats.atm.cspdus_dropped++;
  870                 goto fail;
  871         }
  872 
  873         if (totlen >= pdulen + ATM_CELL_PAYLOAD_SIZE + AAL5_TRAILER_SIZE) {
  874                 sc->stats.atm.cspdus_dropped++;
  875                 goto fail;
  876         }
  877 
  878         crc = ueagle_crc_update(CRC_INITIAL, mtod(m, uint8_t *), totlen);
  879         if (crc != CRC_MAGIC) {
  880                 sc->stats.atm.cspdus_crc_errors++;
  881                 goto fail;
  882         }
  883 
  884         /* finalize mbuf */
  885         ifp = &sc->sc_if;
  886         m->m_pkthdr.rcvif = ifp;
  887         m->m_pkthdr.len = m->m_len = pdulen;
  888 
  889         sc->stats.atm.cspdus_received++;
  890 
  891         s = splnet();
  892 
  893 #if NBPFILTER > 0
  894         if (ifp->if_bpf != NULL)
  895                 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
  896 #endif
  897 
  898         /* send the AAL5 CPCS-PDU to the ATM layer */
  899         ifp->if_ipackets++;
  900         atm_input(ifp, &vcc->aph, m, vcc->rxhand);
  901         vcc->m = NULL;
  902 
  903         splx(s);
  904 
  905         return;
  906 
  907 fail:   m_freem(vcc->m);
  908         vcc->m = NULL;
  909 }
  910 
  911 void
  912 ueagle_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv,
  913     usbd_status status)
  914 {
  915         struct ueagle_isoreq *req = priv;
  916         struct ueagle_softc *sc = req->sc;
  917         uint32_t count;
  918         uint8_t *p;
  919         int i;
  920 
  921         if (status == USBD_CANCELLED)
  922                 return;
  923 
  924         for (i = 0; i < UEAGLE_NISOFRMS; i++) {
  925                 count = req->frlengths[i];
  926                 p = req->offsets[i];
  927 
  928                 while (count >= ATM_CELL_SIZE) {
  929                         ueagle_push_cell(sc, p);
  930                         p += ATM_CELL_SIZE;
  931                         count -= ATM_CELL_SIZE;
  932                 }
  933 #ifdef DIAGNOSTIC
  934                 if (count > 0) {
  935                         printf("%s: truncated cell (%u bytes)\n",
  936                             sc->sc_dev.dv_xname, count);
  937                 }
  938 #endif
  939                 req->frlengths[i] = sc->isize;
  940         }
  941 
  942         usbd_setup_isoc_xfer(req->xfer, sc->pipeh_rx, req, req->frlengths,
  943             UEAGLE_NISOFRMS, USBD_NO_COPY, ueagle_rxeof);
  944         usbd_transfer(xfer);
  945 }
  946 
  947 void
  948 ueagle_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
  949     usbd_status status)
  950 {
  951         struct ueagle_txreq *req = priv;
  952         struct ueagle_softc *sc = req->sc;
  953         struct ifnet *ifp = &sc->sc_if;
  954         int s;
  955 
  956         if (status != USBD_NORMAL_COMPLETION) {
  957                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
  958                         return;
  959 
  960                 printf("%s: could not transmit buffer: %s\n",
  961                     sc->sc_dev.dv_xname, usbd_errstr(status));
  962 
  963                 if (status == USBD_STALLED)
  964                         usbd_clear_endpoint_stall_async(sc->pipeh_tx);
  965 
  966                 ifp->if_oerrors++;
  967                 return;
  968         }
  969 
  970         s = splnet();
  971 
  972         ifp->if_opackets++;
  973         ifp->if_flags &= ~IFF_OACTIVE;
  974         ueagle_start(ifp);
  975 
  976         splx(s);
  977 }
  978 
  979 /*
  980  * Segmentation part of the software ATM AAL5 SAR.
  981  */
  982 int
  983 ueagle_encap(struct ueagle_softc *sc, struct mbuf *m0)
  984 {
  985         struct ueagle_vcc *vcc = &sc->vcc;
  986         struct ueagle_txreq *req;
  987         struct mbuf *m;
  988         uint8_t *src, *dst;
  989         uint32_t crc;
  990         int n, cellleft, mleft;
  991         usbd_status error;
  992 
  993         req = &sc->txreqs[0];
  994 
  995         m_adj(m0, sizeof (struct atm_pseudohdr));
  996 
  997         dst = req->buf;
  998         cellleft = 0;
  999         crc = CRC_INITIAL;
 1000 
 1001         for (m = m0; m != NULL; m = m->m_next) {
 1002                 src = mtod(m, uint8_t *);
 1003                 mleft = m->m_len;
 1004 
 1005                 crc = ueagle_crc_update(crc, src, mleft);
 1006 
 1007                 if (cellleft != 0) {
 1008                         n = min(mleft, cellleft);
 1009 
 1010                         memcpy(dst, src, n);
 1011                         dst += n;
 1012                         src += n;
 1013                         cellleft -= n;
 1014                         mleft -= n;
 1015                 }
 1016 
 1017                 while (mleft >= ATM_CELL_PAYLOAD_SIZE) {
 1018                         memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
 1019                         dst += ATM_CELL_HEADER_SIZE;
 1020                         memcpy(dst, src, ATM_CELL_PAYLOAD_SIZE);
 1021                         dst += ATM_CELL_PAYLOAD_SIZE;
 1022                         src += ATM_CELL_PAYLOAD_SIZE;
 1023                         mleft -= ATM_CELL_PAYLOAD_SIZE;
 1024                         sc->stats.atm.cells_transmitted++;
 1025                 }
 1026 
 1027                 if (mleft != 0) {
 1028                         memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
 1029                         dst += ATM_CELL_HEADER_SIZE;
 1030                         memcpy(dst, src, mleft);
 1031                         dst += mleft;
 1032                         cellleft = ATM_CELL_PAYLOAD_SIZE - mleft;
 1033                         sc->stats.atm.cells_transmitted++;
 1034                 }
 1035         }
 1036 
 1037         /*
 1038          * If there is not enough space to put the AAL5 trailer into this cell,
 1039          * pad the content of this cell with zeros and create a new cell which
 1040          * will contain no data except the AAL5 trailer itself.
 1041          */
 1042         if (cellleft < AAL5_TRAILER_SIZE) {
 1043                 memset(dst, 0, cellleft);
 1044                 crc = ueagle_crc_update(crc, dst, cellleft);
 1045                 dst += cellleft;
 1046 
 1047                 memcpy(dst, vcc->ch, ATM_CELL_HEADER_SIZE);
 1048                 dst += ATM_CELL_HEADER_SIZE;
 1049                 cellleft = ATM_CELL_PAYLOAD_SIZE;
 1050                 sc->stats.atm.cells_transmitted++;
 1051         }
 1052 
 1053         /*
 1054          * Fill the AAL5 CPCS-PDU trailer.
 1055          */
 1056         memset(dst, 0, cellleft - AAL5_TRAILER_SIZE);
 1057 
 1058         /* src now points to the beginning of the last cell */
 1059         src = dst + cellleft - ATM_CELL_SIZE;
 1060         ATM_CH_SETPTFLAGS(src, 1);
 1061 
 1062         AAL5_TR_SETCPSUU(src, 0);
 1063         AAL5_TR_SETCPI(src, 0);
 1064         AAL5_TR_SETPDULEN(src, m0->m_pkthdr.len);
 1065 
 1066         crc = ~ueagle_crc_update(crc, dst, cellleft - 4);
 1067         AAL5_TR_SETCRC(src, crc);
 1068 
 1069         usbd_setup_xfer(req->xfer, sc->pipeh_tx, req, req->buf,
 1070             dst + cellleft - req->buf, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
 1071             UEAGLE_TX_TIMEOUT, ueagle_txeof);
 1072 
 1073         error = usbd_transfer(req->xfer);
 1074         if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
 1075                 return error;
 1076 
 1077         sc->stats.atm.cspdus_transmitted++;
 1078 
 1079         return 0;
 1080 }
 1081 
 1082 void
 1083 ueagle_start(struct ifnet *ifp)
 1084 {
 1085         struct ueagle_softc *sc = ifp->if_softc;
 1086         struct mbuf *m0;
 1087 
 1088         /* nothing goes out until modem is synchronized and VCC is opened */
 1089         if (!(sc->vcc.flags & UEAGLE_VCC_ACTIVE))
 1090                 return;
 1091 
 1092         if (sc->pipeh_tx == NULL)
 1093                 return;
 1094 
 1095         IFQ_POLL(&ifp->if_snd, m0);
 1096         if (m0 == NULL)
 1097                 return;
 1098         IFQ_DEQUEUE(&ifp->if_snd, m0);
 1099 
 1100         if (ueagle_encap(sc, m0) != 0) {
 1101                 m_freem(m0);
 1102                 return;
 1103         }
 1104 
 1105 #if NBPFILTER > 0
 1106         if (ifp->if_bpf != NULL)
 1107                 bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
 1108 #endif
 1109 
 1110         m_freem(m0);
 1111 
 1112         ifp->if_flags |= IFF_OACTIVE;
 1113 }
 1114 
 1115 int
 1116 ueagle_open_vcc(struct ueagle_softc *sc, struct atm_pseudoioctl *api)
 1117 {
 1118         struct ueagle_vcc *vcc = &sc->vcc;
 1119 
 1120         DPRINTF(("%s: opening ATM VCC\n", sc->sc_dev.dv_xname));
 1121 
 1122         vcc->vpi = ATM_PH_VPI(&api->aph);
 1123         vcc->vci = ATM_PH_VCI(&api->aph);
 1124         vcc->rxhand = api->rxhand;
 1125         vcc->m = NULL;
 1126         vcc->aph = api->aph;
 1127         vcc->flags = UEAGLE_VCC_ACTIVE;
 1128 
 1129         /* pre-calculate cell headers (HEC field is set by hardware) */
 1130         ATM_CH_FILL(vcc->ch, 0, vcc->vpi, vcc->vci, 0, 0, 0);
 1131 
 1132         return 0;
 1133 }
 1134 
 1135 int
 1136 ueagle_close_vcc(struct ueagle_softc *sc, struct atm_pseudoioctl *api)
 1137 {
 1138         DPRINTF(("%s: closing ATM VCC\n", sc->sc_dev.dv_xname));
 1139 
 1140         sc->vcc.flags &= ~UEAGLE_VCC_ACTIVE;
 1141 
 1142         return 0;
 1143 }
 1144 
 1145 int
 1146 ueagle_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 1147 {
 1148         struct ueagle_softc *sc = ifp->if_softc;
 1149         struct atm_pseudoioctl *api;
 1150         struct ifaddr *ifa;
 1151         struct ifreq *ifr;
 1152         int s, error = 0;
 1153 
 1154         s = splnet();
 1155 
 1156         switch (cmd) {
 1157         case SIOCSIFADDR:
 1158                 ifa = (struct ifaddr *)data;
 1159                 ifp->if_flags |= IFF_UP;
 1160 
 1161                 ueagle_init(ifp);
 1162 #ifdef INET
 1163                 ifa->ifa_rtrequest = atm_rtrequest;
 1164 #endif
 1165                 break;
 1166 
 1167         case SIOCSIFFLAGS:
 1168                 if (ifp->if_flags & IFF_UP) {
 1169                         if (!(ifp->if_flags & IFF_RUNNING))
 1170                                 ueagle_init(ifp);
 1171                 } else {
 1172                         if (ifp->if_flags & IFF_RUNNING)
 1173                                 ueagle_stop(ifp, 1);
 1174                 }
 1175                 break;
 1176 
 1177         case SIOCSIFMTU:
 1178                 ifr = (struct ifreq *)data;
 1179 
 1180                 if (ifr->ifr_mtu > UEAGLE_IFMTU)
 1181                         error = EINVAL;
 1182                 else
 1183                         ifp->if_mtu = ifr->ifr_mtu;
 1184                 break;
 1185 
 1186         case SIOCATMENA:
 1187                 api = (struct atm_pseudoioctl *)data;
 1188                 error = ueagle_open_vcc(sc, api);
 1189                 break;
 1190 
 1191         case SIOCATMDIS:
 1192                 api = (struct atm_pseudoioctl *)data;
 1193                 error = ueagle_close_vcc(sc, api);
 1194                 break;
 1195 
 1196         default:
 1197                 error = EINVAL;
 1198         }
 1199 
 1200         splx(s);
 1201 
 1202         return error;
 1203 }
 1204 
 1205 int
 1206 ueagle_open_pipes(struct ueagle_softc *sc)
 1207 {
 1208         usb_endpoint_descriptor_t *edesc;
 1209         usbd_interface_handle iface;
 1210         struct ueagle_txreq *txreq;
 1211         struct ueagle_isoreq *isoreq;
 1212         usbd_status error;
 1213         uint8_t *buf;
 1214         int i, j;
 1215 
 1216         error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_US_IFACE_NO,
 1217             &iface);
 1218         if (error != 0) {
 1219                 printf("%s: could not get tx interface handle\n",
 1220                     sc->sc_dev.dv_xname);
 1221                 goto fail;
 1222         }
 1223 
 1224         error = usbd_open_pipe(iface, UEAGLE_TX_PIPE, USBD_EXCLUSIVE_USE,
 1225             &sc->pipeh_tx);
 1226         if (error != 0) {
 1227                 printf("%s: could not open tx pipe\n", sc->sc_dev.dv_xname);
 1228                 goto fail;
 1229         }
 1230 
 1231         for (i = 0; i < UEAGLE_TX_LIST_CNT; i++) {
 1232                 txreq = &sc->txreqs[i];
 1233 
 1234                 txreq->sc = sc;
 1235 
 1236                 txreq->xfer = usbd_alloc_xfer(sc->sc_udev);
 1237                 if (txreq->xfer == NULL) {
 1238                         printf("%s: could not allocate tx xfer\n",
 1239                             sc->sc_dev.dv_xname);
 1240                         error = ENOMEM;
 1241                         goto fail;
 1242                 }
 1243 
 1244                 txreq->buf = usbd_alloc_buffer(txreq->xfer, UEAGLE_TXBUFLEN);
 1245                 if (txreq->buf == NULL) {
 1246                         printf("%s: could not allocate tx buffer\n",
 1247                             sc->sc_dev.dv_xname);
 1248                         error = ENOMEM;
 1249                         goto fail;
 1250                 }
 1251         }
 1252 
 1253         error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_DS_IFACE_NO,
 1254             &iface);
 1255         if (error != 0) {
 1256                 printf("%s: could not get rx interface handle\n",
 1257                     sc->sc_dev.dv_xname);
 1258                 goto fail;
 1259         }
 1260 
 1261         /* XXX: alternative interface number sould depend on downrate */
 1262         error = usbd_set_interface(iface, 8);
 1263         if (error != 0) {
 1264                 printf("%s: could not set rx alternative interface\n",
 1265                     sc->sc_dev.dv_xname);
 1266                 goto fail;
 1267         }
 1268 
 1269         edesc = usbd_get_endpoint_descriptor(iface, UEAGLE_RX_PIPE);
 1270         if (edesc == NULL) {
 1271                 printf("%s: could not get rx endpoint descriptor\n",
 1272                     sc->sc_dev.dv_xname);
 1273                 error = EIO;
 1274                 goto fail;
 1275         }
 1276 
 1277         sc->isize = UGETW(edesc->wMaxPacketSize);
 1278 
 1279         error = usbd_open_pipe(iface, UEAGLE_RX_PIPE, USBD_EXCLUSIVE_USE,
 1280             &sc->pipeh_rx);
 1281         if (error != 0) {
 1282                 printf("%s: could not open rx pipe\n", sc->sc_dev.dv_xname);
 1283                 goto fail;
 1284         }
 1285 
 1286         for (i = 0; i < UEAGLE_NISOREQS; i++) {
 1287                 isoreq = &sc->isoreqs[i];
 1288 
 1289                 isoreq->sc = sc;
 1290 
 1291                 isoreq->xfer = usbd_alloc_xfer(sc->sc_udev);
 1292                 if (isoreq->xfer == NULL) {
 1293                         printf("%s: could not allocate rx xfer\n",
 1294                             sc->sc_dev.dv_xname);
 1295                         error = ENOMEM;
 1296                         goto fail;
 1297                 }
 1298 
 1299                 buf = usbd_alloc_buffer(isoreq->xfer,
 1300                     sc->isize * UEAGLE_NISOFRMS);
 1301                 if (buf == NULL) {
 1302                         printf("%s: could not allocate rx buffer\n",
 1303                             sc->sc_dev.dv_xname);
 1304                         error = ENOMEM;
 1305                         goto fail;
 1306                 }
 1307 
 1308                 for (j = 0; j < UEAGLE_NISOFRMS; j++) {
 1309                         isoreq->frlengths[j] = sc->isize;
 1310                         isoreq->offsets[j] = buf + j * sc->isize;
 1311                 }
 1312 
 1313                 usbd_setup_isoc_xfer(isoreq->xfer, sc->pipeh_rx, isoreq,
 1314                     isoreq->frlengths, UEAGLE_NISOFRMS, USBD_NO_COPY,
 1315                     ueagle_rxeof);
 1316                 usbd_transfer(isoreq->xfer);
 1317         }
 1318 
 1319         ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_LOOPBACKOFF, NULL, 0);
 1320 
 1321         return 0;
 1322 
 1323 fail:   ueagle_close_pipes(sc);
 1324         return error;
 1325 }
 1326 
 1327 void
 1328 ueagle_close_pipes(struct ueagle_softc *sc)
 1329 {
 1330         int i;
 1331 
 1332         ueagle_request(sc, UEAGLE_SETMODE, UEAGLE_LOOPBACKON, NULL, 0);
 1333 
 1334         /* free Tx resources */
 1335         if (sc->pipeh_tx != NULL) {
 1336                 usbd_abort_pipe(sc->pipeh_tx);
 1337                 usbd_close_pipe(sc->pipeh_tx);
 1338                 sc->pipeh_tx = NULL;
 1339         }
 1340 
 1341         for (i = 0; i < UEAGLE_TX_LIST_CNT; i++) {
 1342                 if (sc->txreqs[i].xfer != NULL) {
 1343                         usbd_free_xfer(sc->txreqs[i].xfer);
 1344                         sc->txreqs[i].xfer = NULL;
 1345                 }
 1346         }
 1347 
 1348         /* free Rx resources */
 1349         if (sc->pipeh_rx != NULL) {
 1350                 usbd_abort_pipe(sc->pipeh_rx);
 1351                 usbd_close_pipe(sc->pipeh_rx);
 1352                 sc->pipeh_rx = NULL;
 1353         }
 1354 
 1355         for (i = 0; i < UEAGLE_NISOREQS; i++) {
 1356                 if (sc->isoreqs[i].xfer != NULL) {
 1357                         usbd_free_xfer(sc->isoreqs[i].xfer);
 1358                         sc->isoreqs[i].xfer = NULL;
 1359                 }
 1360         }
 1361 }
 1362 
 1363 int
 1364 ueagle_init(struct ifnet *ifp)
 1365 {
 1366         struct ueagle_softc *sc = ifp->if_softc;
 1367         usbd_interface_handle iface;
 1368         usbd_status error;
 1369         size_t len;
 1370 
 1371         ueagle_stop(ifp, 0);
 1372 
 1373         error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_US_IFACE_NO,
 1374             &iface);
 1375         if (error != 0) {
 1376                 printf("%s: could not get idma interface handle\n",
 1377                     sc->sc_dev.dv_xname);
 1378                 goto fail;
 1379         }
 1380 
 1381         error = usbd_open_pipe(iface, UEAGLE_IDMA_PIPE, USBD_EXCLUSIVE_USE,
 1382             &sc->pipeh_idma);
 1383         if (error != 0) {
 1384                 printf("%s: could not open idma pipe\n",
 1385                     sc->sc_dev.dv_xname);
 1386                 goto fail;
 1387         }
 1388 
 1389         error = usbd_device2interface_handle(sc->sc_udev, UEAGLE_INTR_IFACE_NO,
 1390             &iface);
 1391         if (error != 0) {
 1392                 printf("%s: could not get interrupt interface handle\n",
 1393                     sc->sc_dev.dv_xname);
 1394                 goto fail;
 1395         }
 1396 
 1397         error = loadfirmware("ueagle-dsp", &sc->dsp, &len);
 1398         if (error != 0) {
 1399                 printf("%s: could not load firmware\n", sc->sc_dev.dv_xname);
 1400                 goto fail;
 1401         }
 1402 
 1403         error = usbd_open_pipe_intr(iface, UEAGLE_INTR_PIPE, USBD_SHORT_XFER_OK,
 1404             &sc->pipeh_intr, sc, sc->ibuf, UEAGLE_INTR_MAXSIZE, ueagle_intr,
 1405             UEAGLE_INTR_INTERVAL);
 1406         if (error != 0) {
 1407                 printf("%s: could not open interrupt pipe\n",
 1408                     sc->sc_dev.dv_xname);
 1409                 goto fail;
 1410         }
 1411 
 1412         error = ueagle_boot(sc);
 1413         if (error != 0) {
 1414                 printf("%s: could not boot modem\n", sc->sc_dev.dv_xname);
 1415                 goto fail;
 1416         }
 1417 
 1418         /*
 1419          * Opening of tx and rx pipes if deferred after synchronization is
 1420          * established.
 1421          */
 1422 
 1423         ifp->if_flags |= IFF_RUNNING;
 1424         ifp->if_flags &= ~IFF_OACTIVE;
 1425 
 1426         return 0;
 1427 
 1428 fail:   ueagle_stop(ifp, 1);
 1429         return error;
 1430 }
 1431 
 1432 void
 1433 ueagle_stop(struct ifnet *ifp, int disable)
 1434 {
 1435         struct ueagle_softc *sc = ifp->if_softc;
 1436 
 1437         /* stop any pending task */
 1438         usb_rem_task(sc->sc_udev, &sc->sc_swap_task);
 1439 
 1440         /* free Tx and Rx resources */
 1441         ueagle_close_pipes(sc);
 1442 
 1443         /* free firmware */
 1444         if (sc->dsp != NULL) {
 1445                 free(sc->dsp, M_DEVBUF);
 1446                 sc->dsp = NULL;
 1447         }
 1448 
 1449         /* free interrupt resources */
 1450         if (sc->pipeh_intr != NULL) {
 1451                 usbd_abort_pipe(sc->pipeh_intr);
 1452                 usbd_close_pipe(sc->pipeh_intr);
 1453                 sc->pipeh_intr = NULL;
 1454         }
 1455 
 1456         /* free IDMA resources */
 1457         if (sc->pipeh_idma != NULL) {
 1458                 usbd_abort_pipe(sc->pipeh_idma);
 1459                 usbd_close_pipe(sc->pipeh_idma);
 1460                 sc->pipeh_idma = NULL;
 1461         }
 1462 
 1463         /* reset statistics */
 1464         memset(&sc->stats, 0, sizeof (struct ueagle_stats));
 1465 
 1466         ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 1467 }
 1468 
 1469 int
 1470 ueagle_activate(struct device *self, enum devact act)
 1471 {
 1472         struct ueagle_softc *sc = (struct ueagle_softc *)self;
 1473 
 1474         switch (act) {
 1475         case DVACT_ACTIVATE:
 1476                 break;
 1477 
 1478         case DVACT_DEACTIVATE:
 1479                 sc->gone = 1;
 1480                 break;
 1481         }
 1482 
 1483         return 0;
 1484 }

/* [<][>][^][v][top][bottom][index][help] */