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

Annotation of sys/dev/usb/if_axe.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: if_axe.c,v 1.78 2007/06/14 10:11:15 mbalmer Exp $     */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: /*
        !            20:  * Copyright (c) 1997, 1998, 1999, 2000-2003
        !            21:  *     Bill Paul <wpaul@windriver.com>.  All rights reserved.
        !            22:  *
        !            23:  * Redistribution and use in source and binary forms, with or without
        !            24:  * modification, are permitted provided that the following conditions
        !            25:  * are met:
        !            26:  * 1. Redistributions of source code must retain the above copyright
        !            27:  *    notice, this list of conditions and the following disclaimer.
        !            28:  * 2. Redistributions in binary form must reproduce the above copyright
        !            29:  *    notice, this list of conditions and the following disclaimer in the
        !            30:  *    documentation and/or other materials provided with the distribution.
        !            31:  * 3. All advertising materials mentioning features or use of this software
        !            32:  *    must display the following acknowledgement:
        !            33:  *     This product includes software developed by Bill Paul.
        !            34:  * 4. Neither the name of the author nor the names of any co-contributors
        !            35:  *    may be used to endorse or promote products derived from this software
        !            36:  *    without specific prior written permission.
        !            37:  *
        !            38:  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
        !            39:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            40:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            41:  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
        !            42:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            43:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            44:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            45:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            46:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            47:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
        !            48:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            49:  */
        !            50:
        !            51: #include <sys/cdefs.h>
        !            52:
        !            53: /*
        !            54:  * ASIX Electronics AX88172 USB 2.0 ethernet driver. Used in the
        !            55:  * LinkSys USB200M and various other adapters.
        !            56:  *
        !            57:  * Manuals available from:
        !            58:  * http://www.asix.com.tw/datasheet/mac/Ax88172.PDF
        !            59:  * Note: you need the manual for the AX88170 chip (USB 1.x ethernet
        !            60:  * controller) to find the definitions for the RX control register.
        !            61:  * http://www.asix.com.tw/datasheet/mac/Ax88170.PDF
        !            62:  *
        !            63:  * Written by Bill Paul <wpaul@windriver.com>
        !            64:  * Senior Engineer
        !            65:  * Wind River Systems
        !            66:  */
        !            67:
        !            68: /*
        !            69:  * The AX88172 provides USB ethernet supports at 10 and 100Mbps.
        !            70:  * It uses an external PHY (reference designs use a RealTek chip),
        !            71:  * and has a 64-bit multicast hash filter. There is some information
        !            72:  * missing from the manual which one needs to know in order to make
        !            73:  * the chip function:
        !            74:  *
        !            75:  * - You must set bit 7 in the RX control register, otherwise the
        !            76:  *   chip won't receive any packets.
        !            77:  * - You must initialize all 3 IPG registers, or you won't be able
        !            78:  *   to send any packets.
        !            79:  *
        !            80:  * Note that this device appears to only support loading the station
        !            81:  * address via autload from the EEPROM (i.e. there's no way to manaully
        !            82:  * set it).
        !            83:  *
        !            84:  * (Adam Weinberger wanted me to name this driver if_gir.c.)
        !            85:  */
        !            86:
        !            87: /*
        !            88:  * Ported to OpenBSD 3/28/2004 by Greg Taleck <taleck@oz.net>
        !            89:  * with bits and pieces from the aue and url drivers.
        !            90:  */
        !            91:
        !            92: #include "bpfilter.h"
        !            93:
        !            94: #include <sys/param.h>
        !            95: #include <sys/systm.h>
        !            96: #include <sys/sockio.h>
        !            97: #include <sys/rwlock.h>
        !            98: #include <sys/mbuf.h>
        !            99: #include <sys/kernel.h>
        !           100: #include <sys/proc.h>
        !           101: #include <sys/socket.h>
        !           102:
        !           103: #include <sys/device.h>
        !           104:
        !           105: #include <machine/bus.h>
        !           106:
        !           107: #include <net/if.h>
        !           108: #include <net/if_dl.h>
        !           109: #include <net/if_media.h>
        !           110:
        !           111: #if NBPFILTER > 0
        !           112: #include <net/bpf.h>
        !           113: #endif
        !           114:
        !           115: #ifdef INET
        !           116: #include <netinet/in.h>
        !           117: #include <netinet/in_systm.h>
        !           118: #include <netinet/in_var.h>
        !           119: #include <netinet/ip.h>
        !           120: #include <netinet/if_ether.h>
        !           121: #endif
        !           122:
        !           123: #include <dev/mii/mii.h>
        !           124: #include <dev/mii/miivar.h>
        !           125:
        !           126: #include <dev/usb/usb.h>
        !           127: #include <dev/usb/usbdi.h>
        !           128: #include <dev/usb/usbdi_util.h>
        !           129: #include <dev/usb/usbdivar.h>
        !           130: #include <dev/usb/usbdevs.h>
        !           131:
        !           132: #include <dev/usb/if_axereg.h>
        !           133:
        !           134: #ifdef AXE_DEBUG
        !           135: #define DPRINTF(x)     do { if (axedebug) printf x; } while (0)
        !           136: #define DPRINTFN(n,x)  do { if (axedebug >= (n)) printf x; } while (0)
        !           137: int    axedebug = 0;
        !           138: #else
        !           139: #define DPRINTF(x)
        !           140: #define DPRINTFN(n,x)
        !           141: #endif
        !           142:
        !           143: /*
        !           144:  * Various supported device vendors/products.
        !           145:  */
        !           146: const struct axe_type axe_devs[] = {
        !           147:        { { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UF200}, 0 },
        !           148:        { { USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2}, 0 },
        !           149:        { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172}, 0 },
        !           150:        { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772}, AX772 },
        !           151:        { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178}, AX178 },
        !           152:        { { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T}, 0 },
        !           153:        { { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055 }, AX178 },
        !           154:        { { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_SNAPPORT}, 0 },
        !           155:        { { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR}, 0},
        !           156:        { { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2}, AX772 },
        !           157:        { { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX }, 0},
        !           158:        { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100}, 0 },
        !           159:        { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1 }, AX772 },
        !           160:        { { USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E}, 0 },
        !           161:        { { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2 }, AX178 },
        !           162:        { { USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1}, 0 },
        !           163:        { { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M}, 0 },
        !           164:        { { USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000 }, AX178 },
        !           165:        { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX}, 0 },
        !           166:        { { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120}, 0 },
        !           167:        { { USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS }, AX772 },
        !           168:        { { USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T }, AX178 },
        !           169:        { { USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL}, 0 },
        !           170:        { { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029}, 0 },
        !           171:        { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028 }, AX178 }
        !           172: };
        !           173:
        !           174: #define axe_lookup(v, p) ((struct axe_type *)usb_lookup(axe_devs, v, p))
        !           175:
        !           176: int axe_match(struct device *, void *, void *);
        !           177: void axe_attach(struct device *, struct device *, void *);
        !           178: int axe_detach(struct device *, int);
        !           179: int axe_activate(struct device *, enum devact);
        !           180:
        !           181: struct cfdriver axe_cd = {
        !           182:        NULL, "axe", DV_IFNET
        !           183: };
        !           184:
        !           185: const struct cfattach axe_ca = {
        !           186:        sizeof(struct axe_softc),
        !           187:        axe_match,
        !           188:        axe_attach,
        !           189:        axe_detach,
        !           190:        axe_activate,
        !           191: };
        !           192:
        !           193: int axe_tx_list_init(struct axe_softc *);
        !           194: int axe_rx_list_init(struct axe_softc *);
        !           195: struct mbuf *axe_newbuf(void);
        !           196: int axe_encap(struct axe_softc *, struct mbuf *, int);
        !           197: void axe_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
        !           198: void axe_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
        !           199: void axe_tick(void *);
        !           200: void axe_tick_task(void *);
        !           201: void axe_start(struct ifnet *);
        !           202: int axe_ioctl(struct ifnet *, u_long, caddr_t);
        !           203: void axe_init(void *);
        !           204: void axe_stop(struct axe_softc *);
        !           205: void axe_watchdog(struct ifnet *);
        !           206: int axe_miibus_readreg(struct device *, int, int);
        !           207: void axe_miibus_writereg(struct device *, int, int, int);
        !           208: void axe_miibus_statchg(struct device *);
        !           209: int axe_cmd(struct axe_softc *, int, int, int, void *);
        !           210: int axe_ifmedia_upd(struct ifnet *);
        !           211: void axe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
        !           212: void axe_reset(struct axe_softc *sc);
        !           213:
        !           214: void axe_setmulti(struct axe_softc *);
        !           215: void axe_lock_mii(struct axe_softc *sc);
        !           216: void axe_unlock_mii(struct axe_softc *sc);
        !           217:
        !           218: void axe_ax88178_init(struct axe_softc *);
        !           219: void axe_ax88772_init(struct axe_softc *);
        !           220:
        !           221: /* Get exclusive access to the MII registers */
        !           222: void
        !           223: axe_lock_mii(struct axe_softc *sc)
        !           224: {
        !           225:        sc->axe_refcnt++;
        !           226:        rw_enter_write(&sc->axe_mii_lock);
        !           227: }
        !           228:
        !           229: void
        !           230: axe_unlock_mii(struct axe_softc *sc)
        !           231: {
        !           232:        rw_exit_write(&sc->axe_mii_lock);
        !           233:        if (--sc->axe_refcnt < 0)
        !           234:                usb_detach_wakeup(&sc->axe_dev);
        !           235: }
        !           236:
        !           237: int
        !           238: axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf)
        !           239: {
        !           240:        usb_device_request_t    req;
        !           241:        usbd_status             err;
        !           242:
        !           243:        if (sc->axe_dying)
        !           244:                return(0);
        !           245:
        !           246:        if (AXE_CMD_DIR(cmd))
        !           247:                req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
        !           248:        else
        !           249:                req.bmRequestType = UT_READ_VENDOR_DEVICE;
        !           250:        req.bRequest = AXE_CMD_CMD(cmd);
        !           251:        USETW(req.wValue, val);
        !           252:        USETW(req.wIndex, index);
        !           253:        USETW(req.wLength, AXE_CMD_LEN(cmd));
        !           254:
        !           255:        err = usbd_do_request(sc->axe_udev, &req, buf);
        !           256:
        !           257:        if (err)
        !           258:                return(-1);
        !           259:
        !           260:        return(0);
        !           261: }
        !           262:
        !           263: int
        !           264: axe_miibus_readreg(struct device *dev, int phy, int reg)
        !           265: {
        !           266:        struct axe_softc        *sc = (void *)dev;
        !           267:        usbd_status             err;
        !           268:        uWord                   val;
        !           269:
        !           270:        if (sc->axe_dying) {
        !           271:                DPRINTF(("axe: dying\n"));
        !           272:                return(0);
        !           273:        }
        !           274:
        !           275: #ifdef notdef
        !           276:        /*
        !           277:         * The chip tells us the MII address of any supported
        !           278:         * PHYs attached to the chip, so only read from those.
        !           279:         */
        !           280:
        !           281:        DPRINTF(("axe_miibus_readreg: phy 0x%x reg 0x%x\n", phy, reg));
        !           282:
        !           283:        if (sc->axe_phyaddrs[0] != AXE_NOPHY && phy != sc->axe_phyaddrs[0])
        !           284:                return (0);
        !           285:
        !           286:        if (sc->axe_phyaddrs[1] != AXE_NOPHY && phy != sc->axe_phyaddrs[1])
        !           287:                return (0);
        !           288: #endif
        !           289:        if (sc->axe_phyaddrs[0] != 0xFF && sc->axe_phyaddrs[0] != phy)
        !           290:                return (0);
        !           291:
        !           292:        USETW(val, 0);
        !           293:
        !           294:        axe_lock_mii(sc);
        !           295:        axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
        !           296:        err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, val);
        !           297:        axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
        !           298:        axe_unlock_mii(sc);
        !           299:
        !           300:        if (err) {
        !           301:                printf("axe%d: read PHY failed\n", sc->axe_unit);
        !           302:                return(-1);
        !           303:        }
        !           304:
        !           305:        if (UGETW(val))
        !           306:                sc->axe_phyaddrs[0] = phy;
        !           307:
        !           308:        return (UGETW(val));
        !           309: }
        !           310:
        !           311: void
        !           312: axe_miibus_writereg(struct device *dev, int phy, int reg, int val)
        !           313: {
        !           314:        struct axe_softc        *sc = (void *)dev;
        !           315:        usbd_status             err;
        !           316:        uWord                   uval;
        !           317:
        !           318:        if (sc->axe_dying)
        !           319:                return;
        !           320:
        !           321:        USETW(uval, val);
        !           322:
        !           323:        axe_lock_mii(sc);
        !           324:        axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
        !           325:        err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, uval);
        !           326:        axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
        !           327:        axe_unlock_mii(sc);
        !           328:
        !           329:        if (err) {
        !           330:                printf("axe%d: write PHY failed\n", sc->axe_unit);
        !           331:                return;
        !           332:        }
        !           333: }
        !           334:
        !           335: void
        !           336: axe_miibus_statchg(struct device *dev)
        !           337: {
        !           338:        struct axe_softc        *sc = (void *)dev;
        !           339:        struct mii_data         *mii = GET_MII(sc);
        !           340:        int                     val, err;
        !           341:
        !           342:        if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
        !           343:                val = AXE_MEDIA_FULL_DUPLEX;
        !           344:        else
        !           345:                val = 0;
        !           346:
        !           347:        if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
        !           348:                val |= (AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC);
        !           349:
        !           350:                switch (IFM_SUBTYPE(mii->mii_media_active)) {
        !           351:                case IFM_1000_T:
        !           352:                        val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK;
        !           353:                        break;
        !           354:                case IFM_100_TX:
        !           355:                        val |= AXE_178_MEDIA_100TX;
        !           356:                        break;
        !           357:                case IFM_10_T:
        !           358:                        /* doesn't need to be handled */
        !           359:                        break;
        !           360:                }
        !           361:        }
        !           362:
        !           363:        DPRINTF(("axe_miibus_statchg: val=0x%x\n", val));
        !           364:        err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL);
        !           365:        if (err) {
        !           366:                printf("%s: media change failed\n", sc->axe_dev.dv_xname);
        !           367:                return;
        !           368:        }
        !           369: }
        !           370:
        !           371: /*
        !           372:  * Set media options.
        !           373:  */
        !           374: int
        !           375: axe_ifmedia_upd(struct ifnet *ifp)
        !           376: {
        !           377:        struct axe_softc        *sc = ifp->if_softc;
        !           378:        struct mii_data         *mii = GET_MII(sc);
        !           379:
        !           380:        sc->axe_link = 0;
        !           381:        if (mii->mii_instance) {
        !           382:                struct mii_softc        *miisc;
        !           383:                LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
        !           384:                        mii_phy_reset(miisc);
        !           385:        }
        !           386:        mii_mediachg(mii);
        !           387:
        !           388:        return (0);
        !           389: }
        !           390:
        !           391: /*
        !           392:  * Report current media status.
        !           393:  */
        !           394: void
        !           395: axe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
        !           396: {
        !           397:        struct axe_softc        *sc = ifp->if_softc;
        !           398:        struct mii_data         *mii = GET_MII(sc);
        !           399:
        !           400:        mii_pollstat(mii);
        !           401:        ifmr->ifm_active = mii->mii_media_active;
        !           402:        ifmr->ifm_status = mii->mii_media_status;
        !           403: }
        !           404:
        !           405: void
        !           406: axe_setmulti(struct axe_softc *sc)
        !           407: {
        !           408:        struct ifnet            *ifp;
        !           409:        struct ether_multi *enm;
        !           410:        struct ether_multistep step;
        !           411:        u_int32_t               h = 0;
        !           412:        uWord                   urxmode;
        !           413:        u_int16_t               rxmode;
        !           414:        u_int8_t                hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
        !           415:
        !           416:        if (sc->axe_dying)
        !           417:                return;
        !           418:
        !           419:        ifp = GET_IFP(sc);
        !           420:
        !           421:        axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, urxmode);
        !           422:        rxmode = UGETW(urxmode);
        !           423:
        !           424:        if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
        !           425: allmulti:
        !           426:                rxmode |= AXE_RXCMD_ALLMULTI;
        !           427:                axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
        !           428:                return;
        !           429:        } else
        !           430:                rxmode &= ~AXE_RXCMD_ALLMULTI;
        !           431:
        !           432:        /* now program new ones */
        !           433:        ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
        !           434:        while (enm != NULL) {
        !           435:                if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
        !           436:                           ETHER_ADDR_LEN) != 0)
        !           437:                        goto allmulti;
        !           438:
        !           439:                h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
        !           440:                hashtbl[h / 8] |= 1 << (h % 8);
        !           441:                ETHER_NEXT_MULTI(step, enm);
        !           442:        }
        !           443:
        !           444:        ifp->if_flags &= ~IFF_ALLMULTI;
        !           445:        axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl);
        !           446:        axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
        !           447:        return;
        !           448: }
        !           449:
        !           450: void
        !           451: axe_reset(struct axe_softc *sc)
        !           452: {
        !           453:        if (sc->axe_dying)
        !           454:                return;
        !           455:        /* XXX What to reset? */
        !           456:
        !           457:        /* Wait a little while for the chip to get its brains in order. */
        !           458:        DELAY(1000);
        !           459:        return;
        !           460: }
        !           461:
        !           462: void
        !           463: axe_ax88178_init(struct axe_softc *sc)
        !           464: {
        !           465:        int gpio0 = 0, phymode = 0;
        !           466:        u_int16_t eeprom;
        !           467:
        !           468:        axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL);
        !           469:        /* XXX magic */
        !           470:        axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom);
        !           471:        axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL);
        !           472:
        !           473:        eeprom = letoh16(eeprom);
        !           474:
        !           475:        DPRINTF((" EEPROM is 0x%x\n", eeprom));
        !           476:
        !           477:        /* if EEPROM is invalid we have to use to GPIO0 */
        !           478:        if (eeprom == 0xffff) {
        !           479:                phymode = 0;
        !           480:                gpio0 = 1;
        !           481:        } else {
        !           482:                phymode = eeprom & 7;
        !           483:                gpio0 = (eeprom & 0x80) ? 0 : 1;
        !           484:        }
        !           485:
        !           486:        DPRINTF(("use gpio0: %d, phymode %d\n", gpio0, phymode));
        !           487:
        !           488:        axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x008c, NULL);
        !           489:        usbd_delay_ms(sc->axe_udev, 40);
        !           490:        if ((eeprom >> 8) != 1) {
        !           491:                axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL);
        !           492:                usbd_delay_ms(sc->axe_udev, 30);
        !           493:
        !           494:                axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x001c, NULL);
        !           495:                usbd_delay_ms(sc->axe_udev, 300);
        !           496:
        !           497:                axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL);
        !           498:                usbd_delay_ms(sc->axe_udev, 30);
        !           499:        } else {
        !           500:                DPRINTF(("axe gpio phymode == 1 path\n"));
        !           501:                axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x0004, NULL);
        !           502:                usbd_delay_ms(sc->axe_udev, 30);
        !           503:                axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x000c, NULL);
        !           504:                usbd_delay_ms(sc->axe_udev, 30);
        !           505:        }
        !           506:
        !           507:        /* soft reset */
        !           508:        axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
        !           509:        usbd_delay_ms(sc->axe_udev, 150);
        !           510:        axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
        !           511:            AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL);
        !           512:        usbd_delay_ms(sc->axe_udev, 150);
        !           513:        axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
        !           514: }
        !           515:
        !           516: void
        !           517: axe_ax88772_init(struct axe_softc *sc)
        !           518: {
        !           519:        axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL);
        !           520:        usbd_delay_ms(sc->axe_udev, 40);
        !           521:
        !           522:        if (sc->axe_phyaddrs[1] == AXE_INTPHY) {
        !           523:                /* ask for the embedded PHY */
        !           524:                axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL);
        !           525:                usbd_delay_ms(sc->axe_udev, 10);
        !           526:
        !           527:                /* power down and reset state, pin reset state */
        !           528:                axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
        !           529:                usbd_delay_ms(sc->axe_udev, 60);
        !           530:
        !           531:                /* power down/reset state, pin operating state */
        !           532:                axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
        !           533:                    AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
        !           534:                usbd_delay_ms(sc->axe_udev, 150);
        !           535:
        !           536:                /* power up, reset */
        !           537:                axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL);
        !           538:
        !           539:                /* power up, operating */
        !           540:                axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
        !           541:                    AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL);
        !           542:        } else {
        !           543:                /* ask for external PHY */
        !           544:                axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x00, NULL);
        !           545:                usbd_delay_ms(sc->axe_udev, 10);
        !           546:
        !           547:                /* power down internal PHY */
        !           548:                axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
        !           549:                    AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
        !           550:        }
        !           551:
        !           552:        usbd_delay_ms(sc->axe_udev, 150);
        !           553:        axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
        !           554: }
        !           555:
        !           556: /*
        !           557:  * Probe for a AX88172 chip.
        !           558:  */
        !           559: int
        !           560: axe_match(struct device *parent, void *match, void *aux)
        !           561: {
        !           562:        struct usb_attach_arg *uaa = aux;
        !           563:
        !           564:        if (!uaa->iface)
        !           565:                return(UMATCH_NONE);
        !           566:
        !           567:        return (axe_lookup(uaa->vendor, uaa->product) != NULL ?
        !           568:                UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
        !           569: }
        !           570:
        !           571: /*
        !           572:  * Attach the interface. Allocate softc structures, do ifmedia
        !           573:  * setup and ethernet/BPF attach.
        !           574:  */
        !           575: void
        !           576: axe_attach(struct device *parent, struct device *self, void *aux)
        !           577: {
        !           578:        struct axe_softc *sc = (struct axe_softc *)self;
        !           579:        struct usb_attach_arg *uaa = aux;
        !           580:        usbd_device_handle dev = uaa->device;
        !           581:        usbd_status err;
        !           582:        usb_interface_descriptor_t *id;
        !           583:        usb_endpoint_descriptor_t *ed;
        !           584:        struct mii_data *mii;
        !           585:        u_char eaddr[ETHER_ADDR_LEN];
        !           586:        char *devinfop;
        !           587:        char *devname = sc->axe_dev.dv_xname;
        !           588:        struct ifnet *ifp;
        !           589:        int i, s;
        !           590:
        !           591:        devinfop = usbd_devinfo_alloc(dev, 0);
        !           592:        printf("\n");
        !           593:
        !           594:        sc->axe_unit = self->dv_unit; /*device_get_unit(self);*/
        !           595:
        !           596:        err = usbd_set_config_no(dev, AXE_CONFIG_NO, 1);
        !           597:        if (err) {
        !           598:                printf("axe%d: getting interface handle failed\n",
        !           599:                    sc->axe_unit);
        !           600:                usbd_devinfo_free(devinfop);
        !           601:                return;
        !           602:        }
        !           603:
        !           604:        sc->axe_flags = axe_lookup(uaa->vendor, uaa->product)->axe_flags;
        !           605:
        !           606:        usb_init_task(&sc->axe_tick_task, axe_tick_task, sc);
        !           607:        rw_init(&sc->axe_mii_lock, "axemii");
        !           608:        usb_init_task(&sc->axe_stop_task, (void (*)(void *))axe_stop, sc);
        !           609:
        !           610:        err = usbd_device2interface_handle(dev, AXE_IFACE_IDX, &sc->axe_iface);
        !           611:        if (err) {
        !           612:                printf("axe%d: getting interface handle failed\n",
        !           613:                    sc->axe_unit);
        !           614:                usbd_devinfo_free(devinfop);
        !           615:                return;
        !           616:        }
        !           617:
        !           618:        sc->axe_udev = dev;
        !           619:        sc->axe_product = uaa->product;
        !           620:        sc->axe_vendor = uaa->vendor;
        !           621:
        !           622:        id = usbd_get_interface_descriptor(sc->axe_iface);
        !           623:
        !           624:        printf("%s: %s", sc->axe_dev.dv_xname, devinfop);
        !           625:        usbd_devinfo_free(devinfop);
        !           626:
        !           627:        /* decide on what our bufsize will be */
        !           628:        if (sc->axe_flags & AX178 || sc->axe_flags & AX772)
        !           629:                sc->axe_bufsz = (sc->axe_udev->speed == USB_SPEED_HIGH) ?
        !           630:                    AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ;
        !           631:        else
        !           632:                sc->axe_bufsz = AXE_172_BUFSZ;
        !           633:
        !           634:        /* Find endpoints. */
        !           635:        for (i = 0; i < id->bNumEndpoints; i++) {
        !           636:                ed = usbd_interface2endpoint_descriptor(sc->axe_iface, i);
        !           637:                if (!ed) {
        !           638:                        printf(" couldn't get ep %d\n", i);
        !           639:                        return;
        !           640:                }
        !           641:                if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
        !           642:                    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
        !           643:                        sc->axe_ed[AXE_ENDPT_RX] = ed->bEndpointAddress;
        !           644:                } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
        !           645:                           UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
        !           646:                        sc->axe_ed[AXE_ENDPT_TX] = ed->bEndpointAddress;
        !           647:                } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
        !           648:                           UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
        !           649:                        sc->axe_ed[AXE_ENDPT_INTR] = ed->bEndpointAddress;
        !           650:                }
        !           651:        }
        !           652:
        !           653:        s = splnet();
        !           654:
        !           655:        /* We need the PHYID for init dance in some cases */
        !           656:        axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, (void *)&sc->axe_phyaddrs);
        !           657:
        !           658:        DPRINTF((" phyaddrs[0]: %x phyaddrs[1]: %x\n",
        !           659:            sc->axe_phyaddrs[0], sc->axe_phyaddrs[1]));
        !           660:
        !           661:        if (sc->axe_flags & AX178) {
        !           662:                axe_ax88178_init(sc);
        !           663:                printf(", AX88178");
        !           664:        } else if (sc->axe_flags & AX772) {
        !           665:                axe_ax88772_init(sc);
        !           666:                printf(", AX88772");
        !           667:        } else
        !           668:                printf(", AX88172");
        !           669:
        !           670:        /*
        !           671:         * Get station address.
        !           672:         */
        !           673:        if (sc->axe_flags & AX178 || sc->axe_flags & AX772)
        !           674:                axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, &eaddr);
        !           675:        else
        !           676:                axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, &eaddr);
        !           677:
        !           678:        /*
        !           679:         * Load IPG values
        !           680:         */
        !           681:        axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, (void *)&sc->axe_ipgs);
        !           682:
        !           683:        /*
        !           684:         * Work around broken adapters that appear to lie about
        !           685:         * their PHY addresses.
        !           686:         */
        !           687:        sc->axe_phyaddrs[0] = sc->axe_phyaddrs[1] = 0xFF;
        !           688:
        !           689:        /*
        !           690:         * An ASIX chip was detected. Inform the world.
        !           691:         */
        !           692:        printf(", address %s\n", ether_sprintf(eaddr));
        !           693:
        !           694:        bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
        !           695:
        !           696:        /* Initialize interface info.*/
        !           697:        ifp = &sc->arpcom.ac_if;
        !           698:        ifp->if_softc = sc;
        !           699:        strlcpy(ifp->if_xname, devname, IFNAMSIZ);
        !           700:        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
        !           701:        ifp->if_ioctl = axe_ioctl;
        !           702:        ifp->if_start = axe_start;
        !           703:
        !           704:        ifp->if_watchdog = axe_watchdog;
        !           705:
        !           706: /*     ifp->if_baudrate = 10000000; */
        !           707: /*     ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;*/
        !           708:
        !           709:        IFQ_SET_READY(&ifp->if_snd);
        !           710:
        !           711:        /* Initialize MII/media info. */
        !           712:        mii = &sc->axe_mii;
        !           713:        mii->mii_ifp = ifp;
        !           714:        mii->mii_readreg = axe_miibus_readreg;
        !           715:        mii->mii_writereg = axe_miibus_writereg;
        !           716:        mii->mii_statchg = axe_miibus_statchg;
        !           717:        mii->mii_flags = MIIF_AUTOTSLEEP;
        !           718:
        !           719:        ifmedia_init(&mii->mii_media, 0, axe_ifmedia_upd, axe_ifmedia_sts);
        !           720:        mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
        !           721:
        !           722:        if (LIST_FIRST(&mii->mii_phys) == NULL) {
        !           723:                ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
        !           724:                ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
        !           725:        } else
        !           726:                ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
        !           727:
        !           728:        /* Attach the interface. */
        !           729:        if_attach(ifp);
        !           730:        ether_ifattach(ifp);
        !           731:
        !           732:        timeout_set(&sc->axe_stat_ch, NULL, NULL);
        !           733:
        !           734:        sc->axe_attached = 1;
        !           735:        splx(s);
        !           736:
        !           737:        usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->axe_udev,
        !           738:                           &sc->axe_dev);
        !           739: }
        !           740:
        !           741: int
        !           742: axe_detach(struct device *self, int flags)
        !           743: {
        !           744:        struct axe_softc        *sc = (struct axe_softc *)self;
        !           745:        int                     s;
        !           746:        struct ifnet            *ifp = GET_IFP(sc);
        !           747:
        !           748:        DPRINTFN(2,("%s: %s: enter\n", sc->axe_dev.dv_xname, __func__));
        !           749:
        !           750:        /* Detached before attached finished, so just bail out. */
        !           751:        if (!sc->axe_attached)
        !           752:                return (0);
        !           753:
        !           754:        timeout_del(&sc->axe_stat_ch);
        !           755:
        !           756:        sc->axe_dying = 1;
        !           757:
        !           758:        ether_ifdetach(ifp);
        !           759:
        !           760:        if (sc->axe_ep[AXE_ENDPT_TX] != NULL)
        !           761:                usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_TX]);
        !           762:        if (sc->axe_ep[AXE_ENDPT_RX] != NULL)
        !           763:                usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_RX]);
        !           764:        if (sc->axe_ep[AXE_ENDPT_INTR] != NULL)
        !           765:                usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
        !           766:
        !           767:        /*
        !           768:         * Remove any pending tasks.  They cannot be executing because they run
        !           769:         * in the same thread as detach.
        !           770:         */
        !           771:        usb_rem_task(sc->axe_udev, &sc->axe_tick_task);
        !           772:        usb_rem_task(sc->axe_udev, &sc->axe_stop_task);
        !           773:
        !           774:        s = splusb();
        !           775:
        !           776:        if (--sc->axe_refcnt >= 0) {
        !           777:                /* Wait for processes to go away */
        !           778:                usb_detach_wait(&sc->axe_dev);
        !           779:        }
        !           780:
        !           781:        if (ifp->if_flags & IFF_RUNNING)
        !           782:                axe_stop(sc);
        !           783:
        !           784:        mii_detach(&sc->axe_mii, MII_PHY_ANY, MII_OFFSET_ANY);
        !           785:        ifmedia_delete_instance(&sc->axe_mii.mii_media, IFM_INST_ANY);
        !           786:        ether_ifdetach(ifp);
        !           787:        if_detach(ifp);
        !           788:
        !           789: #ifdef DIAGNOSTIC
        !           790:        if (sc->axe_ep[AXE_ENDPT_TX] != NULL ||
        !           791:            sc->axe_ep[AXE_ENDPT_RX] != NULL ||
        !           792:            sc->axe_ep[AXE_ENDPT_INTR] != NULL)
        !           793:                printf("%s: detach has active endpoints\n",
        !           794:                    sc->axe_dev.dv_xname);
        !           795: #endif
        !           796:
        !           797:        sc->axe_attached = 0;
        !           798:
        !           799:        if (--sc->axe_refcnt >= 0) {
        !           800:                /* Wait for processes to go away. */
        !           801:                usb_detach_wait(&sc->axe_dev);
        !           802:        }
        !           803:        splx(s);
        !           804:
        !           805:        usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->axe_udev,
        !           806:                           &sc->axe_dev);
        !           807:
        !           808:        return (0);
        !           809: }
        !           810:
        !           811: int
        !           812: axe_activate(struct device *self, enum devact act)
        !           813: {
        !           814:        struct axe_softc *sc = (struct axe_softc *)self;
        !           815:
        !           816:        DPRINTFN(2,("%s: %s: enter\n", sc->axe_dev.dv_xname, __func__));
        !           817:
        !           818:        switch (act) {
        !           819:        case DVACT_ACTIVATE:
        !           820:                break;
        !           821:
        !           822:        case DVACT_DEACTIVATE:
        !           823:                sc->axe_dying = 1;
        !           824:                break;
        !           825:        }
        !           826:        return (0);
        !           827: }
        !           828:
        !           829: struct mbuf *
        !           830: axe_newbuf(void)
        !           831: {
        !           832:        struct mbuf             *m;
        !           833:
        !           834:        MGETHDR(m, M_DONTWAIT, MT_DATA);
        !           835:        if (m == NULL)
        !           836:                return (NULL);
        !           837:
        !           838:        MCLGET(m, M_DONTWAIT);
        !           839:        if (!(m->m_flags & M_EXT)) {
        !           840:                m_freem(m);
        !           841:                return (NULL);
        !           842:        }
        !           843:
        !           844:        m->m_len = m->m_pkthdr.len = MCLBYTES;
        !           845:        m_adj(m, ETHER_ALIGN);
        !           846:
        !           847:        return (m);
        !           848: }
        !           849:
        !           850: int
        !           851: axe_rx_list_init(struct axe_softc *sc)
        !           852: {
        !           853:        struct axe_cdata *cd;
        !           854:        struct axe_chain *c;
        !           855:        int i;
        !           856:
        !           857:        DPRINTF(("%s: %s: enter\n", sc->axe_dev.dv_xname, __func__));
        !           858:
        !           859:        cd = &sc->axe_cdata;
        !           860:        for (i = 0; i < AXE_RX_LIST_CNT; i++) {
        !           861:                c = &cd->axe_rx_chain[i];
        !           862:                c->axe_sc = sc;
        !           863:                c->axe_idx = i;
        !           864:                c->axe_mbuf = NULL;
        !           865:                if (c->axe_xfer == NULL) {
        !           866:                        c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
        !           867:                        if (c->axe_xfer == NULL)
        !           868:                                return (ENOBUFS);
        !           869:                        c->axe_buf = usbd_alloc_buffer(c->axe_xfer,
        !           870:                            sc->axe_bufsz);
        !           871:                        if (c->axe_buf == NULL) {
        !           872:                                usbd_free_xfer(c->axe_xfer);
        !           873:                                return (ENOBUFS);
        !           874:                        }
        !           875:                }
        !           876:        }
        !           877:
        !           878:        return (0);
        !           879: }
        !           880:
        !           881: int
        !           882: axe_tx_list_init(struct axe_softc *sc)
        !           883: {
        !           884:        struct axe_cdata *cd;
        !           885:        struct axe_chain *c;
        !           886:        int i;
        !           887:
        !           888:        DPRINTF(("%s: %s: enter\n", sc->axe_dev.dv_xname, __func__));
        !           889:
        !           890:        cd = &sc->axe_cdata;
        !           891:        for (i = 0; i < AXE_TX_LIST_CNT; i++) {
        !           892:                c = &cd->axe_tx_chain[i];
        !           893:                c->axe_sc = sc;
        !           894:                c->axe_idx = i;
        !           895:                c->axe_mbuf = NULL;
        !           896:                if (c->axe_xfer == NULL) {
        !           897:                        c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
        !           898:                        if (c->axe_xfer == NULL)
        !           899:                                return (ENOBUFS);
        !           900:                        c->axe_buf = usbd_alloc_buffer(c->axe_xfer,
        !           901:                            sc->axe_bufsz);
        !           902:                        if (c->axe_buf == NULL) {
        !           903:                                usbd_free_xfer(c->axe_xfer);
        !           904:                                return (ENOBUFS);
        !           905:                        }
        !           906:                }
        !           907:        }
        !           908:
        !           909:        return (0);
        !           910: }
        !           911:
        !           912: /*
        !           913:  * A frame has been uploaded: pass the resulting mbuf chain up to
        !           914:  * the higher level protocols.
        !           915:  */
        !           916: void
        !           917: axe_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
        !           918: {
        !           919:        struct axe_chain        *c = (struct axe_chain *)priv;
        !           920:        struct axe_softc        *sc = c->axe_sc;
        !           921:        struct ifnet            *ifp = GET_IFP(sc);
        !           922:        u_char                  *buf = c->axe_buf;
        !           923:        u_int32_t               total_len;
        !           924:        u_int16_t               pktlen = 0;
        !           925:        struct mbuf             *m;
        !           926:        struct axe_sframe_hdr   hdr;
        !           927:        int                     s;
        !           928:
        !           929:        DPRINTFN(10,("%s: %s: enter\n", sc->axe_dev.dv_xname,__func__));
        !           930:
        !           931:        if (sc->axe_dying)
        !           932:                return;
        !           933:
        !           934:        if (!(ifp->if_flags & IFF_RUNNING))
        !           935:                return;
        !           936:
        !           937:        if (status != USBD_NORMAL_COMPLETION) {
        !           938:                if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
        !           939:                        return;
        !           940:                if (usbd_ratecheck(&sc->axe_rx_notice)) {
        !           941:                        printf("%s: usb errors on rx: %s\n",
        !           942:                            sc->axe_dev.dv_xname, usbd_errstr(status));
        !           943:                }
        !           944:                if (status == USBD_STALLED)
        !           945:                        usbd_clear_endpoint_stall_async(sc->axe_ep[AXE_ENDPT_RX]);
        !           946:                goto done;
        !           947:        }
        !           948:
        !           949:        usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
        !           950:
        !           951:        do {
        !           952:                if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
        !           953:                        if (total_len < sizeof(hdr)) {
        !           954:                                ifp->if_ierrors++;
        !           955:                                goto done;
        !           956:                        }
        !           957:
        !           958:                        buf += pktlen;
        !           959:
        !           960:                        memcpy(&hdr, buf, sizeof(hdr));
        !           961:                        total_len -= sizeof(hdr);
        !           962:
        !           963:                        if ((hdr.len ^ hdr.ilen) != 0xffff) {
        !           964:                                ifp->if_ierrors++;
        !           965:                                goto done;
        !           966:                        }
        !           967:                        pktlen = letoh16(hdr.len);
        !           968:                        if (pktlen > total_len) {
        !           969:                                ifp->if_ierrors++;
        !           970:                                goto done;
        !           971:                        }
        !           972:
        !           973:                        buf += sizeof(hdr);
        !           974:
        !           975:                        if ((pktlen % 2) != 0)
        !           976:                                pktlen++;
        !           977:
        !           978:                        if ((total_len - pktlen) < 0)
        !           979:                                total_len = 0;
        !           980:                        else
        !           981:                                total_len -= pktlen;
        !           982:                } else {
        !           983:                        pktlen = total_len; /* crc on the end? */
        !           984:                        total_len = 0;
        !           985:                }
        !           986:
        !           987:                m = axe_newbuf();
        !           988:                if (m == NULL) {
        !           989:                        ifp->if_ierrors++;
        !           990:                        goto done;
        !           991:                }
        !           992:
        !           993:                ifp->if_ipackets++;
        !           994:                m->m_pkthdr.rcvif = ifp;
        !           995:                m->m_pkthdr.len = m->m_len = pktlen;
        !           996:
        !           997:                memcpy(mtod(m, char *), buf, pktlen);
        !           998:
        !           999:                /* push the packet up */
        !          1000:                s = splnet();
        !          1001: #if NBPFILTER > 0
        !          1002:                if (ifp->if_bpf)
        !          1003:                        bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
        !          1004: #endif
        !          1005:
        !          1006:                ether_input_mbuf(ifp, m);
        !          1007:
        !          1008:                splx(s);
        !          1009:
        !          1010:        } while (total_len > 0);
        !          1011:
        !          1012: done:
        !          1013:        memset(c->axe_buf, 0, sc->axe_bufsz);
        !          1014:
        !          1015:        /* Setup new transfer. */
        !          1016:        usbd_setup_xfer(xfer, sc->axe_ep[AXE_ENDPT_RX],
        !          1017:            c, c->axe_buf, sc->axe_bufsz,
        !          1018:            USBD_SHORT_XFER_OK | USBD_NO_COPY,
        !          1019:            USBD_NO_TIMEOUT, axe_rxeof);
        !          1020:        usbd_transfer(xfer);
        !          1021:
        !          1022:        DPRINTFN(10,("%s: %s: start rx\n", sc->axe_dev.dv_xname, __func__));
        !          1023:
        !          1024:        return;
        !          1025: }
        !          1026:
        !          1027: /*
        !          1028:  * A frame was downloaded to the chip. It's safe for us to clean up
        !          1029:  * the list buffers.
        !          1030:  */
        !          1031:
        !          1032: void
        !          1033: axe_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
        !          1034: {
        !          1035:        struct axe_softc        *sc;
        !          1036:        struct axe_chain        *c;
        !          1037:        struct ifnet            *ifp;
        !          1038:        int                     s;
        !          1039:
        !          1040:        c = priv;
        !          1041:        sc = c->axe_sc;
        !          1042:        ifp = &sc->arpcom.ac_if;
        !          1043:
        !          1044:        if (sc->axe_dying)
        !          1045:                return;
        !          1046:
        !          1047:        s = splnet();
        !          1048:
        !          1049:        if (status != USBD_NORMAL_COMPLETION) {
        !          1050:                if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
        !          1051:                        splx(s);
        !          1052:                        return;
        !          1053:                }
        !          1054:                ifp->if_oerrors++;
        !          1055:                printf("axe%d: usb error on tx: %s\n", sc->axe_unit,
        !          1056:                    usbd_errstr(status));
        !          1057:                if (status == USBD_STALLED)
        !          1058:                        usbd_clear_endpoint_stall_async(sc->axe_ep[AXE_ENDPT_TX]);
        !          1059:                splx(s);
        !          1060:                return;
        !          1061:        }
        !          1062:
        !          1063:        ifp->if_timer = 0;
        !          1064:        ifp->if_flags &= ~IFF_OACTIVE;
        !          1065:
        !          1066:        m_freem(c->axe_mbuf);
        !          1067:        c->axe_mbuf = NULL;
        !          1068:
        !          1069:        if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
        !          1070:                axe_start(ifp);
        !          1071:
        !          1072:        ifp->if_opackets++;
        !          1073:        splx(s);
        !          1074:        return;
        !          1075: }
        !          1076:
        !          1077: void
        !          1078: axe_tick(void *xsc)
        !          1079: {
        !          1080:        struct axe_softc *sc = xsc;
        !          1081:
        !          1082:        if (sc == NULL)
        !          1083:                return;
        !          1084:
        !          1085:        DPRINTFN(0xff, ("%s: %s: enter\n", sc->axe_dev.dv_xname,
        !          1086:                        __func__));
        !          1087:
        !          1088:        if (sc->axe_dying)
        !          1089:                return;
        !          1090:
        !          1091:        /* Perform periodic stuff in process context */
        !          1092:        usb_add_task(sc->axe_udev, &sc->axe_tick_task);
        !          1093:
        !          1094: }
        !          1095:
        !          1096: void
        !          1097: axe_tick_task(void *xsc)
        !          1098: {
        !          1099:        int                     s;
        !          1100:        struct axe_softc        *sc;
        !          1101:        struct ifnet            *ifp;
        !          1102:        struct mii_data         *mii;
        !          1103:
        !          1104:        sc = xsc;
        !          1105:
        !          1106:        if (sc == NULL)
        !          1107:                return;
        !          1108:
        !          1109:        if (sc->axe_dying)
        !          1110:                return;
        !          1111:
        !          1112:        ifp = GET_IFP(sc);
        !          1113:        mii = GET_MII(sc);
        !          1114:        if (mii == NULL)
        !          1115:                return;
        !          1116:
        !          1117:        s = splnet();
        !          1118:
        !          1119:        mii_tick(mii);
        !          1120:        if (!sc->axe_link && mii->mii_media_status & IFM_ACTIVE &&
        !          1121:            IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
        !          1122:                DPRINTF(("%s: %s: got link\n",
        !          1123:                         sc->axe_dev.dv_xname, __func__));
        !          1124:                sc->axe_link++;
        !          1125:                if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
        !          1126:                           axe_start(ifp);
        !          1127:        }
        !          1128:
        !          1129:        timeout_del(&sc->axe_stat_ch);
        !          1130:        timeout_set(&sc->axe_stat_ch, axe_tick, sc);
        !          1131:        timeout_add(&sc->axe_stat_ch, hz);
        !          1132:
        !          1133:        splx(s);
        !          1134: }
        !          1135:
        !          1136: int
        !          1137: axe_encap(struct axe_softc *sc, struct mbuf *m, int idx)
        !          1138: {
        !          1139:        struct axe_chain        *c;
        !          1140:        usbd_status             err;
        !          1141:        struct axe_sframe_hdr   hdr;
        !          1142:        int                     length, boundary;
        !          1143:
        !          1144:        c = &sc->axe_cdata.axe_tx_chain[idx];
        !          1145:
        !          1146:        if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
        !          1147:                boundary = (sc->axe_udev->speed == USB_SPEED_HIGH) ? 512 : 64;
        !          1148:
        !          1149:                hdr.len = htole16(m->m_pkthdr.len);
        !          1150:                hdr.ilen = ~hdr.len;
        !          1151:
        !          1152:                memcpy(c->axe_buf, &hdr, sizeof(hdr));
        !          1153:                length = sizeof(hdr);
        !          1154:
        !          1155:                m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf + length);
        !          1156:                length += m->m_pkthdr.len;
        !          1157:
        !          1158:                if ((length % boundary) == 0) {
        !          1159:                        hdr.len = 0x0000;
        !          1160:                        hdr.ilen = 0xffff;
        !          1161:                        memcpy(c->axe_buf + length, &hdr, sizeof(hdr));
        !          1162:                        length += sizeof(hdr);
        !          1163:                }
        !          1164:
        !          1165:        } else {
        !          1166:                m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf);
        !          1167:                length = m->m_pkthdr.len;
        !          1168:        }
        !          1169:
        !          1170:        c->axe_mbuf = m;
        !          1171:
        !          1172:        usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_TX],
        !          1173:            c, c->axe_buf, length, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
        !          1174:            10000, axe_txeof);
        !          1175:
        !          1176:        /* Transmit */
        !          1177:        err = usbd_transfer(c->axe_xfer);
        !          1178:        if (err != USBD_IN_PROGRESS) {
        !          1179:                axe_stop(sc);
        !          1180:                return(EIO);
        !          1181:        }
        !          1182:
        !          1183:        sc->axe_cdata.axe_tx_cnt++;
        !          1184:
        !          1185:        return(0);
        !          1186: }
        !          1187:
        !          1188: void
        !          1189: axe_start(struct ifnet *ifp)
        !          1190: {
        !          1191:        struct axe_softc        *sc;
        !          1192:        struct mbuf             *m_head = NULL;
        !          1193:
        !          1194:        sc = ifp->if_softc;
        !          1195:
        !          1196:        if (!sc->axe_link)
        !          1197:                return;
        !          1198:
        !          1199:        if (ifp->if_flags & IFF_OACTIVE)
        !          1200:                return;
        !          1201:
        !          1202:        IFQ_POLL(&ifp->if_snd, m_head);
        !          1203:        if (m_head == NULL)
        !          1204:                return;
        !          1205:
        !          1206:        if (axe_encap(sc, m_head, 0)) {
        !          1207:                ifp->if_flags |= IFF_OACTIVE;
        !          1208:                return;
        !          1209:        }
        !          1210:        IFQ_DEQUEUE(&ifp->if_snd, m_head);
        !          1211:
        !          1212:        /*
        !          1213:         * If there's a BPF listener, bounce a copy of this frame
        !          1214:         * to him.
        !          1215:         */
        !          1216: #if NBPFILTER > 0
        !          1217:        if (ifp->if_bpf)
        !          1218:                bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
        !          1219: #endif
        !          1220:
        !          1221:        ifp->if_flags |= IFF_OACTIVE;
        !          1222:
        !          1223:        /*
        !          1224:         * Set a timeout in case the chip goes out to lunch.
        !          1225:         */
        !          1226:        ifp->if_timer = 5;
        !          1227:
        !          1228:        return;
        !          1229: }
        !          1230:
        !          1231: void
        !          1232: axe_init(void *xsc)
        !          1233: {
        !          1234:        struct axe_softc        *sc = xsc;
        !          1235:        struct ifnet            *ifp = &sc->arpcom.ac_if;
        !          1236:        struct axe_chain        *c;
        !          1237:        usbd_status             err;
        !          1238:        int                     rxmode;
        !          1239:        int                     i, s;
        !          1240:
        !          1241:        s = splnet();
        !          1242:
        !          1243:        /*
        !          1244:         * Cancel pending I/O and free all RX/TX buffers.
        !          1245:         */
        !          1246:        axe_reset(sc);
        !          1247:
        !          1248:        /* Enable RX logic. */
        !          1249:
        !          1250:        /* Init RX ring. */
        !          1251:        if (axe_rx_list_init(sc) == ENOBUFS) {
        !          1252:                printf("axe%d: rx list init failed\n", sc->axe_unit);
        !          1253:                splx(s);
        !          1254:                return;
        !          1255:        }
        !          1256:
        !          1257:        /* Init TX ring. */
        !          1258:        if (axe_tx_list_init(sc) == ENOBUFS) {
        !          1259:                printf("axe%d: tx list init failed\n", sc->axe_unit);
        !          1260:                splx(s);
        !          1261:                return;
        !          1262:        }
        !          1263:
        !          1264:        /* Set transmitter IPG values */
        !          1265:        if (sc->axe_flags & AX178 || sc->axe_flags & AX772)
        !          1266:                axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->axe_ipgs[2],
        !          1267:                    (sc->axe_ipgs[1] << 8) | (sc->axe_ipgs[0]), NULL);
        !          1268:        else {
        !          1269:                axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->axe_ipgs[0], NULL);
        !          1270:                axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->axe_ipgs[1], NULL);
        !          1271:                axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->axe_ipgs[2], NULL);
        !          1272:        }
        !          1273:
        !          1274:        /* Enable receiver, set RX mode */
        !          1275:        rxmode = AXE_RXCMD_MULTICAST|AXE_RXCMD_ENABLE;
        !          1276:        if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
        !          1277:                if (sc->axe_udev->speed == USB_SPEED_HIGH) {
        !          1278:                        /* largest possible USB buffer size for AX88178 */
        !          1279:                        rxmode |= AXE_178_RXCMD_MFB;
        !          1280:                }
        !          1281:        } else
        !          1282:                rxmode |= AXE_172_RXCMD_UNICAST;
        !          1283:
        !          1284:        /* If we want promiscuous mode, set the allframes bit. */
        !          1285:        if (ifp->if_flags & IFF_PROMISC)
        !          1286:                rxmode |= AXE_RXCMD_PROMISC;
        !          1287:
        !          1288:        if (ifp->if_flags & IFF_BROADCAST)
        !          1289:                rxmode |= AXE_RXCMD_BROADCAST;
        !          1290:
        !          1291:        axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
        !          1292:
        !          1293:        /* Load the multicast filter. */
        !          1294:        axe_setmulti(sc);
        !          1295:
        !          1296:        /* Open RX and TX pipes. */
        !          1297:        err = usbd_open_pipe(sc->axe_iface, sc->axe_ed[AXE_ENDPT_RX],
        !          1298:            USBD_EXCLUSIVE_USE, &sc->axe_ep[AXE_ENDPT_RX]);
        !          1299:        if (err) {
        !          1300:                printf("axe%d: open rx pipe failed: %s\n",
        !          1301:                    sc->axe_unit, usbd_errstr(err));
        !          1302:                splx(s);
        !          1303:                return;
        !          1304:        }
        !          1305:
        !          1306:        err = usbd_open_pipe(sc->axe_iface, sc->axe_ed[AXE_ENDPT_TX],
        !          1307:            USBD_EXCLUSIVE_USE, &sc->axe_ep[AXE_ENDPT_TX]);
        !          1308:        if (err) {
        !          1309:                printf("axe%d: open tx pipe failed: %s\n",
        !          1310:                    sc->axe_unit, usbd_errstr(err));
        !          1311:                splx(s);
        !          1312:                return;
        !          1313:        }
        !          1314:
        !          1315:        /* Start up the receive pipe. */
        !          1316:        for (i = 0; i < AXE_RX_LIST_CNT; i++) {
        !          1317:                c = &sc->axe_cdata.axe_rx_chain[i];
        !          1318:                usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_RX],
        !          1319:                    c, c->axe_buf, sc->axe_bufsz,
        !          1320:                    USBD_SHORT_XFER_OK | USBD_NO_COPY,
        !          1321:                    USBD_NO_TIMEOUT, axe_rxeof);
        !          1322:                usbd_transfer(c->axe_xfer);
        !          1323:        }
        !          1324:
        !          1325:        ifp->if_flags |= IFF_RUNNING;
        !          1326:        ifp->if_flags &= ~IFF_OACTIVE;
        !          1327:
        !          1328:        splx(s);
        !          1329:
        !          1330:        timeout_del(&sc->axe_stat_ch);
        !          1331:        timeout_set(&sc->axe_stat_ch, axe_tick, sc);
        !          1332:        timeout_add(&sc->axe_stat_ch, hz);
        !          1333:        return;
        !          1334: }
        !          1335:
        !          1336: int
        !          1337: axe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
        !          1338: {
        !          1339:        struct axe_softc        *sc = ifp->if_softc;
        !          1340:        struct ifreq            *ifr = (struct ifreq *)data;
        !          1341:        struct ifaddr           *ifa = (struct ifaddr *)data;
        !          1342:        struct mii_data         *mii;
        !          1343:        uWord                   rxmode;
        !          1344:        int                     error = 0;
        !          1345:
        !          1346:        switch(cmd) {
        !          1347:        case SIOCSIFADDR:
        !          1348:                ifp->if_flags |= IFF_UP;
        !          1349:                if (!(ifp->if_flags & IFF_RUNNING))
        !          1350:                        axe_init(sc);
        !          1351: #ifdef INET
        !          1352:                if (ifa->ifa_addr->sa_family == AF_INET)
        !          1353:                        arp_ifinit(&sc->arpcom, ifa);
        !          1354: #endif
        !          1355:                break;
        !          1356:
        !          1357:        case SIOCSIFMTU:
        !          1358:                if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu)
        !          1359:                        error = EINVAL;
        !          1360:                else if (ifp->if_mtu != ifr->ifr_mtu)
        !          1361:                        ifp->if_mtu = ifr->ifr_mtu;
        !          1362:                break;
        !          1363:
        !          1364:        case SIOCSIFFLAGS:
        !          1365:                if (ifp->if_flags & IFF_UP) {
        !          1366:                        if (ifp->if_flags & IFF_RUNNING &&
        !          1367:                            ifp->if_flags & IFF_PROMISC &&
        !          1368:                            !(sc->axe_if_flags & IFF_PROMISC)) {
        !          1369:
        !          1370:                                axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, rxmode);
        !          1371:                                axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0,
        !          1372:                                    UGETW(rxmode) | AXE_RXCMD_PROMISC, NULL);
        !          1373:
        !          1374:                                axe_setmulti(sc);
        !          1375:                        } else if (ifp->if_flags & IFF_RUNNING &&
        !          1376:                            !(ifp->if_flags & IFF_PROMISC) &&
        !          1377:                            sc->axe_if_flags & IFF_PROMISC) {
        !          1378:                                axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, rxmode);
        !          1379:                                axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0,
        !          1380:                                    UGETW(rxmode) & ~AXE_RXCMD_PROMISC, NULL);
        !          1381:                                axe_setmulti(sc);
        !          1382:                        } else if (!(ifp->if_flags & IFF_RUNNING))
        !          1383:                                axe_init(sc);
        !          1384:                } else {
        !          1385:                        if (ifp->if_flags & IFF_RUNNING)
        !          1386:                                axe_stop(sc);
        !          1387:                }
        !          1388:                sc->axe_if_flags = ifp->if_flags;
        !          1389:                break;
        !          1390:        case SIOCADDMULTI:
        !          1391:        case SIOCDELMULTI:
        !          1392:                error = (cmd == SIOCADDMULTI) ?
        !          1393:                    ether_addmulti(ifr, &sc->arpcom) :
        !          1394:                    ether_delmulti(ifr, &sc->arpcom);
        !          1395:
        !          1396:                if (error == ENETRESET) {
        !          1397:                        /*
        !          1398:                         * Multicast list has changed; set the hardware
        !          1399:                         * filter accordingly.
        !          1400:                         */
        !          1401:                        if (ifp->if_flags & IFF_RUNNING)
        !          1402:                                axe_setmulti(sc);
        !          1403:                        error = 0;
        !          1404:                }
        !          1405:                break;
        !          1406:        case SIOCGIFMEDIA:
        !          1407:        case SIOCSIFMEDIA:
        !          1408:                mii = GET_MII(sc);
        !          1409:                error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
        !          1410:                break;
        !          1411:
        !          1412:        default:
        !          1413:                error = EINVAL;
        !          1414:                break;
        !          1415:        }
        !          1416:
        !          1417:        return(error);
        !          1418: }
        !          1419:
        !          1420: void
        !          1421: axe_watchdog(struct ifnet *ifp)
        !          1422: {
        !          1423:        struct axe_softc        *sc;
        !          1424:        struct axe_chain        *c;
        !          1425:        usbd_status             stat;
        !          1426:        int                     s;
        !          1427:
        !          1428:        sc = ifp->if_softc;
        !          1429:
        !          1430:        ifp->if_oerrors++;
        !          1431:        printf("axe%d: watchdog timeout\n", sc->axe_unit);
        !          1432:
        !          1433:        s = splusb();
        !          1434:        c = &sc->axe_cdata.axe_tx_chain[0];
        !          1435:        usbd_get_xfer_status(c->axe_xfer, NULL, NULL, NULL, &stat);
        !          1436:        axe_txeof(c->axe_xfer, c, stat);
        !          1437:
        !          1438:        if (!IFQ_IS_EMPTY(&ifp->if_snd))
        !          1439:                axe_start(ifp);
        !          1440:        splx(s);
        !          1441: }
        !          1442:
        !          1443: /*
        !          1444:  * Stop the adapter and free any mbufs allocated to the
        !          1445:  * RX and TX lists.
        !          1446:  */
        !          1447: void
        !          1448: axe_stop(struct axe_softc *sc)
        !          1449: {
        !          1450:        usbd_status             err;
        !          1451:        struct ifnet            *ifp;
        !          1452:        int                     i;
        !          1453:
        !          1454:        axe_reset(sc);
        !          1455:
        !          1456:        ifp = &sc->arpcom.ac_if;
        !          1457:        ifp->if_timer = 0;
        !          1458:        ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
        !          1459:
        !          1460:        timeout_del(&sc->axe_stat_ch);
        !          1461:
        !          1462:        /* Stop transfers. */
        !          1463:        if (sc->axe_ep[AXE_ENDPT_RX] != NULL) {
        !          1464:                err = usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_RX]);
        !          1465:                if (err) {
        !          1466:                        printf("axe%d: abort rx pipe failed: %s\n",
        !          1467:                            sc->axe_unit, usbd_errstr(err));
        !          1468:                }
        !          1469:                err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_RX]);
        !          1470:                if (err) {
        !          1471:                        printf("axe%d: close rx pipe failed: %s\n",
        !          1472:                            sc->axe_unit, usbd_errstr(err));
        !          1473:                }
        !          1474:                sc->axe_ep[AXE_ENDPT_RX] = NULL;
        !          1475:        }
        !          1476:
        !          1477:        if (sc->axe_ep[AXE_ENDPT_TX] != NULL) {
        !          1478:                err = usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_TX]);
        !          1479:                if (err) {
        !          1480:                        printf("axe%d: abort tx pipe failed: %s\n",
        !          1481:                            sc->axe_unit, usbd_errstr(err));
        !          1482:                }
        !          1483:                err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_TX]);
        !          1484:                if (err) {
        !          1485:                        printf("axe%d: close tx pipe failed: %s\n",
        !          1486:                            sc->axe_unit, usbd_errstr(err));
        !          1487:                }
        !          1488:                sc->axe_ep[AXE_ENDPT_TX] = NULL;
        !          1489:        }
        !          1490:
        !          1491:        if (sc->axe_ep[AXE_ENDPT_INTR] != NULL) {
        !          1492:                err = usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
        !          1493:                if (err) {
        !          1494:                        printf("axe%d: abort intr pipe failed: %s\n",
        !          1495:                            sc->axe_unit, usbd_errstr(err));
        !          1496:                }
        !          1497:                err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
        !          1498:                if (err) {
        !          1499:                        printf("axe%d: close intr pipe failed: %s\n",
        !          1500:                            sc->axe_unit, usbd_errstr(err));
        !          1501:                }
        !          1502:                sc->axe_ep[AXE_ENDPT_INTR] = NULL;
        !          1503:        }
        !          1504:
        !          1505:        /* Free RX resources. */
        !          1506:        for (i = 0; i < AXE_RX_LIST_CNT; i++) {
        !          1507:                if (sc->axe_cdata.axe_rx_chain[i].axe_mbuf != NULL) {
        !          1508:                        m_freem(sc->axe_cdata.axe_rx_chain[i].axe_mbuf);
        !          1509:                        sc->axe_cdata.axe_rx_chain[i].axe_mbuf = NULL;
        !          1510:                }
        !          1511:                if (sc->axe_cdata.axe_rx_chain[i].axe_xfer != NULL) {
        !          1512:                        usbd_free_xfer(sc->axe_cdata.axe_rx_chain[i].axe_xfer);
        !          1513:                        sc->axe_cdata.axe_rx_chain[i].axe_xfer = NULL;
        !          1514:                }
        !          1515:        }
        !          1516:
        !          1517:        /* Free TX resources. */
        !          1518:        for (i = 0; i < AXE_TX_LIST_CNT; i++) {
        !          1519:                if (sc->axe_cdata.axe_tx_chain[i].axe_mbuf != NULL) {
        !          1520:                        m_freem(sc->axe_cdata.axe_tx_chain[i].axe_mbuf);
        !          1521:                        sc->axe_cdata.axe_tx_chain[i].axe_mbuf = NULL;
        !          1522:                }
        !          1523:                if (sc->axe_cdata.axe_tx_chain[i].axe_xfer != NULL) {
        !          1524:                        usbd_free_xfer(sc->axe_cdata.axe_tx_chain[i].axe_xfer);
        !          1525:                        sc->axe_cdata.axe_tx_chain[i].axe_xfer = NULL;
        !          1526:                }
        !          1527:        }
        !          1528:
        !          1529:        sc->axe_link = 0;
        !          1530: }
        !          1531:

CVSweb