📄 cs8950.c
字号:
{
pCD->pRxStatNext = pCD->pRxStat;
}
/* Enqueue the number of receive descriptors processed to the chip */
WriteDWord( OpReg_RxDEQ, 1 );
/* Enqueue the number of receive status entries processed to the chip */
WriteDWord( OpReg_RxSEQ, 1 );
//
// Need to perform a dummy read to clear the interrupt status if there are no
// more interrupt packets.
//
Status = pCD->pRxStatNext->RxStat;
if (!(Status & RxStat_RxFP))
{
Status = ReadDWord(OpReg_IntStsC);
}
Global_RxTotalCnt++;
// EdbgOutputDebugString("\nCS8950 CS8950GetFrame(): Global_RxTotalCnt=%d\n",Global_RxTotalCnt);
//RxWorkaround();
/* Frame Length == 0 means the received frame with error*/
if ( *pwLength == 0 )
{
EdbgOutputDebugString("\n CS8950GetFrame(): Length = 0\r\n");
return FALSE;
}
//
// Lets send the frame out again as a broadcast packet.
//
#if 0
memcpy(tempFrame, pbData,*pwLength);
tempFrame[0] = 0x00;
tempFrame[1] = 0x06;
tempFrame[2] = 0x5B;
tempFrame[3] = 0xd3;
tempFrame[4] = 0xFC;
tempFrame[5] = 0x98;
tempFrame[6] = 0x00;
tempFrame[7] = 0x00;
tempFrame[8] = 0x00;
tempFrame[9] = 0x00;
tempFrame[10] = 0x00;
tempFrame[11] = 0x00;
CS8950SendFrame
(
tempFrame,
*pwLength
);
#endif // 0
return TRUE;
}
//****************************************************************************
// CS8950EnableInts
//****************************************************************************
// Public function that enables ethernet interrupts.
//
//
void CS8950EnableInts(void)
{
EdbgOutputDebugString("CS8950EnableInts\r\n");
WriteDWord(OpReg_IntEn, IntEn_RxEOFiE );
WriteDWord(OpReg_FERMask, GIntMask_Interrupt);
}
//****************************************************************************
// CS8950DisableInts
//****************************************************************************
// Public function that disables ethernet interrupts.
//
//
void CS8950DisableInts(void)
{
EdbgOutputDebugString("CS8950DisableInts\r\n");
WriteDWord(OpReg_IntEn, 0);
WriteDWord(OpReg_FERMask, 0 );
}
//****************************************************************************
// CS8950GetPendingInterrupts
//****************************************************************************
// Public function that return INTR_TYPE_RX if there are pending ethernet
// receive interrupts.
//
//
DWORD CS8950GetPendingInterrupts(void)
{
PCD pCD;
pCD = (PCD)pChip->pData;
if (pCD->pRxStatNext->RxStat & RxStat_RxFP)
{
EdbgOutputDebugString("R");
return INTR_TYPE_RX;
}
EdbgOutputDebugString("n");
return 0;
}
//****************************************************************************
// CS8950ReadEEPROM
//****************************************************************************
// Public function to read the pseudo EEPROM
//
//
BOOL CS8950ReadEEPROM
(
UINT16 EEPROMAddress,
UINT16 *pwVal
)
{
*pwVal = gusMacAddr[EEPROMAddress];
return TRUE;
}
//****************************************************************************
// CS8950WriteEEPROM
//****************************************************************************
// Public function to write the psuedo EEPROM.
//
//
BOOL CS8950WriteEEPROM
(
UINT16 EEPROMAddress,
UINT16 Data
)
{
gusMacAddr[EEPROMAddress] = Data;
return TRUE;
}
/******************************************************************************
*
* CS8950MulticastAddAll()
*
******************************************************************************/
void CS8950MulticastAddAll(void)
{
DWORD RxControl;
/* Get the current settings of the receiver control register */
RxControl=ReadDWord( OpReg_RxCTL );
/* Turn off the receiver while changing the hash table */
WriteDWord( OpReg_RxCTL, RxControl & ~RxCTL_SerRxON );
/* Set all the bits in the hash table */
WriteByte( OpReg_AFP, AFP_Hash );
WriteDWord( OpReg_HashTb , 0xFFFFFFFF );
WriteDWord( OpReg_HashTb+4, 0xFFFFFFFF );
/* Turn the receiver back on */
WriteDWord(OpReg_RxCTL, RxControl );
}
//****************************************************************************
// GetMACAddress
//****************************************************************************
//
//
//
static int GetMACAddress(USHORT *MacAddr)
{
if(gusMacAddr[0] == 0 && gusMacAddr[1] == 0 && gusMacAddr[2] == 0)
return FALSE;
//
// Currently copy the Mac Address from internal ram.
//
MacAddr[0] = gusMacAddr[0];
MacAddr[1] = gusMacAddr[1];
MacAddr[2] = gusMacAddr[2];
return TRUE;
}
/******************************************************************************
*
* PHYAutoNegotiation();
* Purpose: PHY Auto Negotiation to detect the link speed (10/100Mbps) and
* duplex (half/full).
* return: TRUE: successful. FALSE: fail
*
******************************************************************************/
static BOOL PHYAutoNegotiation()
{
unsigned short val;
int x;
unsigned short PhyId;
unsigned char b8;
WORD Result;
char *strDuplex, *strSpeed;
FindPHYType(pChip);
PhyId = ((PCD)pChip->pData)->PHYAddress;
//
// Write to Auto-Negotiation Advertisement Register (0x04)
// Set IEEE_802.3, and advertise 100/10M full/half duplex available
//
val = ANAR_SeltField_IEEE8023 | ANAR_10BaseT_HDX_Able | ANAR_10BaseT_FDX_Able |
ANAR_100BaseTX_HDX_Able | ANAR_100BaseTX_FDX_Able;
Result = WritePHY( pChip, PhyId, PHYReg_ANAR, val);
ASSERT(Result);
/*write to Basic Mode Control Register (0x00), enable and restart auto negotiation*/
val = BMCR_Restart_Auto_Neg| BMCR_Auto_Neg_Enable;
Result = WritePHY( pChip, PhyId, PHYReg_BMCR, val);
for(x = 0; x<MAX_AUTOCONFIGTIME; x++) /* 02/14/02 @melody Auto_Neg should be compeleted in 5 min.*/
{
/* Check if Auto-Negotiation complete? */
DelayInMsec(1);
Result = ReadPHY( pChip, PhyId, PHYReg_BMSR, &val );
if((val & BMSR_Auto_Neg_Complete) )
{
break;
}
}
if(x == MAX_AUTOCONFIGTIME)
{
//
// If this fails set PHY to Full_Duplex 100 Mbit.
//
Result = WritePHY( pChip, 0x0, PHYReg_BMCR, BMCR_Full_Duplex|BMCR_100_MBPS);
//set MAC for Full Duplex too.
b8 = ReadByte(OpReg_TestCTL);
b8 |= TestCTL_MACFDX;
WriteByte(OpReg_TestCTL, b8);
EdbgOutputDebugString("EthernetMAC: Error! PHY cannot complete Auto Negotiation. Set to 100MBps Full Duplex.\n");
return FALSE;
}
//CS8952 needs 1 second delay. Otherwise it won't send the 1st frame.
if ( ((PCD)pChip->pData)->PHYType == PHY_TYPE_CRYSTAL)
{
DelayInMsec(1000);
}
strDuplex = "Half";
/* if the Link is Full Duplex, then set MAC for Full Duplex too. */
Result = ReadPHY( pChip, PhyId, PHYReg_ANLPAR, &val );
if((val & ANLPAR_10BaseT_FDX_Able) || (val & ANLPAR_100BaseTX_FDX_Able))
{
b8 = ReadByte(OpReg_TestCTL);
b8 |= TestCTL_MACFDX;
WriteByte(OpReg_TestCTL, b8);
strDuplex = "Full";
}
strSpeed = "10";
//
// Lets print out the current mode that we are operating in.
//
if((val & ANLPAR_100BaseTX_FDX_Able) || (val & ANLPAR_100BaseTX_HDX_Able))
{
strSpeed = "100";
}
//
// Show the current link mode.
//
EdbgOutputDebugString("EthernetMAC: PhyId=%d PhyType=%d Speed=%s Mbs Duplex=%s.\n",
PhyId, ((PCD)pChip->pData)->PHYType, strSpeed, strDuplex);
return TRUE;
}
/******************************************************************************
*
* ReadPHY()
*
******************************************************************************/
static BOOL ReadPHY( PCHIP pChip, WORD Address, WORD Register, WORD *pValue )
{
BYTE Status;
int x;
/* Ensure that the PHY is not busy */
for ( x=0; x<MAXLOOP; x++ )
{
Status=ReadByte( OpReg_MIISts );
if ( !(Status & MIISts_Busy) ) break;
}
if ( x == MAXLOOP )
{
EdbgOutputDebugString
(
"First PHY read failed, Address =0x%x, Register= 0x%x. \r\n",
Address,
Register
);
return FALSE;
}
/* Issue the command to read the register within the PHY */
WriteWord(OpReg_MIICmd, (WORD)(MIICmd_Opcode_Read |(Address<<5)| Register));
/* Wait until the command is completed */
for ( x=0; x<MAXLOOP; x++ )
{
Status=ReadByte( OpReg_MIISts);
if ( !(Status & MIISts_Busy) )
break;
}
if ( x == MAXLOOP )
{
EdbgOutputDebugString("Second PHY read failed!");
return MAC_FAILED;
}
/* Get the PHY data from the PHY Data register */
*pValue=ReadWord( OpReg_MIIData );
return TRUE;
}
/******************************************************************************
*
* WritePHY()
*
******************************************************************************/
static BOOL WritePHY( PCHIP pChip, WORD Address, WORD Register, WORD Value )
{
BYTE Status;
int x;
/* Ensure that the PHY is not busy */
for ( x=0; x<MAXLOOP; x++ )
{
Status=ReadByte( OpReg_MIISts);
if ( !(Status & MIISts_Busy) ) break;
}
if ( x == MAXLOOP )
{
EdbgOutputDebugString
(
"First PHY write failed, Address = 0x%x, Register = 0x%x, Value = 0x%x.\r\n",
(ULONG)Address,
(ULONG)Register,
(ULONG)Value
);
return FALSE;
}
/* Put the PHY data into the PHY Data register */
WriteWord( OpReg_MIIData, Value );
/* Issue the command to write to the register within the PHY */
WriteWord( OpReg_MIICmd,(WORD)(MIICmd_Opcode_Write |(Address<<5)| Register));
/* Wait until the command is completed */
for ( x=0; x<MAXLOOP; x++ )
{
Status=ReadByte( OpReg_MIISts );
if ( !(Status & MIISts_Busy) )
break;
}
if ( x == MAXLOOP )
{
EdbgOutputDebugString
(
"Second PHY write failed, Address = 0x%x, Register = 0x%x, Value = 0x%x.\r\n",
(ULONG)Address,
(ULONG)Register,
(ULONG)Value
);
return FALSE;
}
return TRUE;
}
static BOOL Check_PHY_ID_Type( PCHIP pChip, WORD PHYAddress)
{
PCD pCD;
BOOL Result;
union
{
WORD Word[2];
DWORD DWord;
} PHYID;
pCD = (PCD)pChip->pData;
/* Read PHY ID register 1 */
Result = ReadPHY( pChip, PHYAddress, PHYReg_PHYIDR1, &PHYID.Word[1] );
if ( Result != TRUE )
{
return FALSE;
}
/* Read PHY ID register 2 */
Result = ReadPHY( pChip, PHYAddress, PHYReg_PHYIDR2, &PHYID.Word[0] );
if ( Result != TRUE )
{
return FALSE;
}
/* Not a Valid PhyID */
if (PHYID.DWord == 0xffffffff || PHYID.DWord == 0x0)
{
return FALSE;
}
/* Check if it is a PHY that we know about */
if ( ((PHYID.DWord & PHYID_OUI_Mask) == PHYID_OUI_National) &&
((PHYID.DWord & PHYID_Model_Mask) == PHYID_Model_DP83840) )
{
pCD->PHYType = PHY_TYPE_NATIONAL;
DEBUGMSG(ZONE_INIT,(TEXT("Detected National PHY at address: %x\r\n"), PHYAddress) );
}
else if ( ((PHYID.DWord & PHYID_OUI_Mask) == PHYID_OUI_Crystal) &&
((PHYID.DWord & PHYID_Model_Mask) == PHYID_Model_CS8952) )
{
pCD->PHYType = PHY_TYPE_CRYSTAL;
DEBUGMSG(ZONE_INIT,(TEXT("Detected Crystal PHY at address: %x\r\n"), PHYAddress) );
}
else if ( ((PHYID.DWord & PHYID_OUI_Mask) == PHYID_OUI_ICS) &&
((PHYID.DWord & PHYID_Model_Mask) == PHYID_Model_ICS1890) )
{
pCD->PHYType = PHY_TYPE_ICS;
DEBUGMSG(ZONE_INIT,(TEXT("Detected ICS1890 PHY at address: %x\r\n"), PHYAddress) );
}
else if ( ((PHYID.DWord & PHYID_OUI_Mask) == PHYID_OUI_BROADCOM) &&
((PHYID.DWord & PHYID_Model_Mask) == PHYID_Model_BCM5201) )
{
pCD->PHYType = PHY_TYPE_BROADCOM;
DEBUGMSG(ZONE_INIT,(TEXT("Detected Broadcom PHY at address: %x\r\n"), PHYAddress) );
}
else if ( ((PHYID.DWord & PHYID_OUI_Mask) == PHYID_OUI_MICREL) &&
((PHYID.DWord & PHYID_Model_Mask) == PHYID_Model_KS8721BL) )
{
pCD->PHYType = PHY_TYPE_MICREL_8721BL;
DEBUGMSG(ZONE_INIT,(TEXT("Detected Micrel KS8721BL PHY at address: %x\r\n"), PHYAddress ));
}
else if (PHYID.DWord == 0x00406212)
{
pCD->PHYType = PHY_TYPE_BROADCOM;
DEBUGMSG(ZONE_INIT,(TEXT("Detected Broadcom PHY at address: %x\r\n"), PHYAddress) );
}
else if (PHYID.DWord == 0x78100003)
{
pCD->PHYType = PHY_TYPE_LEVEL1; /* clc */
DEBUGMSG(ZONE_INIT,(TEXT("Detected Level1 PHY at address: %x\r\n"), PHYAddress) );
} else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -