📄 etherne.c
字号:
/* NE2000-compatible net card drivers for 'TCP/IP Lean' (c) Iosoft Ltd. 2000
This software is only licensed for distribution with the book 'TCP/IP Lean',
and may only be used for personal experimentation by the purchaser
of that book, on condition that this copyright notice is retained.
For commercial licensing, contact license@iosoft.co.uk
This is experimental software; use it entirely at your own risk. The author
offers no warranties of any kind, including its fitness for purpose. */
/*
** v0.01 JPB 19/6/97
** v0.02 JPB 19/6/97 Added SPIBB code
** v0.03 JPB 20/6/97 Changed I/O address from 340h to 280h
** Added mem status byte clear
** v0.04 JPB 31/7/97 Added experimental whole-packet read
** v0.05 JPB 15/8/97 Fixed bug in length calculation for odd-length packets
** v0.06 JPB 9/1/98 Added assembly-language insert
** v0.07 JPB 13/1/97 Poll Rx interrupt flag to see if packet arrived
** v0.08 JPB 11/12/98 Added base addr. and 16-bit flag to 'etinit'
** Removed SPIBB driver code
** v0.10 JPB 28/6/99 Significant rework & simplification of the code
** Now works OK on fast CPUs!
** Reduced RAM size for 8-bit mode (p43 of UM9008 data sheet)
** v0.11 JPB 20/7/99 Added delay between detecting Rx interrupt & polling regs
** v0.12 JPB 21/7/99 Added interrupt capability
** v0.13 JPB 22/7/99 Added 'DMA complete' check at end of 'putnic'
** v0.14 JPB 22/7/99 Minor speed improvement to 'getnic' and 'putnic'
** v0.15 JPB 22/7/99 Removed unused local vars
** v0.16 JPB 29/10/99 Renamed functions for TCPIPFS compatibility
** Rxpacket now returns length excl. CRC
** v0.17 JPB 10/11/99 Restored inline I/O code
** v0.18 JPB 15/11/99 Added Tx and Rx circular buffers
** v0.19 JPB 16/11/99 Removed Starlan length hack - does more harm than good!
** v0.20 JPB 16/11/99 Removed interrupt code
** v0.21 JPB 17/11/99 Replaced min() with minw() or mini()
** v0.22 JPB 7/1/00 Added 'maxlen' to initialisation
** v0.23 JPB 17/1/00 Removed 'maxlen' again!
** v0.24 JPB 20/1/00 Added support for multiple cards
** v0.25 JPB 3/7/00 Revised header for CD
*/
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -