⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ne2000.c

📁 该BSP是基于PXA270+WINCE的BSP
💻 C
📖 第 1 页 / 共 3 页
字号:

//
//  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 + -