📄 smc.c
字号:
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
if( NULL != MacAddr ) {
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);
}
WriteWord( BANKSEL_REG, BANK1 );
WriteWord( CONFIG_REG, 0xB0B1 );
// Initialize the control register
WriteWord( BANKSEL_REG, BANK1 );
WriteWord( CONTROL_REG, 0x0120 );//Unset AUTO RELEASE bit
// 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 < 2 );
AutoNegotiation();
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;
}
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;
}
static BOOL
SMCReleaseMemory (UINT16 wCmd)
{
DWORD dwStartTime;
// issuem the release command
WriteWord (MMUCOMMAND_REG, wCmd);
// Wait until release finishes executing
dwStartTime = OEMEthGetSecs();
while (ReadWord (MMUCOMMAND_REG) & MMU_CMD_BUSY) {
if ((OEMEthGetSecs() - dwStartTime) > 2) {
EdbgOutputDebugString ("!GetFrame: Timed out releasing memory (wCmd = %u)\n", wCmd);
return FALSE;
}
}
return TRUE;
}
static UINT16
SMCRetrieveFrame (BYTE *pbData, UINT16 *pwLength)
{
UINT16 i, wStatusWord;
UINT16 *pwData = (UINT16 *)pbData;
UINT16 wLen;
// Setup pointer address register to point to first byte of Frame
WriteWord( POINTER_REG, 0xE000 );
// read status and filter frames if error detected
if (!((wStatusWord = ReadWord (DATA_REG)) & FRAME_FILTER)) {
// 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
wLen = (0x07FF & ReadWord( DATA_REG )) - 6;
EDBG_DEBUGLED(LED_PKTLEN,*pwLength);
if (*pwLength < wLen) {
EdbgOutputDebugString("SMC111: received packet larger (%u) than buffer (%u)\n",wLen, *pwLength);
return 0x0800; // frame too long
}
// 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 UNALIGNED *)pbData)->wFrameType) != 0x0806) {
return BROADCAST_FILTER_BIT; // broadcast, not ARPs
}
}
wStatusWord = 0;
*pwLength = wLen; // set return length
// Read all but the last word, which will contain the control word
wLen >>= 1; // in words
EDBG_DEBUGLED(LED_COPY,0);
for( ; i < wLen; i++ )
*pwData++ = ReadWord( DATA_REG );
EDBG_DEBUGLED(LED_COPY,wLen);
// 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).
wLen = ReadWord( DATA_REG );
if (wLen & 0x2000) {
*pwData = (BYTE)wLen;
(*pwLength)++;
}
}
return wStatusWord;
}
// 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; // some error value
WORD wInt;
EDBG_ADAPTERMSG(ZONE_RECV,("+GetFrame\n"));
EDBG_DEBUGLED(LED_GETFRAME_ENTRY,0);
if ((DWORD) pbData & 1) {
EdbgOutputDebugString ("!SMCGetFrame: Data MUST be 16bit aligned\r\n");
return FALSE;
}
// For the bootloader we don't want to deal with interrupts, so I'll poll the ISR routine
WriteWord( BANKSEL_REG, BANK2 );
WriteWord (INTERRUPT_REG, 0);
do {
wInt = ReadWord (INTERRUPT_REG);
if (wInt & RX_OVRN_INT) {
// ack
WriteWord (INTERRUPT_REG, RX_OVRN_INT);
EDBG_ADAPTERMSG(ZONE_WARNING,("!GetFrame: RX Overrun, wInt = 0x%x\n", wInt));
}
if (!(wInt & RCV_INT)) {
WriteWord (INTERRUPT_REG, wIntMask); // re-enable interrupt
return FALSE; // no data
}
// receive the frame
wStatusWord = SMCRetrieveFrame (pbData, pwLength);
// Release the memory for the received Frame
SMCReleaseMemory (CMD_REM_REL_TOP);
#ifdef SMC_DUMP_FRAMES
DumpEtherFrame(pbData, *pwLength);
#endif
// 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" );
} while (wStatusWord);
// re-enable interrupt only if there is no pending frame
if (!(ReadWord (INTERRUPT_REG) & RCV_INT))
WriteWord (INTERRUPT_REG, wIntMask);
// debug message.
EDBG_ADAPTERMSG(ZONE_RECV,("-GetFrame %s, *pwLength = %u\n", wStatusWord? "Fail" : "Success", *pwLength));
EDBG_DEBUGLED(LED_GETFRAME_EXIT, wStatusWord);
if (!wStatusWord && *pwLength>=4)
*pwLength -=4;// Take away CRC
return !wStatusWord;
} // 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 )
{
static UINT16 wFrameHandle;
UINT16 cwBufferSize;
UINT16 wCompletionCode = 0;
UINT16 *pwData;
DWORD dwStartTime;
BOOL bErr = FALSE;
UINT16 wInt;
DWORD i;
UINT16 wTxDonePacketNum;
static BOOL flgFirst=TRUE;
if ((DWORD) pbData & 1) {
EdbgOutputDebugString ("!SMCSendFrame: Data MUST be 16bit aligned\r\n");
return FALSE;
}
WriteWord( BANKSEL_REG, BANK2 );
WriteWord (INTERRUPT_REG, 0);
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 amount of memory needed. This needs to be rounded up to an even number
cwBufferSize = 2 + 2 + (UINT16)dwLength + 1;
if (cwBufferSize & 1)
cwBufferSize++;
if(flgFirst) {
flgFirst = FALSE;
// Allocate memory in the buffer for the Frame
WriteWord( MMUCOMMAND_REG, CMD_ALLOC | (UINT16)(1500 >> 8) );
// Loop here until the request is satisfied, or we timeout
dwStartTime = OEMEthGetSecs();
while (!((wInt = 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 );
WriteWord (INTERRUPT_REG, wIntMask);
return wCompletionCode;
}
}
wFrameHandle = (0x3f00 & 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, (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, CMD_ENQ_TX );
bErr = TRUE;
dwStartTime = OEMEthGetSecs();
while (OEMEthGetSecs() - dwStartTime < 2) {
wInt = ReadWord (INTERRUPT_REG);
if (wInt & TX_INT) {
wTxDonePacketNum = ReadWord (FIFOPORTS_REG);
wTxDonePacketNum &= 0x003f;
WriteWord( PNR_ARR_REG, wTxDonePacketNum );
WriteWord( POINTER_REG, 0x2000 );
if ( ReadWord( DATA_REG ) & EPH_TX_OK) {
bErr = FALSE;
} else {
bErr = TRUE;
}
break;
}
}
if (bErr)
EdbgOutputDebugString( "SendFrame timeout waiting for TX interrupt! INTERRUPT_REG = 0x%x\r\n", wInt);
if (bErr) {
// Get the status word so that it can be returned.
WriteWord( POINTER_REG, 0x2000 );
wCompletionCode = ReadWord( DATA_REG );
SendFrameError("!EDBG error ",wCompletionCode);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -