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.nextnext_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; imyeth[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 */