[BACK]Return to if_xi.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / pcmcia

Annotation of src/sys/dev/pcmcia/if_xi.c, Revision 1.6.2.2

1.6.2.2 ! bouyer      1: /*     $NetBSD: if_xi.c,v 1.6.2.1 2000/11/20 11:42:45 bouyer Exp $     */
        !             2: /*     OpenBSD: if_xe.c,v 1.9 1999/09/16 11:28:42 niklas Exp   */
        !             3:
        !             4: /*
        !             5:  * XXX THIS DRIVER IS BROKEN WRT. MULTICAST LISTS AND PROMISC/ALLMULTI
        !             6:  * XXX FLAGS!
        !             7:  */
        !             8:
        !             9: /*
        !            10:  * Copyright (c) 1999 Niklas Hallqvist, Brandon Creighton, Job de Haas
        !            11:  * All rights reserved.
        !            12:  *
        !            13:  * Redistribution and use in source and binary forms, with or without
        !            14:  * modification, are permitted provided that the following conditions
        !            15:  * are met:
        !            16:  * 1. Redistributions of source code must retain the above copyright
        !            17:  *    notice, this list of conditions and the following disclaimer.
        !            18:  * 2. Redistributions in binary form must reproduce the above copyright
        !            19:  *    notice, this list of conditions and the following disclaimer in the
        !            20:  *    documentation and/or other materials provided with the distribution.
        !            21:  * 3. All advertising materials mentioning features or use of this software
        !            22:  *    must display the following acknowledgement:
        !            23:  *     This product includes software developed by Niklas Hallqvist,
        !            24:  *     Brandon Creighton and Job de Haas.
        !            25:  * 4. The name of the author may not be used to endorse or promote products
        !            26:  *    derived from this software without specific prior written permission
        !            27:  *
        !            28:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            29:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            30:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            31:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            32:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            33:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            34:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            35:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            36:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            37:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            38:  */
        !            39:
        !            40: /*
        !            41:  * A driver for Xircom CreditCard PCMCIA Ethernet adapters.
        !            42:  */
        !            43:
        !            44: /*
        !            45:  * Known Bugs:
        !            46:  *
        !            47:  * 1) Promiscuous mode doesn't work on at least the CE2.
        !            48:  * 2) Slow. ~450KB/s.  Memory access would be better.
        !            49:  */
        !            50:
        !            51: #include "opt_inet.h"
        !            52: #include "bpfilter.h"
        !            53:
        !            54: #include <sys/param.h>
        !            55: #include <sys/systm.h>
        !            56: #include <sys/device.h>
        !            57: #include <sys/ioctl.h>
        !            58: #include <sys/mbuf.h>
        !            59: #include <sys/malloc.h>
        !            60: #include <sys/socket.h>
        !            61:
        !            62: #include <net/if.h>
        !            63: #include <net/if_dl.h>
        !            64: #include <net/if_media.h>
        !            65: #include <net/if_types.h>
        !            66: #include <net/if_ether.h>
        !            67:
        !            68: #ifdef INET
        !            69: #include <netinet/in.h>
        !            70: #include <netinet/in_systm.h>
        !            71: #include <netinet/in_var.h>
        !            72: #include <netinet/ip.h>
        !            73: #include <netinet/if_inarp.h>
        !            74: #endif
        !            75:
        !            76: #ifdef IPX
        !            77: #include <netipx/ipx.h>
        !            78: #include <netipx/ipx_if.h>
        !            79: #endif
        !            80:
        !            81: #ifdef NS
        !            82: #include <netns/ns.h>
        !            83: #include <netns/ns_if.h>
        !            84: #endif
        !            85:
        !            86: #if NBPFILTER > 0
        !            87: #include <net/bpf.h>
        !            88: #include <net/bpfdesc.h>
        !            89: #endif
        !            90:
        !            91: #define ETHER_MIN_LEN 64
        !            92: #define ETHER_CRC_LEN 4
        !            93:
        !            94: /*
        !            95:  * Maximum number of bytes to read per interrupt.  Linux recommends
        !            96:  * somewhere between 2000-22000.
        !            97:  * XXX This is currently a hard maximum.
        !            98:  */
        !            99: #define MAX_BYTES_INTR 12000
        !           100:
        !           101: #include <dev/mii/mii.h>
        !           102: #include <dev/mii/miivar.h>
        !           103:
        !           104: #include <dev/pcmcia/pcmciareg.h>
        !           105: #include <dev/pcmcia/pcmciavar.h>
        !           106: #include <dev/pcmcia/pcmciadevs.h>
        !           107:
        !           108: #define XI_IOSIZ       16
        !           109:
        !           110: #include <dev/pcmcia/if_xireg.h>
        !           111:
        !           112: #ifdef __GNUC__
        !           113: #define INLINE __inline
        !           114: #else
        !           115: #define INLINE
        !           116: #endif /* __GNUC__ */
        !           117:
        !           118: #ifdef XIDEBUG
        !           119: #define DPRINTF(cat, x) if (xidebug & (cat)) printf x
        !           120:
        !           121: #define XID_CONFIG     0x1
        !           122: #define XID_MII                0x2
        !           123: #define XID_INTR       0x4
        !           124: #define XID_FIFO       0x8
        !           125:
        !           126: #ifdef XIDEBUG_VALUE
        !           127: int xidebug = XIDEBUG_VALUE;
        !           128: #else
        !           129: int xidebug = 0;
        !           130: #endif
        !           131: #else
        !           132: #define DPRINTF(cat, x) (void)0
        !           133: #endif
        !           134:
        !           135: int    xi_pcmcia_match __P((struct device *, struct cfdata *, void *));
        !           136: void   xi_pcmcia_attach __P((struct device *, struct device *, void *));
        !           137: int    xi_pcmcia_detach __P((struct device *, int));
        !           138: int    xi_pcmcia_activate __P((struct device *, enum devact));
        !           139:
        !           140: /*
        !           141:  * In case this chipset ever turns up out of pcmcia attachments (very
        !           142:  * unlikely) do the driver splitup.
        !           143:  */
        !           144: struct xi_softc {
        !           145:        struct device sc_dev;                   /* Generic device info */
        !           146:        struct ethercom sc_ethercom;            /* Ethernet common part */
        !           147:
        !           148:        struct mii_data sc_mii;                 /* MII media information */
        !           149:
        !           150:        bus_space_tag_t         sc_bst;         /* Bus cookie */
        !           151:        bus_space_handle_t      sc_bsh;         /* Bus I/O handle */
        !           152:        bus_addr_t              sc_offset;      /* Offset of registers */
        !           153:
        !           154:        u_int8_t        sc_rev;                 /* Chip revision */
        !           155:        u_int32_t       sc_flags;               /* Misc. flags */
        !           156:        int             sc_all_mcasts;          /* Receive all multicasts */
        !           157:        u_int8_t        sc_enaddr[ETHER_ADDR_LEN];
        !           158: };
        !           159:
        !           160: struct xi_pcmcia_softc {
        !           161:        struct  xi_softc sc_xi;                 /* Generic device info */
        !           162:
        !           163:        /* PCMCIA-specific goo */
        !           164:        struct  pcmcia_function *sc_pf;         /* PCMCIA function */
        !           165:        struct  pcmcia_io_handle sc_pcioh;      /* iospace info */
        !           166:        int     sc_io_window;                   /* io window info */
        !           167:        void    *sc_ih;                         /* Interrupt handler */
        !           168:
        !           169:        int     sc_resource;                    /* resource allocated */
        !           170: #define XI_RES_PCIC    1
        !           171: #define XI_RES_IO      2
        !           172: #define XI_RES_MI      8
        !           173: };
        !           174:
        !           175: struct cfattach xi_pcmcia_ca = {
        !           176:        sizeof(struct xi_pcmcia_softc), xi_pcmcia_match, xi_pcmcia_attach,
        !           177:        xi_pcmcia_detach, xi_pcmcia_activate
        !           178: };
        !           179:
        !           180: static int xi_pcmcia_cis_quirks __P((struct pcmcia_function *));
        !           181: static void xi_cycle_power __P((struct xi_softc *));
        !           182: static int xi_ether_ioctl __P((struct ifnet *, u_long cmd, caddr_t));
        !           183: static void xi_full_reset __P((struct xi_softc *));
        !           184: static void xi_init __P((struct xi_softc *));
        !           185: static int xi_intr __P((void *));
        !           186: static int xi_ioctl __P((struct ifnet *, u_long, caddr_t));
        !           187: static int xi_mdi_read __P((struct device *, int, int));
        !           188: static void xi_mdi_write __P((struct device *, int, int, int));
        !           189: static int xi_mediachange __P((struct ifnet *));
        !           190: static void xi_mediastatus __P((struct ifnet *, struct ifmediareq *));
        !           191: static int xi_pcmcia_funce_enaddr __P((struct device *, u_int8_t *));
        !           192: static int xi_pcmcia_lan_nid_ciscallback __P((struct pcmcia_tuple *, void *));
        !           193: static int xi_pcmcia_manfid_ciscallback __P((struct pcmcia_tuple *, void *));
        !           194: static u_int16_t xi_get __P((struct xi_softc *));
        !           195: static void xi_reset __P((struct xi_softc *));
        !           196: static void xi_set_address __P((struct xi_softc *));
        !           197: static void xi_start __P((struct ifnet *));
        !           198: static void xi_statchg __P((struct device *));
        !           199: static void xi_stop __P((struct xi_softc *));
        !           200: static void xi_watchdog __P((struct ifnet *));
        !           201: struct xi_pcmcia_product *xi_pcmcia_identify __P((struct device *,
        !           202:                                                struct pcmcia_attach_args *));
        !           203:
        !           204: /* flags */
        !           205: #define XIFLAGS_MOHAWK 0x001           /* 100Mb capabilities (has phy) */
        !           206: #define XIFLAGS_DINGO  0x002           /* realport cards ??? */
        !           207: #define XIFLAGS_MODEM  0x004           /* modem also present */
        !           208:
        !           209: struct xi_pcmcia_product {
        !           210:        u_int32_t       xpp_vendor;     /* vendor ID */
        !           211:        u_int32_t       xpp_product;    /* product ID */
        !           212:        int             xpp_expfunc;    /* expected function number */
        !           213:        int             xpp_flags;      /* initial softc flags */
        !           214:        const char      *xpp_name;      /* device name */
        !           215: } xi_pcmcia_products[] = {
        !           216: #ifdef NOT_SUPPORTED
        !           217:        { PCMCIA_VENDOR_XIRCOM,         0x0141,
        !           218:          0,                            0,
        !           219:          PCMCIA_STR_XIRCOM_CE },
        !           220: #endif
        !           221:        { PCMCIA_VENDOR_XIRCOM,         0x0141,
        !           222:          0,                            0,
        !           223:          PCMCIA_STR_XIRCOM_CE2 },
        !           224:        { PCMCIA_VENDOR_XIRCOM,         0x0142,
        !           225:          0,                            0,
        !           226:          PCMCIA_STR_XIRCOM_CE2 },
        !           227:        { PCMCIA_VENDOR_XIRCOM,         0x0143,
        !           228:          0,                            XIFLAGS_MOHAWK,
        !           229:          PCMCIA_STR_XIRCOM_CE3 },
        !           230:        { PCMCIA_VENDOR_COMPAQ2,        0x0143,
        !           231:          0,                            XIFLAGS_MOHAWK,
        !           232:          PCMCIA_STR_COMPAQ2_CPQ_10_100 },
        !           233:        { PCMCIA_VENDOR_INTEL,          0x0143,
        !           234:          0,                            XIFLAGS_MOHAWK | XIFLAGS_MODEM,
        !           235:          PCMCIA_STR_INTEL_EEPRO100 },
        !           236: #ifdef NOT_SUPPORTED
        !           237:        { PCMCIA_VENDOR_XIRCOM,         0x1141,
        !           238:          0,                            XIFLAGS_MODEM,
        !           239:          PCMCIA_STR_XIRCOM_CEM },
        !           240: #endif
        !           241:        { PCMCIA_VENDOR_XIRCOM,         0x1142,
        !           242:          0,                            XIFLAGS_MODEM,
        !           243:          PCMCIA_STR_XIRCOM_CEM },
        !           244:        { PCMCIA_VENDOR_XIRCOM,         0x1143,
        !           245:          0,                            XIFLAGS_MODEM,
        !           246:          PCMCIA_STR_XIRCOM_CEM },
        !           247:        { PCMCIA_VENDOR_XIRCOM,         0x1144,
        !           248:          0,                            XIFLAGS_MODEM,
        !           249:          PCMCIA_STR_XIRCOM_CEM33 },
        !           250:        { PCMCIA_VENDOR_XIRCOM,         0x1145,
        !           251:          0,                            XIFLAGS_MOHAWK | XIFLAGS_MODEM,
        !           252:          PCMCIA_STR_XIRCOM_CEM56 },
        !           253:        { PCMCIA_VENDOR_XIRCOM,         0x1146,
        !           254:          0,                            XIFLAGS_MOHAWK | XIFLAGS_DINGO | XIFLAGS_MODEM,
        !           255:          PCMCIA_STR_XIRCOM_REM56 },
        !           256:        { PCMCIA_VENDOR_XIRCOM,         0x1147,
        !           257:          0,                            XIFLAGS_MOHAWK | XIFLAGS_DINGO | XIFLAGS_MODEM,
        !           258:          PCMCIA_STR_XIRCOM_REM56 },
        !           259:        { 0,                            0,
        !           260:          0,                            0,
        !           261:          NULL },
        !           262: };
        !           263:
        !           264:
        !           265: struct xi_pcmcia_product *
        !           266: xi_pcmcia_identify(dev, pa)
        !           267:        struct device *dev;
        !           268:         struct pcmcia_attach_args *pa;
        !           269: {
        !           270:        struct xi_pcmcia_product *xpp;
        !           271:         u_int8_t id;
        !           272:        u_int32_t prod;
        !           273:
        !           274:        /*
        !           275:         * The Xircom ethernet cards swap the revision and product fields
        !           276:         * inside the CIS, which makes identification just a little
        !           277:         * bit different.
        !           278:         */
        !           279:
        !           280:         pcmcia_scan_cis(dev, xi_pcmcia_manfid_ciscallback, &id);
        !           281:
        !           282:        prod = (pa->product & ~0xff) | id;
        !           283:
        !           284:        DPRINTF(XID_CONFIG, ("product=0x%x\n", prod));
        !           285:
        !           286:        for (xpp = xi_pcmcia_products; xpp->xpp_name != NULL; xpp++)
        !           287:                if (pa->manufacturer == xpp->xpp_vendor &&
        !           288:                        prod == xpp->xpp_product &&
        !           289:                        pa->pf->number == xpp->xpp_expfunc)
        !           290:                        return (xpp);
        !           291:        return (NULL);
        !           292: }
        !           293:
        !           294: /*
        !           295:  * If someone can determine which manufacturers/products require cis_quirks,
        !           296:  * then the proper infrastucture can be used.  Until then...
        !           297:  * This also becomes a pain with detaching.
        !           298:  */
        !           299: static int
        !           300: xi_pcmcia_cis_quirks(pf)
        !           301:        struct pcmcia_function *pf;
        !           302: {
        !           303:        struct pcmcia_config_entry *cfe;
        !           304:
        !           305:        /* Tell the pcmcia framework where the CCR is. */
        !           306:        pf->ccr_base = 0x800;
        !           307:        pf->ccr_mask = 0x67;
        !           308:
        !           309:        /* Fake a cfe. */
        !           310:        SIMPLEQ_FIRST(&pf->cfe_head) = cfe = (struct pcmcia_config_entry *)
        !           311:            malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
        !           312:
        !           313:        if (cfe == NULL)
        !           314:                return -1;
        !           315:        bzero(cfe, sizeof(*cfe));
        !           316:
        !           317:        /*
        !           318:         * XXX Use preprocessor symbols instead.
        !           319:         * Enable ethernet & its interrupts, wiring them to -INT
        !           320:         * No I/O base.
        !           321:         */
        !           322:        cfe->number = 0x5;
        !           323:        cfe->flags = 0;         /* XXX Check! */
        !           324:        cfe->iftype = PCMCIA_IFTYPE_IO;
        !           325:        cfe->num_iospace = 0;
        !           326:        cfe->num_memspace = 0;
        !           327:        cfe->irqmask = 0x8eb0;
        !           328:
        !           329:        return 0;
        !           330: }
        !           331:
        !           332: int
        !           333: xi_pcmcia_match(parent, match, aux)
        !           334:        struct device *parent;
        !           335:        struct cfdata *match;
        !           336:        void *aux;
        !           337: {
        !           338:        struct pcmcia_attach_args *pa = aux;
        !           339:
        !           340:        if (pa->pf->function != PCMCIA_FUNCTION_NETWORK)
        !           341:                return (0);
        !           342:
        !           343:        if (pa->manufacturer == PCMCIA_VENDOR_COMPAQ2 &&
        !           344:            pa->product == PCMCIA_PRODUCT_COMPAQ2_CPQ_10_100)
        !           345:                return (1);
        !           346:
        !           347:        if (pa->manufacturer == PCMCIA_VENDOR_INTEL &&
        !           348:           pa->product == PCMCIA_PRODUCT_INTEL_EEPRO100)
        !           349:                return (1);
        !           350:
        !           351:        if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM &&
        !           352:            ((pa->product >> 8) == XIMEDIA_ETHER ||
        !           353:            (pa->product >> 8) == (XIMEDIA_ETHER | XIMEDIA_MODEM)))
        !           354:                return (1);
        !           355:
        !           356:        return (0);
        !           357: }
        !           358:
        !           359: void
        !           360: xi_pcmcia_attach(parent, self, aux)
        !           361:        struct device *parent, *self;
        !           362:        void *aux;
        !           363: {
        !           364:        struct xi_pcmcia_softc *psc = (struct xi_pcmcia_softc *)self;
        !           365:        struct xi_softc *sc = &psc->sc_xi;
        !           366:        struct pcmcia_attach_args *pa = aux;
        !           367:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
        !           368:        struct xi_pcmcia_product *xpp;
        !           369:
        !           370:        if (xi_pcmcia_cis_quirks(pa->pf) < 0) {
        !           371:                printf(": function enable failed\n");
        !           372:                return;
        !           373:        }
        !           374:
        !           375:        /* Enable the card */
        !           376:        psc->sc_pf = pa->pf;
        !           377:        pcmcia_function_init(psc->sc_pf, psc->sc_pf->cfe_head.sqh_first);
        !           378:        if (pcmcia_function_enable(psc->sc_pf)) {
        !           379:                printf(": function enable failed\n");
        !           380:                goto fail;
        !           381:        }
        !           382:        psc->sc_resource |= XI_RES_PCIC;
        !           383:
        !           384:        /* allocate/map ISA I/O space */
        !           385:        if (pcmcia_io_alloc(psc->sc_pf, 0, XI_IOSIZ, XI_IOSIZ,
        !           386:                &psc->sc_pcioh) != 0) {
        !           387:                printf(": i/o allocation failed\n");
        !           388:                goto fail;
        !           389:        }
        !           390:        if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_IO16, 0, XI_IOSIZ,
        !           391:                &psc->sc_pcioh, &psc->sc_io_window)) {
        !           392:                printf(": can't map i/o space\n");
        !           393:                goto fail;
        !           394:        }
        !           395:        sc->sc_bst = psc->sc_pcioh.iot;
        !           396:        sc->sc_bsh = psc->sc_pcioh.ioh;
        !           397:        sc->sc_offset = 0;
        !           398:        psc->sc_resource |= XI_RES_IO;
        !           399:
        !           400:        xpp = xi_pcmcia_identify(parent,pa);
        !           401:        if (xpp == NULL) {
        !           402:                printf(": unrecognised model\n");
        !           403:                return;
        !           404:        }
        !           405:        sc->sc_flags = xpp->xpp_flags;
        !           406:
        !           407:        printf(": %s\n", xpp->xpp_name);
        !           408:
        !           409:        /*
        !           410:         * Configuration as adviced by DINGO documentation.
        !           411:         * Dingo has some extra configuration registers in the CCR space.
        !           412:         */
        !           413:        if (sc->sc_flags & XIFLAGS_DINGO) {
        !           414:                struct pcmcia_mem_handle pcmh;
        !           415:                int ccr_window;
        !           416:                bus_addr_t ccr_offset;
        !           417:
        !           418:                if (pcmcia_mem_alloc(psc->sc_pf, PCMCIA_CCR_SIZE_DINGO,
        !           419:                        &pcmh)) {
        !           420:                        DPRINTF(XID_CONFIG, ("xi: bad mem alloc\n"));
        !           421:                        goto fail;
        !           422:                }
        !           423:
        !           424:                if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR,
        !           425:                        psc->sc_pf->ccr_base, PCMCIA_CCR_SIZE_DINGO,
        !           426:                        &pcmh, &ccr_offset, &ccr_window)) {
        !           427:                        DPRINTF(XID_CONFIG, ("xi: bad mem map\n"));
        !           428:                        pcmcia_mem_free(psc->sc_pf, &pcmh);
        !           429:                        goto fail;
        !           430:                }
        !           431:
        !           432:                bus_space_write_1(pcmh.memt, pcmh.memh,
        !           433:                    ccr_offset + PCMCIA_CCR_DCOR0, PCMCIA_CCR_DCOR0_SFINT);
        !           434:                bus_space_write_1(pcmh.memt, pcmh.memh,
        !           435:                    ccr_offset + PCMCIA_CCR_DCOR1,
        !           436:                    PCMCIA_CCR_DCOR1_FORCE_LEVIREQ | PCMCIA_CCR_DCOR1_D6);
        !           437:                bus_space_write_1(pcmh.memt, pcmh.memh,
        !           438:                    ccr_offset + PCMCIA_CCR_DCOR2, 0);
        !           439:                bus_space_write_1(pcmh.memt, pcmh.memh,
        !           440:                    ccr_offset + PCMCIA_CCR_DCOR3, 0);
        !           441:                bus_space_write_1(pcmh.memt, pcmh.memh,
        !           442:                    ccr_offset + PCMCIA_CCR_DCOR4, 0);
        !           443:
        !           444:                /* We don't need them anymore and can free them (I think). */
        !           445:                pcmcia_mem_unmap(psc->sc_pf, ccr_window);
        !           446:                pcmcia_mem_free(psc->sc_pf, &pcmh);
        !           447:        }
        !           448:
        !           449:        /*
        !           450:         * Try to get the ethernet address from FUNCE/LAN_NID tuple.
        !           451:         */
        !           452:        xi_pcmcia_funce_enaddr(parent, sc->sc_enaddr);
        !           453:        if (!sc->sc_enaddr) {
        !           454:                printf("%s: unable to get ethernet address\n",
        !           455:                        sc->sc_dev.dv_xname);
        !           456:                goto fail;
        !           457:        }
        !           458:
        !           459:        printf("%s: Ethernet address %s\n", sc->sc_dev.dv_xname,
        !           460:            ether_sprintf(sc->sc_enaddr));
        !           461:
        !           462:        ifp = &sc->sc_ethercom.ec_if;
        !           463:        memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
        !           464:        ifp->if_softc = sc;
        !           465:        ifp->if_start = xi_start;
        !           466:        ifp->if_ioctl = xi_ioctl;
        !           467:        ifp->if_watchdog = xi_watchdog;
        !           468:        ifp->if_flags =
        !           469:            IFF_BROADCAST | IFF_NOTRAILERS | IFF_SIMPLEX | IFF_MULTICAST;
        !           470:        ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
        !           471:
        !           472:        /* Reset and initialize the card. */
        !           473:        xi_full_reset(sc);
        !           474:
        !           475:        /*
        !           476:         * Initialize our media structures and probe the MII.
        !           477:         */
        !           478:        sc->sc_mii.mii_ifp = ifp;
        !           479:        sc->sc_mii.mii_readreg = xi_mdi_read;
        !           480:        sc->sc_mii.mii_writereg = xi_mdi_write;
        !           481:        sc->sc_mii.mii_statchg = xi_statchg;
        !           482:        ifmedia_init(&sc->sc_mii.mii_media, 0, xi_mediachange,
        !           483:            xi_mediastatus);
        !           484:        DPRINTF(XID_MII | XID_CONFIG,
        !           485:            ("xi: bmsr %x\n", xi_mdi_read(&sc->sc_dev, 0, 1)));
        !           486:        mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
        !           487:                MII_OFFSET_ANY, 0);
        !           488:        if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL)
        !           489:                ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO, 0,
        !           490:                    NULL);
        !           491:        ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
        !           492:
        !           493:        /*
        !           494:         * Attach the interface.
        !           495:         */
        !           496:        if_attach(ifp);
        !           497:        ether_ifattach(ifp, sc->sc_enaddr);
        !           498:        psc->sc_resource |= XI_RES_MI;
        !           499:
        !           500: #if NBPFILTER > 0
        !           501:        bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
        !           502: #endif /* NBPFILTER > 0 */
        !           503:
        !           504:        /*
        !           505:         * Reset and initialize the card again for DINGO (as found in Linux
        !           506:         * driver).  Without this Dingo will get a watchdog timeout the first
        !           507:         * time.  The ugly media tickling seems to be necessary for getting
        !           508:         * autonegotiation to work too.
        !           509:         */
        !           510:        if (sc->sc_flags & XIFLAGS_DINGO) {
        !           511:                xi_full_reset(sc);
        !           512:                xi_init(sc);
        !           513:                ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
        !           514:                ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE);
        !           515:                xi_stop(sc);
        !           516:        }
        !           517:
        !           518:        /* Establish the interrupt. */
        !           519:        psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, xi_intr, sc);
        !           520:        if (psc->sc_ih == NULL) {
        !           521:                printf("%s: couldn't establish interrupt\n",
        !           522:                        sc->sc_dev.dv_xname);
        !           523:                goto fail;
        !           524:        }
        !           525:
        !           526:        return;
        !           527:
        !           528: fail:
        !           529:        if ((psc->sc_resource & XI_RES_IO) != 0) {
        !           530:                /* Unmap our i/o windows. */
        !           531:                pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
        !           532:                 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
        !           533:         }
        !           534:         psc->sc_resource &= ~XI_RES_IO;
        !           535:        if (psc->sc_resource & XI_RES_PCIC) {
        !           536:                pcmcia_function_disable(pa->pf);
        !           537:                psc->sc_resource &= ~XI_RES_PCIC;
        !           538:        }
        !           539:        free(SIMPLEQ_FIRST(&psc->sc_pf->cfe_head), M_DEVBUF);
        !           540: }
        !           541:
        !           542: int
        !           543: xi_pcmcia_detach(self, flags)
        !           544:      struct device *self;
        !           545:      int flags;
        !           546: {
        !           547:        struct xi_pcmcia_softc *psc = (struct xi_pcmcia_softc *)self;
        !           548:        struct xi_softc *sc = &psc->sc_xi;
        !           549:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
        !           550:
        !           551:        DPRINTF(XID_CONFIG, ("xi_pcmcia_detach()\n"));
        !           552:
        !           553:        if ((ifp->if_flags & IFF_RUNNING) == 0) {
        !           554:                xi_stop(sc);
        !           555:        }
        !           556:
        !           557:        pcmcia_function_disable(psc->sc_pf);
        !           558:        psc->sc_resource &= ~XI_RES_PCIC;
        !           559:        pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
        !           560:        ifp->if_flags &= ~IFF_RUNNING;
        !           561:        ifp->if_timer = 0;
        !           562:
        !           563:        if ((psc->sc_resource & XI_RES_MI) != 0) {
        !           564:
        !           565:                mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
        !           566:
        !           567:                ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
        !           568: #if NBPFILTER > 0
        !           569:                bpfdetach(ifp);
        !           570: #endif
        !           571:                ether_ifdetach(ifp);
        !           572:                if_detach(ifp);
        !           573:                psc->sc_resource &= ~XI_RES_MI;
        !           574:        }
        !           575:
        !           576:        if ((psc->sc_resource & XI_RES_IO) != 0) {
        !           577:                /* Unmap our i/o windows. */
        !           578:                pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
        !           579:                 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
        !           580:         }
        !           581:         free(SIMPLEQ_FIRST(&psc->sc_pf->cfe_head), M_DEVBUF);
        !           582:        psc->sc_resource &= ~XI_RES_IO;
        !           583:
        !           584:        return 0;
        !           585: }
        !           586:
        !           587: int
        !           588: xi_pcmcia_activate(self, act)
        !           589:      struct device *self;
        !           590:      enum devact act;
        !           591: {
        !           592:        struct xi_pcmcia_softc *psc = (struct xi_pcmcia_softc *)self;
        !           593:        struct xi_softc *sc = &psc->sc_xi;
        !           594:        int s, rv=0;
        !           595:
        !           596:        DPRINTF(XID_CONFIG, ("xi_pcmcia_activate()\n"));
        !           597:
        !           598:        s = splnet();
        !           599:        switch (act) {
        !           600:        case DVACT_ACTIVATE:
        !           601:                rv = EOPNOTSUPP;
        !           602:                break;
        !           603:
        !           604:        case DVACT_DEACTIVATE:
        !           605:                if_deactivate(&sc->sc_ethercom.ec_if);
        !           606:                break;
        !           607:        }
        !           608:        splx(s);
        !           609:        return (rv);
        !           610: }
        !           611:
        !           612: /*
        !           613:  * XXX These two functions might be OK to factor out into pcmcia.c since
        !           614:  * if_sm_pcmcia.c uses similar ones.
        !           615:  */
        !           616: static int
        !           617: xi_pcmcia_funce_enaddr(parent, myla)
        !           618:        struct device *parent;
        !           619:        u_int8_t *myla;
        !           620: {
        !           621:        /* XXX The Linux driver has more ways to do this in case of failure. */
        !           622:        return (pcmcia_scan_cis(parent, xi_pcmcia_lan_nid_ciscallback, myla));
        !           623: }
        !           624:
        !           625: static int
        !           626: xi_pcmcia_lan_nid_ciscallback(tuple, arg)
        !           627:        struct pcmcia_tuple *tuple;
        !           628:        void *arg;
        !           629: {
        !           630:        u_int8_t *myla = arg;
        !           631:        int i;
        !           632:
        !           633:        DPRINTF(XID_CONFIG, ("xi_pcmcia_lan_nid_ciscallback()\n"));
        !           634:
        !           635:        if (tuple->code == PCMCIA_CISTPL_FUNCE) {
        !           636:                if (tuple->length < 2)
        !           637:                        return (0);
        !           638:
        !           639:                switch (pcmcia_tuple_read_1(tuple, 0)) {
        !           640:                case PCMCIA_TPLFE_TYPE_LAN_NID:
        !           641:                        if (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN)
        !           642:                                return (0);
        !           643:                        break;
        !           644:
        !           645:                case 0x02:
        !           646:                        /*
        !           647:                         * Not sure about this, I don't have a CE2
        !           648:                         * that puts the ethernet addr here.
        !           649:                         */
        !           650:                        if (pcmcia_tuple_read_1(tuple, 1) != 13)
        !           651:                                return (0);
        !           652:                        break;
        !           653:
        !           654:                default:
        !           655:                        return (0);
        !           656:                }
        !           657:
        !           658:                for (i = 0; i < ETHER_ADDR_LEN; i++)
        !           659:                        myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
        !           660:                return (1);
        !           661:        }
        !           662:
        !           663:        /* Yet another spot where this might be. */
        !           664:        if (tuple->code == 0x89) {
        !           665:                pcmcia_tuple_read_1(tuple, 1);
        !           666:                for (i = 0; i < ETHER_ADDR_LEN; i++)
        !           667:                        myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
        !           668:                return (1);
        !           669:        }
        !           670:        return (0);
        !           671: }
        !           672:
        !           673: int
        !           674: xi_pcmcia_manfid_ciscallback(tuple, arg)
        !           675:        struct pcmcia_tuple *tuple;
        !           676:        void *arg;
        !           677: {
        !           678:        u_int8_t *id = arg;
        !           679:
        !           680:        DPRINTF(XID_CONFIG, ("xi_pcmcia_manfid_callback()\n"));
        !           681:
        !           682:        if (tuple->code != PCMCIA_CISTPL_MANFID)
        !           683:                return (0);
        !           684:
        !           685:        if (tuple->length < 2)
        !           686:                return (0);
        !           687:
        !           688:        *id = pcmcia_tuple_read_1(tuple, 4);
        !           689:        return (1);
        !           690: }
        !           691:
        !           692:
        !           693:
        !           694: static int
        !           695: xi_intr(arg)
        !           696:        void *arg;
        !           697: {
        !           698:        struct xi_softc *sc = arg;
        !           699:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
        !           700:        u_int8_t esr, rsr, isr, rx_status, savedpage;
        !           701:        u_int16_t tx_status, recvcount = 0, tempint;
        !           702:
        !           703:        DPRINTF(XID_CONFIG, ("xi_intr()\n"));
        !           704:
        !           705: #if 0
        !           706:        if (!(ifp->if_flags & IFF_RUNNING))
        !           707:                return (0);
        !           708: #endif
        !           709:
        !           710:        ifp->if_timer = 0;      /* turn watchdog timer off */
        !           711:
        !           712:        if (sc->sc_flags & XIFLAGS_MOHAWK) {
        !           713:                /* Disable interrupt (Linux does it). */
        !           714:                bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
        !           715:                    0);
        !           716:        }
        !           717:
        !           718:        savedpage =
        !           719:            bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + PR);
        !           720:
        !           721:        PAGE(sc, 0);
        !           722:        esr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + ESR);
        !           723:        isr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + ISR0);
        !           724:        rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RSR);
        !           725:
        !           726:        /* Check to see if card has been ejected. */
        !           727:        if (isr == 0xff) {
        !           728: #ifdef DIAGNOSTIC
        !           729:                printf("%s: interrupt for dead card\n", sc->sc_dev.dv_xname);
        !           730: #endif
        !           731:                goto end;
        !           732:        }
        !           733:
        !           734:        PAGE(sc, 40);
        !           735:        rx_status =
        !           736:            bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RXST0);
        !           737:        tx_status =
        !           738:            bus_space_read_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + TXST0);
        !           739:
        !           740:        /*
        !           741:         * XXX Linux writes to RXST0 and TXST* here.  My CE2 works just fine
        !           742:         * without it, and I can't see an obvious reason for it.
        !           743:         */
        !           744:
        !           745:        PAGE(sc, 0);
        !           746:        while (esr & FULL_PKT_RCV) {
        !           747:                if (!(rsr & RSR_RX_OK))
        !           748:                        break;
        !           749:
        !           750:                /* Compare bytes read this interrupt to hard maximum. */
        !           751:                if (recvcount > MAX_BYTES_INTR) {
        !           752:                        DPRINTF(XID_INTR,
        !           753:                            ("xi: too many bytes this interrupt\n"));
        !           754:                        ifp->if_iqdrops++;
        !           755:                        /* Drop packet. */
        !           756:                        bus_space_write_2(sc->sc_bst, sc->sc_bsh,
        !           757:                            sc->sc_offset + DO0, DO_SKIP_RX_PKT);
        !           758:                }
        !           759:                tempint = xi_get(sc);   /* XXX doesn't check the error! */
        !           760:                recvcount += tempint;
        !           761:                ifp->if_ibytes += tempint;
        !           762:                esr = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
        !           763:                    sc->sc_offset + ESR);
        !           764:                rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
        !           765:                    sc->sc_offset + RSR);
        !           766:        }
        !           767:
        !           768:        /* Packet too long? */
        !           769:        if (rsr & RSR_TOO_LONG) {
        !           770:                ifp->if_ierrors++;
        !           771:                DPRINTF(XID_INTR, ("xi: packet too long\n"));
        !           772:        }
        !           773:
        !           774:        /* CRC error? */
        !           775:        if (rsr & RSR_CRCERR) {
        !           776:                ifp->if_ierrors++;
        !           777:                DPRINTF(XID_INTR, ("xi: CRC error detected\n"));
        !           778:        }
        !           779:
        !           780:        /* Alignment error? */
        !           781:        if (rsr & RSR_ALIGNERR) {
        !           782:                ifp->if_ierrors++;
        !           783:                DPRINTF(XID_INTR, ("xi: alignment error detected\n"));
        !           784:        }
        !           785:
        !           786:        /* Check for rx overrun. */
        !           787:        if (rx_status & RX_OVERRUN) {
        !           788:                bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
        !           789:                    CLR_RX_OVERRUN);
        !           790:                DPRINTF(XID_INTR, ("xi: overrun cleared\n"));
        !           791:        }
        !           792:
        !           793:        /* Try to start more packets transmitting. */
        !           794:        if (ifp->if_snd.ifq_head)
        !           795:                xi_start(ifp);
        !           796:
        !           797:        /* Detected excessive collisions? */
        !           798:        if ((tx_status & EXCESSIVE_COLL) && ifp->if_opackets > 0) {
        !           799:                DPRINTF(XID_INTR, ("xi: excessive collisions\n"));
        !           800:                bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
        !           801:                    RESTART_TX);
        !           802:                ifp->if_oerrors++;
        !           803:        }
        !           804:
        !           805:        if ((tx_status & TX_ABORT) && ifp->if_opackets > 0)
        !           806:                ifp->if_oerrors++;
        !           807:
        !           808: end:
        !           809:        /* Reenable interrupts. */
        !           810:        PAGE(sc, savedpage);
        !           811:        bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
        !           812:            ENABLE_INT);
        !           813:
        !           814:        return (1);
        !           815: }
        !           816:
        !           817: /*
        !           818:  * Pull a packet from the card into an mbuf chain.
        !           819:  */
        !           820: static u_int16_t
        !           821: xi_get(sc)
        !           822:        struct xi_softc *sc;
        !           823: {
        !           824:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
        !           825:        struct mbuf *top, **mp, *m;
        !           826:        u_int16_t pktlen, len, recvcount = 0;
        !           827:        u_int8_t *data;
        !           828:        u_int8_t rsr;
        !           829:
        !           830:        DPRINTF(XID_CONFIG, ("xi_get()\n"));
        !           831:
        !           832:        PAGE(sc, 0);
        !           833:        rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RSR);
        !           834:
        !           835:        pktlen =
        !           836:            bus_space_read_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RBC0) &
        !           837:            RBC_COUNT_MASK;
        !           838:
        !           839:        DPRINTF(XID_CONFIG, ("xi_get: pktlen=%d\n", pktlen));
        !           840:
        !           841:        if (pktlen == 0) {
        !           842:                /*
        !           843:                 * XXX At least one CE2 sets RBC0 == 0 occasionally, and only
        !           844:                 * when MPE is set.  It is not known why.
        !           845:                 */
        !           846:                return (0);
        !           847:        }
        !           848:
        !           849:        /* XXX should this be incremented now ? */
        !           850:        recvcount += pktlen;
        !           851:
        !           852:        MGETHDR(m, M_DONTWAIT, MT_DATA);
        !           853:        if (m == 0)
        !           854:                return (recvcount);
        !           855:        m->m_pkthdr.rcvif = ifp;
        !           856:        m->m_pkthdr.len = pktlen;
        !           857:        len = MHLEN;
        !           858:        top = 0;
        !           859:        mp = &top;
        !           860:
        !           861:        while (pktlen > 0) {
        !           862:                if (top) {
        !           863:                        MGET(m, M_DONTWAIT, MT_DATA);
        !           864:                        if (m == 0) {
        !           865:                                m_freem(top);
        !           866:                                return (recvcount);
        !           867:                        }
        !           868:                        len = MLEN;
        !           869:                }
        !           870:                if (pktlen >= MINCLSIZE) {
        !           871:                        MCLGET(m, M_DONTWAIT);
        !           872:                        if (!(m->m_flags & M_EXT)) {
        !           873:                                m_freem(m);
        !           874:                                m_freem(top);
        !           875:                                return (recvcount);
        !           876:                        }
        !           877:                        len = MCLBYTES;
        !           878:                }
        !           879:                if (!top) {
        !           880:                        caddr_t newdata = (caddr_t)ALIGN(m->m_data +
        !           881:                            sizeof(struct ether_header)) -
        !           882:                            sizeof(struct ether_header);
        !           883:                        len -= newdata - m->m_data;
        !           884:                        m->m_data = newdata;
        !           885:                }
        !           886:                len = min(pktlen, len);
        !           887:                data = mtod(m, u_int8_t *);
        !           888:                if (len > 1) {
        !           889:                        len &= ~1;
        !           890:                        bus_space_read_multi_2(sc->sc_bst, sc->sc_bsh,
        !           891:                            sc->sc_offset + EDP, data, len>>1);
        !           892:                } else
        !           893:                        *data = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
        !           894:                            sc->sc_offset + EDP);
        !           895:                m->m_len = len;
        !           896:                pktlen -= len;
        !           897:                *mp = m;
        !           898:                mp = &m->m_next;
        !           899:        }
        !           900:
        !           901:        /* Skip Rx packet. */
        !           902:        bus_space_write_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + DO0,
        !           903:            DO_SKIP_RX_PKT);
        !           904:
        !           905:        ifp->if_ipackets++;
        !           906:
        !           907: #if NBPFILTER > 0
        !           908:        if (ifp->if_bpf)
        !           909:                bpf_mtap(ifp->if_bpf, top);
        !           910: #endif
        !           911:
        !           912:        (*ifp->if_input)(ifp, top);
        !           913:        return (recvcount);
        !           914: }
        !           915:
        !           916: /*
        !           917:  * Serial management for the MII.
        !           918:  * The DELAY's below stem from the fact that the maximum frequency
        !           919:  * acceptable on the MDC pin is 2.5 MHz and fast processors can easily
        !           920:  * go much faster than that.
        !           921:  */
        !           922:
        !           923: /* Let the MII serial management be idle for one period. */
        !           924: static INLINE void xi_mdi_idle __P((struct xi_softc *));
        !           925: static INLINE void
        !           926: xi_mdi_idle(sc)
        !           927:        struct xi_softc *sc;
        !           928: {
        !           929:        bus_space_tag_t bst = sc->sc_bst;
        !           930:        bus_space_handle_t bsh = sc->sc_bsh;
        !           931:        bus_addr_t offset = sc->sc_offset;
        !           932:
        !           933:        /* Drive MDC low... */
        !           934:        bus_space_write_1(bst, bsh, offset + GP2, MDC_LOW);
        !           935:        DELAY(1);
        !           936:
        !           937:        /* and high again. */
        !           938:        bus_space_write_1(bst, bsh, offset + GP2, MDC_HIGH);
        !           939:        DELAY(1);
        !           940: }
        !           941:
        !           942: /* Pulse out one bit of data. */
        !           943: static INLINE void xi_mdi_pulse __P((struct xi_softc *, int));
        !           944: static INLINE void
        !           945: xi_mdi_pulse(sc, data)
        !           946:        struct xi_softc *sc;
        !           947:        int data;
        !           948: {
        !           949:        bus_space_tag_t bst = sc->sc_bst;
        !           950:        bus_space_handle_t bsh = sc->sc_bsh;
        !           951:        bus_addr_t offset = sc->sc_offset;
        !           952:        u_int8_t bit = data ? MDIO_HIGH : MDIO_LOW;
        !           953:
        !           954:        /* First latch the data bit MDIO with clock bit MDC low...*/
        !           955:        bus_space_write_1(bst, bsh, offset + GP2, bit | MDC_LOW);
        !           956:        DELAY(1);
        !           957:
        !           958:        /* then raise the clock again, preserving the data bit. */
        !           959:        bus_space_write_1(bst, bsh, offset + GP2, bit | MDC_HIGH);
        !           960:        DELAY(1);
        !           961: }
        !           962:
        !           963: /* Probe one bit of data. */
        !           964: static INLINE int xi_mdi_probe __P((struct xi_softc *sc));
        !           965: static INLINE int
        !           966: xi_mdi_probe(sc)
        !           967:        struct xi_softc *sc;
        !           968: {
        !           969:        bus_space_tag_t bst = sc->sc_bst;
        !           970:        bus_space_handle_t bsh = sc->sc_bsh;
        !           971:        bus_addr_t offset = sc->sc_offset;
        !           972:        u_int8_t x;
        !           973:
        !           974:        /* Pull clock bit MDCK low... */
        !           975:        bus_space_write_1(bst, bsh, offset + GP2, MDC_LOW);
        !           976:        DELAY(1);
        !           977:
        !           978:        /* Read data and drive clock high again. */
        !           979:        x = bus_space_read_1(bst, bsh, offset + GP2) & MDIO;
        !           980:        bus_space_write_1(bst, bsh, offset + GP2, MDC_HIGH);
        !           981:        DELAY(1);
        !           982:
        !           983:        return (x);
        !           984: }
        !           985:
        !           986: /* Pulse out a sequence of data bits. */
        !           987: static INLINE void xi_mdi_pulse_bits __P((struct xi_softc *, u_int32_t, int));
        !           988: static INLINE void
        !           989: xi_mdi_pulse_bits(sc, data, len)
        !           990:        struct xi_softc *sc;
        !           991:        u_int32_t data;
        !           992:        int len;
        !           993: {
        !           994:        u_int32_t mask;
        !           995:
        !           996:        for (mask = 1 << (len - 1); mask; mask >>= 1)
        !           997:                xi_mdi_pulse(sc, data & mask);
        !           998: }
        !           999:
        !          1000: /* Read a PHY register. */
        !          1001: static int
        !          1002: xi_mdi_read(self, phy, reg)
        !          1003:        struct device *self;
        !          1004:        int phy;
        !          1005:        int reg;
        !          1006: {
        !          1007:        struct xi_softc *sc = (struct xi_softc *)self;
        !          1008:        int i;
        !          1009:        u_int32_t mask;
        !          1010:        u_int32_t data = 0;
        !          1011:
        !          1012:        PAGE(sc, 2);
        !          1013:        for (i = 0; i < 32; i++)        /* Synchronize. */
        !          1014:                xi_mdi_pulse(sc, 1);
        !          1015:        xi_mdi_pulse_bits(sc, 0x06, 4); /* Start + Read opcode */
        !          1016:        xi_mdi_pulse_bits(sc, phy, 5);  /* PHY address */
        !          1017:        xi_mdi_pulse_bits(sc, reg, 5);  /* PHY register */
        !          1018:        xi_mdi_idle(sc);                /* Turn around. */
        !          1019:        xi_mdi_probe(sc);               /* Drop initial zero bit. */
        !          1020:
        !          1021:        for (mask = 1 << 15; mask; mask >>= 1) {
        !          1022:                if (xi_mdi_probe(sc))
        !          1023:                        data |= mask;
        !          1024:        }
        !          1025:        xi_mdi_idle(sc);
        !          1026:
        !          1027:        DPRINTF(XID_MII,
        !          1028:            ("xi_mdi_read: phy %d reg %d -> %x\n", phy, reg, data));
        !          1029:
        !          1030:        return (data);
        !          1031: }
        !          1032:
        !          1033: /* Write a PHY register. */
        !          1034: static void
        !          1035: xi_mdi_write(self, phy, reg, value)
        !          1036:        struct device *self;
        !          1037:        int phy;
        !          1038:        int reg;
        !          1039:        int value;
        !          1040: {
        !          1041:        struct xi_softc *sc = (struct xi_softc *)self;
        !          1042:        int i;
        !          1043:
        !          1044:        PAGE(sc, 2);
        !          1045:        for (i = 0; i < 32; i++)        /* Synchronize. */
        !          1046:                xi_mdi_pulse(sc, 1);
        !          1047:        xi_mdi_pulse_bits(sc, 0x05, 4); /* Start + Write opcode */
        !          1048:        xi_mdi_pulse_bits(sc, phy, 5);  /* PHY address */
        !          1049:        xi_mdi_pulse_bits(sc, reg, 5);  /* PHY register */
        !          1050:        xi_mdi_pulse_bits(sc, 0x02, 2); /* Turn around. */
        !          1051:        xi_mdi_pulse_bits(sc, value, 16);       /* Write the data */
        !          1052:        xi_mdi_idle(sc);                /* Idle away. */
        !          1053:
        !          1054:        DPRINTF(XID_MII,
        !          1055:            ("xi_mdi_write: phy %d reg %d val %x\n", phy, reg, value));
        !          1056: }
        !          1057:
        !          1058: static void
        !          1059: xi_statchg(self)
        !          1060:        struct device *self;
        !          1061: {
        !          1062:        /* XXX Update ifp->if_baudrate */
        !          1063: }
        !          1064:
        !          1065: /*
        !          1066:  * Change media according to request.
        !          1067:  */
        !          1068: static int
        !          1069: xi_mediachange(ifp)
        !          1070:        struct ifnet *ifp;
        !          1071: {
        !          1072:        DPRINTF(XID_CONFIG, ("xi_mediachange()\n"));
        !          1073:
        !          1074:        if (ifp->if_flags & IFF_UP)
        !          1075:                xi_init(ifp->if_softc);
        !          1076:        return (0);
        !          1077: }
        !          1078:
        !          1079: /*
        !          1080:  * Notify the world which media we're using.
        !          1081:  */
        !          1082: static void
        !          1083: xi_mediastatus(ifp, ifmr)
        !          1084:        struct ifnet *ifp;
        !          1085:        struct ifmediareq *ifmr;
        !          1086: {
        !          1087:        struct xi_softc *sc = ifp->if_softc;
        !          1088:
        !          1089:        DPRINTF(XID_CONFIG, ("xi_mediastatus()\n"));
        !          1090:
        !          1091:        mii_pollstat(&sc->sc_mii);
        !          1092:        ifmr->ifm_status = sc->sc_mii.mii_media_status;
        !          1093:        ifmr->ifm_active = sc->sc_mii.mii_media_active;
        !          1094: }
        !          1095:
        !          1096: static void
        !          1097: xi_reset(sc)
        !          1098:        struct xi_softc *sc;
        !          1099: {
        !          1100:        int s;
        !          1101:
        !          1102:        DPRINTF(XID_CONFIG, ("xi_reset()\n"));
        !          1103:
        !          1104:        s = splnet();
        !          1105:        xi_stop(sc);
        !          1106:        xi_full_reset(sc);
        !          1107:        xi_init(sc);
        !          1108:        splx(s);
        !          1109: }
        !          1110:
        !          1111: static void
        !          1112: xi_watchdog(ifp)
        !          1113:        struct ifnet *ifp;
        !          1114: {
        !          1115:        struct xi_softc *sc = ifp->if_softc;
        !          1116:
        !          1117:        printf("%s: device timeout\n", sc->sc_dev.dv_xname);
        !          1118:        ++ifp->if_oerrors;
        !          1119:
        !          1120:        xi_reset(sc);
        !          1121: }
        !          1122:
        !          1123: static void
        !          1124: xi_stop(sc)
        !          1125:        register struct xi_softc *sc;
        !          1126: {
        !          1127:        DPRINTF(XID_CONFIG, ("xi_stop()\n"));
        !          1128:
        !          1129:        /* Disable interrupts. */
        !          1130:        PAGE(sc, 0);
        !          1131:        bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR, 0);
        !          1132:
        !          1133:        PAGE(sc, 1);
        !          1134:        bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + IMR0, 0);
        !          1135:
        !          1136:        /* Power down, wait. */
        !          1137:        PAGE(sc, 4);
        !          1138:        bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + GP1, 0);
        !          1139:        DELAY(40000);
        !          1140:
        !          1141:        /* Cancel watchdog timer. */
        !          1142:        sc->sc_ethercom.ec_if.if_timer = 0;
        !          1143: }
        !          1144:
        !          1145: static void
        !          1146: xi_init(sc)
        !          1147:        struct xi_softc *sc;
        !          1148: {
        !          1149:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
        !          1150:        int s;
        !          1151:
        !          1152:        DPRINTF(XID_CONFIG, ("xi_init()\n"));
        !          1153:
        !          1154:        s = splimp();
        !          1155:
        !          1156:        xi_set_address(sc);
        !          1157:
        !          1158:        /* Set current media. */
        !          1159:        mii_mediachg(&sc->sc_mii);
        !          1160:
        !          1161:        ifp->if_flags |= IFF_RUNNING;
        !          1162:        ifp->if_flags &= ~IFF_OACTIVE;
        !          1163:        splx(s);
        !          1164: }
        !          1165:
        !          1166: /*
        !          1167:  * Start outputting on the interface.
        !          1168:  * Always called as splnet().
        !          1169:  */
        !          1170: static void
        !          1171: xi_start(ifp)
        !          1172:        struct ifnet *ifp;
        !          1173: {
        !          1174:        struct xi_softc *sc = ifp->if_softc;
        !          1175:        bus_space_tag_t bst = sc->sc_bst;
        !          1176:        bus_space_handle_t bsh = sc->sc_bsh;
        !          1177:        bus_addr_t offset = sc->sc_offset;
        !          1178:        unsigned int s, len, pad = 0;
        !          1179:        struct mbuf *m0, *m;
        !          1180:        u_int16_t space;
        !          1181:
        !          1182:        DPRINTF(XID_CONFIG, ("xi_start()\n"));
        !          1183:
        !          1184:        /* Don't transmit if interface is busy or not running. */
        !          1185:        if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) {
        !          1186:                DPRINTF(XID_CONFIG, ("xi: interface busy or not running\n"));
        !          1187:                return;
        !          1188:        }
        !          1189:
        !          1190:        /* Peek at the next packet. */
        !          1191:        m0 = ifp->if_snd.ifq_head;
        !          1192:        if (m0 == 0)
        !          1193:                return;
        !          1194:
        !          1195:        /* We need to use m->m_pkthdr.len, so require the header. */
        !          1196:        if (!(m0->m_flags & M_PKTHDR))
        !          1197:                panic("xi_start: no header mbuf");
        !          1198:
        !          1199:        len = m0->m_pkthdr.len;
        !          1200:
        !          1201:        /* Pad to ETHER_MIN_LEN - ETHER_CRC_LEN. */
        !          1202:        if (len < ETHER_MIN_LEN - ETHER_CRC_LEN)
        !          1203:                pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;
        !          1204:
        !          1205:        PAGE(sc, 0);
        !          1206:        space = bus_space_read_2(bst, bsh, offset + TSO0) & 0x7fff;
        !          1207:        if (len + pad + 2 > space) {
        !          1208:                DPRINTF(XID_FIFO,
        !          1209:                    ("xi: not enough space in output FIFO (%d > %d)\n",
        !          1210:                    len + pad + 2, space));
        !          1211:                return;
        !          1212:        }
        !          1213:
        !          1214:        IF_DEQUEUE(&ifp->if_snd, m0);
        !          1215:
        !          1216: #if NBPFILTER > 0
        !          1217:        if (ifp->if_bpf)
        !          1218:                bpf_mtap(ifp->if_bpf, m0);
        !          1219: #endif
        !          1220:
        !          1221:        /*
        !          1222:         * Do the output at splhigh() so that an interrupt from another device
        !          1223:         * won't cause a FIFO underrun.
        !          1224:         */
        !          1225:        s = splhigh();
        !          1226:
        !          1227:        bus_space_write_2(bst, bsh, offset + TSO2, (u_int16_t)len + pad + 2);
        !          1228:        bus_space_write_2(bst, bsh, offset + EDP, (u_int16_t)len + pad);
        !          1229:        for (m = m0; m; ) {
        !          1230:                if (m->m_len > 1)
        !          1231:                        bus_space_write_multi_2(bst, bsh, offset + EDP,
        !          1232:                            mtod(m, u_int8_t *), m->m_len>>1);
        !          1233:                if (m->m_len & 1)
        !          1234:                        bus_space_write_1(bst, bsh, offset + EDP,
        !          1235:                            *(mtod(m, u_int8_t *) + m->m_len - 1));
        !          1236:                MFREE(m, m0);
        !          1237:                m = m0;
        !          1238:        }
        !          1239:        if (sc->sc_flags & XIFLAGS_MOHAWK)
        !          1240:                bus_space_write_1(bst, bsh, offset + CR, TX_PKT | ENABLE_INT);
        !          1241:        else {
        !          1242:                for (; pad > 1; pad -= 2)
        !          1243:                        bus_space_write_2(bst, bsh, offset + EDP, 0);
        !          1244:                if (pad == 1)
        !          1245:                        bus_space_write_1(bst, bsh, offset + EDP, 0);
        !          1246:        }
        !          1247:
        !          1248:        splx(s);
        !          1249:
        !          1250:        ifp->if_timer = 5;
        !          1251:        ++ifp->if_opackets;
        !          1252: }
        !          1253:
        !          1254: static int
        !          1255: xi_ether_ioctl(ifp, cmd, data)
        !          1256:        struct ifnet *ifp;
        !          1257:        u_long cmd;
        !          1258:        caddr_t data;
        !          1259: {
        !          1260:        struct ifaddr *ifa = (struct ifaddr *)data;
        !          1261:        struct xi_softc *sc = ifp->if_softc;
        !          1262:
        !          1263:
        !          1264:        DPRINTF(XID_CONFIG, ("xi_ether_ioctl()\n"));
        !          1265:
        !          1266:        switch (cmd) {
        !          1267:        case SIOCSIFADDR:
        !          1268:                ifp->if_flags |= IFF_UP;
        !          1269:
        !          1270:                switch (ifa->ifa_addr->sa_family) {
        !          1271: #ifdef INET
        !          1272:                case AF_INET:
        !          1273:                        xi_init(sc);
        !          1274:                        arp_ifinit(ifp, ifa);
        !          1275:                        break;
        !          1276: #endif /* INET */
        !          1277:
        !          1278: #ifdef NS
        !          1279:                case AF_NS:
        !          1280:                {
        !          1281:                        struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
        !          1282:
        !          1283:                        if (ns_nullhost(*ina))
        !          1284:                                ina->x_host = *(union ns_host *)
        !          1285:                                        LLADDR(ifp->if_sadl);
        !          1286:                        else
        !          1287:                                bcopy(ina->x_host.c_host,
        !          1288:                                        LLADDR(ifp->if_sadl),
        !          1289:                                        ifp->if_addrlen);
        !          1290:                        /* Set new address. */
        !          1291:                        xi_init(sc);
        !          1292:                        break;
        !          1293:                }
        !          1294: #endif  /* NS */
        !          1295:
        !          1296:                default:
        !          1297:                        xi_init(sc);
        !          1298:                        break;
        !          1299:                }
        !          1300:                break;
        !          1301:
        !          1302:        default:
        !          1303:                return (EINVAL);
        !          1304:        }
        !          1305:
        !          1306:        return (0);
        !          1307: }
        !          1308:
        !          1309: static int
        !          1310: xi_ioctl(ifp, command, data)
        !          1311:        struct ifnet *ifp;
        !          1312:        u_long command;
        !          1313:        caddr_t data;
        !          1314: {
        !          1315:        struct xi_softc *sc = ifp->if_softc;
        !          1316:        struct ifreq *ifr = (struct ifreq *)data;
        !          1317:        int s, error = 0;
        !          1318:
        !          1319:        DPRINTF(XID_CONFIG, ("xi_ioctl()\n"));
        !          1320:
        !          1321:        s = splimp();
        !          1322:
        !          1323:        switch (command) {
        !          1324:        case SIOCSIFADDR:
        !          1325:                error = xi_ether_ioctl(ifp, command, data);
        !          1326:                break;
        !          1327:
        !          1328:        case SIOCSIFFLAGS:
        !          1329:                sc->sc_all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
        !          1330:
        !          1331:                PAGE(sc, 0x42);
        !          1332:                if ((ifp->if_flags & IFF_PROMISC) ||
        !          1333:                    (ifp->if_flags & IFF_ALLMULTI))
        !          1334:                        bus_space_write_1(sc->sc_bst, sc->sc_bsh,
        !          1335:                            sc->sc_offset + SWC1,
        !          1336:                            SWC1_PROMISC | SWC1_MCAST_PROM);
        !          1337:                else
        !          1338:                        bus_space_write_1(sc->sc_bst, sc->sc_bsh,
        !          1339:                            sc->sc_offset + SWC1, 0);
        !          1340:
        !          1341:                /*
        !          1342:                 * If interface is marked up and not running, then start it.
        !          1343:                 * If it is marked down and running, stop it.
        !          1344:                 * XXX If it's up then re-initialize it. This is so flags
        !          1345:                 * such as IFF_PROMISC are handled.
        !          1346:                 */
        !          1347:                if (ifp->if_flags & IFF_UP) {
        !          1348:                        xi_init(sc);
        !          1349:                } else {
        !          1350:                        if (ifp->if_flags & IFF_RUNNING) {
        !          1351:                                xi_stop(sc);
        !          1352:                                ifp->if_flags &= ~IFF_RUNNING;
        !          1353:                        }
        !          1354:                }
        !          1355:                break;
        !          1356:
        !          1357:        case SIOCADDMULTI:
        !          1358:        case SIOCDELMULTI:
        !          1359:                sc->sc_all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
        !          1360:                error = (command == SIOCADDMULTI) ?
        !          1361:                    ether_addmulti(ifr, &sc->sc_ethercom) :
        !          1362:                    ether_delmulti(ifr, &sc->sc_ethercom);
        !          1363:
        !          1364:                if (error == ENETRESET) {
        !          1365:                        /*
        !          1366:                         * Multicast list has changed; set the hardware
        !          1367:                         * filter accordingly.
        !          1368:                         */
        !          1369:                        if (!sc->sc_all_mcasts &&
        !          1370:                            !(ifp->if_flags & IFF_PROMISC))
        !          1371:                                xi_set_address(sc);
        !          1372:
        !          1373:                        /*
        !          1374:                         * xi_set_address() can turn on all_mcasts if we run
        !          1375:                         * out of space, so check it again rather than else {}.
        !          1376:                         */
        !          1377:                        if (sc->sc_all_mcasts)
        !          1378:                                xi_init(sc);
        !          1379:                        error = 0;
        !          1380:                }
        !          1381:                break;
        !          1382:
        !          1383:        case SIOCSIFMEDIA:
        !          1384:        case SIOCGIFMEDIA:
        !          1385:                error =
        !          1386:                    ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command);
        !          1387:                break;
        !          1388:
        !          1389:        default:
        !          1390:                error = EINVAL;
        !          1391:        }
        !          1392:        splx(s);
        !          1393:        return (error);
        !          1394: }
        !          1395:
        !          1396: static void
        !          1397: xi_set_address(sc)
        !          1398:        struct xi_softc *sc;
        !          1399: {
        !          1400:        bus_space_tag_t bst = sc->sc_bst;
        !          1401:        bus_space_handle_t bsh = sc->sc_bsh;
        !          1402:        bus_addr_t offset = sc->sc_offset;
        !          1403:        struct ethercom *ether = &sc->sc_ethercom;
        !          1404:        struct ether_multi *enm;
        !          1405:        struct ether_multistep step;
        !          1406:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
        !          1407:        int i, page, pos, num;
        !          1408:
        !          1409:        DPRINTF(XID_CONFIG, ("xi_set_address()\n"));
        !          1410:
        !          1411:        PAGE(sc, 0x50);
        !          1412:        for (i = 0; i < 6; i++) {
        !          1413:                bus_space_write_1(bst, bsh, offset + IA + i,
        !          1414:                    sc->sc_enaddr[(sc->sc_flags & XIFLAGS_MOHAWK) ?  5-i : i]);
        !          1415:        }
        !          1416:
        !          1417:        if (ether->ec_multicnt > 0) {
        !          1418:                if (ether->ec_multicnt > 9) {
        !          1419:                        PAGE(sc, 0x42);
        !          1420:                        bus_space_write_1(sc->sc_bst, sc->sc_bsh,
        !          1421:                            sc->sc_offset + SWC1,
        !          1422:                            SWC1_PROMISC | SWC1_MCAST_PROM);
        !          1423:                        return;
        !          1424:                }
        !          1425:
        !          1426:                ETHER_FIRST_MULTI(step, ether, enm);
        !          1427:
        !          1428:                pos = IA + 6;
        !          1429:                for (page = 0x50, num = ether->ec_multicnt; num > 0 && enm;
        !          1430:                    num--) {
        !          1431:                        if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
        !          1432:                            sizeof(enm->enm_addrlo)) != 0) {
        !          1433:                                /*
        !          1434:                                 * The multicast address is really a range;
        !          1435:                                 * it's easier just to accept all multicasts.
        !          1436:                                 * XXX should we be setting IFF_ALLMULTI here?
        !          1437:                                 */
        !          1438:                                ifp->if_flags |= IFF_ALLMULTI;
        !          1439:                                sc->sc_all_mcasts=1;
        !          1440:                                break;
        !          1441:                        }
        !          1442:
        !          1443:                        for (i = 0; i < 6; i++) {
        !          1444:                                bus_space_write_1(bst, bsh, offset + pos,
        !          1445:                                    enm->enm_addrlo[
        !          1446:                                    (sc->sc_flags & XIFLAGS_MOHAWK) ? 5-i : i]);
        !          1447:
        !          1448:                                if (++pos > 15) {
        !          1449:                                        pos = IA;
        !          1450:                                        page++;
        !          1451:                                        PAGE(sc, page);
        !          1452:                                }
        !          1453:                        }
        !          1454:                }
        !          1455:        }
        !          1456: }
        !          1457:
        !          1458: static void
        !          1459: xi_cycle_power(sc)
        !          1460:        struct xi_softc *sc;
        !          1461: {
        !          1462:        bus_space_tag_t bst = sc->sc_bst;
        !          1463:        bus_space_handle_t bsh = sc->sc_bsh;
        !          1464:        bus_addr_t offset = sc->sc_offset;
        !          1465:
        !          1466:        DPRINTF(XID_CONFIG, ("xi_cycle_power()\n"));
        !          1467:
        !          1468:        PAGE(sc, 4);
        !          1469:        DELAY(1);
        !          1470:        bus_space_write_1(bst, bsh, offset + GP1, 0);
        !          1471:        DELAY(40000);
        !          1472:        if (sc->sc_flags & XIFLAGS_MOHAWK)
        !          1473:                bus_space_write_1(bst, bsh, offset + GP1, POWER_UP);
        !          1474:        else
        !          1475:                /* XXX What is bit 2 (aka AIC)? */
        !          1476:                bus_space_write_1(bst, bsh, offset + GP1, POWER_UP | 4);
        !          1477:        DELAY(20000);
        !          1478: }
        !          1479:
        !          1480: static void
        !          1481: xi_full_reset(sc)
        !          1482:        struct xi_softc *sc;
        !          1483: {
        !          1484:        bus_space_tag_t bst = sc->sc_bst;
        !          1485:        bus_space_handle_t bsh = sc->sc_bsh;
        !          1486:        bus_addr_t offset = sc->sc_offset;
        !          1487:
        !          1488:        DPRINTF(XID_CONFIG, ("xi_full_reset()\n"));
        !          1489:
        !          1490:        /* Do an as extensive reset as possible on all functions. */
        !          1491:        xi_cycle_power(sc);
        !          1492:        bus_space_write_1(bst, bsh, offset + CR, SOFT_RESET);
        !          1493:        DELAY(20000);
        !          1494:        bus_space_write_1(bst, bsh, offset + CR, 0);
        !          1495:        DELAY(20000);
        !          1496:        if (sc->sc_flags & XIFLAGS_MOHAWK) {
        !          1497:                PAGE(sc, 4);
        !          1498:                /*
        !          1499:                 * Drive GP1 low to power up ML6692 and GP2 high to power up
        !          1500:                 * the 10Mhz chip.  XXX What chip is that?  The phy?
        !          1501:                 */
        !          1502:                bus_space_write_1(bst, bsh, offset + GP0,
        !          1503:                    GP1_OUT | GP2_OUT | GP2_WR);
        !          1504:        }
        !          1505:        DELAY(500000);
        !          1506:
        !          1507:        /* Get revision information.  XXX Symbolic constants. */
        !          1508:        sc->sc_rev = bus_space_read_1(bst, bsh, offset + BV) &
        !          1509:            ((sc->sc_flags & XIFLAGS_MOHAWK) ? 0x70 : 0x30) >> 4;
        !          1510:
        !          1511:        /* Media selection.  XXX Maybe manual overriding too? */
        !          1512:        if (!(sc->sc_flags & XIFLAGS_MOHAWK)) {
        !          1513:                PAGE(sc, 4);
        !          1514:                /*
        !          1515:                 * XXX I have no idea what this really does, it is from the
        !          1516:                 * Linux driver.
        !          1517:                 */
        !          1518:                bus_space_write_1(bst, bsh, offset + GP0, GP1_OUT);
        !          1519:        }
        !          1520:        DELAY(40000);
        !          1521:
        !          1522:        /* Setup the ethernet interrupt mask. */
        !          1523:        PAGE(sc, 1);
        !          1524:        bus_space_write_1(bst, bsh, offset + IMR0,
        !          1525:            ISR_TX_OFLOW | ISR_PKT_TX | ISR_MAC_INT | /* ISR_RX_EARLY | */
        !          1526:            ISR_RX_FULL | ISR_RX_PKT_REJ | ISR_FORCED_INT);
        !          1527: #if 0
        !          1528:        bus_space_write_1(bst, bsh, offset + IMR0, 0xff);
        !          1529: #endif
        !          1530:        if (!(sc->sc_flags & XIFLAGS_DINGO)) {
        !          1531:                /* XXX What is this?  Not for Dingo at least. */
        !          1532:                bus_space_write_1(bst, bsh, offset + IMR1, 1);
        !          1533:        }
        !          1534:
        !          1535:        /*
        !          1536:         * Disable source insertion.
        !          1537:         * XXX Dingo does not have this bit, but Linux does it unconditionally.
        !          1538:         */
        !          1539:        if (!(sc->sc_flags & XIFLAGS_DINGO)) {
        !          1540:                PAGE(sc, 0x42);
        !          1541:                bus_space_write_1(bst, bsh, offset + SWC0, 0x20);
        !          1542:        }
        !          1543:
        !          1544:        /* Set the local memory dividing line. */
        !          1545:        if (sc->sc_rev != 1) {
        !          1546:                PAGE(sc, 2);
        !          1547:                /* XXX Symbolic constant preferrable. */
        !          1548:                bus_space_write_2(bst, bsh, offset + RBS0, 0x2000);
        !          1549:        }
        !          1550:
        !          1551:        xi_set_address(sc);
        !          1552:
        !          1553:        /*
        !          1554:         * Apparently the receive byte pointer can be bad after a reset, so
        !          1555:         * we hardwire it correctly.
        !          1556:         */
        !          1557:        PAGE(sc, 0);
        !          1558:        bus_space_write_2(bst, bsh, offset + DO0, DO_CHG_OFFSET);
        !          1559:
        !          1560:        /* Setup ethernet MAC registers. XXX Symbolic constants. */
        !          1561:        PAGE(sc, 0x40);
        !          1562:        bus_space_write_1(bst, bsh, offset + RX0MSK,
        !          1563:            PKT_TOO_LONG | CRC_ERR | RX_OVERRUN | RX_ABORT | RX_OK);
        !          1564:        bus_space_write_1(bst, bsh, offset + TX0MSK,
        !          1565:            CARRIER_LOST | EXCESSIVE_COLL | TX_UNDERRUN | LATE_COLLISION |
        !          1566:            SQE | TX_ABORT | TX_OK);
        !          1567:        if (!(sc->sc_flags & XIFLAGS_DINGO))
        !          1568:                /* XXX From Linux, dunno what 0xb0 means. */
        !          1569:                bus_space_write_1(bst, bsh, offset + TX1MSK, 0xb0);
        !          1570:        bus_space_write_1(bst, bsh, offset + RXST0, 0);
        !          1571:        bus_space_write_1(bst, bsh, offset + TXST0, 0);
        !          1572:        bus_space_write_1(bst, bsh, offset + TXST1, 0);
        !          1573:
        !          1574:        /* Enable MII function if available. */
        !          1575:        if (LIST_FIRST(&sc->sc_mii.mii_phys)) {
        !          1576:                PAGE(sc, 2);
        !          1577:                bus_space_write_1(bst, bsh, offset + MSR,
        !          1578:                    bus_space_read_1(bst, bsh, offset + MSR) | SELECT_MII);
        !          1579:                DELAY(20000);
        !          1580:        } else {
        !          1581:                PAGE(sc, 0);
        !          1582:
        !          1583:                /* XXX Do we need to do this? */
        !          1584:                PAGE(sc, 0x42);
        !          1585:                bus_space_write_1(bst, bsh, offset + SWC1, SWC1_AUTO_MEDIA);
        !          1586:                DELAY(50000);
        !          1587:
        !          1588:                /* XXX Linux probes the media here. */
        !          1589:        }
        !          1590:
        !          1591:        /* Configure the LED registers. */
        !          1592:        PAGE(sc, 2);
        !          1593:
        !          1594:        /* XXX This is not good for 10base2. */
        !          1595:        bus_space_write_1(bst, bsh, offset + LED,
        !          1596:            LED_TX_ACT << LED1_SHIFT | LED_10MB_LINK << LED0_SHIFT);
        !          1597:        if (sc->sc_flags & XIFLAGS_DINGO)
        !          1598:                bus_space_write_1(bst, bsh, offset + LED3,
        !          1599:                    LED_100MB_LINK << LED3_SHIFT);
        !          1600:
        !          1601:        /* Enable receiver and go online. */
        !          1602:        PAGE(sc, 0x40);
        !          1603:        bus_space_write_1(bst, bsh, offset + CMD0, ENABLE_RX | ONLINE);
        !          1604:
        !          1605: #if 0
        !          1606:        /* XXX Linux does this here - is it necessary? */
        !          1607:        PAGE(sc, 1);
        !          1608:        bus_space_write_1(bst, bsh, offset + IMR0, 0xff);
        !          1609:        if (!(sc->sc_flags & XIFLAGS_DINGO)) {
        !          1610:                /* XXX What is this?  Not for Dingo at least. */
        !          1611:                bus_space_write_1(bst, bsh, offset + IMR1, 1);
        !          1612:        }
        !          1613: #endif
        !          1614:
        !          1615:        /* Enable interrupts. */
        !          1616:        PAGE(sc, 0);
        !          1617:        bus_space_write_1(bst, bsh, offset + CR, ENABLE_INT);
        !          1618:
        !          1619:        /* XXX This is pure magic for me, found in the Linux driver. */
        !          1620:        if ((sc->sc_flags & (XIFLAGS_DINGO | XIFLAGS_MODEM)) == XIFLAGS_MODEM) {
        !          1621:                if ((bus_space_read_1(bst, bsh, offset + 0x10) & 0x01) == 0)
        !          1622:                        /* Unmask the master interrupt bit. */
        !          1623:                        bus_space_write_1(bst, bsh, offset + 0x10, 0x11);
        !          1624:        }
        !          1625:
        !          1626:        /*
        !          1627:         * The Linux driver says this:
        !          1628:         * We should switch back to page 0 to avoid a bug in revision 0
        !          1629:         * where regs with offset below 8 can't be read after an access
        !          1630:         * to the MAC registers.
        !          1631:         */
        !          1632:        PAGE(sc, 0);
        !          1633: }

CVSweb <webmaster@jp.NetBSD.org>