📄 ne2000.c
字号:
//
// HWRamTest - figure out how much adapter RAM there is.
//
static BOOL
HWRamTest(void)
{
DWORD ramEnd;
BOOL bRet;
#define MAX_RAM_BASE 0x10000
// find some RAM starting at 1K thru 64K. if it's greater then 64K, then
// assume it isn't there.
ramEnd = 0;
HWStopAdapter();
for (srambase = 1024; srambase < MAX_RAM_BASE; srambase += 1024) {
if (HWCheckRam(srambase, 4)) {
// found the starting point, now find out how much RAM there is.
// assume it will increase in 1K chunks.
for (ramEnd = srambase; !(ramEnd & 0xffff0000); ramEnd += 1024) {
// RAM ends at the first location that fails the RAM test.
if (!HWCheckRam(ramEnd, 4)) {
pstop = (BYTE)(ramEnd>>8);
break;
}
}
break;
}
}
// check for failure
if ((srambase > MAX_RAM_BASE) || (srambase == ramEnd) || (ramEnd == 0)) {
EdbgOutputDebugString("EDBG:NE2000:HWRamTest fail. srambase = 0x%X, ramEnd = 0x%X\r\n",
srambase, ramEnd);
bRet = FALSE;
goto hwrt_done;
}
// if ramEnd is >= 64K, then back off one 256 byte chunk to avoid the 16
// bit wrap around.
if (ramEnd & 0xffff0000) {
pstop = 0xff;
}
//
// Allocate 1 packet for transmit
//
tbb_start = (BYTE)(srambase>>8);
pstart = tbb_start+6; // Allocate 6 256 byte buffers for transmit
// compute sramsize
sramsize = ramEnd - srambase;
EdbgOutputDebugString("EDBG:NE2000:HWRamTest: srambase: 0x%X, sramsize: 0x%X, pstart: 0x%B\r\n",
srambase, sramsize, pstart);
// check the full RAM bank
if (!HWCheckRam(srambase,sramsize)) {
EdbgOutputDebugString("EDBG:NE2000:HWRamTest full RAM check failed.\r\n");
bRet = FALSE;
goto hwrt_done;
}
bRet = TRUE;
hwrt_done:
HWStartAdapter();
return bRet;
} // HWRamTest
//
// HWClearMCRegs - Clear the adapter's multicast address registers.
//
static void
HWClearMCRegs(void)
{
DWORD j;
UsePage1();
j = NIC_MC_ADDR;
// Now clear out all multicast address registers.
while (j < NIC_MC_ADDR+8) {
WriteByte(j, 0);
j++;
}
UsePage0();
} // HWClearMCRegs
//
// HWInit - completely initialize the hardware and leave it in a
// state that is ready to transmit and receive packets.
//
static BOOL
HWInit(void)
{
int n;
int temp1,temp2,temp3;
WriteCmd(NIC_AbortDmaStop); // Stop the NIC
// Initialize Data Configuration register for auto remove.
// This gets reset later on.
WriteByte(NIC_DATA_CONFIG, NIC_DCR_FIFO|NIC_DCR_AUTO_INIT);
// Bug workaround for SRAM memory protection.
WriteByte(NIC_XMIT_START, 0xA0);
WriteByte(NIC_XMIT_CONFIG, 0);
WriteByte(NIC_RCV_CONFIG, NIC_RECEIVE_MONITOR_MODE);
WriteByte(NIC_PAGE_START, 4);
WriteByte(NIC_BOUNDARY, 4);
WriteByte(NIC_PAGE_STOP, 0xff);
WriteByte(NIC_XMIT_COUNT_LSB, 0x3c);
WriteByte(NIC_XMIT_COUNT_MSB, 0);
WriteByte(NIC_INTR_STATUS, 0xff);
UsePage1Stop();
WriteByte(NIC_CURRENT, 4);
UsePage0();
// If command register reflects the last command assume it is OK
if (ReadCmd() != NIC_Page0) {
EdbgOutputDebugString("EDBG:NE2000Init:HWInit failed to read cmd reg\r\n");
goto hw_dead;
}
WriteByte(NIC_RMT_COUNT_LSB, 55); // initialization errata
WriteCmd(NIC_RemoteDmaRd);
HWStartAdapter();
if (!HWRamTest()) { // see how much adapter RAM
EdbgOutputDebugString("EDBG:NE2000Init:HWInit HWRamTest failed\r\n");
goto hw_dead;
}
WriteCmd(NIC_AbortDmaStop);
// Read the ethernet address
// The NE2000 address PROM only decodes even addresses, so you
// have to read WORDs and discard the high byte.
WriteByte(NIC_RMT_COUNT_LSB, 12);
WriteByte(NIC_RMT_COUNT_MSB, 0);
WriteByte(NIC_RMT_ADDR_LSB, 0);
WriteByte(NIC_RMT_ADDR_MSB, 0);
WriteCmd(NIC_RemoteDmaRd);
// EdbgOutputDebugString("About to read MAC address .. \r\n");
// msWait(5000);
temp1 = ReadLong(NIC_RACK_NIC);
temp2 = ReadLong(NIC_RACK_NIC);
temp3 = ReadLong(NIC_RACK_NIC);
ethernetaddr[0] = (temp1 & 0x000000FF);
ethernetaddr[1] = (temp1 & 0x00FF0000) >> 16;
ethernetaddr[2] = (temp2 & 0x000000FF);
ethernetaddr[3] = (temp2 & 0x00FF0000) >> 16;
ethernetaddr[4] = (temp3 & 0x000000FF);
ethernetaddr[5] = (temp3 & 0x00FF0000) >> 16;
EdbgOutputDebugString("MAC address 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\r\n",ethernetaddr[0],ethernetaddr[1], ethernetaddr[2], ethernetaddr[3], ethernetaddr[4], ethernetaddr[5]);
/* for (n = 0; n < 6; n++) {
ethernetaddr[n] =
temp = ReadLong(NIC_RACK_NIC);
}
*/
// copy node address to page1 physical address registers
UsePage1Stop();
for (n = 0; n < 6; n++) {
WriteByte(NIC_PHYS_ADDR+n, ethernetaddr[n]);
}
HWClearMCRegs(); // Init multicast registers to 0
WriteCmd(NIC_AbortDmaStop); // back to page0
// Initialize the page start, stop, and boundary registers based on the
// results of ram_test().
WriteByte(NIC_PAGE_START, pstart);
WriteByte(NIC_BOUNDARY, (BYTE)(pstart+1));
WriteByte(NIC_PAGE_STOP, pstop);
UsePage1Stop();
WriteByte(NIC_CURRENT, (BYTE)(pstart+1));
WriteCmd(NIC_AbortDmaStop); // back to page0
NextPage = pstart+1;
tbb_start = (BYTE)(srambase >> 8);
memset(erase_header, 0xff, sizeof(erase_header));
return TRUE;
hw_dead:
WriteCmd(NIC_AbortDmaStop); // stop NIC
return FALSE;
} // HWinit
// This is called to initialze the ethernet low level driver. The base address of the ethernet hardware
// is passed into the routine. The routine will return TRUE for a successful initialization.
BOOL
NE2000Init( BYTE *pbBaseAddress, DWORD dwMultiplier, USHORT MacAddr[3])
{
BOOL bRet;
int n;
PBYTE pDst;
PBYTE pSrc;
EdbgOutputDebugString("+EDBG:NE2000Init\r\n");
#ifdef USE_ISA_PNP_STUFF
pbBaseAddress = NE2000InitISAPNP(DEFAULT_IOBASE, DEFAULT_IRQ);
#endif // USE_ISA_PNP_STUFF
pbEthernetBase = pbBaseAddress;
EdbgOutputDebugString("EDBG:NE2000Init using I/O range at 0x%X\r\n", pbBaseAddress);
InitRcvQueue();
bRet = HWInit();
pDst = (PBYTE)MacAddr;
pSrc = ethernetaddr;
for (n = 6; n; n--) {
*pDst++ = *pSrc++;
}
EdbgOutputDebugString("-EDBG:NE2000Init\r\n");
return bRet;
} // NE2000Init
// Interrupts left disabled at init, call this function to turn them on
void
NE2000EnableInts()
{
//EdbgOutputDebugString("NE2000EnableInts\n");
bIntMask = IMR_RCV|IMR_XMIT|IMR_RCV_ERR|IMR_XMIT_ERR|IMR_OVERFLOW;
UsePage0();
WriteByte(NIC_INTR_MASK, bIntMask);
}
void
NE2000DisableInts()
{
//EdbgOutputDebugString("NE2000DisableInts\n");
bIntMask = 0;
UsePage0();
WriteByte(NIC_INTR_MASK, bIntMask);
}
//
// HandleBufferOverflow - Perform the first 7 steps of the 11 step process to
// recover from receive buffer overflow. Step 8 is to remove packets from the
// buffer which HandleReceive does. A flag is set to tell HandleReceive to do
// steps 9-11.
//
// Returns TRUE if current transmit needs resend.
//
static BOOL
HandleBufferOverflow(void)
{
BOOL bResend = FALSE;
#ifdef DEBUG_SINGLE_CHAR
EdbgOutputDebugString("V"); // overflow
#endif
#define STOP_LOOP_CNT 6000
// 1. remember TXP bit (it's already in _command_reg)
WriteCmd(NIC_AbortDmaStop); // 2. take the controller offline
iodelay(STOP_LOOP_CNT); // 3. Wait 1.6ms for NIC to stop
WriteByte(NIC_RMT_COUNT_LSB, 0); // 4. clear the remote byte count
WriteByte(NIC_RMT_COUNT_MSB, 0);
// The transmit may have completed while waiting for the NIC to stop
int_status |= ReadByte(NIC_INTR_STATUS); // BUGBUG???
if (command_reg & NIC_CMD_XMIT) {
if (int_status & (NIC_ISR_PACKET_XMITD|NIC_ISR_XMIT_ERR)) {
bResend = TRUE;
}
}
WriteByte(NIC_INTR_STATUS, int_status); // ack ints
WriteByte(NIC_XMIT_CONFIG, NIC_TCR_LOOPBACK1); // 6. place NIC in loopback mode.
UsePage0(); // 7. restart in loopback mode
overflowrestartflag = 1;
return bResend;
} // HandleBufferOverflow
//
// alignframe - sometimes the frame gets shifted right by a WORD.
// Fix up the frame header and return with BX=packet offset
// Increment DI to track alignments done/undone.
//
// input: called == 0 -> first time in, shift frame right
// called == 1 -> second time in, shift frame left
//
// side effects: packet header (at rcv_status) is shifted around.
// first case: 123456 -> 561234
// second case: 123456 -> 345612
//
static void
alignframe(int called)
{
BYTE tmp0;
BYTE tmp1;
if (called) {
// shift the receive header left by a WORD
tmp0 = rcv_dest_addr0;
tmp1 = rcv_dest_addr1;
rcv_dest_addr0 = rcv_frame_len0;
rcv_dest_addr1 = rcv_frame_len1;
rcv_frame_len0 = rcv_status;
rcv_frame_len1 = rcv_next_buff;
rcv_status = tmp0;
rcv_next_buff = tmp1;
} else {
// first time in for this packet, shift it right.
tmp0 = rcv_status;
tmp1 = rcv_next_buff;
rcv_status = rcv_frame_len0;
rcv_next_buff = rcv_frame_len1;
rcv_frame_len0 = rcv_dest_addr0;
rcv_frame_len1 = rcv_dest_addr1;
rcv_dest_addr0 = tmp0;
rcv_dest_addr1 = tmp1;
}
} // alignframe
//
// check_rcv_header - check status and length fields and possibly call alignframe.
//
// Return 0, 2, or 0xffff for failure
//
static WORD
check_rcv_header(void)
{
int alignframecalls = 0;
BYTE prev_len0;
BYTE prev_len1;
WORD len;
crh_restart:
if (alignframecalls >= 2) {
return 0xffff;
}
if (rcv_status & 0x5E) {
// receive status bits look wrong
//EdbgOutputDebugString("check_rcv_header: rcv_status = %B\r\n", rcv_status);
alignframe(alignframecalls++);
}
// If it's a multicast or broadcast frame and we haven't realigned the
// header, then see if the first byte of the destination address has its
// lsb set. If it doesn't then it's in error.
if (rcv_status & NIC_RCV_STAT_MC_BC) {
if (!alignframecalls) {
if (!(rcv_dest_addr0 & 1)) {
//EdbgOutputDebugString("check_rcv_header: rcv_dest_addr0 = %B\r\n", rcv_dest_addr0);
alignframe(alignframecalls++);
goto crh_restart;
}
}
}
prev_len0 = rcv_frame_len0;
prev_len1 = rcv_frame_len1;
if (rcv_frame_len0 == rcv_frame_len1) {
// If the length bytes are the same, the low byte may have been copied into the high byte.
// We will compute the packet length based on rcv_next_buff, NextPage and the low byte
// Calculate high byte of pkt length: (in high speed systems, the low
// byte of the packet length gets copied into rcv_frame_len0 and rcv_frame_len1)
rcv_frame_len1 = rcv_next_buff - NextPage - 1;
if (rcv_frame_len1 & 0x80) {
rcv_frame_len1 = (pstop - NextPage) + (rcv_next_buff - pstart) - 1;
}
if (rcv_frame_len0 > 0xFC) {
rcv_frame_len1++;
rcv_frame_len0 = 0;
}
len = (WORD)(rcv_frame_len0 + (rcv_frame_len1<<8));
//EdbgOutputDebugString("check_rcv_header: packet len = %d\r\n", len);
}
len = (WORD)(rcv_frame_len0 + (rcv_frame_len1<<8));
// if ((len > MAX_FRAME_SIZE + NIC_HEADER_LEN) || (len < MIN_FRAME_SIZE + NIC_HEADER_LEN)) {
if (len > MAX_FRAME_SIZE + NIC_HEADER_LEN) {
rcv_frame_len0 = prev_len0;
rcv_frame_len1 = prev_len1;
//EdbgOutputDebugString("check_rcv_header: packet len = %d.\r\n", len);
alignframe(alignframecalls++);
goto crh_restart;
}
if ((rcv_next_buff < pstart) || (rcv_next_buff > pstop)) {
alignframe(alignframecalls++);
goto crh_restart;
}
return (alignframecalls == 1) ? 2 : 0;
} // check_rcv_header
static void
HWSetBoundary(BYTE next)
{
if (next < pstart) {
//EdbgOutputDebugString("HWSetBoundary: next = %B\r\n", next);
next = pstart;
}
if (next > pstop) {
//EdbgOutputDebugString("HWSetBoundary: next = %B\r\n", next);
next = pstart;
}
WriteByte(NIC_BOUNDARY, (BYTE)((next == pstart) ? pstop-1 : next-1));
}
static void InitRcvQueue(void)
{
DWORD n;
for (n = 0; n < RCV_Q_SIZE; n++) {
g_rcv_list[n].re_state = RCV_FREE;
}
g_rcv_index = 0;
g_rcv_next = 0;
g_rcv_cnt = 0;
}
static BOOL
QueueRcv(
WORD packetlen,
WORD packetptr,
BYTE nextbuff
)
{
PRCV_ENTRY prcv = &(g_rcv_list[g_rcv_index]);
if (prcv->re_state != RCV_FREE) {
//EdbgOutputDebugString("QueueRcv: No free receives!\r\n");
return FALSE;
}
prcv->re_state = RCV_USED;
prcv->re_next = nextbuff;
prcv->re_len = packetlen;
prcv->re_ptr = packetptr;
//EdbgOutputDebugString("QueueRcv: Queued %d at 0x%x, len %d\r\n", g_rcv_index, packetptr, packetlen);
g_rcv_cnt++;
g_rcv_index++;
if (g_rcv_index == RCV_Q_SIZE) {
g_rcv_index = 0;
}
return TRUE;
} // QueueRcv
//
// HandleReceive - Check that there is a packet in the receive buffer and
// check its length and status. Then queue the receive if
// the packet is OK.
//
static void HandleReceive(void)
{
BYTE rsr; // receive status register
WORD packetlen;
WORD packetptr;
int loopcnt;
WORD adjust;
#define MAX_RCV_CNT 32
loopcnt = MAX_RCV_CNT;
//EdbgOutputDebugString("+HandleReceive\r\n");
// Loop looking for more receive packets
hr_more_packets:
if (!loopcnt) {
//EdbgOutputDebugString("HandleReceive Skipped %d packets\r\n", MAX_RCV_CNT);
goto hr_exit;
}
loopcnt--;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -