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

📄 smc.c

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 C
📖 第 1 页 / 共 2 页
字号:
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-2000 Microsoft Corporation.  All rights reserved.

Module Name:  

Abstract:  
    Routines for the SMC9000 ethernet controller used for the Windows CE
    debug ethernet services, and bootloaders.

Functions:


Notes: 
    These routines are called at system init and other times when system calls aren't allowed, so
    they can't make any system calls.
    
--*/


// Note : The Odo SMC implementation sometimes encounters read errors if we
// optimize this routine.  So for now I'm just going to turn of all 
// optimizations.
#pragma optimize("", off)

#include <windows.h>
#include <halether.h>
#include "smchw.h"
#include "smcsw.h"
#include "udp.h"

// The base address of the SMC registers.  Also, allow for a multiplier, since the Odo
// platform uses 32 bit accesses of the registers.
static BYTE volatile *pbEthernetBase;
static DWORD dwRegisterMultiplier;

//#define ReadWord( wOffset ) READ_PORT_USHORT((PUSHORT)(pbEthernetBase + (wOffset*dwRegisterMultiplier)))
__inline USHORT ReadWord( USHORT wOffset ) 
{
	return READ_PORT_BYTE((PBYTE)(pbEthernetBase + (wOffset*dwRegisterMultiplier)))+\
        (((USHORT)READ_PORT_BYTE((PBYTE)(pbEthernetBase + ((wOffset+1)*dwRegisterMultiplier))))<<8);
};

//#define WriteWord( wOffset, Value ) WRITE_PORT_USHORT((PUSHORT)(pbEthernetBase + (wOffset*dwRegisterMultiplier)),(USHORT)(Value))
__inline VOID WriteWord( USHORT wOffset, USHORT Value ) 
{   WRITE_PORT_BYTE((PBYTE)(pbEthernetBase + (wOffset*dwRegisterMultiplier)),(BYTE)(Value));\
    WRITE_PORT_BYTE((PBYTE)(pbEthernetBase + ((wOffset+1)*dwRegisterMultiplier)),(BYTE)(Value>>8));
};


// If this is defined, broadcast frames will be discarded.  Since we need to process
// ARPs, leave broadcast filter off, and filter out packets as soon as we can.  This, since
// we have to take an interrupt anyway, looking at the first few bytes isn't that bad. If
// the SMC chip could be configured so that we didn't even get interrupts for broadcast
// packets, we might look at updating the ARP cache on the desktop and filtering out all
// broadcasts...
#define NO_BROADCAST 0

#define BROADCAST_FILTER_BIT 0x4000

// If any of the following bits are set in the received status word, discard frame
#if NO_BROADCAST
#define FRAME_FILTER  (0xAC00 | BROADCAST_FILTER_BIT)  // No broadcast
#else
#define FRAME_FILTER  0xAC00   // Allow broadcast
#endif

// For debugging, if defined, this will cause all Rx/Tx data to be dumped to debug serial port
#undef SMC_DUMP_FRAMES
//#define SMC_DUMP_FRAMES

// This flag indicates when Frames are pending in the receive buffer.
//  It is set by the ISR when a RCV_INT is generated, and will be cleared when the GetFrame() routine
//  detects that all Frames have been removed from the buffer.
static UINT16 fFrameReceived;

// Mask to use for interrupts
static UINT16 wIntMask;

// Controls whether we filter out broadcast packets (except ARP requests...)
static DWORD dwConfigOptions;

static void SendFrameError( char *pszPrefix, UINT16 wCompletionCode );
static void SMC_ISR( void );
#ifdef SMC_DUMP_FRAMES
static void DumpEtherFrame( BYTE *pFrame, WORD cwFrameLength );
#endif

