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

Annotation of sys/dev/ic/lemac.c, Revision 1.1

1.1     ! nbrk        1: /* $OpenBSD: lemac.c,v 1.10 2006/04/16 16:32:08 miod Exp $ */
        !             2: /* $NetBSD: lemac.c,v 1.20 2001/06/13 10:46:02 wiz Exp $ */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 1994, 1995, 1997 Matt Thomas <matt@3am-software.com>
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. The name of the author may not be used to endorse or promote products
        !            14:  *    derived from this software without specific prior written permission
        !            15:  *
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            19:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            20:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            21:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            22:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            23:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            24:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            25:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            26:  */
        !            27:
        !            28: /*
        !            29:  * DEC EtherWORKS 3 Ethernet Controllers
        !            30:  *
        !            31:  * Written by Matt Thomas
        !            32:  * BPF support code stolen directly from if_ec.c
        !            33:  *
        !            34:  *   This driver supports the LEMAC DE203/204/205 cards.
        !            35:  */
        !            36:
        !            37: #include <sys/param.h>
        !            38: #include <sys/systm.h>
        !            39: #include <sys/mbuf.h>
        !            40: #include <sys/protosw.h>
        !            41: #include <sys/socket.h>
        !            42: #include <sys/sockio.h>
        !            43: #include <sys/errno.h>
        !            44: #include <sys/malloc.h>
        !            45: #include <sys/device.h>
        !            46:
        !            47: #include <net/if.h>
        !            48: #include <net/if_types.h>
        !            49: #include <net/if_dl.h>
        !            50: #include <net/route.h>
        !            51: #include <net/if_media.h>
        !            52:
        !            53: #ifdef INET
        !            54: #include <netinet/in.h>
        !            55: #include <netinet/in_systm.h>
        !            56: #include <netinet/in_var.h>
        !            57: #include <netinet/ip.h>
        !            58: #include <netinet/if_ether.h>
        !            59: #endif
        !            60:
        !            61: #include <machine/bus.h>
        !            62:
        !            63: #include <dev/ic/lemacreg.h>
        !            64: #include <dev/ic/lemacvar.h>
        !            65:
        !            66: #if 0
        !            67: #include <uvm/uvm_extern.h>
        !            68: #endif
        !            69:
        !            70: #include "bpfilter.h"
        !            71: #if NBPFILTER > 0
        !            72: #include <net/bpf.h>
        !            73: #endif
        !            74:
        !            75: int    lemac_ifioctl(struct ifnet *, u_long, caddr_t);
        !            76: int    lemac_ifmedia_change(struct ifnet *const);
        !            77: void   lemac_ifmedia_status(struct ifnet *const, struct ifmediareq *);
        !            78: void   lemac_ifstart(struct ifnet *);
        !            79: void   lemac_init(struct lemac_softc *);
        !            80: void   lemac_init_adapmem(struct lemac_softc *);
        !            81: void   lemac_input(struct lemac_softc *, bus_size_t, size_t);
        !            82: void   lemac_multicast_filter(struct lemac_softc *);
        !            83: void   lemac_multicast_op(u_int16_t *, const u_char *, int);
        !            84: int    lemac_read_eeprom(struct lemac_softc *);
        !            85: int    lemac_read_macaddr(unsigned char *, const bus_space_tag_t,
        !            86:     const bus_space_handle_t, const bus_size_t, int);
        !            87: void   lemac_reset(struct lemac_softc *);
        !            88: void   lemac_rne_intr(struct lemac_softc *);
        !            89: void   lemac_rxd_intr(struct lemac_softc *, unsigned);
        !            90: void   lemac_tne_intr(struct lemac_softc *);
        !            91: void   lemac_txd_intr(struct lemac_softc *, unsigned);
        !            92:
        !            93: struct cfdriver lc_cd = {
        !            94:        NULL, "lc", DV_IFNET
        !            95: };
        !            96:
        !            97: static const u_int16_t lemac_allmulti_mctbl[LEMAC_MCTBL_SIZE/sizeof(u_int16_t)] = {
        !            98:        0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
        !            99:        0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
        !           100:        0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
        !           101:        0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
        !           102:        0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
        !           103:        0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
        !           104:        0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
        !           105:        0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
        !           106: };
        !           107:
        !           108: /*
        !           109:  * Some tuning/monitoring variables.
        !           110:  */
        !           111: unsigned lemac_txmax = 16;
        !           112:
        !           113: void
        !           114: lemac_rxd_intr(struct lemac_softc *sc, unsigned cs_value)
        !           115: {
        !           116:        /*
        !           117:         * Handle CS_RXD (Receiver disabled) here.
        !           118:         *
        !           119:         * Check Free Memory Queue Count. If not equal to zero
        !           120:         * then just turn Receiver back on. If it is equal to
        !           121:         * zero then check to see if transmitter is disabled.
        !           122:         * Process transmit TXD loop once more.  If all else
        !           123:         * fails then do software init (0xC0 to EEPROM Init)
        !           124:         * and rebuild Free Memory Queue.
        !           125:         */
        !           126:
        !           127:        sc->sc_cntrs.cntr_rxd_intrs++;
        !           128:
        !           129:        /*
        !           130:         *  Re-enable Receiver.
        !           131:         */
        !           132:
        !           133:        cs_value &= ~LEMAC_CS_RXD;
        !           134:        LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value);
        !           135:
        !           136:        if (LEMAC_INB(sc, LEMAC_REG_FMC) > 0)
        !           137:                return;
        !           138:
        !           139:        if (cs_value & LEMAC_CS_TXD)
        !           140:                lemac_txd_intr(sc, cs_value);
        !           141:
        !           142:        if ((LEMAC_INB(sc, LEMAC_REG_CS) & LEMAC_CS_RXD) == 0)
        !           143:                return;
        !           144:
        !           145:        printf("%s: fatal RXD error, attempting recovery\n",
        !           146:            sc->sc_if.if_xname);
        !           147:
        !           148:        lemac_reset(sc);
        !           149:        if (sc->sc_if.if_flags & IFF_UP) {
        !           150:                lemac_init(sc);
        !           151:                return;
        !           152:        }
        !           153:
        !           154:        /*
        !           155:         *  Error during initialization.  Mark card as disabled.
        !           156:         */
        !           157:        printf("%s: recovery failed -- board disabled\n", sc->sc_if.if_xname);
        !           158: }
        !           159:
        !           160: void
        !           161: lemac_tne_intr(struct lemac_softc *sc)
        !           162: {
        !           163:        unsigned txcount = LEMAC_INB(sc, LEMAC_REG_TDC);
        !           164:
        !           165:        sc->sc_cntrs.cntr_tne_intrs++;
        !           166:        while (txcount-- > 0) {
        !           167:                unsigned txsts = LEMAC_INB(sc, LEMAC_REG_TDQ);
        !           168:                sc->sc_if.if_opackets++;                /* another one done */
        !           169:                if ((txsts & (LEMAC_TDQ_LCL|LEMAC_TDQ_NCL))
        !           170:                    || (txsts & LEMAC_TDQ_COL) == LEMAC_TDQ_EXCCOL) {
        !           171:                        if (txsts & LEMAC_TDQ_NCL)
        !           172:                                sc->sc_flags &= ~LEMAC_LINKUP;
        !           173:                        sc->sc_if.if_oerrors++;
        !           174:                } else {
        !           175:                        sc->sc_flags |= LEMAC_LINKUP;
        !           176:                        if ((txsts & LEMAC_TDQ_COL) != LEMAC_TDQ_NOCOL)
        !           177:                                sc->sc_if.if_collisions++;
        !           178:                }
        !           179:        }
        !           180:        sc->sc_if.if_flags &= ~IFF_OACTIVE;
        !           181:        lemac_ifstart(&sc->sc_if);
        !           182: }
        !           183:
        !           184: void
        !           185: lemac_txd_intr(struct lemac_softc *sc, unsigned cs_value)
        !           186: {
        !           187:        /*
        !           188:         * Read transmit status, remove transmit buffer from
        !           189:         * transmit queue and place on free memory queue,
        !           190:         * then reset transmitter.
        !           191:         * Increment appropriate counters.
        !           192:         */
        !           193:
        !           194:        sc->sc_cntrs.cntr_txd_intrs++;
        !           195:        if (sc->sc_txctl & LEMAC_TX_STP) {
        !           196:                sc->sc_if.if_oerrors++;
        !           197:                /* return page to free queue */
        !           198:                LEMAC_OUTB(sc, LEMAC_REG_FMQ, LEMAC_INB(sc, LEMAC_REG_TDQ));
        !           199:        }
        !           200:
        !           201:        /* Turn back on transmitter if disabled */
        !           202:        LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value & ~LEMAC_CS_TXD);
        !           203:        sc->sc_if.if_flags &= ~IFF_OACTIVE;
        !           204: }
        !           205:
        !           206: int
        !           207: lemac_read_eeprom(struct lemac_softc *sc)
        !           208: {
        !           209:        int     word_off, cksum;
        !           210:
        !           211:        u_char *ep;
        !           212:
        !           213:        cksum = 0;
        !           214:        ep = sc->sc_eeprom;
        !           215:        for (word_off = 0; word_off < LEMAC_EEP_SIZE / 2; word_off++) {
        !           216:                LEMAC_OUTB(sc, LEMAC_REG_PI1, word_off);
        !           217:                LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEREAD);
        !           218:
        !           219:                DELAY(LEMAC_EEP_DELAY);
        !           220:
        !           221:                *ep = LEMAC_INB(sc, LEMAC_REG_EE1);
        !           222:                cksum += *ep++;
        !           223:                *ep = LEMAC_INB(sc, LEMAC_REG_EE2);
        !           224:                cksum += *ep++;
        !           225:        }
        !           226:
        !           227:        /*
        !           228:         *  Set up Transmit Control Byte for use later during transmit.
        !           229:         */
        !           230:
        !           231:        sc->sc_txctl |= LEMAC_TX_FLAGS;
        !           232:
        !           233:        if ((sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_SQE) == 0)
        !           234:                sc->sc_txctl &= ~LEMAC_TX_SQE;
        !           235:
        !           236:        if (sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_LAB)
        !           237:                sc->sc_txctl |= LEMAC_TX_LAB;
        !           238:
        !           239:        bcopy(&sc->sc_eeprom[LEMAC_EEP_PRDNM], sc->sc_prodname,
        !           240:            LEMAC_EEP_PRDNMSZ);
        !           241:        sc->sc_prodname[LEMAC_EEP_PRDNMSZ] = '\0';
        !           242:
        !           243:        return (cksum % 256);
        !           244: }
        !           245:
        !           246: void
        !           247: lemac_init_adapmem(struct lemac_softc *sc)
        !           248: {
        !           249:        int pg, conf;
        !           250:
        !           251:        conf = LEMAC_INB(sc, LEMAC_REG_CNF);
        !           252:
        !           253:        if ((sc->sc_eeprom[LEMAC_EEP_SETUP] & LEMAC_EEP_ST_DRAM) == 0) {
        !           254:                sc->sc_lastpage = 63;
        !           255:                conf &= ~LEMAC_CNF_DRAM;
        !           256:        } else {
        !           257:                sc->sc_lastpage = 127;
        !           258:                conf |= LEMAC_CNF_DRAM;
        !           259:        }
        !           260:
        !           261:        LEMAC_OUTB(sc, LEMAC_REG_CNF, conf);
        !           262:
        !           263:        for (pg = 1; pg <= sc->sc_lastpage; pg++)
        !           264:                LEMAC_OUTB(sc, LEMAC_REG_FMQ, pg);
        !           265: }
        !           266:
        !           267: void
        !           268: lemac_input(struct lemac_softc *sc, bus_size_t offset, size_t length)
        !           269: {
        !           270:        struct ether_header eh;
        !           271:        struct mbuf *m;
        !           272:
        !           273:        if (length - sizeof(eh) > ETHERMTU ||
        !           274:            length - sizeof(eh) < ETHERMIN) {
        !           275:                sc->sc_if.if_ierrors++;
        !           276:                return;
        !           277:        }
        !           278:        if (LEMAC_USE_PIO_MODE(sc)) {
        !           279:                LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(eh), (void *)&eh);
        !           280:        } else {
        !           281:                LEMAC_GETBUF16(sc, offset, sizeof(eh) / 2, (void *)&eh);
        !           282:        }
        !           283:
        !           284:        MGETHDR(m, M_DONTWAIT, MT_DATA);
        !           285:        if (m == NULL) {
        !           286:                sc->sc_if.if_ierrors++;
        !           287:                return;
        !           288:        }
        !           289:        if (length + 2 > MHLEN) {
        !           290:                MCLGET(m, M_DONTWAIT);
        !           291:                if ((m->m_flags & M_EXT) == 0) {
        !           292:                        m_free(m);
        !           293:                        sc->sc_if.if_ierrors++;
        !           294:                        return;
        !           295:                }
        !           296:        }
        !           297:        m->m_data += 2;
        !           298:        bcopy((caddr_t)&eh, m->m_data, sizeof(eh));
        !           299:        if (LEMAC_USE_PIO_MODE(sc)) {
        !           300:                LEMAC_INSB(sc, LEMAC_REG_DAT, length - sizeof(eh),
        !           301:                    mtod(m, caddr_t) + sizeof(eh));
        !           302:        } else {
        !           303:                LEMAC_GETBUF16(sc, offset + sizeof(eh),
        !           304:                    (length - sizeof(eh)) / 2,
        !           305:                    (void *)(mtod(m, caddr_t) + sizeof(eh)));
        !           306:                if (length & 1)
        !           307:                        m->m_data[length - 1] = LEMAC_GET8(sc,
        !           308:                            offset + length - 1);
        !           309:        }
        !           310: #if NBPFILTER > 0
        !           311:        if (sc->sc_if.if_bpf != NULL) {
        !           312:                m->m_pkthdr.len = m->m_len = length;
        !           313:                bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_IN);
        !           314:        }
        !           315:
        !           316:        /*
        !           317:         * If this is single cast but not to us
        !           318:         * drop it!
        !           319:         */
        !           320:        if ((eh.ether_dhost[0] & 1) == 0 &&
        !           321:            !LEMAC_ADDREQUAL(eh.ether_dhost, sc->sc_arpcom.ac_enaddr)) {
        !           322:                m_freem(m);
        !           323:                return;
        !           324:        }
        !           325: #endif
        !           326:        m->m_pkthdr.len = m->m_len = length;
        !           327:        m->m_pkthdr.rcvif = &sc->sc_if;
        !           328:        ether_input_mbuf(&sc->sc_if, m);
        !           329: }
        !           330:
        !           331: void
        !           332: lemac_rne_intr(struct lemac_softc *sc)
        !           333: {
        !           334:        int rxcount;
        !           335:
        !           336:        sc->sc_cntrs.cntr_rne_intrs++;
        !           337:        rxcount = LEMAC_INB(sc, LEMAC_REG_RQC);
        !           338:        while (rxcount--) {
        !           339:                unsigned rxpg = LEMAC_INB(sc, LEMAC_REG_RQ);
        !           340:                u_int32_t rxlen;
        !           341:
        !           342:                sc->sc_if.if_ipackets++;
        !           343:                if (LEMAC_USE_PIO_MODE(sc)) {
        !           344:                        LEMAC_OUTB(sc, LEMAC_REG_IOP, rxpg);
        !           345:                        LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
        !           346:                        LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
        !           347:                        LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(rxlen),
        !           348:                            (void *)&rxlen);
        !           349:                } else {
        !           350:                        LEMAC_OUTB(sc, LEMAC_REG_MPN, rxpg);
        !           351:                        rxlen = LEMAC_GET32(sc, 0);
        !           352:                }
        !           353:                if (rxlen & LEMAC_RX_OK) {
        !           354:                        sc->sc_flags |= LEMAC_LINKUP;
        !           355:                        /*
        !           356:                         * Get receive length - subtract out checksum.
        !           357:                         */
        !           358:                        rxlen = ((rxlen >> 8) & 0x7FF) - 4;
        !           359:                        lemac_input(sc, sizeof(rxlen), rxlen);
        !           360:                } else {
        !           361:                        sc->sc_if.if_ierrors++;
        !           362:                }
        !           363:                /* Return this page to Free Memory Queue */
        !           364:                LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg);
        !           365:        }  /* end while (recv_count--) */
        !           366:
        !           367:        return;
        !           368: }
        !           369:
        !           370: /*
        !           371:  *  This is the standard method of reading the DEC Address ROMS.
        !           372:  *  I don't understand it but it does work.
        !           373:  */
        !           374: int
        !           375: lemac_read_macaddr(unsigned char *hwaddr, const bus_space_tag_t iot,
        !           376:     const bus_space_handle_t ioh, const bus_size_t ioreg, int skippat)
        !           377: {
        !           378:        int cksum, rom_cksum;
        !           379:        unsigned char addrbuf[6];
        !           380:
        !           381:        if (!skippat) {
        !           382:                int idx, idx2, found, octet;
        !           383:                static u_char testpat[] = {
        !           384:                        0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA
        !           385:                };
        !           386:                idx2 = found = 0;
        !           387:
        !           388:                for (idx = 0; idx < 32; idx++) {
        !           389:                        octet = bus_space_read_1(iot, ioh, ioreg);
        !           390:
        !           391:                        if (octet == testpat[idx2]) {
        !           392:                                if (++idx2 == sizeof(testpat)) {
        !           393:                                        ++found;
        !           394:                                        break;
        !           395:                                }
        !           396:                        } else {
        !           397:                                idx2 = 0;
        !           398:                        }
        !           399:                }
        !           400:
        !           401:                if (!found)
        !           402:                        return (-1);
        !           403:        }
        !           404:
        !           405:        if (hwaddr == NULL)
        !           406:                hwaddr = addrbuf;
        !           407:
        !           408:        cksum = 0;
        !           409:        hwaddr[0] = bus_space_read_1(iot, ioh, ioreg);
        !           410:        hwaddr[1] = bus_space_read_1(iot, ioh, ioreg);
        !           411:
        !           412:        /* hardware address can't be multicast */
        !           413:        if (hwaddr[0] & 1)
        !           414:                return (-1);
        !           415:
        !           416: #if BYTE_ORDER == LITTLE_ENDIAN
        !           417:        cksum = *(u_short *)&hwaddr[0];
        !           418: #else
        !           419:        cksum = ((u_short)hwaddr[1] << 8) | (u_short)hwaddr[0];
        !           420: #endif
        !           421:
        !           422:        hwaddr[2] = bus_space_read_1(iot, ioh, ioreg);
        !           423:        hwaddr[3] = bus_space_read_1(iot, ioh, ioreg);
        !           424:        cksum *= 2;
        !           425:        if (cksum > 65535)
        !           426:                cksum -= 65535;
        !           427: #if BYTE_ORDER == LITTLE_ENDIAN
        !           428:        cksum += *(u_short *)&hwaddr[2];
        !           429: #else
        !           430:        cksum += ((u_short)hwaddr[3] << 8) | (u_short)hwaddr[2];
        !           431: #endif
        !           432:        if (cksum > 65535)
        !           433:                cksum -= 65535;
        !           434:
        !           435:        hwaddr[4] = bus_space_read_1(iot, ioh, ioreg);
        !           436:        hwaddr[5] = bus_space_read_1(iot, ioh, ioreg);
        !           437:        cksum *= 2;
        !           438:        if (cksum > 65535)
        !           439:                cksum -= 65535;
        !           440: #if BYTE_ORDER == LITTLE_ENDIAN
        !           441:        cksum += *(u_short *)&hwaddr[4];
        !           442: #else
        !           443:        cksum += ((u_short)hwaddr[5] << 8) | (u_short)hwaddr[4];
        !           444: #endif
        !           445:        if (cksum >= 65535)
        !           446:                cksum -= 65535;
        !           447:
        !           448:        /* 00-00-00 is an illegal OUI */
        !           449:        if (hwaddr[0] == 0 && hwaddr[1] == 0 && hwaddr[2] == 0)
        !           450:                return (-1);
        !           451:
        !           452:        rom_cksum = bus_space_read_1(iot, ioh, ioreg);
        !           453:        rom_cksum |= bus_space_read_1(iot, ioh, ioreg) << 8;
        !           454:
        !           455:        if (cksum != rom_cksum)
        !           456:                return (-1);
        !           457:        return (0);
        !           458: }
        !           459:
        !           460: void
        !           461: lemac_multicast_op(u_int16_t *mctbl, const u_char *mca, int enable)
        !           462: {
        !           463:        u_int idx, bit, crc;
        !           464:
        !           465:        crc = ether_crc32_le(mca, ETHER_ADDR_LEN);
        !           466:
        !           467:        /*
        !           468:         * The following two lines convert the N bit index into a
        !           469:         * longword index and a longword mask.
        !           470:         */
        !           471: #if LEMAC_MCTBL_BITS < 0
        !           472:        crc >>= (32 + LEMAC_MCTBL_BITS);
        !           473:        crc &= (1 << -LEMAC_MCTBL_BITS) - 1;
        !           474: #else
        !           475:        crc &= (1 << LEMAC_MCTBL_BITS) - 1;
        !           476: #endif
        !           477:        bit = 1 << (crc & 0x0F);
        !           478:        idx = crc >> 4;
        !           479:
        !           480:        /*
        !           481:         * Set or clear hash filter bit in our table.
        !           482:         */
        !           483:        if (enable) {
        !           484:                mctbl[idx] |= bit;              /* Set Bit */
        !           485:        } else {
        !           486:                mctbl[idx] &= ~bit;             /* Clear Bit */
        !           487:        }
        !           488: }
        !           489:
        !           490: void
        !           491: lemac_multicast_filter(struct lemac_softc *sc)
        !           492: {
        !           493: #if 0
        !           494:        struct ether_multistep step;
        !           495:        struct ether_multi *enm;
        !           496: #endif
        !           497:
        !           498:        bzero(sc->sc_mctbl, LEMAC_MCTBL_BITS / 8);
        !           499:
        !           500:        lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, 1);
        !           501:
        !           502: #if 0
        !           503:        ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
        !           504:        while (enm != NULL) {
        !           505:                if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) {
        !           506:                        sc->sc_flags |= LEMAC_ALLMULTI;
        !           507:                        sc->sc_if.if_flags |= IFF_ALLMULTI;
        !           508:                        return;
        !           509:                }
        !           510:                lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE);
        !           511:                ETHER_NEXT_MULTI(step, enm);
        !           512:        }
        !           513: #endif
        !           514:        sc->sc_flags &= ~LEMAC_ALLMULTI;
        !           515:        sc->sc_if.if_flags &= ~IFF_ALLMULTI;
        !           516: }
        !           517:
        !           518: /*
        !           519:  * Do a hard reset of the board;
        !           520:  */
        !           521: void
        !           522: lemac_reset(struct lemac_softc *const sc)
        !           523: {
        !           524:        unsigned data;
        !           525:
        !           526:        /*
        !           527:         * Initialize board..
        !           528:         */
        !           529:        sc->sc_flags &= ~LEMAC_LINKUP;
        !           530:        sc->sc_if.if_flags &= ~IFF_OACTIVE;
        !           531:        LEMAC_INTR_DISABLE(sc);
        !           532:
        !           533:        LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT);
        !           534:        DELAY(LEMAC_EEP_DELAY);
        !           535:
        !           536:        /*
        !           537:         * Read EEPROM information.  NOTE - the placement of this function
        !           538:         * is important because functions hereafter may rely on information
        !           539:         * read from the EEPROM.
        !           540:         */
        !           541:        if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) {
        !           542:                printf("%s: reset: EEPROM checksum failed (0x%x)\n",
        !           543:                    sc->sc_if.if_xname, data);
        !           544:                return;
        !           545:        }
        !           546:
        !           547:        /*
        !           548:         * Update the control register to reflect the media choice
        !           549:         */
        !           550:        data = LEMAC_INB(sc, LEMAC_REG_CTL);
        !           551:        if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) {
        !           552:                data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL);
        !           553:                data |= sc->sc_ctlmode;
        !           554:                LEMAC_OUTB(sc, LEMAC_REG_CTL, data);
        !           555:        }
        !           556:
        !           557:        /*
        !           558:         *  Force to 2K mode if not already configured.
        !           559:         */
        !           560:
        !           561:        data = LEMAC_INB(sc, LEMAC_REG_MBR);
        !           562:        if (LEMAC_IS_2K_MODE(data)) {
        !           563:                sc->sc_flags |= LEMAC_2K_MODE;
        !           564:        } else if (LEMAC_IS_64K_MODE(data)) {
        !           565:                data = (((data * 2) & 0xF) << 4);
        !           566:                sc->sc_flags |= LEMAC_WAS_64K_MODE;
        !           567:                LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
        !           568:        } else if (LEMAC_IS_32K_MODE(data)) {
        !           569:                data = ((data & 0xF) << 4);
        !           570:                sc->sc_flags |= LEMAC_WAS_32K_MODE;
        !           571:                LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
        !           572:        } else {
        !           573:                sc->sc_flags |= LEMAC_PIO_MODE;
        !           574:                /* PIO mode */
        !           575:        }
        !           576:
        !           577:        /*
        !           578:         *  Initialize Free Memory Queue, Init mcast table with broadcast.
        !           579:         */
        !           580:
        !           581:        lemac_init_adapmem(sc);
        !           582:        sc->sc_flags |= LEMAC_ALIVE;
        !           583: }
        !           584:
        !           585: void
        !           586: lemac_init(struct lemac_softc *const sc)
        !           587: {
        !           588:        if ((sc->sc_flags & LEMAC_ALIVE) == 0)
        !           589:                return;
        !           590:
        !           591:        /*
        !           592:         * If the interface has the up flag
        !           593:         */
        !           594:        if (sc->sc_if.if_flags & IFF_UP) {
        !           595:                int saved_cs = LEMAC_INB(sc, LEMAC_REG_CS);
        !           596:                LEMAC_OUTB(sc, LEMAC_REG_CS,
        !           597:                    saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD));
        !           598:                LEMAC_OUTB(sc, LEMAC_REG_PA0, sc->sc_arpcom.ac_enaddr[0]);
        !           599:                LEMAC_OUTB(sc, LEMAC_REG_PA1, sc->sc_arpcom.ac_enaddr[1]);
        !           600:                LEMAC_OUTB(sc, LEMAC_REG_PA2, sc->sc_arpcom.ac_enaddr[2]);
        !           601:                LEMAC_OUTB(sc, LEMAC_REG_PA3, sc->sc_arpcom.ac_enaddr[3]);
        !           602:                LEMAC_OUTB(sc, LEMAC_REG_PA4, sc->sc_arpcom.ac_enaddr[4]);
        !           603:                LEMAC_OUTB(sc, LEMAC_REG_PA5, sc->sc_arpcom.ac_enaddr[5]);
        !           604:
        !           605:                LEMAC_OUTB(sc, LEMAC_REG_IC,
        !           606:                    LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE);
        !           607:
        !           608:                if (sc->sc_if.if_flags & IFF_PROMISC) {
        !           609:                        LEMAC_OUTB(sc, LEMAC_REG_CS,
        !           610:                            LEMAC_CS_MCE | LEMAC_CS_PME);
        !           611:                } else {
        !           612:                        LEMAC_INTR_DISABLE(sc);
        !           613:                        lemac_multicast_filter(sc);
        !           614:                        if (sc->sc_flags & LEMAC_ALLMULTI)
        !           615:                                bcopy(lemac_allmulti_mctbl, sc->sc_mctbl,
        !           616:                                    sizeof(sc->sc_mctbl));
        !           617:                        if (LEMAC_USE_PIO_MODE(sc)) {
        !           618:                                LEMAC_OUTB(sc, LEMAC_REG_IOP, 0);
        !           619:                                LEMAC_OUTB(sc, LEMAC_REG_PI1,
        !           620:                                    LEMAC_MCTBL_OFF & 0xFF);
        !           621:                                LEMAC_OUTB(sc, LEMAC_REG_PI2,
        !           622:                                    LEMAC_MCTBL_OFF >> 8);
        !           623:                                LEMAC_OUTSB(sc, LEMAC_REG_DAT,
        !           624:                                    sizeof(sc->sc_mctbl),
        !           625:                                    (void *)sc->sc_mctbl);
        !           626:                        } else {
        !           627:                                LEMAC_OUTB(sc, LEMAC_REG_MPN, 0);
        !           628:                                LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF,
        !           629:                                    sizeof(sc->sc_mctbl),
        !           630:                                    (void *)sc->sc_mctbl);
        !           631:                        }
        !           632:
        !           633:                        LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE);
        !           634:                }
        !           635:
        !           636:                LEMAC_OUTB(sc, LEMAC_REG_CTL,
        !           637:                    LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
        !           638:
        !           639:                LEMAC_INTR_ENABLE(sc);
        !           640:                sc->sc_if.if_flags |= IFF_RUNNING;
        !           641:                lemac_ifstart(&sc->sc_if);
        !           642:        } else {
        !           643:                LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD);
        !           644:
        !           645:                LEMAC_INTR_DISABLE(sc);
        !           646:                sc->sc_if.if_flags &= ~IFF_RUNNING;
        !           647:        }
        !           648: }
        !           649:
        !           650: void
        !           651: lemac_ifstart(struct ifnet *ifp)
        !           652: {
        !           653:        struct lemac_softc *const sc = LEMAC_IFP_TO_SOFTC(ifp);
        !           654:
        !           655:        if ((ifp->if_flags & IFF_RUNNING) == 0)
        !           656:                return;
        !           657:
        !           658:        LEMAC_INTR_DISABLE(sc);
        !           659:
        !           660:        for (;;) {
        !           661:                struct mbuf *m;
        !           662:                struct mbuf *m0;
        !           663:                int tx_pg;
        !           664:
        !           665:                IFQ_POLL(&ifp->if_snd, m);
        !           666:                if (m == NULL)
        !           667:                        break;
        !           668:
        !           669:                if ((sc->sc_csr.csr_tqc = LEMAC_INB(sc, LEMAC_REG_TQC)) >=
        !           670:                    lemac_txmax) {
        !           671:                        sc->sc_cntrs.cntr_txfull++;
        !           672:                        ifp->if_flags |= IFF_OACTIVE;
        !           673:                        break;
        !           674:                }
        !           675:
        !           676:                /*
        !           677:                 * get free memory page
        !           678:                 */
        !           679:                tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ);
        !           680:
        !           681:                /*
        !           682:                 * Check for good transmit page.
        !           683:                 */
        !           684:                if (tx_pg == 0 || tx_pg > sc->sc_lastpage) {
        !           685:                        sc->sc_cntrs.cntr_txnospc++;
        !           686:                        ifp->if_flags |= IFF_OACTIVE;
        !           687:                        break;
        !           688:                }
        !           689:
        !           690:                IFQ_DEQUEUE(&ifp->if_snd, m);
        !           691:
        !           692:                /*
        !           693:                 * The first four bytes of each transmit buffer are for
        !           694:                 * control information.  The first byte is the control
        !           695:                 * byte, then the length (why not word aligned?), then
        !           696:                 * the offset to the buffer.
        !           697:                 */
        !           698:
        !           699:                if (LEMAC_USE_PIO_MODE(sc)) {
        !           700:                        /* Shift 2K window. */
        !           701:                        LEMAC_OUTB(sc, LEMAC_REG_IOP, tx_pg);
        !           702:                        LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
        !           703:                        LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
        !           704:                        LEMAC_OUTB(sc, LEMAC_REG_DAT, sc->sc_txctl);
        !           705:                        LEMAC_OUTB(sc, LEMAC_REG_DAT,
        !           706:                            (m->m_pkthdr.len >> 0) & 0xFF);
        !           707:                        LEMAC_OUTB(sc, LEMAC_REG_DAT,
        !           708:                            (m->m_pkthdr.len >> 8) & 0xFF);
        !           709:                        LEMAC_OUTB(sc, LEMAC_REG_DAT, LEMAC_TX_HDRSZ);
        !           710:                        for (m0 = m; m0 != NULL; m0 = m0->m_next)
        !           711:                                LEMAC_OUTSB(sc, LEMAC_REG_DAT,
        !           712:                                    m0->m_len, m0->m_data);
        !           713:                } else {
        !           714:                        bus_size_t txoff = /* (mtod(m, u_int32_t) &
        !           715:                            (sizeof(u_int32_t) - 1)) + */ LEMAC_TX_HDRSZ;
        !           716:                        /* Shift 2K window. */
        !           717:                        LEMAC_OUTB(sc, LEMAC_REG_MPN, tx_pg);
        !           718:                        LEMAC_PUT8(sc, 0, sc->sc_txctl);
        !           719:                        LEMAC_PUT8(sc, 1, (m->m_pkthdr.len >> 0) & 0xFF);
        !           720:                        LEMAC_PUT8(sc, 2, (m->m_pkthdr.len >> 8) & 0xFF);
        !           721:                        LEMAC_PUT8(sc, 3, txoff);
        !           722:
        !           723:                        /*
        !           724:                         * Copy the packet to the board
        !           725:                         */
        !           726:                        for (m0 = m; m0 != NULL; m0 = m0->m_next) {
        !           727: #if 0
        !           728:                                LEMAC_PUTBUF8(sc, txoff, m0->m_len,
        !           729:                                    m0->m_data);
        !           730:                                txoff += m0->m_len;
        !           731: #else
        !           732:                                const u_int8_t *cp = m0->m_data;
        !           733:                                int len = m0->m_len;
        !           734: #if 0
        !           735:                                if ((txoff & 3) == (((long)cp) & 3) &&
        !           736:                                    len >= 4) {
        !           737:                                        if (txoff & 3) {
        !           738:                                                int alen = (~txoff & 3);
        !           739:                                                LEMAC_PUTBUF8(sc, txoff, alen,
        !           740:                                                    cp);
        !           741:                                                cp += alen;
        !           742:                                                txoff += alen;
        !           743:                                                len -= alen;
        !           744:                                        }
        !           745:                                        if (len >= 4) {
        !           746:                                                LEMAC_PUTBUF32(sc, txoff,
        !           747:                                                    len / 4, cp);
        !           748:                                                cp += len & ~3;
        !           749:                                                txoff += len & ~3;
        !           750:                                                len &= 3;
        !           751:                                        }
        !           752:                                }
        !           753: #endif
        !           754:                                if ((txoff & 1) == (((long)cp) & 1) &&
        !           755:                                    len >= 2) {
        !           756:                                        if (txoff & 1) {
        !           757:                                                int alen = (~txoff & 1);
        !           758:                                                LEMAC_PUTBUF8(sc, txoff, alen,
        !           759:                                                    cp);
        !           760:                                                cp += alen;
        !           761:                                                txoff += alen;
        !           762:                                                len -= alen;
        !           763:                                        }
        !           764:                                        if (len >= 2) {
        !           765:                                                LEMAC_PUTBUF16(sc, txoff,
        !           766:                                                    len / 2, (void *)cp);
        !           767:                                                cp += len & ~1;
        !           768:                                                txoff += len & ~1;
        !           769:                                                len &= 1;
        !           770:                                        }
        !           771:                                }
        !           772:                                if (len > 0) {
        !           773:                                        LEMAC_PUTBUF8(sc, txoff, len, cp);
        !           774:                                        txoff += len;
        !           775:                                }
        !           776: #endif
        !           777:                        }
        !           778:                }
        !           779:
        !           780:                /* tell chip to transmit this packet */
        !           781:                LEMAC_OUTB(sc, LEMAC_REG_TQ, tx_pg);
        !           782: #if NBPFILTER > 0
        !           783:                if (sc->sc_if.if_bpf != NULL)
        !           784:                        bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_OUT);
        !           785: #endif
        !           786:                m_freem(m);                     /* free the mbuf */
        !           787:        }
        !           788:        LEMAC_INTR_ENABLE(sc);
        !           789: }
        !           790:
        !           791: int
        !           792: lemac_ifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
        !           793: {
        !           794:        struct lemac_softc *const sc = LEMAC_IFP_TO_SOFTC(ifp);
        !           795:        int s;
        !           796:        int error = 0;
        !           797:        struct ifaddr *ifa = (struct ifaddr *)data;
        !           798:        struct ifreq *ifr = (struct ifreq *)data;
        !           799:
        !           800:        s = splnet();
        !           801:
        !           802:        if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
        !           803:                splx(s);
        !           804:                return (error);
        !           805:        }
        !           806:
        !           807:        switch (cmd) {
        !           808:        case SIOCSIFADDR:
        !           809:                ifp->if_flags |= IFF_UP;
        !           810:                lemac_init(sc);
        !           811:                switch (ifa->ifa_addr->sa_family) {
        !           812: #ifdef INET
        !           813:                case AF_INET:
        !           814:                        arp_ifinit(&sc->sc_arpcom, ifa);
        !           815:                        break;
        !           816: #endif /* INET */
        !           817:
        !           818:                default:
        !           819:                        break;
        !           820:                }
        !           821:                break;
        !           822:
        !           823:        case SIOCSIFFLAGS:
        !           824:                lemac_init(sc);
        !           825:                break;
        !           826:
        !           827:        case SIOCADDMULTI:
        !           828:        case SIOCDELMULTI:
        !           829:                /*
        !           830:                 * Update multicast listeners
        !           831:                 */
        !           832:                error = (cmd == SIOCADDMULTI) ?
        !           833:                    ether_addmulti(ifr, &sc->sc_arpcom) :
        !           834:                    ether_delmulti(ifr, &sc->sc_arpcom);
        !           835:
        !           836:                if (error == ENETRESET) {
        !           837:                        /* Reset multicast filtering. */
        !           838:                        if (ifp->if_flags & IFF_RUNNING)
        !           839:                                lemac_init(sc);
        !           840:                        error = 0;
        !           841:                }
        !           842:                break;
        !           843:
        !           844:        case SIOCSIFMEDIA:
        !           845:        case SIOCGIFMEDIA:
        !           846:                error = ifmedia_ioctl(ifp, (struct ifreq *)data,
        !           847:                    &sc->sc_ifmedia, cmd);
        !           848:                break;
        !           849:
        !           850:        case SIOCSIFMTU:
        !           851:                if (ifr->ifr_mtu > ETHERMTU || ifr->ifr_mtu < ETHERMIN) {
        !           852:                        error = EINVAL;
        !           853:                } else if (ifp->if_mtu != ifr->ifr_mtu) {
        !           854:                        ifp->if_mtu = ifr->ifr_mtu;
        !           855:                }
        !           856:                break;
        !           857:
        !           858:        default:
        !           859:                error = EINVAL;
        !           860:                break;
        !           861:        }
        !           862:
        !           863:        splx(s);
        !           864:        return (error);
        !           865: }
        !           866:
        !           867: int
        !           868: lemac_ifmedia_change(struct ifnet *const ifp)
        !           869: {
        !           870:        struct lemac_softc *const sc = LEMAC_IFP_TO_SOFTC(ifp);
        !           871:        unsigned new_ctl;
        !           872:
        !           873:        switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
        !           874:        case IFM_10_T:
        !           875:                new_ctl = LEMAC_CTL_APD;
        !           876:                break;
        !           877:        case IFM_10_2:
        !           878:        case IFM_10_5:
        !           879:                new_ctl = LEMAC_CTL_APD|LEMAC_CTL_PSL;
        !           880:                break;
        !           881:        case IFM_AUTO:
        !           882:                new_ctl = 0;
        !           883:                break;
        !           884:        default:
        !           885:                return (EINVAL);
        !           886:        }
        !           887:        if (sc->sc_ctlmode != new_ctl) {
        !           888:                sc->sc_ctlmode = new_ctl;
        !           889:                lemac_reset(sc);
        !           890:                if (sc->sc_if.if_flags & IFF_UP)
        !           891:                        lemac_init(sc);
        !           892:        }
        !           893:        return (0);
        !           894: }
        !           895:
        !           896: /*
        !           897:  * Media status callback
        !           898:  */
        !           899: void
        !           900: lemac_ifmedia_status(struct ifnet *const ifp, struct ifmediareq *req)
        !           901: {
        !           902:        struct lemac_softc *sc = LEMAC_IFP_TO_SOFTC(ifp);
        !           903:        unsigned data = LEMAC_INB(sc, LEMAC_REG_CNF);
        !           904:
        !           905:        req->ifm_status = IFM_AVALID;
        !           906:        if (sc->sc_flags & LEMAC_LINKUP)
        !           907:                req->ifm_status |= IFM_ACTIVE;
        !           908:
        !           909:        if (sc->sc_ctlmode & LEMAC_CTL_APD) {
        !           910:                if (sc->sc_ctlmode & LEMAC_CTL_PSL) {
        !           911:                        req->ifm_active = IFM_10_5;
        !           912:                } else {
        !           913:                        req->ifm_active = IFM_10_T;
        !           914:                }
        !           915:        } else {
        !           916:                /*
        !           917:                 * The link bit of the configuration register reflects the
        !           918:                 * current media choice when auto-port is enabled.
        !           919:                 */
        !           920:                if (data & LEMAC_CNF_NOLINK) {
        !           921:                        req->ifm_active = IFM_10_5;
        !           922:                } else {
        !           923:                        req->ifm_active = IFM_10_T;
        !           924:                }
        !           925:        }
        !           926:
        !           927:        req->ifm_active |= IFM_ETHER;
        !           928: }
        !           929:
        !           930: int
        !           931: lemac_port_check(const bus_space_tag_t iot, const bus_space_handle_t ioh)
        !           932: {
        !           933:        unsigned char hwaddr[6];
        !           934:
        !           935:        if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 0) == 0)
        !           936:                return (1);
        !           937:        if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 1) == 0)
        !           938:                return (1);
        !           939:        return (0);
        !           940: }
        !           941:
        !           942: void
        !           943: lemac_info_get(const bus_space_tag_t iot, const bus_space_handle_t ioh,
        !           944:     bus_addr_t *maddr_p, bus_size_t *msize_p, int *irq_p)
        !           945: {
        !           946:        unsigned data;
        !           947:
        !           948:        *irq_p = LEMAC_DECODEIRQ(bus_space_read_1(iot, ioh, LEMAC_REG_IC) &
        !           949:            LEMAC_IC_IRQMSK);
        !           950:
        !           951:        data = bus_space_read_1(iot, ioh, LEMAC_REG_MBR);
        !           952:        if (LEMAC_IS_2K_MODE(data)) {
        !           953:                *maddr_p = data * (2 * 1024) + (512 * 1024);
        !           954:                *msize_p =  2 * 1024;
        !           955:        } else if (LEMAC_IS_64K_MODE(data)) {
        !           956:                *maddr_p = data * 64 * 1024;
        !           957:                *msize_p = 64 * 1024;
        !           958:        } else if (LEMAC_IS_32K_MODE(data)) {
        !           959:                *maddr_p = data * 32 * 1024;
        !           960:                *msize_p = 32* 1024;
        !           961:        } else {
        !           962:                *maddr_p = 0;
        !           963:                *msize_p = 0;
        !           964:        }
        !           965: }
        !           966:
        !           967: /*
        !           968:  * What to do upon receipt of an interrupt.
        !           969:  */
        !           970: int
        !           971: lemac_intr(void *arg)
        !           972: {
        !           973:        struct lemac_softc *const sc = arg;
        !           974:        int cs_value;
        !           975:
        !           976:        LEMAC_INTR_DISABLE(sc); /* Mask interrupts */
        !           977:
        !           978:        /*
        !           979:         * Determine cause of interrupt.  Receive events take
        !           980:         * priority over Transmit.
        !           981:         */
        !           982:
        !           983:        cs_value = LEMAC_INB(sc, LEMAC_REG_CS);
        !           984:
        !           985:        /*
        !           986:         * Check for Receive Queue not being empty.
        !           987:         * Check for Transmit Done Queue not being empty.
        !           988:         */
        !           989:
        !           990:        if (cs_value & LEMAC_CS_RNE)
        !           991:                lemac_rne_intr(sc);
        !           992:        if (cs_value & LEMAC_CS_TNE)
        !           993:                lemac_tne_intr(sc);
        !           994:
        !           995:        /*
        !           996:         * Check for Transmitter Disabled.
        !           997:         * Check for Receiver Disabled.
        !           998:         */
        !           999:
        !          1000:        if (cs_value & LEMAC_CS_TXD)
        !          1001:                lemac_txd_intr(sc, cs_value);
        !          1002:        if (cs_value & LEMAC_CS_RXD)
        !          1003:                lemac_rxd_intr(sc, cs_value);
        !          1004:
        !          1005:        /*
        !          1006:         * Toggle LED and unmask interrupts.
        !          1007:         */
        !          1008:
        !          1009:        sc->sc_csr.csr_cs = LEMAC_INB(sc, LEMAC_REG_CS);
        !          1010:
        !          1011:        LEMAC_OUTB(sc, LEMAC_REG_CTL,
        !          1012:            LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
        !          1013:        LEMAC_INTR_ENABLE(sc);          /* Unmask interrupts */
        !          1014:
        !          1015: #if 0
        !          1016:        if (cs_value)
        !          1017:                rnd_add_uint32(&sc->rnd_source, cs_value);
        !          1018: #endif
        !          1019:
        !          1020:        return (1);
        !          1021: }
        !          1022:
        !          1023: void
        !          1024: lemac_shutdown(void *arg)
        !          1025: {
        !          1026:        lemac_reset((struct lemac_softc *)arg);
        !          1027: }
        !          1028:
        !          1029: const char *const lemac_modes[4] = {
        !          1030:        "PIO mode (internal 2KB window)",
        !          1031:        "2KB window",
        !          1032:        "changed 32KB window to 2KB",
        !          1033:        "changed 64KB window to 2KB",
        !          1034: };
        !          1035:
        !          1036: void
        !          1037: lemac_ifattach(struct lemac_softc *sc)
        !          1038: {
        !          1039:        struct ifnet *const ifp = &sc->sc_if;
        !          1040:
        !          1041:        bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
        !          1042:
        !          1043:        lemac_reset(sc);
        !          1044:
        !          1045:        lemac_read_macaddr(sc->sc_arpcom.ac_enaddr, sc->sc_iot, sc->sc_ioh,
        !          1046:            LEMAC_REG_APD, 0);
        !          1047:
        !          1048:        printf(": %s\n", sc->sc_prodname);
        !          1049:
        !          1050:        printf("%s: address %s, %dKB RAM, %s\n", ifp->if_xname,
        !          1051:            ether_sprintf(sc->sc_arpcom.ac_enaddr), sc->sc_lastpage * 2 + 2,
        !          1052:            lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]);
        !          1053:
        !          1054:        ifp->if_softc = (void *)sc;
        !          1055:        ifp->if_start = lemac_ifstart;
        !          1056:        ifp->if_ioctl = lemac_ifioctl;
        !          1057:
        !          1058:        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX
        !          1059: #ifdef IFF_NOTRAILERS
        !          1060:                | IFF_NOTRAILERS
        !          1061: #endif
        !          1062:                | IFF_MULTICAST;
        !          1063:
        !          1064:        if (sc->sc_flags & LEMAC_ALIVE) {
        !          1065:                int media;
        !          1066:
        !          1067:                IFQ_SET_READY(&ifp->if_snd);
        !          1068:
        !          1069:                if_attach(ifp);
        !          1070:                ether_ifattach(ifp);
        !          1071:
        !          1072: #if 0
        !          1073:                rnd_attach_source(&sc->rnd_source, sc->sc_dv.dv_xname,
        !          1074:                    RND_TYPE_NET, 0);
        !          1075: #endif
        !          1076:
        !          1077:                ifmedia_init(&sc->sc_ifmedia, 0, lemac_ifmedia_change,
        !          1078:                    lemac_ifmedia_status);
        !          1079:                if (sc->sc_prodname[4] == '5')  /* DE205 is UTP/AUI */
        !          1080:                        ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0,
        !          1081:                            0);
        !          1082:                if (sc->sc_prodname[4] != '3')  /* DE204 & 205 have UTP */
        !          1083:                        ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0,
        !          1084:                            0);
        !          1085:                if (sc->sc_prodname[4] != '4')  /* DE203 & 205 have BNC */
        !          1086:                        ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0,
        !          1087:                            0);
        !          1088:                switch (sc->sc_prodname[4]) {
        !          1089:                case '3':
        !          1090:                        media = IFM_10_5;
        !          1091:                        break;
        !          1092:                case '4':
        !          1093:                        media = IFM_10_T;
        !          1094:                        break;
        !          1095:                default:
        !          1096:                        media = IFM_AUTO;
        !          1097:                        break;
        !          1098:                }
        !          1099:                ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media);
        !          1100:        } else {
        !          1101:                printf("%s: disabled due to error\n", ifp->if_xname);
        !          1102:        }
        !          1103: }

CVSweb