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

📄 smc.c

📁 ARM9基于WINDOWSCE的BSP源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
{
    DWORD dwStartTime;
    
    // issuem the release command
    LAN91C96_Write (MMUCOMMAND_REG, wCmd);

    // Wait until release finishes executing
    dwStartTime = OEMEthGetSecs();
    while (LAN91C96_Read (MMUCOMMAND_REG) & MMU_CMD_BUSY) {
        if ((OEMEthGetSecs() - dwStartTime) > 2) {
            EdbgOutputDebugString ("!GetFrame: Timed out releasing memory (wCmd = %u)\n", wCmd);
            return FALSE;
        }
    }
    return TRUE;
}


// 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
SMCGetFrame( BYTE *pbData, UINT16 *pwLength ) {

    UINT16 wStatusWord, wControlWord, i;
    UINT16 *pwData;
    DWORD dwStartTime;
    BOOL fDropFrame;
    WORD wBufLen = *pwLength;
    
    
    // For the bootloader we don't want to deal with interrupts, so I'll poll the ISR routine
    SMC_ISR();

    while (fFrameReceived) {
        // Setup pointer address register to point to first byte of Frame
        LAN91C96_Write( BANKSEL_REG, BANK2 );
    	 LAN91C96_Write(POINTER_REG,  (USHORT) (PTR_RCV |  PTR_READ |0x0));
	LAN91C96_Write(POINTER_REG,  (USHORT) (PTR_AUTO));

        // Check for an error.  If no error, then get the Frame out
        wStatusWord = LAN91C96_Read( DATA_REG );
        if (wStatusWord & FRAME_FILTER) {
            // Don't deliver this frame to the user
            fDropFrame = TRUE;
        } else {
            fDropFrame = FALSE;
            pwData = (UINT16 *)pbData;
			
		 LAN91C96_Write(POINTER_REG,  (USHORT) (PTR_RCV |  PTR_READ |0x2));
		LAN91C96_Write(POINTER_REG,  (USHORT) (PTR_AUTO));
	
            // The top bits of the byte count are reserved, so mask those (pg 26 of SMC91C94 spec).
            // The byte count includes the status word, byte count and control byte so subtract 6
         
            *pwLength = (0x07FF & LAN91C96_Read( DATA_REG )) - 6;
     //       EdbgOutputDebugString("SMC9000: received packet largth 0x%x\r\n",TMP);

            if (*pwLength > wBufLen) {
                EdbgOutputDebugString("SMC9000: received packet larger (%u) than buffer (%u)\n",*pwLength,wBufLen);
                fDropFrame = TRUE;
                goto ReleaseFrame;
            }

            // For broadcast frames, filter out all except for ARPs
            i=0;
            if ((dwConfigOptions & OPT_BROADCAST_FILTERING) && (wStatusWord & BROADCAST_FILTER_BIT)) {
                for (; i< sizeof(EthernetFrameHeader); i++)
                    {
				LAN91C96_Write(POINTER_REG,  (USHORT) (PTR_RCV |  PTR_READ |(i*2+0x4)));
				LAN91C96_Write(POINTER_REG,  (USHORT) (PTR_AUTO));
				*pwData++ = LAN91C96_Read( DATA_REG );
                	}
                if (ntohs(((EthernetFrameHeader *)pbData)->wFrameType) != 0x0806) {
                    fDropFrame = TRUE;
                    goto ReleaseFrame;
                }
            }

            // Read all but the last word, which will contain the control word
            for( ; i < (*pwLength >> 1); i++ )
             {

			LAN91C96_Write(POINTER_REG,  (USHORT) (PTR_RCV |  PTR_READ |(i*2+0x4)));
			LAN91C96_Write(POINTER_REG,  (USHORT) (PTR_AUTO));
			 *pwData++ = LAN91C96_Read( DATA_REG );
            	}
          
            
           
            	LAN91C96_Write(POINTER_REG,  (USHORT) (PTR_RCV |  PTR_READ |(i*2+0x4)));
		LAN91C96_Write(POINTER_REG,  (USHORT) (PTR_AUTO));
            wControlWord = LAN91C96_Read( DATA_REG );
            if (wControlWord & 0x2000) {
                *pwData = (BYTE)wControlWord;
                (*pwLength)++;
            }
        }

        // Release the memory for the received Frame
ReleaseFrame:
        LAN91C96_Write( MMUCOMMAND_REG, 0x0080 );

        // Wait until release finishes executing
        dwStartTime = OEMEthGetSecs();
        while( LAN91C96_Read( MMUCOMMAND_REG ) & 1 ) {
            if ((OEMEthGetSecs() - dwStartTime) > 2) {
                EdbgOutputDebugString("!GetFrame: Timed out releasing memory\n");
                break;
            }
        }
        // If the buffer is now empty, re-enable the RCV_INT and clear the fFrameReceived flag
        if (!(LAN91C96_Read( INTERRUPT_REG ) & RCV_INT)) {
            fFrameReceived = 0;
            LAN91C96_Write( INTERRUPT_REG, wIntMask );
        }
    
        // Check the status word for errors (pg 28 of the SMC91C94 spec).
        if (wStatusWord & 0x8000)
            EdbgOutputDebugString( "GetFrame() - Receive Alignment Error\n" );
        if (wStatusWord & 0x2000)
            EdbgOutputDebugString( "GetFrame() - CRC Error\n" );
        if (wStatusWord & 0x0800)
            EdbgOutputDebugString( "GetFrame() - Frame Was Too Long\n" );
        if (wStatusWord & 0x0400)
            EdbgOutputDebugString( "GetFrame() - Frame Was Too Short\n" );

//      if (wStatusWord & 0x4000) 
//          EdbgOutputDebugString( "GetFrame() - Broadcast\n" );

#ifdef SMC_DUMP_FRAMES        
        DumpEtherFrame(pbData, *pwLength);
#endif
        // If frame isn't filtered, return data to user. Otherwise, get next frame.
        if (!fDropFrame) {
            
            return 1;
        }
    }

    return 0;

} // GetFrame()