// 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
SMCInit( BYTE *pbBaseAddress, DWORD dwMultiplier, USHORT MacAddr[3]) {

    DWORD dwStartTime;
    USHORT wBSR, wConfig;
    WORD wData;
    DWORD dwIndex;
    
    if (! pbBaseAddress)
        return FALSE;
    
    pbEthernetBase = pbBaseAddress;
    dwRegisterMultiplier = dwMultiplier;

    // DANGER - May have to wait 750 usec after reset while EEPROM info loads (Pg 50 of the SMC91C94 spec).
    // until this occurs, SMC registers are inaccessible.
    EdbgOutputDebugString("+SMCInit\r\n");
    WriteWord( BANKSEL_REG, BANK1 );
    
    dwStartTime = OEMEthGetSecs();
    while( ReadWord( CONTROL_REG ) & 0x0003 && OEMEthGetSecs() - dwStartTime < 2);

    // Verify the I/O base.  The upper byte of the BSR always reads 0x33, use this.
    // For Odo, the bus cycles will time out and garbage values will be returned.
    wBSR = ReadWord(BANKSEL_REG);
    if ((wBSR & 0xFF00) != 0x3300) {
        EdbgOutputDebugString("SMC card not detected, I/O base 0x%X, BSR: 0x%X\n",pbEthernetBase,wBSR);
        EdbgOutputDebugString("SMC card debug data %X,%X,%X,%X,%X,%X,%X,%X !\n",
            ReadWord(0),ReadWord(2),ReadWord(4),ReadWord(6),ReadWord(8),ReadWord(10),ReadWord(12),ReadWord(14));

        for (dwIndex=0;dwIndex<0x400;dwIndex++) {
            wData=ReadWord((USHORT)dwIndex);
            if ((wData & 0xff)==0x33) {
                EdbgOutputDebugString("SMC found 0x33 at 0x%X\n",dwIndex);
            }
        }
        return FALSE;
    }
    EdbgOutputDebugString( "SMC Ethernet card detected at I/O base 0x%X\r\n",pbEthernetBase);

    // Read the MAC address from the 91C94.  This should have been read in from the EEPROM during reset
    WriteWord( BANKSEL_REG, BANK1 );
    MacAddr[0] = ReadWord( MACADDR_REG0 );
    MacAddr[1] = ReadWord( MACADDR_REG1 );
    MacAddr[2] = ReadWord( MACADDR_REG2 );

    EdbgOutputDebugString("SMC Ethernet Address: %B:%B:%B:%B:%B:%B\r\n",
                          MacAddr[0] & 0x00FF, MacAddr[0] >> 8,
                          MacAddr[1] & 0x00FF, MacAddr[1] >> 8,
                          MacAddr[2] & 0x00FF, MacAddr[2] >> 8);

    EdbgOutputDebugString( "SMC Ethernet card Config_Reg=%x\n",ReadWord(CONFIG_REG));
    EdbgOutputDebugString( "SMC Ethernet card Config_Base=%x\n",ReadWord(BASE_REG));
    EdbgOutputDebugString( "SMC Ethernet card Swtich=%x\n",SMCReadSwitches());

#ifdef PREDEFINED_MACOFFSET
    // The following code used to initial Mac Address in EEPROM.
    //if (MacAddr[0]==0xffff && MacAddr[1]==0xffff && MacAddr[2]==0xffff ) 
	{ // Empty address
        // Write to it.
        WriteWord(MACADDR_REG0,0x0008);
        WriteWord(MACADDR_REG1,0x000F);
        WriteWord(MACADDR_REG2,0x0001+PREDEFINED_MACOFFSET);

        MacAddr[0]=0x0008;
        MacAddr[1]=0x000f;
        MacAddr[3]=0x0001;
        SMCWriteEEPROM(0x0 , 0x0030);
        SMCWriteEEPROM(0x1 , 0x1867);
        SMCWriteEEPROM( 0x20, 0x0008 );
        SMCWriteEEPROM( 0x21, 0x000f );
        SMCWriteEEPROM( 0x22, 0x0001+PREDEFINED_MACOFFSET );
        SMCReadEEPROM(0x20 , MacAddr);
        SMCReadEEPROM(0x21 , MacAddr+1);
        SMCReadEEPROM(0x22 , MacAddr+2);

            EdbgOutputDebugString("SMC Ethernet Address In Eeprom: %B:%B:%B:%B:%B:%B\r\n",
                          MacAddr[0] & 0x00FF, MacAddr[0] >> 8,
                          MacAddr[1] & 0x00FF, MacAddr[1] >> 8,
                          MacAddr[2] & 0x00FF, MacAddr[2] >> 8);
        EdbgOutputDebugString("SMC Ethernet Address set to 0x08000f 000100\r\n");
    }
#endif
    
    // Set SQUELCH bit - this changes the threshold for a valid signal from 300mV to 180mV.
    // This is to attempt to fix problems we have seen with some (usually 8 port) hubs.
    WriteWord( BANKSEL_REG, BANK1 );
    wConfig = ReadWord(CONFIG_REG);
    wConfig |= CFG_SETSQLCH|CFG_NO_WAIT;
    WriteWord(CONFIG_REG, wConfig);
    EdbgOutputDebugString("SMC config reg val: %X\n",wConfig);
    
    // Initialize the control register
    WriteWord( BANKSEL_REG, BANK1 );
    WriteWord( CONTROL_REG, CONTROL_REG_INIT );

    // Initialize memory configuration register
    WriteWord( BANKSEL_REG, BANK0 );
    WriteWord( MCR_REG, MCR_REG_INIT );

    // Initialize transmit control register
    WriteWord( BANKSEL_REG, BANK0 );
    WriteWord( TCR_REG, TCR_REG_INIT );

    // Initialize interrupt mask register (all ints disabled to start)
    WriteWord( BANKSEL_REG, BANK2 );
    WriteWord( INTERRUPT_REG, 0);

    // The receive register should be the last thing initialzed so that we don't start
    //  getting Frames before we're ready for them.
    
    // Initialize the Receive Control Register (Pg 39 of the SMC91C94 spec):
    WriteWord( BANKSEL_REG, BANK0 );
    WriteWord( RCR_REG, RCR_REG_INIT );

    EdbgOutputDebugString("SMC Reset complete2\r\n");
    
    // Even if the card is present, it likes to have a second to stabilize before the first transmission
    while( OEMEthGetSecs() - dwStartTime < 1 );
    
    EdbgOutputDebugString( "-SMCInit\r\n");
    return TRUE;
}

