[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     ! 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