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 + -
显示快捷键?