// Interrupts left disabled at init, call this function to turn them on
void
SMCEnableInts()
{
    // Only enable receive interrupts (we poll for Tx completion)
    wIntMask = RCV_INTM;
    WriteWord( BANKSEL_REG, BANK2 );
    WriteWord( INTERRUPT_REG, wIntMask );
}

void
SMCDisableInts()
{
    wIntMask = 0;
    WriteWord( BANKSEL_REG, BANK2 );
    WriteWord( INTERRUPT_REG, wIntMask );
}

DWORD
SMCGetPendingInterrupts()
{
    WORD wInts;
	DWORD dwRet = 0;
    UINT16 wBankSave;

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

    // Just check for Rx int
    if (wInts & (RCV_INT | RX_OVRN_INT)) {
        dwRet = INTR_TYPE_RX;
        EdbgOutputDebugString("R");
    }
    
    WriteWord( BANKSEL_REG, wBankSave );

    return dwRet;
}

//
// This routine is used by the OAL to configure the debug Ethernet driver. Currently
// the following options are defined:
//     OPT_BROADCAST_FILTERING  -- If set, filter out all broadcast packets except ARP packets
// 
DWORD
SMCSetOptions(DWORD dwOptions)
{
    DWORD dwOldOptions = dwConfigOptions;
    dwConfigOptions = dwOptions;
    return dwOldOptions;
}

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

⌨️ 快捷键说明

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