[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

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