//  ISR routine. Three global flags are used to communicate with GetFrame() and SendFrame().
//  They are fFrameReceived, fTXEMPTY_INT and fTX_INT and are described at the top of the file.  
static void SMC_ISR( void ) {

    UINT16 wInterruptReg;
    UINT16 wBankSave;
	//clear GPIO int
//	*(volatile long *)(VA_GPIO8_BASE + GPIOIC)	|= 0x2;			//level int		
    // I need to save/restore the affected registers in the 91C94
    wBankSave = LAN91C96_Read( BANKSEL_REG );
    LAN91C96_Write( BANKSEL_REG, BANK2 );

    // Get the currently pending interrupts
    wInterruptReg = LAN91C96_Read( INTERRUPT_REG );
    // Disable any more interrupts
    LAN91C96_Write( INTERRUPT_REG, 0 );
    
    if (wInterruptReg & RX_OVRN_INT) {
        LAN91C96_Write( INTERRUPT_REG, RX_OVRN_INT);
    }

    // This interrupt indicates that the RX buffer is not empty.  It just stays asserted until
    //  all the Frames are read out of the buffer.  I will accept one of these and set the fFrameReceived
    //  flag to indicate this to the GetFrame() routine, then I'll disable the interrupt from here.
    //  After GetFrame() gets called it will check the buffer and if it is empty it will re-enable the
    //  interrupt.
    if (wInterruptReg & RCV_INT) {
        fFrameReceived = 1;
        wInterruptReg &= (~RCV_INTM);
    }

    // Restore the interrupt mask register, with possible modification
    LAN91C96_Write( INTERRUPT_REG, (USHORT)(wInterruptReg & 0xFF00 ));
    LAN91C96_Write( BANKSEL_REG, wBankSave );

}

// 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 SMCSendFrame( BYTE *pbData, DWORD dwLength ) {

    UINT16 wFrameHandle;
    UINT16 cwBufferSize;
    UINT16 wCompletionCode = 0;
    UINT16 *pwData;
    DWORD  dwStartTime;
    BOOL bErr = FALSE;
    UINT16 wInt;
    DWORD i;
//	USHORT TMP;
// EdbgOutputDebugString( "+SMCSendFrame\r\n");
    if ((DWORD) pbData & 1) {
        EdbgOutputDebugString ("!SMCSendFrame: Data MUST be 16bit aligned\r\n");
        return FALSE;
    }	
    LAN91C96_Write( BANKSEL_REG, BANK2 );
//	EdbgOutputDebugString( "SMCSendFrame M68K_DATA 0x%X\r\n",LAN91C96_Read(BANKSEL_REG));
    LAN91C96_Write (INTERRUPT_REG, 0);
// 	EdbgOutputDebugString( "+SendFrame dwLength: %u\r\n",dwLength);

#ifdef SMC_DUMP_FRAMES    
    DumpEtherFrame(pbData, (USHORT)dwLength);
#endif        

    // Calculate the amount of memory needed. This needs to be rounded up to an even number
    cwBufferSize = 2 + 2 + (UINT16)dwLength + 1;
    if (cwBufferSize & 1)
        cwBufferSize++;

    // Allocate memory in the buffer for the Frame
    LAN91C96_Write( MMUCOMMAND_REG, CMD_ALLOC | (UINT16)((cwBufferSize >> 8)&0x0007 ));
    // Loop here until the request is satisfied, or we timeout
    dwStartTime = OEMEthGetSecs();
	
    while (!LAN91C96_Read( INTERRUPT_REG ) & ALLOC_INT) {
        if (OEMEthGetSecs() - dwStartTime > 2) {
            EdbgOutputDebugString("Timed out waiting for ALLOC_INT\n");

            // Get the status word so that it can be returned.
         	LAN91C96_Write( POINTER_REG, 0x2000 );
            wCompletionCode = LAN91C96_Read( DATA_REG );
            LAN91C96_Write (INTERRUPT_REG, wIntMask);
            return wCompletionCode;
        }
    }
    wFrameHandle = (0x3f00 & LAN91C96_Read( PNR_ARR_REG )) >> 8;

    // Now write the Frame into the buffer (Pg 39 of the SMC91C94 spec)
    	LAN91C96_Write( PNR_ARR_REG, wFrameHandle );
//    LAN91C96_Write( POINTER_REG, 0x4000 );
	 LAN91C96_Write( POINTER_REG, 0x0000 );
    // Write the Status Word
    	LAN91C96_Write( DATA_REG, 0 );
    // Write the byte count = status word + byte count + data area + control byte
   	LAN91C96_Write( POINTER_REG, 0x0002);
    	LAN91C96_Write( DATA_REG, cwBufferSize );
    // Now write all except possibly the last data byte
    	pwData = (UINT16 *)pbData;
    for( i = 0; i < (dwLength >> 1); i++ )
    	{
    		LAN91C96_Write( POINTER_REG, (USHORT)( 0x0004 + 2*i ));
        	LAN91C96_Write( DATA_REG, *pwData++ );
    	}
    // If the number of data bytes was odd we can put that just before the Control Byte
    if (dwLength & 1) 
	{
		LAN91C96_Write( POINTER_REG, (USHORT)( 0x0004 + 2*i ));
		LAN91C96_Write( DATA_REG, (0x3000) | *(pbData + dwLength - 1));
    	}
    // Otherwise, the number of bytes is even, and I'll just pad the last byte with 0
    else    
    	{
    		LAN91C96_Write( POINTER_REG, (USHORT)( 0x0004 + 2*i ));
		LAN91C96_Write( DATA_REG, 0x1000 );
    	}

    // Enqueue Frame number into TX FIFO
    LAN91C96_Write( MMUCOMMAND_REG, CMD_ENQ_TX );

    bErr = TRUE;
    dwStartTime = OEMEthGetSecs();
    do {
        wInt = LAN91C96_Read (INTERRUPT_REG);
		
        if (wInt & TXEMPTY_INT) {
            LAN91C96_Write (INTERRUPT_REG, TXEMPTY_INT); // ACK
            wInt = LAN91C96_Read (INTERRUPT_REG);        // read status
   
            bErr = FALSE;
            break;
        }
    } while (OEMEthGetSecs() - dwStartTime < 2);

    if (bErr)
        EdbgOutputDebugString( "SendFrame timeout waiting for TXEMPTY! INTERRUPT_REG = 0x%x\r\n", wInt);

    //  If an error occured during transmission, TX_INT will be generated.
    //  If this happens, I need to delete the untransmitted Frame
    //  from the buffer.  If no error occurred, this will be done by the chip because it's in
    //  AUTO RELEASE mode.  (Page 72, SMC spec)
    if (bErr || (TX_INT & wInt)) {
        // Get the status word so that it can be returned.
        LAN91C96_Write( POINTER_REG, 0x2000 );
        wCompletionCode = LAN91C96_Read( DATA_REG );

  //   SendFrameError("!EDBG error  0x%x *******************************",wCompletionCode);
        
        // Clear the statistics registers
        LAN91C96_Write( BANKSEL_REG, BANK0 );
        LAN91C96_Read( COUNTER_REG );
        // Re-enable TXENA
        LAN91C96_Write( TCR_REG, TCR_REG_INIT );

        LAN91C96_Write( BANKSEL_REG, BANK2 );

        // Release the buffer memory for the Frame that failed to transmit
        SMCReleaseMemory (CMD_REL_SPEC);

        if (TX_INT & wInt) {
        	LAN91C96_Write (INTERRUPT_REG, TX_INT);		// Ack TX_INT
        }

        
    } else {
        // Successful transmission, clear collision count
        LAN91C96_Write( BANKSEL_REG, BANK0 );        
         wInt=LAN91C96_Read(COUNTER_REG);
	wCompletionCode = LAN91C96_Read( EPHSTATUS_REG );	
  	SMCReleaseMemory (CMD_REL_SPEC);
	return 0;
    }
    
    LAN91C96_Write (BANKSEL_REG, BANK2);        
    LAN91C96_Write (INTERRUPT_REG, wIntMask);

    return wCompletionCode;
    // The TXEMPTY_INT will be disabled by the ISR.

} // SendFrame()



// This routine is called by a higher level routine if an error was detected by SendFrame()
//  returning non-zero.  The completion code that is returned is decoded here and error
//  message(s) are printed, prefixed by the supplied string.
static void SendFrameError( char *pszPrefix, UINT16 wCompletionCode ) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -