Annotation of Net2/arch/i386/netboot/wd80x3.c, revision 1.1.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.