ne2000.c
来自「三星2410的BSP开发包」· C语言 代码 · 共 1,793 行 · 第 1/4 页
C
1,793 行
// For a given multicast address, returns the byte and bit in the card
// multicast registers that it hashes to. Calls CardComputeCrc() to
// determine the CRC value.
//
// Arguments:
//
// Address - the address
// Byte - the byte that it hashes to
// Value - will have a 1 in the relevant bit
//
// Return value:
//
// None.
//
// Note:
//
// This function is adopted from netcard\ne2000 miniport driver.
//
VOID
GetMulticastBit(
IN UCHAR Address[6],
OUT UCHAR * Byte,
OUT UCHAR * Value
)
{
ULONG Crc;
UINT BitNumber;
//
// First compute the CRC.
//
Crc = ComputeCrc(Address, 6);
//
// The bit number is now in the 6 most significant bits of CRC.
//
BitNumber = (UINT)((Crc >> 26) & 0x3f);
*Byte = (UCHAR)(BitNumber / 8);
*Value = (UCHAR)((UCHAR)1 << (BitNumber % 8));
} // GetMulticastBit()
////////////////////////////////////////////////////////////////////////////////
// NE2000MulticastList()
//
// Description:
//
// This function is used to insert multicast addresses to the h/w.
//
// Arguments:
//
// pucMulticastAddresses :: The list of multicast addressses.
// dwNoOfAddresses :: The number of addresses in the list.
//
// Return value:
//
// TRUE if successful, FALSE otherwise.
//
BOOL
NE2000MulticastList(PUCHAR pucMulticastAddresses, DWORD dwNoOfAddresses)
{
UCHAR NicMulticastRegs[8]; // contents of card multicast registers
UINT i;
UCHAR Byte, Bit;
#if 0
EdbgOutputDebugString(
"NE2KDBG:: NE2000MulticastList() set [%d] multicast list addrs.\r\n",
dwNoOfAddresses);
#endif
//
// Make sure it's below max list we can handle..
//
if (dwNoOfAddresses > MAX_MULTICAST_LIST)
{
EdbgOutputDebugString(
"Ne2kDbg:: NE2000MulticastList exceeds max list..\r\n");
return FALSE;
}
//
// Remember these addresses as we may need them again when filter
// is switched from All Multicast to multicast.
//
memset(
g_pucMulticastList,
0x00,
MAX_MULTICAST_LIST * 6);
memcpy(
g_pucMulticastList,
pucMulticastAddresses,
dwNoOfAddresses * 6);
g_dwMulticastListInUse = dwNoOfAddresses;
#if 0
for (i = 0 ; i < dwNoOfAddresses ; i++)
{
EdbgOutputDebugString(
"NE2KDBG:: Multicast[%d] = %x-%x-%x-%x-%x-%x\r\n",
i,
pucMulticastAddresses[6*i + 0],
pucMulticastAddresses[6*i + 1],
pucMulticastAddresses[6*i + 2],
pucMulticastAddresses[6*i + 3],
pucMulticastAddresses[6*i + 4],
pucMulticastAddresses[6*i + 5]);
}
#endif
//
// If we are already in Multicast or Promiscuous mode, then no
// need to set this..
//
if (dwNdisFilter & (PACKET_TYPE_PROMISCUOUS |
PACKET_TYPE_ALL_MULTICAST))
{
return TRUE;
}
//
// First turn all bits off.
//
for (i=0; i<8; i++)
NicMulticastRegs[i] = 0;
//
// Now turn on the bit for each address in the multicast list.
//
for (i=0 ; i<dwNoOfAddresses; i++)
{
GetMulticastBit(&pucMulticastAddresses[6*i], &Byte, &Bit);
NicMulticastRegs[Byte] |= Bit;
}
#if 0
EdbgOutputDebugString(
"NE2KDBG:: MulticastRegs = %x-%x-%x-%x-%x-%x-%x-%x\r\n",
NicMulticastRegs[0],
NicMulticastRegs[1],
NicMulticastRegs[2],
NicMulticastRegs[3],
NicMulticastRegs[4],
NicMulticastRegs[5],
NicMulticastRegs[6],
NicMulticastRegs[7]);
#endif
//
// Finally, burn that in the h/w..
//
HWSetMCRegs(NicMulticastRegs, FALSE);
return TRUE;
} // NE2000MulticastList()
//
// 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--;
// 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
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?