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

📄 smc.c

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 C
📖 第 1 页 / 共 2 页
字号:

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

//		EdbgOutputDebugString("-SendFrame, success(EPSR=0x%x,Count=0x%x)\n",wCompletionCode,wInt);
        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));
    
    if (wInterruptReg & RX_OVRN_INT) {
        EDBG_DEBUGLED(LED_OVERRUN,wInterruptReg);
        EDBG_ADAPTERMSG(ZONE_WARNING,("RX_OVRN_INT\n"));
        WriteWord( 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
    WriteWord( INTERRUPT_REG, (USHORT)(wInterruptReg & 0xFF00 ));
    WriteWord( BANKSEL_REG, wBankSave );

    EDBG_ADAPTERMSG(ZONE_INTR,("-SMC_ISR: Ints pending: %X, fFrameReceived: %u\n", wInterruptReg, fFrameReceived));
}

#ifdef SMC_DUMP_FRAMES
static void DumpEtherFrame( BYTE *pFrame, WORD cwFrameLength ) {

    int i,j;

    EdbgOutputDebugString( "Frame Buffer Address: 0x%X\r\n", pFrame );
    EdbgOutputDebugString( "To: %B:%B:%B:%B:%B:%B  From: %B:%B:%B:%B:%B:%B  Type: 0x%H  Length: %u\r\n",
        pFrame[0], pFrame[1], pFrame[2], pFrame[3], pFrame[4], pFrame[5],
        pFrame[6], pFrame[7], pFrame[8], pFrame[9], pFrame[10], pFrame[11],
        ntohs(*((UINT16 *)(pFrame + 12))), cwFrameLength );
    for( i = 0; i < cwFrameLength / 16; i++ ) {
        for( j = 0; j < 16; j++ )
            EdbgOutputDebugString( " %B", pFrame[i*16 + j] );
        EdbgOutputDebugString( "\r\n" );
    }
    for( j = 0; j < cwFrameLength % 16; j++ )
        EdbgOutputDebugString( " %B", pFrame[i*16 + j] );
    EdbgOutputDebugString( "\r\n" );
}
#endif

// The read and write EEPROM routines access the 64 word by 16-bit EEPROM that is attached to the
//  91C94.  There are locations within the EEPROM that the chip does not need and can be used to
//  store other important information.  The memory map of the EEPROM is given in the ethernet.doc
//  spec.  The procedure used here for accessing these words is discussed on pages 88 and 89 of
//  the SMC91C94 spec.
BOOL SMCReadEEPROM( UINT16 EEPROMAddress , UINT16 *pwVal) {

    DWORD dwCurTime;
    WriteWord( BANKSEL_REG, BANK2 );
    WriteWord( POINTER_REG, (USHORT)((EEPROMAddress & 0x003F) | 0x6000 ));
    WriteWord( BANKSEL_REG, BANK1 );
    WriteWord( CONTROL_REG, (USHORT)(ReadWord(CONTROL_REG) | 0x0006) );

    // Loop until EEPROM data is retrieved
    dwCurTime = OEMEthGetSecs();
    
    while( ReadWord( CONTROL_REG ) & 0x0003 ) {
        if ((OEMEthGetSecs() - dwCurTime) > 2) {
            EdbgOutputDebugString("!SMCReadEEPROM read timed out\n");
            return FALSE;
        }
    }
    *pwVal = ReadWord( GENERAL_REG );
    return TRUE;
}

BOOL SMCWriteEEPROM( UINT16 EEPROMAddress, UINT16 Data ) {
    DWORD dwCurTime;
    WriteWord( BANKSEL_REG, BANK2 );
    WriteWord( POINTER_REG, (USHORT)((EEPROMAddress & 0x003F) | 0x6000 ));
    WriteWord( BANKSEL_REG, BANK1 );
    WriteWord( GENERAL_REG, Data );
    WriteWord( CONTROL_REG, (USHORT)(ReadWord(CONTROL_REG) | 0x0005 ));

    // Loop until EEPROM data is written
    dwCurTime = OEMEthGetSecs();
    while( ReadWord( CONTROL_REG ) & 0x0003 ) {
        if ((OEMEthGetSecs() - dwCurTime) > 5) {
            EdbgOutputDebugString("!SMCWriteEEPROM read timed out\n");
            return FALSE;
        }
    }
    return TRUE;
}

// Read the value on the IOS lines, used to indicate the status of the switches on both the Odo
// Ethernet board, and the SMC eval board.
UINT16 SMCReadSwitches(void) {
    WriteWord( BANKSEL_REG, BANK3 );
    return ReadWord(MGMT_REG) >> 8;
}

⌨️ 快捷键说明

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