Annotation of Net2/arch/i386/netboot/wd80x3.c, revision 1.1

1.1     ! root        1: /* netboot
        !             2:  *
        !             3:  * wd80x3.c,v
        !             4:  * Revision 1.2  1993/07/09  15:24:14  brezak
        !             5:  * Cleanup warnings and add netbsd kernel name suffix.
        !             6:  *
        !             7:  * Revision 1.1  1993/07/08  16:04:14  brezak
        !             8:  * Diskless boot prom code from Jim McKim ([email protected])
        !             9:  *
        !            10:  * Revision 1.2  1993/06/08  14:35:17  mckim
        !            11:  * *** empty log message ***
        !            12:  *
        !            13:  * Revision 1.1.1.1  1993/05/28  11:41:07  mckim
        !            14:  * Initial version.
        !            15:  *
        !            16:  *
        !            17:  * source in this file came from
        !            18:  * the Mach ethernet boot written by Leendert van Doorn.
        !            19:  *
        !            20:  * A very simple network driver for WD80x3 boards that polls.
        !            21:  *
        !            22:  * Copyright (c) 1992 by Leendert van Doorn
        !            23:  */
        !            24: 
        !            25: #include "proto.h"
        !            26: #include "assert.h"
        !            27: #include "packet.h"
        !            28: #include "ether.h"
        !            29: #include "dp8390.h"
        !            30: 
        !            31: /* configurable parameters */
        !            32: #define        WD_BASEREG      0x280           /* base register */
        !            33: /* the base address doesn't have to be particularly accurate - the
        !            34:    board seems to pick up on addresses in the range a0000..effff.
        !            35:    */
        !            36: #define        WD_BASEMEM      0xd0000         /* base ram */
        !            37: 
        !            38: /* bit definitions for board features */
        !            39: #define        INTERFACE_CHIP  01              /* has an WD83C583 interface chip */
        !            40: #define        BOARD_16BIT     02              /* 16 bit board */
        !            41: #define        SLOT_16BIT      04              /* 16 bit slot */
        !            42: 
        !            43: /* register offset definitions */
        !            44: #define        WD_MSR          0x00            /* control (w) and status (r) */
        !            45: #define WD_REG0                0x00            /* generic register definitions */
        !            46: #define WD_REG1                0x01
        !            47: #define WD_REG2                0x02
        !            48: #define WD_REG3                0x03
        !            49: #define WD_REG4                0x04
        !            50: #define WD_REG5                0x05
        !            51: #define WD_REG6                0x06
        !            52: #define WD_REG7                0x07
        !            53: #define        WD_EA0          0x08            /* most significant addr byte */
        !            54: #define        WD_EA1          0x09
        !            55: #define        WD_EA2          0x0A
        !            56: #define        WD_EA3          0x0B
        !            57: #define        WD_EA4          0x0C
        !            58: #define        WD_EA5          0x0D            /* least significant addr byte */
        !            59: #define        WD_LTB          0x0E            /* LAN type byte */
        !            60: #define        WD_CHKSUM       0x0F            /* sum from WD_EA0 upto here is 0xFF */
        !            61: #define        WD_DP8390       0x10            /* natsemi chip */
        !            62: 
        !            63: /* bits in control register */
        !            64: #define        WD_MSR_MEMMASK  0x3F            /* memory enable bits mask */
        !            65: #define        WD_MSR_MENABLE  0x40            /* memory enable */
        !            66: #define        WD_MSR_RESET    0x80            /* software reset */
        !            67: 
        !            68: /* bits in bus size register */
        !            69: #define        WD_BSR_16BIT    0x01            /* 16 bit bus */
        !            70: 
        !            71: /* bits in LA address register */
        !            72: #define        WD_LAAR_A19     0x01            /* address lines for above 1Mb ram */
        !            73: #define        WD_LAAR_LAN16E  0x40            /* enables 16bit shrd RAM for LAN */
        !            74: #define        WD_LAAR_MEM16E  0x80            /* enables 16bit shrd RAM for host */
        !            75: 
        !            76: u_char eth_myaddr[ETH_ADDRSIZE];
        !            77: 
        !            78: static int boardid;
        !            79: static dpconf_t dpc;
        !            80: 
        !            81: /*
        !            82:  * Determine whether wd8003 hardware performs register aliasing
        !            83:  * (i.e. whether it is an old WD8003E board).
        !            84:  */
        !            85: static int
        !            86: Aliasing(void) {
        !            87:   if (inb(WD_BASEREG + WD_REG1) != inb(WD_BASEREG + WD_EA1))
        !            88:     return 0;
        !            89:   if (inb(WD_BASEREG + WD_REG2) != inb(WD_BASEREG + WD_EA2))
        !            90:     return 0;
        !            91:   if (inb(WD_BASEREG + WD_REG3) != inb(WD_BASEREG + WD_EA3))
        !            92:     return 0;
        !            93:   if (inb(WD_BASEREG + WD_REG4) != inb(WD_BASEREG + WD_EA4))
        !            94:     return 0;
        !            95:   if (inb(WD_BASEREG + WD_REG7) != inb(WD_BASEREG + WD_CHKSUM))
        !            96:     return 0;
        !            97:   return 1;
        !            98: }
        !            99: 
        !           100: /*
        !           101:  * This trick is stolen from the clarkson packet driver
        !           102: TBD - this is _ugly_ bogus! should use system timer
        !           103:  */
        !           104: static void
        !           105: LongPause(void) {
        !           106:   short i;
        !           107:   for (i = 1600; i > 0; i++)
        !           108:     (void) inb(0x61);
        !           109: }
        !           110: 
        !           111: /*
        !           112:  * Determine whether this board has 16-bit capabilities
        !           113:  */
        !           114: static int
        !           115: BoardIs16Bit(void) {
        !           116:   u_char bsreg = inb(WD_BASEREG + WD_REG1);
        !           117: 
        !           118:   outb(WD_BASEREG + WD_REG1, bsreg ^ WD_BSR_16BIT);
        !           119:   LongPause();
        !           120:   if (inb(WD_BASEREG + WD_REG1) == bsreg) {
        !           121:     /*
        !           122:      * Pure magic: LTB is 0x05 indicates that this is a WD8013EB board,
        !           123:      * 0x27 indicates that this is an WD8013 Elite board, and 0x29
        !           124:      * indicates an SMC Elite 16 board.
        !           125:      */
        !           126:     u_char tlb = inb(WD_BASEREG + WD_LTB);
        !           127:     return tlb == 0x05 || tlb == 0x27 || tlb == 0x29;
        !           128:   }
        !           129:   outb(WD_BASEREG + WD_REG1, bsreg);
        !           130:   return 1;
        !           131: }
        !           132: 
        !           133: /*
        !           134:  * Determine whether the 16 bit capable board is plugged
        !           135:  * into a 16 bit slot.
        !           136:  */
        !           137: static int
        !           138: SlotIs16Bit(void) {
        !           139:   return inb(WD_BASEREG + WD_REG1) & WD_BSR_16BIT;
        !           140: }
        !           141: 
        !           142: /*
        !           143:  * Reset ethernet board after a timeout
        !           144:  */
        !           145: void
        !           146: EtherReset(void) {
        !           147:   int dpreg = dpc.dc_reg;
        !           148:   /* initialize the board */
        !           149:   outb(WD_BASEREG + WD_MSR,
        !           150:        WD_MSR_MENABLE | (((u_long)WD_BASEMEM >> 13) & WD_MSR_MEMMASK));
        !           151: 
        !           152:   /* reset dp8390 ethernet chip */
        !           153:   outb(dpreg + DP_CR, CR_STP|CR_DM_ABORT);
        !           154: 
        !           155:   /* initialize first register set */
        !           156:   outb(dpreg + DP_IMR, 0);
        !           157:   outb(dpreg + DP_CR, CR_PS_P0|CR_STP|CR_DM_ABORT);
        !           158:   outb(dpreg + DP_TPSR, dpc.dc_tpsr);
        !           159:   outb(dpreg + DP_PSTART, dpc.dc_pstart);
        !           160:   outb(dpreg + DP_PSTOP, dpc.dc_pstop);
        !           161:   outb(dpreg + DP_BNRY, dpc.dc_pstart);
        !           162:   outb(dpreg + DP_RCR, RCR_MON);
        !           163:   outb(dpreg + DP_TCR, TCR_NORMAL|TCR_OFST);
        !           164:   if (boardid & SLOT_16BIT)
        !           165:     outb(dpreg + DP_DCR, DCR_WORDWIDE|DCR_8BYTES);
        !           166:   else
        !           167:     outb(dpreg + DP_DCR, DCR_BYTEWIDE|DCR_8BYTES);
        !           168:   outb(dpreg + DP_RBCR0, 0);
        !           169:   outb(dpreg + DP_RBCR1, 0);
        !           170:   outb(dpreg + DP_ISR, 0xFF);
        !           171: 
        !           172:   /* initialize second register set */
        !           173:   outb(dpreg + DP_CR, CR_PS_P1|CR_DM_ABORT);
        !           174:   outb(dpreg + DP_PAR0, eth_myaddr[0]);
        !           175:   outb(dpreg + DP_PAR1, eth_myaddr[1]);
        !           176:   outb(dpreg + DP_PAR2, eth_myaddr[2]);
        !           177:   outb(dpreg + DP_PAR3, eth_myaddr[3]);
        !           178:   outb(dpreg + DP_PAR4, eth_myaddr[4]);
        !           179:   outb(dpreg + DP_PAR5, eth_myaddr[5]);
        !           180:   outb(dpreg + DP_CURR, dpc.dc_pstart+1);
        !           181: 
        !           182:   /* and back to first register set */
        !           183:   outb(dpreg + DP_CR, CR_PS_P0|CR_DM_ABORT);
        !           184:   outb(dpreg + DP_RCR, RCR_AB);
        !           185: 
        !           186:   /* flush counters */
        !           187:   (void) inb(dpreg + DP_CNTR0);
        !           188:   (void) inb(dpreg + DP_CNTR1);
        !           189:   (void) inb(dpreg + DP_CNTR2);
        !           190: 
        !           191:   /* and go ... */
        !           192:   outb(dpreg + DP_CR, CR_STA|CR_DM_ABORT);
        !           193: }
        !           194: 
        !           195: /*
        !           196:  * Initialize the WD80X3 board
        !           197:  */
        !           198: int
        !           199: EtherInit(void) {
        !           200:   unsigned sum;
        !           201:   int memsize;
        !           202:   /* reset the ethernet card */
        !           203:   outb(WD_BASEREG + WD_MSR, WD_MSR_RESET);
        !           204:   LongPause();
        !           205:   outb(WD_BASEREG + WD_MSR, 0);
        !           206: 
        !           207:   /* determine whether the controller is there */
        !           208:   sum = inb(WD_BASEREG + WD_EA0) + inb(WD_BASEREG + WD_EA1) +
        !           209:     inb(WD_BASEREG + WD_EA2) + inb(WD_BASEREG + WD_EA3) +
        !           210:       inb(WD_BASEREG + WD_EA4) + inb(WD_BASEREG + WD_EA5) +
        !           211:        inb(WD_BASEREG + WD_LTB) + inb(WD_BASEREG + WD_CHKSUM);
        !           212:   if ((sum & 0xFF) != 0xFF)
        !           213:     return 0;
        !           214: 
        !           215:   /*
        !           216:    * Determine the type of board
        !           217:    */
        !           218:   boardid = 0;
        !           219:   if (!Aliasing()) {
        !           220:     if (BoardIs16Bit()) {
        !           221:       boardid |= BOARD_16BIT;
        !           222:       if (SlotIs16Bit())
        !           223:        boardid |= SLOT_16BIT;
        !           224:     }
        !           225:   }
        !           226:   memsize = (boardid & BOARD_16BIT) ? 0x4000 : 0x2000; /* 16 or 8 Kb */
        !           227: 
        !           228:   /* special setup needed for WD8013 boards */
        !           229:   if (boardid & SLOT_16BIT)
        !           230:     outb(WD_BASEREG + WD_REG5, WD_LAAR_A19|WD_LAAR_LAN16E);
        !           231: 
        !           232:   /* get ethernet address */
        !           233:   eth_myaddr[0] = inb(WD_BASEREG + WD_EA0);
        !           234:   eth_myaddr[1] = inb(WD_BASEREG + WD_EA1);
        !           235:   eth_myaddr[2] = inb(WD_BASEREG + WD_EA2);
        !           236:   eth_myaddr[3] = inb(WD_BASEREG + WD_EA3);
        !           237:   eth_myaddr[4] = inb(WD_BASEREG + WD_EA4);
        !           238:   eth_myaddr[5] = inb(WD_BASEREG + WD_EA5);
        !           239: 
        !           240:   /* save settings for future use */
        !           241:   dpc.dc_reg = WD_BASEREG + WD_DP8390;
        !           242:   dpc.dc_mem = WD_BASEMEM;
        !           243:   dpc.dc_tpsr = 0;
        !           244:   dpc.dc_pstart = 6;
        !           245:   dpc.dc_pstop = (memsize >> 8) & 0xFF;
        !           246: 
        !           247:   printf("Using wd80x3 board, port 0x%x, iomem 0x%x, iosiz %d\n", WD_BASEREG, WD_BASEMEM, memsize);
        !           248: 
        !           249:   EtherReset();
        !           250:   return 1;
        !           251: }
        !           252: 
        !           253: /*
        !           254:  * Stop ethernet board
        !           255:  */
        !           256: void
        !           257: EtherStop(void) {
        !           258:   /* stop dp8390, followed by a board reset */
        !           259:   outb(dpc.dc_reg + DP_CR, CR_STP|CR_DM_ABORT);
        !           260:   outb(WD_BASEREG + WD_MSR, WD_MSR_RESET);
        !           261:   outb(WD_BASEREG + WD_MSR, 0);
        !           262: }
        !           263: 
        !           264: /* TBD - all users must take care to use the current "data seg" value
        !           265: when moving data from/to the controller */
        !           266: static void
        !           267: WdCopy(u_long src, u_long dst, u_long count) {
        !           268: #if TRACE > 0
        !           269: printf("WdCopy from %x to %x for %d\n", src, dst, count);
        !           270: #endif
        !           271:   assert(count <= 1514);
        !           272:   if (boardid & SLOT_16BIT)
        !           273:     outb(WD_BASEREG + WD_REG5,
        !           274:         WD_LAAR_MEM16E|WD_LAAR_LAN16E|WD_LAAR_A19);
        !           275:   PhysBcopy(src, dst, count);
        !           276:   if (boardid & SLOT_16BIT)
        !           277:     outb(WD_BASEREG + WD_REG5, WD_LAAR_LAN16E|WD_LAAR_A19);
        !           278: }
        !           279: 
        !           280: /*
        !           281:  * Send an ethernet packet to destination 'dest'
        !           282:  */
        !           283: void
        !           284: EtherSend(packet_t *pkt, u_short proto, u_char *dest) {
        !           285:   ethhdr_t *ep;
        !           286: 
        !           287:   pkt->pkt_len += sizeof(ethhdr_t);
        !           288:   pkt->pkt_offset -= sizeof(ethhdr_t);
        !           289:   ep = (ethhdr_t *) pkt->pkt_offset;
        !           290:   ep->eth_proto = htons(proto);
        !           291:   bcopy((char *)dest, (char *)ep->eth_dst, ETH_ADDRSIZE);
        !           292:   bcopy((char *)eth_myaddr, (char *)ep->eth_src, ETH_ADDRSIZE);
        !           293: #if 0
        !           294: DUMP_STRUCT("ethhdr_t", ep, sizeof(ethhdr_t));
        !           295: #endif
        !           296:   if (pkt->pkt_len < 60)
        !           297:     pkt->pkt_len = 60;
        !           298: 
        !           299: #if TRACE > 0
        !           300:   {
        !           301:     int i;
        !           302: DUMP_STRUCT("EtherSend: pkt", pkt->pkt_offset, pkt->pkt_len);
        !           303: #if 0
        !           304:     for(i=0; i<(pkt->pkt_len<MDUMP?pkt->pkt_len:MDUMP); i++) printe("%x ", *((u_char*)(pkt->pkt_offset)+i));
        !           305:     printe("\n");
        !           306: #endif
        !           307:   }
        !           308: #endif
        !           309: 
        !           310: #if 0
        !           311: printe("EtherSend: WdCopy from %x to %x for %d\n", LA(pkt->pkt_offset), dpc.dc_mem + (dpc.dc_tpsr << 8), (u_long)pkt->pkt_len);
        !           312: #endif
        !           313:   WdCopy(LA(pkt->pkt_offset),
        !           314:         dpc.dc_mem + (dpc.dc_tpsr << 8), (u_long)pkt->pkt_len);
        !           315:   outb(dpc.dc_reg + DP_TPSR, dpc.dc_tpsr);
        !           316:   outb(dpc.dc_reg + DP_TBCR0, (pkt->pkt_len & 0xFF));
        !           317:   outb(dpc.dc_reg + DP_TBCR1, (pkt->pkt_len >> 8) & 0xFF);
        !           318:   outb(dpc.dc_reg + DP_CR, CR_TXP);
        !           319: 
        !           320: #if 0
        !           321:   printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TPSR, dpc.dc_tpsr);
        !           322:   printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR0, (pkt->pkt_len & 0xFF));
        !           323:   printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR1, (pkt->pkt_len >> 8) & 0xFF);
        !           324:   printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_CR, CR_TXP);
        !           325: #endif
        !           326: }
        !           327: 
        !           328: /*
        !           329:  * Copy dp8390 packet header for observation
        !           330:  */
        !           331: static void
        !           332: GetHeader(u_long haddr, dphdr_t *dph) {
        !           333: #if TRACE > 0
        !           334: printe("GetHeader: WdCopy from %x to %x for %d\n", haddr, LA(dph), sizeof(dphdr_t));
        !           335: #endif
        !           336:   WdCopy(haddr, LA(dph), sizeof(dphdr_t));
        !           337: #if 0
        !           338: DUMP_STRUCT("GetHeader: dphdr_t", dph, sizeof(dphdr_t));
        !           339: #endif
        !           340: }
        !           341: 
        !           342: /*
        !           343:  * Poll the dp8390 just see if there's an Ethernet packet
        !           344:  * available. If there is, its contents is returned in a
        !           345:  * pkt structure, otherwise a nil pointer is returned.
        !           346:  */
        !           347: packet_t *
        !           348: EtherReceive(void) {
        !           349:   u_char pageno, curpage, nextpage;
        !           350:   int dpreg = dpc.dc_reg;
        !           351:   packet_t *pkt;
        !           352:   dphdr_t dph;
        !           353:   u_long addr;
        !           354: 
        !           355:   pkt = (packet_t *)0;
        !           356:   if (inb(dpreg + DP_RSR) & RSR_PRX) {
        !           357:     /* get current page numbers */
        !           358:     pageno = inb(dpreg + DP_BNRY) + 1;
        !           359:     if (pageno == dpc.dc_pstop)
        !           360:       pageno = dpc.dc_pstart;
        !           361:     outb(dpreg + DP_CR, CR_PS_P1);
        !           362:     curpage = inb(dpreg + DP_CURR);
        !           363:     outb(dpreg + DP_CR, CR_PS_P0);
        !           364:     if (pageno == curpage)
        !           365:       return (packet_t *) 0;
        !           366: 
        !           367:     /* get packet header */
        !           368:     addr = dpc.dc_mem + (pageno << 8);
        !           369:     GetHeader(addr, &dph);
        !           370:     nextpage = dph.dh_next;
        !           371: 
        !           372:     /* allocate packet */
        !           373:     pkt = PktAlloc(0);
        !           374: #if 0
        !           375: printe("EtherReceive: allocated pkt %x\n", pkt);
        !           376: #endif
        !           377:     pkt->pkt_len = ((dph.dh_rbch & 0xFF) << 8) | (dph.dh_rbcl & 0xFF);
        !           378:     pkt->pkt_len -= sizeof(dphdr_t);
        !           379:     if (pkt->pkt_len > 1514) /* bug in dp8390 */
        !           380:       pkt->pkt_len = 1514;
        !           381: 
        !           382: #if TRACE > 0
        !           383:     {
        !           384:       int i;
        !           385:       printe("EtherReceive %d bytes: ", pkt->pkt_len);
        !           386: #if 0
        !           387:       for(i=0; i<(pkt->pkt_len<MDUMP?pkt->pkt_len:MDUMP); i++) printe("%x ", *((u_char*)pkt+i));
        !           388: #else
        !           389:       DUMP_STRUCT("", pkt, pkt->pkt_len);
        !           390: #endif
        !           391:       printe("\n");
        !           392:     }
        !           393: #endif
        !           394: 
        !           395:     /*
        !           396:      * The dp8390 maintains a circular buffer of pages (256 bytes)
        !           397:      * in which incomming ethernet packets are stored. The following
        !           398:      * if detects wrap arounds, and copies the ethernet packet to
        !           399:      * our local buffer in two chunks if necesarry.
        !           400:      */
        !           401:     assert(pkt->pkt_offset);
        !           402:     assert(pkt->pkt_len <= (6 << 8));
        !           403:     if (nextpage < pageno && nextpage > dpc.dc_pstart) {
        !           404:       u_long nbytes = ((dpc.dc_pstop - pageno) << 8) - sizeof(dphdr_t);
        !           405: 
        !           406:       assert(nbytes <= (6 << 8));
        !           407: #if TRACE > 0
        !           408: printe("EtherReceive1: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt->pkt_offset), nbytes);
        !           409: #endif
        !           410:       WdCopy(addr + sizeof(dphdr_t),
        !           411:             LA(pkt->pkt_offset), nbytes);
        !           412:       if ((pkt->pkt_len - nbytes) > 0)
        !           413:        /* TBD - this OK? */
        !           414: #if TRACE > 0
        !           415: printe("EtherReceive2: WdCopy from %x to %x for %x\n",dpc.dc_mem + (dpc.dc_pstart << 8), LA(pkt->pkt_offset) + nbytes, pkt->pkt_len - nbytes);
        !           416: #endif
        !           417:        WdCopy(dpc.dc_mem + (dpc.dc_pstart << 8),
        !           418:               LA(pkt->pkt_offset) + nbytes,
        !           419:               pkt->pkt_len - nbytes); 
        !           420:     } else {
        !           421: #if TRACE > 0
        !           422: printe("EtherReceive3: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt->pkt_offset), (u_long)pkt->pkt_len);
        !           423: #endif
        !           424:       WdCopy(addr + sizeof(dphdr_t),
        !           425:             LA(pkt->pkt_offset), (u_long)pkt->pkt_len);
        !           426:     }
        !           427: 
        !           428:     /* release occupied pages */
        !           429:     if (nextpage == dpc.dc_pstart)
        !           430:       nextpage = dpc.dc_pstop;
        !           431:     outb(dpreg + DP_BNRY, nextpage - 1);
        !           432:   }
        !           433: 
        !           434:   return pkt;
        !           435: }
        !           436: 
        !           437: /*
        !           438:  * Print an ethernet address in human readable form
        !           439:  */
        !           440: void
        !           441: EtherPrintAddr(u_char *addr) {
        !           442:   printf("%x:%x:%x:%x:%x:%x",
        !           443:         addr[0] & 0xFF, addr[1] & 0xFF, addr[2] & 0xFF,
        !           444:         addr[3] & 0xFF, addr[4] & 0xFF, addr[5] & 0xFF);
        !           445: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.