[BACK]Return to ueagle.c CVS log [TXT][DIR] Up to [local] / sys / dev / usb

Annotation of sys/dev/usb/ueagle.c, Revision 1.1.1.1

1.1       nbrk        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: }

CVSweb