📄 smc.c
字号:
// Clear the statistics registers
WriteWord( BANKSEL_REG, BANK0 );
ReadWord( COUNTER_REG );
// Re-enable TXENA
WriteWord( TCR_REG, TCR_REG_INIT );
WriteWord( BANKSEL_REG, BANK2 );
if (TX_INT & wInt) {
WriteWord (INTERRUPT_REG, TX_INT); // Ack TX_INT
}
EDBG_DEBUGLED(LED_SENDFRAME_EXIT, wCompletionCode);
} else {
WriteWord( BANKSEL_REG, BANK2 );
WriteWord (INTERRUPT_REG, TX_INT); // Ack TX_INT
EDBG_ADAPTERMSG(ZONE_SEND,("-SendFrame, success\n"));
EDBG_DEBUGLED(LED_SENDFRAME_EXIT,0);
}
WriteWord (BANKSEL_REG, BANK2);
WriteWord (INTERRUPT_REG, wIntMask);
return wCompletionCode;
} // 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 );
}
#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, (EEPROMAddress & 0x003F) | 0x6000 );
WriteWord( BANKSEL_REG, BANK1 );
WriteWord( CONTROL_REG, 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, (EEPROMAddress & 0x003F) | 0x6000 );
WriteWord( BANKSEL_REG, BANK1 );
WriteWord( GENERAL_REG, Data );
WriteWord( CONTROL_REG, ReadWord(CONTROL_REG) | 0x0005 );
// Loop until EEPROM data is written
dwCurTime = OEMEthGetSecs();
while( ReadWord( CONTROL_REG ) & 0x0003 ) {
if ((OEMEthGetSecs() - dwCurTime) > 2) {
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;
}
////////////////////////////////////////////////////////////////////////////////
// SMCComputeCrc()
//
// Description:
//
// Runs the AUTODIN II CRC algorithm on buffer Buffer of length Length.
//
// Arguments:
//
// Buffer - the input buffer
// Length - the length of Buffer
//
// Return value:
//
// The 32-bit CRC value.
//
// Note:
//
// This function is adopted from netcard\ne2000 miniport driver.
//
ULONG
SMCComputeCrc(
IN PUCHAR Buffer,
IN UINT Length)
{
ULONG Crc, Carry;
UINT i, j;
UCHAR CurByte;
Crc = 0xffffffff;
for (i = 0; i < Length; i++) {
CurByte = Buffer[i];
for (j = 0; j < 8; j++) {
Carry = ((Crc & 0x80000000) ? 1 : 0) ^ (CurByte & 0x01);
Crc <<= 1;
CurByte >>= 1;
if (Carry) {
Crc = (Crc ^ 0x04c11db6) | Carry;
}
}
}
return Crc;
} // SMCComputeCrc()
////////////////////////////////////////////////////////////////////////////////
// SMCMulticastList()
//
// Description:
//
// This function is used to insert multicast addresses to the h/w.
//
// Arguments:
//
// pucMulticastAddresses :: The list of multicast addressses.
// dwNoOfAddresses :: The number of addresses in the list.
//
// Return value:
//
// TRUE if successful, FALSE otherwise.
//
BOOL
SMCMulticastList(PUCHAR pucMulticastAddresses, DWORD dwNoOfAddresses)
{
UCHAR NicMulticastRegs[8]; // contents of card multicast registers
UINT i;
DWORD dwCRC;
EdbgOutputDebugString(
"SMC111:: SMCMulticastList() set [%d] multicast list addrs.\r\n",
dwNoOfAddresses);
#if 1
for (i = 0 ; i < dwNoOfAddresses ; i++)
{
EdbgOutputDebugString(
"SMC111:: Multicast[%d] = %x-%x-%x-%x-%x-%x\r\n",
i,
pucMulticastAddresses[6*i + 0],
pucMulticastAddresses[6*i + 1],
pucMulticastAddresses[6*i + 2],
pucMulticastAddresses[6*i + 3],
pucMulticastAddresses[6*i + 4],
pucMulticastAddresses[6*i + 5]);
}
#endif
//
// First turn all bits off.
//
memset (NicMulticastRegs, 0x00, sizeof(NicMulticastRegs));
//
// Now turn on the bit for each address in the multicast list.
//
for (i = 0 ; i < dwNoOfAddresses ; i++)
{
dwCRC = SMCComputeCrc(
&pucMulticastAddresses[6*i],
6);
//
// Here is what the spec says:
// The hash value is defined as the six MSB of the CRC of the
// destination addr.
// The three MSB determine the register to be used (MT0..MT7)
// The other three determine the bit within the register.
//
NicMulticastRegs[dwCRC >> 29] |= (1 << ((dwCRC >> 26) & 0x07));
}
#if 1
EdbgOutputDebugString(
"SMC111:: Writing MulticastRegs = %x-%x-%x-%x-%x-%x-%x-%x\r\n",
NicMulticastRegs[0],
NicMulticastRegs[1],
NicMulticastRegs[2],
NicMulticastRegs[3],
NicMulticastRegs[4],
NicMulticastRegs[5],
NicMulticastRegs[6],
NicMulticastRegs[7]);
#endif
//
// Finally, burn that in the h/w..
//
WriteWord (BANKSEL_REG, BANK3);
WriteWord (MULTITAB_REG0, *(PWORD)&NicMulticastRegs[0]);
WriteWord (MULTITAB_REG1, *(PWORD)&NicMulticastRegs[2]);
WriteWord (MULTITAB_REG2, *(PWORD)&NicMulticastRegs[4]);
WriteWord (MULTITAB_REG3, *(PWORD)&NicMulticastRegs[6]);
EdbgOutputDebugString(
"SMC111:: Read back: %x-%x-%x-%x\r\n",
ReadWord(MULTITAB_REG0),
ReadWord(MULTITAB_REG1),
ReadWord(MULTITAB_REG2),
ReadWord(MULTITAB_REG3));
return TRUE;
} // SMCMulticastList()
////////////////////////////////////////////////////////////////////////////////
// SMCCurrentPacketFilter()
//
// Description:
//
// This function is called to set the h/w filter.
// We support:
// PROMISCUOUS, ALL MULTICAST, BROADCAST, DIRECTED.
//
// Arguments:
//
// dwFilter:: The filter mode
//
// Return value:
//
// TRUE if successful, FALSE otherwise.
//
void
SMCCurrentPacketFilter(DWORD dwFilter)
{
//
// EDBG always receive directed and broadcast as a minimum.
// So our default will be RCR_REG_INIT..
//
WORD wRxControlReg = RCR_REG_INIT;
if (dwFilter & PACKET_TYPE_ALL_MULTICAST)
wRxControlReg |= 0x04;
if (dwFilter & PACKET_TYPE_PROMISCUOUS)
wRxControlReg |= 0x02;
//
// I think Broadcast is always received for smc111, so we don't
// need to do anything to this flag..
//
EdbgOutputDebugString("SMC111:: Set filter to : [0x%x]\r\n",
wRxControlReg);
WriteWord (BANKSEL_REG, BANK0);
WriteWord (RCR_REG, wRxControlReg);
} // SMCCurrentPacketFilter()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -