📄 ne2000.c
字号:
// If current_page register is not equal to NextPage
// then we have a packet in the ring buffer.
UsePage1();
new_current_page = ReadByte(NIC_CURRENT);
UsePage0();
if ((int_status & NIC_ISR_RCV_ERR) && (!overflowrestartflag)) {
rsr = ReadByte(NIC_RCV_STATUS);
if (!(rsr & RSR_PACKET_OK)) {
//EdbgOutputDebugString("HandleReceive NIC_ISR_RCV_ERR (rsr = %B)\r\n", rsr);
INSB((NextPage<<8), sizeof(rcv_header), rcv_header);
#ifdef NE2000_DUMP_FRAMES
DumpNE2000Header();
#endif
/*
if (rsr & RSR_CRC_ERROR) {
EdbgOutputDebugString("CRC Error\r\n");
}
if (rsr & RSR_MULTICAST) {
EdbgOutputDebugString("MULTICAST\r\n");
}
if (rsr & RSR_DISABLED) {
EdbgOutputDebugString("Receiver is disabled\r\n");
}
if (rsr & RSR_DEFERRING) {
EdbgOutputDebugString("Receiver is deferring\r\n");
}
*/
#ifdef NE2000_DUMP_FRAMES
DumpEtherFrame(&(rcv_dest_addr0), 14);
#endif
InitRcvQueue();
HWSetBoundary(new_current_page);
NextPage = new_current_page;
goto hr_exit;
}
}
if (new_current_page == NextPage) {
//EdbgOutputDebugString("HandleReceive No new packets\r\n");
goto hr_exit;
}
// There is another packet in the receive buffer.
// Look at the packet's header
INSB((NextPage<<8), sizeof(rcv_header), rcv_header);
if ((adjust = check_rcv_header()) == 0xffff) {
//EdbgOutputDebugString("HandleReceive check_rcv_header() failed!\r\n");
// Advance receive buffer pointer on packet errors
NextPage = new_current_page;
goto hr_exit;
}
packetlen = (WORD)(rcv_frame_len1<<8)+(WORD)rcv_frame_len0 - NIC_HEADER_LEN;
rcv_next_buff = NextPage + rcv_frame_len1 + 1;
if (rcv_next_buff > pstop) {
rcv_next_buff -= pstop - pstart;
}
//
// Filter out non-ARP broadcast packets.
//
if (rcv_status & NIC_RCV_STAT_MC_BC) {
if ((dwConfigOptions & OPT_BROADCAST_FILTERING) &&
((rcv_header[16] != 8) || (rcv_header[17] != 6))) {
NextPage = rcv_next_buff;
//EdbgOutputDebugString("HandleReceive Dropping non-ARP broadcast packet!\r\n");
#ifdef NE2000_DUMP_FRAMES
DumpEtherFrame(&(rcv_dest_addr0), 14);
#endif
goto hr_more_packets;
}
}
packetptr = (NextPage << 8) + NIC_HEADER_LEN + adjust;
if (QueueRcv(packetlen, packetptr, rcv_next_buff)) {
NextPage = rcv_next_buff;
goto hr_more_packets;
}
hr_exit: // Done looking for receive packets
if (!g_rcv_cnt) {
//
// We have caught up with receive packets, advance the boundary ptr
//
HWSetBoundary(NextPage);
}
if (overflowrestartflag) {
// Do steps 9 and 10 of overflow recovery
WriteByte(NIC_INTR_STATUS, NIC_ISR_OVERWRITE); // 9. reset the OVW bit
WriteByte(NIC_XMIT_CONFIG, NIC_TCR_NORMAL); // 10. Get out of loopback mode.
overflowrestartflag = 0;
}
//EdbgOutputDebugString("-HandleReceive\r\n");
} // HandleReceive
static void HandleTransmit(void)
{
// check for transmit errors
if ((int_status & NIC_ISR_XMIT_ERR) || (!(ReadByte(NIC_XMIT_STATUS) & NIC_TSR_SUCCESS))) {
iodelay(15);
WriteByte(NIC_XMIT_CONFIG, NIC_TCR_LOOPBACK1); // place NIC in loopback mode.
UsePage0(); // start in loopback mode.
ReadCmd();
WriteByte(NIC_XMIT_CONFIG, NIC_TCR_NORMAL); // get out of loopback mode.
UsePage0(); // start the NIC
ReadCmd();
}
transmitting = 0;
}
void NE2000_ISR(void)
{
#define ISR_LOOP_MAX 32
int loopcnt = ISR_LOOP_MAX;
command_reg = ReadCmd();
UsePage0();
int_status = ReadByte(NIC_INTR_STATUS);
while (int_status & NIC_ISR_MOREWORK) {
WriteByte(NIC_INTR_STATUS, int_status); // ack the interrupts
//
// Respond to the interrupt status register bits.
//
if (int_status & NIC_ISR_OVERWRITE) {
HandleBufferOverflow();
}
//if (int_status & (NIC_ISR_PACKET_RCVD|NIC_ISR_RCV_ERR)) {
HandleReceive();
//}
if (int_status & (NIC_ISR_PACKET_XMITD|NIC_ISR_XMIT_ERR)) {
HandleTransmit();
}
if (!-- loopcnt)
break;
command_reg = ReadCmd();
int_status = ReadByte(NIC_INTR_STATUS);
}
} // NE2000_ISR
DWORD
NE2000GetPendingInts()
{
//EdbgOutputDebugString("+NE2000GetPendingInts\r\n");
NE2000_ISR();
//EdbgOutputDebugString("-NE2000GetPendingInts\r\n");
if (g_rcv_cnt) {
#ifdef DEBUG_SINGLE_CHAR
EdbgOutputDebugString("R"); // indicating a received packet
#endif
return INTR_TYPE_RX;
}
#ifdef DEBUG_SINGLE_CHAR
EdbgOutputDebugString("B"); // discarding non-ARP broadcast traffic.
#endif
return 0;
} // NE2000GetPendingInts
//
// This routine is polled to find out if a frame has been received. If there are no frames
// in the RX FIFO, the routine will return 0. If there was a frame that was received correctly,
// it will be stored in pwData, otherwise it will be discarded.
//
UINT16
NE2000GetFrame(BYTE *pbData, UINT16 *pwLength )
{
PRCV_ENTRY prcv;
WORD len;
//EdbgOutputDebugString("+NE2000GetFrame\r\n");
EDBG_DEBUGLED(LED_GETFRAME_ENTRY,0);
len = *pwLength;
*pwLength = 0;
if (!g_rcv_cnt) {
NE2000_ISR();
}
if (g_rcv_cnt) {
prcv = &(g_rcv_list[g_rcv_next]);
if (prcv->re_state == RCV_USED) {
//EdbgOutputDebugString("NE2000GetFrame: reading %d (ptr 0x%x, len %d)\r\n",
// g_rcv_next, prcv->re_ptr, prcv->re_len);
if (prcv->re_len < len) {
len = prcv->re_len;
}
INSB(prcv->re_ptr, len, pbData);
HWSetBoundary(prcv->re_next);
*pwLength = len;
prcv->re_state = RCV_FREE;
g_rcv_cnt--;
g_rcv_next++;
if (g_rcv_next == RCV_Q_SIZE) {
g_rcv_next = 0;
}
}
} else {
#ifdef DEBUG_SINGLE_CHAR
EdbgOutputDebugString("Z"); // Receive buffer empty
#endif
}
//EdbgOutputDebugString("-NE2000GetFrame *pwLength = %d\r\n", *pwLength);
EDBG_DEBUGLED(LED_GETFRAME_EXIT,0);
return *pwLength;
} // NE2000GetFrame()
//
// This routine should be called with a pointer to the ethernet frame data. It is the caller's
// responsibility to fill in all information including the destination and source addresses and
// the frame type. The length parameter gives the number of bytes in the ethernet frame.
// The routine will not return until the frame has been transmitted or an error has occured. If
// the frame transmits successfully, 0 is returned. If an error occured, a message is sent to
// the serial port and the routine returns non-zero.
//
UINT16
NE2000SendFrame( BYTE *pbData, DWORD dwLength )
{
int nIters;
//EdbgOutputDebugString("+NE2000SendFrame\r\n");
//
// Loop here until the request is satisfied, or we timeout
//
for (nIters = 0; transmitting; nIters ++) {
iodelay(20);
NE2000_ISR();
if (nIters > 1000) {
EdbgOutputDebugString("NE2000SendFrame Timed out waiting for transmit buffers\n");
//
// 2 seconds ought to be enough to transmit a packet!!! Reset for transmit errors
//
iodelay(15);
WriteByte(NIC_XMIT_CONFIG, NIC_TCR_LOOPBACK1); // place NIC in loopback mode.
UsePage0(); // start in loopback mode.
ReadCmd();
WriteByte(NIC_XMIT_CONFIG, NIC_TCR_NORMAL); // get out of loopback mode.
UsePage0(); // start the NIC
ReadCmd();
HWReset();
transmitting = 0;
}
}
curr_xmit_len = (WORD)dwLength;
//EdbgOutputDebugString("NE2000SendFrame %d byte packet\r\n", curr_xmit_len);
#ifdef DEBUG_SINGLE_CHAR
EdbgOutputDebugString("S"); // Send packet
#endif
OUTSB(srambase, curr_xmit_len, pbData);
WriteByte(NIC_XMIT_START, tbb_start);
if (curr_xmit_len < 60) {
curr_xmit_len = 60;
}
if (curr_xmit_len > 1536) {
curr_xmit_len = 1536;
}
WriteByte(NIC_XMIT_COUNT_LSB, (BYTE)curr_xmit_len);
WriteByte(NIC_XMIT_COUNT_MSB, (BYTE)(curr_xmit_len>>8));
transmitting = 1;
WriteCmd(NIC_Transmit);
iodelay(80);
NE2000_ISR();
//EdbgOutputDebugString("-NE2000SendFrame\r\n");
return 0;
} // NE2000SendFrame()
#ifdef NE2000_DUMP_FRAMES
static void
DumpEtherFrame( BYTE *pFrame, WORD cwFrameLength )
{
int i,j;
EdbgOutputDebugString( "Frame Buffer Address: 0x%X\r\n", pFrame );
EdbgOutputDebugString( "To: %B:%B:%B:%B:%B:%B From: %B:%B:%B:%B:%B:%B Type: 0x%H Length: %u\r\n",
pFrame[0], pFrame[1], pFrame[2], pFrame[3], pFrame[4], pFrame[5],
pFrame[6], pFrame[7], pFrame[8], pFrame[9], pFrame[10], pFrame[11],
ntohs(*((UINT16 *)(pFrame + 12))), cwFrameLength );
for( i = 0; i < cwFrameLength / 16; i++ ) {
for( j = 0; j < 16; j++ )
EdbgOutputDebugString( " %B", pFrame[i*16 + j] );
EdbgOutputDebugString( "\r\n" );
}
for( j = 0; j < cwFrameLength % 16; j++ )
EdbgOutputDebugString( " %B", pFrame[i*16 + j] );
EdbgOutputDebugString( "\r\n" );
}
static void
DumpNE2000Header(void)
{
EdbgOutputDebugString( "NE2000 Frame Header at %B: Status: %B, Next Buffer: %B, Len0: %B, Len1: %B\r\n",
NextPage, rcv_status, rcv_next_buff, rcv_frame_len0, rcv_frame_len1);
}
#endif // NE2000_DUMP_FRAMES
BOOL
NE2000ReadEEPROM( UINT16 EEPROMAddress , UINT16 *pwVal)
{
return FALSE;
}
BOOL
NE2000WriteEEPROM( UINT16 EEPROMAddress, UINT16 Data )
{
return FALSE;
}
//
// This routine is used by the OAL to configure the debug Ethernet driver. Currently
// the following options are defined:
// OPT_BROADCAST_FILTERING -- If set, filter out all broadcast packets except ARP packets
//
DWORD
NE2000SetOptions(DWORD dwOptions)
{
DWORD dwOldOptions = dwConfigOptions;
dwConfigOptions = dwOptions;
return dwOldOptions;
}
#ifdef USE_ISA_PNP_STUFF
BYTE *
NE2000InitISAPNP(DWORD dwIOBase, DWORD dwIRQ)
{
ULONG nTmpVal = 0;
ISA_PNP_CONFIG PnPInfo;
ISA_PNP_RESOURCES PnPResources;
int nCSN;
DWORD nLogicalDevice;
DWORD i;
BOOL bFoundIt;
ULONG ulReturn;
BYTE * pbRet;
EdbgOutputDebugString("NE2000InitISAPNP: Init\r\n");
bFoundIt = FALSE;
pbRet = (BYTE *) dwIOBase;
//
// Scan the PnP ISA cards for an NE2000
//
for (nCSN = 1; ; nCSN++) {
ulReturn = ISAGetBusDataByOffset(0, nCSN << 8, &PnPInfo, 0, sizeof(PnPInfo));
if (ulReturn == 0) {
// Couldn't even get the card data, though it's supposed to exist.
EdbgOutputDebugString("NE2000InitISAPNP: Couldn't find a ISA PnP NE2000.\r\n");
return NULL;
}
switch (PnPInfo.VendorID) {
case 0x07052201: // LINKSYS
break;
default:
//
// Not a recognized NE2000 ISA PNP card, skip to the next CSN...
//
continue;
}
EdbgOutputDebugString("NE2000InitISAPNP: Found NE2000 ISA PNP card: serial# 0x%x\r\n", PnPInfo.SerialNumber);
for (nLogicalDevice = 0; nLogicalDevice < PnPInfo.NumberLogicalDevices; nLogicalDevice++) {
EdbgOutputDebugString("NE2000InitISAPNP: LogicalDeviceID[%d] = 0x%x\r\n",
nLogicalDevice, PnPInfo.LogicalDeviceInfo[nLogicalDevice].LogicalDeviceID);
switch (PnPInfo.LogicalDeviceInfo[nLogicalDevice].LogicalDeviceID) {
case 0x7052201: // LINKSYS ISA PNP NE2000
bFoundIt = TRUE;
break;
default:
continue;
}
break;
}
if (bFoundIt) {
break;
}
}
EdbgOutputDebugString("Out of scan loop\r\n");
if (!bFoundIt) {
EdbgOutputDebugString("NE2000InitISAPNP: Couldn't find a ISA PnP NE2000\r\n");
return NULL;
}
//
// Get the resource information for this card.
//
ulReturn = ISAGetBusDataByOffset(0, (nCSN << 8) | nLogicalDevice, &PnPResources, 1, sizeof(PnPResources));
if (ulReturn == 0) {
EdbgOutputDebugString("NE2000InitISAPNP: Couldn't read resources\r\n");
return NULL;
}
EdbgOutputDebugString("After Reading 1st.\r\n");
//if (!(PnPResources.Flags & ISA_PNP_RESOURCE_FLAG_ACTIVE)) {
//
// Need to set the resources and activate the device
//
EdbgOutputDebugString("Setup the resources\r\n");
PnPResources.IoPortDescriptors[0] = (USHORT) dwIOBase;
PnPResources.IRQDescriptors[0].IRQLevel = (UCHAR) dwIRQ;
PnPResources.IRQDescriptors[0].IRQType = 2; // High Edge Triggered
PnPResources.Flags = ISA_PNP_RESOURCE_FLAG_ACTIVE;
EdbgOutputDebugString("After Assigning.\r\n");
EdbgOutputDebugString("About to Set the resources\r\n");
ulReturn = ISASetBusDataByOffset(0, (nCSN << 8) | nLogicalDevice, &PnPResources, 1, sizeof(PnPResources));
if (ulReturn == 0) {
EdbgOutputDebugString("NE2000InitISAPNP: Error writing resources\r\n");
return NULL;
}
EdbgOutputDebugString("After Setting.\r\n");
ulReturn = ISAGetBusDataByOffset(0, (nCSN << 8) | nLogicalDevice, &PnPResources, 1, sizeof(PnPResources));
if (ulReturn == 0) {
EdbgOutputDebugString("NE2000InitISAPNP: Couldn't read resources\r\n");
return NULL;
}
EdbgOutputDebugString("NE2000InitISAPNP: Current settings: IOBase = 0x%x, IRQ = %d\r\n",
PnPResources.IoPortDescriptors[0], PnPResources.IRQDescriptors[0].IRQLevel);
/*
} else {
EdbgOutputDebugString("second option on resources\r\n");
pbRet = (BYTE*)PnPResources.IoPortDescriptors[0];
dwIRQ = PnPResources.IRQDescriptors[0].IRQLevel;
*/
//}
//
// For now disable the other logical devices
//
EdbgOutputDebugString("Disable logical devices\r\n");
memset(&PnPResources, 0, sizeof(PnPResources));
for (i = 0; i < PnPInfo.NumberLogicalDevices; i++) {
if (i != nLogicalDevice) {
ulReturn = ISASetBusDataByOffset(0, (nCSN << 8) | i, &PnPResources, 1, sizeof(PnPResources));
}
}
EdbgOutputDebugString("NE2000InitISAPNP Detected, Interrupt = %d, I/O = 0x%x\r\n",
dwIRQ, pbRet);
ISAPNP_Sleep(100); // allow .1Sec stabilization
return pbRet;
}
#endif // x86
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -