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

📄 smc.c

📁 针对Intel Xscale PXA255的WinCE boot loader源代码包!极具参考价值!
💻 C
📖 第 1 页 / 共 3 页
字号:
SMCGetFrame( BYTE *pbData, UINT16 *pwLength ) {

    UINT16 wStatusWord, wControlWord, i;
    UINT16 *pwData;
    DWORD dwStartTime;
    BOOL fDropFrame;
    WORD wBufLen = *pwLength;
    
    EDBG_ADAPTERMSG(ZONE_RECV,("+GetFrame\n"));
    EDBG_DEBUGLED(LED_GETFRAME_ENTRY,0);
    
    // 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
        WriteWord( BANKSEL_REG, BANK2 );
        WriteWord( POINTER_REG, 0xE000 );

        // Check for an error.  If no error, then get the Frame out
        wStatusWord = ReadWord( DATA_REG );
        if (wStatusWord & FRAME_FILTER) {
            // Don't deliver this frame to the user
            fDropFrame = TRUE;
        } else {
            fDropFrame = FALSE;
            pwData = (UINT16 *)pbData;
            // 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 & ReadWord( DATA_REG )) - 6;
            EDBG_DEBUGLED(LED_PKTLEN,*pwLength);
            
            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++)
                    *pwData++ = ReadWord( DATA_REG );
                if (ntohs(((EthernetFrameHeader *)pbData)->wFrameType) != 0x0806) {
                    fDropFrame = TRUE;
                    goto ReleaseFrame;
                }
            }

            // Read all but the last word, which will contain the control word
            EDBG_DEBUGLED(LED_COPY,0);
            for( ; i < (*pwLength >> 1); i++ )
                *pwData++ = ReadWord( DATA_REG );
            EDBG_DEBUGLED(LED_COPY,*pwLength);
            
            // Now check to see if there were an odd number of bytes sent.  If so, I have to extract the
            //  last one (pg 27 of the SCM91C94 spec).
            wControlWord = ReadWord( DATA_REG );
            if (wControlWord & 0x2000) {
                *pwData = (BYTE)wControlWord;
                (*pwLength)++;
            }
        }

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

        // Wait until release finishes executing
        dwStartTime = OEMEthGetSecs();
        while( ReadWord( 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 (!(ReadWord( INTERRUPT_REG ) & RCV_INT)) {
            fFrameReceived = 0;
            WriteWord( 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) {
            EDBG_ADAPTERMSG(ZONE_RECV,("-GetFrame, returning %u bytes\n", *pwLength));
            EDBG_DEBUGLED(LED_GETFRAME_EXIT,1);            

            // Take away CRC value.
            //
            if (pwLength)
                *pwLength -= 4;

            return 1;
        }
    }
    EDBG_ADAPTERMSG(ZONE_RECV,("-GetFrame\n"));
    EDBG_DEBUGLED(LED_GETFRAME_EXIT,0);
    return 0;

} // GetFrame()



// 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;
    UINT16 *pwData;
    DWORD  dwStartTime;
    BOOL bErr = FALSE;
    UINT16 wInt;
    DWORD i;

    EDBG_DEBUGLED(LED_SENDFRAME_ENTRY,0);
    EDBG_ADAPTERMSG(ZONE_SEND,("+SendFrame, dwLength: %u\n",dwLength));

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

    // Calculate the memory needed = status word + byte count + data area + control byte
    // 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
    WriteWord( BANKSEL_REG, BANK2 );
    WriteWord( MMUCOMMAND_REG, (USHORT)(0x0020 | (UINT16)(cwBufferSize >> 8)) );
    // Loop here until the request is satisfied, or we timeout
    dwStartTime = OEMEthGetSecs();
    while (!(ReadWord( 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.
            WriteWord( POINTER_REG, 0x2000 );
            wCompletionCode = ReadWord( DATA_REG );
		    EdbgOutputDebugString( "SendFrame return with wCompoletionCode=%x\r\n", wCompletionCode);
            return wCompletionCode;
        }
    }
    wFrameHandle = ReadWord( PNR_ARR_REG ) >> 8;

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

    // Enqueue Frame number into TX FIFO
    WriteWord( MMUCOMMAND_REG, 0x00C0 );

	bErr = TRUE;
    dwStartTime = OEMEthGetSecs();
    while (OEMEthGetSecs() - dwStartTime < 2) {
    	wInt = ReadWord (INTERRUPT_REG);
    	if (wInt & TXEMPTY_INT) {
    		WriteWord (INTERRUPT_REG, TXEMPTY_INT);	// ACK
    		wInt = ReadWord (INTERRUPT_REG);		// read status
			WriteWord (INTERRUPT_REG, wIntMask);	// re-enable interrupt
		    bErr = FALSE;
		    break;
	   	}
    }
    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.
        WriteWord( POINTER_REG, 0x2000 );
        wCompletionCode = ReadWord( DATA_REG );

        SendFrameError("!EDBG error ",wCompletionCode);
        
        // Clear the statistics registers
        WriteWord( BANKSEL_REG, BANK0 );
        ReadWord( COUNTER_REG );
        // Re-enable TXENA
        WriteWord( TCR_REG, TCR_REG_INIT );

        WriteWord( BANKSEL_REG, BANK2 );

        // Release the buffer memory for the Frame that failed to transmit
        WriteWord( MMUCOMMAND_REG, 0x00A0 );
        // Wait for MMU Release to complete
        dwStartTime = OEMEthGetSecs();
        while (ReadWord( MMUCOMMAND_REG ) & 1) {
            if (OEMEthGetSecs() - dwStartTime > 2) {
                EdbgOutputDebugString("Timed out waiting for MMUCOMMAND_REG bit 1\n");
                break;
            }
        }

        if (TX_INT & wInt) {
        	WriteWord (INTERRUPT_REG, TX_INT);		// Ack TX_INT
        	WriteWord (INTERRUPT_REG, wIntMask);	// enable interrupt
        }
        EDBG_DEBUGLED(LED_SENDFRAME_EXIT, wCompletionCode);
        return wCompletionCode;
    }
    else {
        // Successful transmission, clear collision count
        WriteWord( BANKSEL_REG, BANK0 );        
        wInt=ReadWord(COUNTER_REG);
        wCompletionCode = ReadWord( EPHSTATUS_REG );
        EDBG_DEBUGLED(LED_SENDFRAME_EXIT,0);
        return 0;
    }
    
    // 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 ) {

    // Output any transmit error messages.  These correspond to the 
    //  EPH Status Register described on page 37 of the SMC91C94 spec.
    if (wCompletionCode & 0x8000)
        EdbgOutputDebugString( "%s::SendFrame()::Transmission Underrun\n", pszPrefix );
    if (wCompletionCode & 0x4000)
        EdbgOutputDebugString( "%s::SendFrame()::Link Test Failed\n", pszPrefix );
    if (wCompletionCode & 0x2000)
        EdbgOutputDebugString( "%s::SendFrame()::Receive Overrun\n", pszPrefix );
    if (wCompletionCode & 0x1000)
        EdbgOutputDebugString( "%s::SendFrame()::Statistics Counter Roll Over\n", pszPrefix );
    if (wCompletionCode & 0x0800)
        EdbgOutputDebugString( "%s::SendFrame()::Excessive Deferral\n", pszPrefix );
    if (wCompletionCode & 0x0400)
        EdbgOutputDebugString( "%s::SendFrame()::Lost Carrier\n", pszPrefix );
    if (wCompletionCode & 0x0200)
        EdbgOutputDebugString( "%s::SendFrame()::Late Collision\n", pszPrefix );
    if (wCompletionCode & 0x0080)
        EdbgOutputDebugString( "%s::SendFrame()::Transmission Deferred\n", pszPrefix );
    if (wCompletionCode & 0x0040)
        EdbgOutputDebugString( "%s::SendFrame()::Last Frame Was Broadcast\n", pszPrefix );
    if (wCompletionCode & 0x0020)
        EdbgOutputDebugString( "%s::SendFrame()::Signal Quality Error\n", pszPrefix );
    if (wCompletionCode & 0x0010)
        EdbgOutputDebugString( "%s::SendFrame()::16 Collisions Reached\n", pszPrefix );
    if (wCompletionCode & 0x0008)
        EdbgOutputDebugString( "%s::SendFrame()::Last Frame Was Multicast\n", pszPrefix );
    if (wCompletionCode & 0x0004)
        EdbgOutputDebugString( "%s::SendFrame()::Multiple Collisions Detected\n", pszPrefix );
    if (wCompletionCode & 0x0002)
        EdbgOutputDebugString( "%s::SendFrame()::Single Collion Detected\n", pszPrefix );
    if (wCompletionCode & 0x0001)
        EdbgOutputDebugString( "%s::SendFrame()::Transmit Successful\n", pszPrefix );
    EdbgOutputDebugString( "%s::SendFrame()::EPH Reg %Hh\n", pszPrefix, wCompletionCode );
}



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

    // I need to save/restore the affected registers in the 91C94
    wBankSave = ReadWord( BANKSEL_REG );
    WriteWord( BANKSEL_REG, BANK2 );

    // Get the currently pending interrupts
    wInterruptReg = ReadWord( INTERRUPT_REG );
    // Disable any more interrupts
    WriteWord( INTERRUPT_REG, 0 );

    EDBG_ADAPTERMSG(ZONE_INTR,("+SMC_ISR: Ints pending: %X\n",wInterruptReg));

⌨️ 快捷键说明

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