www.pudn.com > Source_program.rar > ETHERNE.C
#include#include #include #include "ether.h" /* Typedefs and function prototypes */ #include "netutil.h" #include "net.h" #define WORDMODE 1 /* Set to zero if using 8-bit XT-bus cards */ /* NE2000 definitions */ #define DATAPORT 0x10 #define NE_RESET 0x1f /* 8390 Network Interface Controller (NIC) page0 register offsets */ #define CMDR 0x00 /* command register for read & write */ #define PSTART 0x01 /* page start register for write */ #define PSTOP 0x02 /* page stop register for write */ #define BNRY 0x03 /* boundary reg for rd and wr */ #define TPSR 0x04 /* tx start page start reg for wr */ #define TBCR0 0x05 /* tx byte count 0 reg for wr */ #define TBCR1 0x06 /* tx byte count 1 reg for wr */ #define ISR 0x07 /* interrupt status reg for rd and wr */ #define RSAR0 0x08 /* low byte of remote start addr */ #define RSAR1 0x09 /* hi byte of remote start addr */ #define RBCR0 0x0A /* remote byte count reg 0 for wr */ #define RBCR1 0x0B /* remote byte count reg 1 for wr */ #define RCR 0x0C /* rx configuration reg for wr */ #define TCR 0x0D /* tx configuration reg for wr */ #define DCR 0x0E /* data configuration reg for wr */ #define IMR 0x0F /* interrupt mask reg for wr */ /* NIC page 1 register offsets */ #define PAR0 0x01 /* physical addr reg 0 for rd and wr */ #define CURR 0x07 /* current page reg for rd and wr */ #define MAR0 0x08 /* multicast addr reg 0 for rd and WR */ /* Buffer Length and Field Definition Info */ #define TXSTART 0x40 /* Tx buffer start page */ #define TXPAGES 6 /* Pages for Tx buffer */ #define RXSTART (TXSTART+TXPAGES) /* Rx buffer start page */ #if WORDMODE #define RXSTOP 0x7e /* Rx buffer end page for word mode */ #define DCRVAL 0x49 /* DCR values for word mode */ #else #define RXSTOP 0x5f /* Ditto for byte mode */ #define DCRVAL 0x48 #endif #define STARHACK 0 /* Set non-zero to enable Starlan length hack */ typedef struct /* Net driver configuration data */ { WORD dtype; /* Driver type */ BYTE myeth[MACLEN]; /* MAC (Ethernet) addr */ WORD ebase; /* Card I/O base addr */ WORD next_pkt; /* Next (current) Rx page */ } CONFIGNE; static CONFIGNE configs[MAXNETS]; /* Driver configurations */ static WORD ebase; /* Temp I/O base addr; usually 280h for PC */ int promisc=0; /* Flag to enable promiscuous mode */ typedef struct { /* NIC hardware packet header */ BYTE stat; /* Error status */ BYTE next; /* Pointer to next block */ WORD len; /* Length of this frame incl. CRC */ } NICHDR; NICHDR nichdr; /* Private prototypes */ void resetnic(CONFIGNE *cp, char cold); void getnic(WORD addr, BYTE data[], WORD len); void putnic(WORD addr, BYTE data[], WORD len); BYTE nicwrap(int page); BYTE innic(int reg); void outnic(int reg, int b); /* Initialise card given driver type and base addr. ** Return driver type, 0 if error */ int init_etherne(WORD dtype, WORD baseaddr) { int ok=0; CONFIGNE *cp; cp = &configs[dtype & NETNUM_MASK]; /* Get pointer into driver data */ cp->dtype = dtype; /* Set driver type */ cp->ebase = ebase = baseaddr; /* Set card I/O base address */ outnic(NE_RESET, innic(NE_RESET)); /* Do reset */ delay(2); if ((innic(ISR) & 0x80) == 0) /* Report if failed */ { printf(" Ethernet card failed to reset!\n"); } else { resetnic(cp, 1); /* Reset Ethernet card, get my addr */ ok = 1; } return(ok); } /* Close down ethernet controller */ void close_etherne(WORD dtype) { ebase = configs[dtype & NETNUM_MASK].ebase; if (ebase) { outnic(CMDR, 0x21); /* Stop, DMA abort, page 0 */ configs[dtype & NETNUM_MASK].ebase = 0; } } /* Return pointer to my Ethernet addr, given driver type */ BYTE *etherne_addr(WORD dtype) { return(configs[dtype & NETNUM_MASK].myeth); } /* Poll network interface to keep it alive; send & receive frames */ void poll_etherne(WORD dtype) { WORD len; static BYTE ebuff[MAXFRAMEC]; CONFIGNE *cp; cp = &configs[dtype & NETNUM_MASK]; if (cp->ebase) /* If Ether card in use.. */ { ebase = cp->ebase; /* Set card I/O address */ outnic(ISR, 0x01); /* Clear interrupt flag */ /* Receive */ while ((len=get_etherne(cp->dtype, ebuff))>0) { /* Store frames in buff */ receive_upcall(cp->dtype, ebuff, len); } /* Transmit */ while (!(innic(CMDR)&0x04) && /* While NIC ready & frame avail */ (len=transmit_upcall(cp->dtype, ebuff, MAXFRAME))>0) { /* ..transmit frame */ put_etherne(cp->dtype, ebuff, len); } } } /* Get packet into buffer, return length (excl CRC), or 0 if none available */ WORD get_etherne(WORD dtype, void *pkt) { WORD len=0, curr; BYTE bnry; CONFIGNE *cp; #if STARHACK int hilen, lolen; #endif cp = &configs[dtype & NETNUM_MASK]; ebase = cp->ebase; if (innic(ISR) & 0x10) /* If Rx overrun.. */ { printf(" NIC Rx overrun\n"); resetnic(cp, 0); /* ..reset controller (drastic!) */ } outnic(CMDR, 0x60); /* DMA abort, page 1 */ curr = innic(CURR); /* Get current page */ outnic(CMDR, 0x20); /* DMA abort, page 0 */ if (curr != cp->next_pkt) /* If Rx packet.. */ { memset(&nichdr, 0xee, sizeof(nichdr)); /* ..get NIC header */ getnic((WORD)(cp->next_pkt<<8), (BYTE *)&nichdr, sizeof(nichdr)); #if STARHACK hilen = nichdr.next - cp->next_pkt - 1; lolen = nichdr.len & 0xff; if (hilen < 0) /* Do len calc from NIC datasheet */ hilen = RXSTOP - cp->next_pkt + nichdr.next - RXSTART - 1; if (lolen > 0xfc) hilen++; len = (hilen<<8) + lolen; if (len != nichdr.len) /* ..and compare with actual value */ { if (netdebug) printf(" NIC length mismatch %Xh - %Xh\n", len, nichdr.len); } #else len = nichdr.len; /* Take length from stored header */ #endif if ((nichdr.stat&1) && len>=MINFRAMEC && len<=MAXFRAMEC) { /* If hdr is OK, get packet */ len -= CRCLEN; /* ..without CRC! */ if (pkt) getnic((WORD)((cp->next_pkt<<8)+sizeof(nichdr)), pkt, len); } else /* If not, no packet data */ { printf(" NIC packet error\n"); } /* Update next packet ptr */ if (nichdr.next>=RXSTART && nichdr.next next_pkt = nichdr.next; else /* If invalid, use prev+1 */ { printf(" NIC pointer error\n"); cp->next_pkt = nicwrap(cp->next_pkt + 1); } /* Update boundary register */ bnry = nicwrap(cp->next_pkt - 1); outnic(BNRY, bnry); } return(len); /* Return length excl. CRC */ } /* Send Ethernet packet given len excl. CRC, return 0 if NIC is busy */ WORD put_etherne(WORD dtype, void *pkt, WORD len) { CONFIGNE *cp; cp = &configs[dtype & NETNUM_MASK]; ebase = cp->ebase; if (!ebase || innic(CMDR) & 4) /* If still Txing, return 0 */ len = 0; else if (pkt) { /* If last Tx is complete.. */ len = minw(MAXFRAME, maxw(MINFRAME, len)); /* Constrain length */ memcpy((BYTE *)pkt+MACLEN, cp->myeth, MACLEN); /* Set source addr */ outnic(ISR, 0x0a); /* Clear interrupt flags */ outnic(TBCR0, len & 0xff); /* Set Tx length regs */ outnic(TBCR1, len >> 8); putnic(TXSTART<<8, pkt, len); outnic(CMDR, 0x24); /* Transmit the packet */ } return(len); } /* Reset the Ethernet card, if 'cold' start, get my 6-byte address */ void resetnic(CONFIGNE *cp, char cold) { int i; BYTE temp[MACLEN*2]; outnic(CMDR, 0x21); /* Stop, DMA abort, page 0 */ delay(2); /* ..wait to take effect */ outnic(DCR, DCRVAL); outnic(RBCR0, 0); /* Clear remote byte count */ outnic(RBCR1, 0); outnic(RCR, 0x20); /* Rx monitor mode */ outnic(TCR, 0x02); /* Tx internal loopback */ outnic(TPSR, TXSTART); /* Set Tx start page */ outnic(PSTART, RXSTART); /* Set Rx start, stop, boundary */ outnic(PSTOP, RXSTOP); outnic(BNRY, (BYTE)(RXSTOP-1)); outnic(ISR, 0xff); /* Clear interrupt flags */ outnic(IMR, 0); /* Mask all interrupts */ if (cold) { outnic(CMDR, 0x22); /* Start NIC, DMA abort */ getnic(0, temp, 12); /* Get 6-byte addr */ for (i=0; i myeth[i] = temp[WORDMODE ? i+i : i]; } outnic(CMDR, 0x61); /* Stop, DMA abort, page 1 */ delay(2); for (i=0; i<6; i++) /* Set Phys addr */ outnic(PAR0+i, cp->myeth[i]); for (i=0; i<8; i++) /* Multicast accept-all */ outnic(MAR0+i, 0xff); outnic(CURR, RXSTART+1); /* Set current Rx page */ cp->next_pkt = RXSTART + 1; outnic(CMDR, 0x20); /* DMA abort, page 0 */ outnic(RCR, promisc ? 0x14 : 0x04); /* Allow broadcasts, maybe all pkts */ outnic(TCR, 0); /* Normal Tx operation */ outnic(ISR, 0xff); /* Clear interrupt flags */ outnic(CMDR, 0x22); /* Start NIC */ } /* Get a packet from a given address in the NIC's RAM */ void getnic(WORD addr, BYTE data[], WORD len) { register int count; register WORD *dataw, dataport; count = WORDMODE ? len>>1 : len; /* Halve byte count if word I/P */ dataport = ebase + DATAPORT; /* Address of NIC data port */ outnic(ISR, 0x40); /* Clear remote DMA interrupt flag */ outnic(RBCR0, len&0xff); /* Byte count */ outnic(RBCR1, len>>8); outnic(RSAR0, addr&0xff); /* Data addr */ outnic(RSAR1, addr>>8); outnic(CMDR, 0x0a); /* Start, DMA remote read */ #if WORDMODE dataw = (WORD *)data; /* Use pointer for speed */ while(count--) /* Get words */ *dataw++ = inpw(dataport); if (len & 1) /* If odd length, do last byte */ *(BYTE *)dataw = inp(dataport); #else while(count--) /* Get bytes */ *data++ = inp(dataport); #endif } /* Put a packet into a given address in the NIC's RAM */ void putnic(WORD addr, BYTE data[], WORD len) { register int count; register WORD *dataw, dataport; len += len & 1; /* Round length up to an even value */ count = WORDMODE ? len>>1 : len; /* Halve byte count if word O/P */ dataport = ebase + DATAPORT; /* Address of NIC data port */ outnic(ISR, 0x40); /* Clear remote DMA interrupt flag */ outnic(RBCR0, len&0xff); /* Byte count */ outnic(RBCR1, len>>8); outnic(RSAR0, addr&0xff); /* Data addr */ outnic(RSAR1, addr>>8); outnic(CMDR, 0x12); /* Start, DMA remote write */ #if WORDMODE /* Word transfer? */ dataw = (WORD *)data; while(count--) outpw(dataport, *dataw++); /* O/P words */ #else while(count--) /* O/P bytes */ outp(dataport, *data++); #endif count = 10000; /* Done: must ensure DMA complete */ while(count && (innic(ISR)&0x40)==0) count--; } /* Wrap an NIC Rx page number */ BYTE nicwrap(int page) { if (page >= RXSTOP) page += RXSTART - RXSTOP; else if (page < RXSTART) page += RXSTOP - RXSTART; return(page); } /* Input a byte from a NIC register */ BYTE innic(int reg) { return(inp((WORD)(ebase+reg))); } /* Output a byte to a NIC register */ void outnic(int reg, int b) { outp((WORD)(ebase+reg), b); } /* EOF */