📄 lan91c.c
字号:
if ((INPORT16(&g_pLAN91C->INTR) & INTR_TX) == 0)
{
OALMSGS(OAL_ERROR, (L"ERROR: LAN91CSendFrame: Timed out waiting for the transfer to complete.\r\n"));
return(1);
}
// Read TXDONE Pkt# from FIFO Port Register
OUTPORT16(&g_pLAN91C->BANKSEL, 2);
packetNumber = (INPORT16(&g_pLAN91C->FIFO) & 0x3F);
// Write to Packet Number Register
OUTPORT16(&g_pLAN91C->PNRARR, packetNumber);
// Retrieve packet status
OUTPORT16(&g_pLAN91C->PTR, (PTR_AUTOINC | PTR_READ));
OALStall(100);
rc = INPORT16(&g_pLAN91C->DATA);
// SQET bit always set on lan91c111 and lan100FD (so mask it) on all plats
rc &= ~EPH_STAT_SQET;
// Release the packet
switch (GET_CHIP_ID(g_chipRevision)) {
case CHIP_ID_LAN91C111:
OUTPORT16(&g_pLAN91C->MMUCR, MMUCR_111_RELEASE_TX);
break;
default:
OUTPORT16(&g_pLAN91C->MMUCR, MMUCR_REL_SPEC);
}
while ((INPORT16(&g_pLAN91C->MMUCR) & MMUCR_BUSY) != 0);
// Clear the tx interrupt status
SETPORT16(&g_pLAN91C->INTR, INTR_TX);
// Tx error?
if (rc & (EPH_STAT_TXUNRN | EPH_STAT_SQET | EPH_STAT_LOSTCARR | EPH_STAT_LATCOL | EPH_STAT_16COL))
{
// Display error status.
OALMSGS(OAL_ERROR, (L"ERROR: LAN91CSendFrame: status = ( "));
if (rc & EPH_STAT_TXUNRN)
{
OALMSGS(OAL_ERROR, (L"TXUNRN "));
}
if (rc & EPH_STAT_SQET)
{
OALMSGS(OAL_ERROR, (L"SQET "));
}
if (rc & EPH_STAT_LOSTCARR)
{
OALMSGS(OAL_ERROR, (L"LOSTCARR "));
}
if (rc & EPH_STAT_LATCOL)
{
OALMSGS(OAL_ERROR, (L"LATCOL "));
}
if (rc & EPH_STAT_16COL)
{
OALMSGS(OAL_ERROR, (L"16COL "));
}
OALMSGS(OAL_ERROR, (L")\r\n"));
// Re-enable TXENA
OUTPORT16(&g_pLAN91C->BANKSEL, 0);
OUTPORT16(&g_pLAN91C->TCR, TCR_PADEN|TCR_TXEN);
// Failure.
rc = 1;
}
else
{
// Success.
rc = 0;
}
// Clear the statistics registers
OUTPORT16(&g_pLAN91C->BANKSEL, 0);
INPORT16(&g_pLAN91C->ECR);
// Set back bank 2
OUTPORT16(&g_pLAN91C->BANKSEL, 2);
return rc;
}
//------------------------------------------------------------------------------
UINT16 LAN91CGetFrame(UINT8 *pBuffer, UINT16 *pLength)
{
UINT8 *pos = pBuffer;
UINT16 code, pointer;
UINT32 length, count;
BOOL bErr = FALSE;
// Make sure that bank 2 is actual
OUTPORT16(&g_pLAN91C->BANKSEL, 2);
length = 0;
while ((INPORT16(&g_pLAN91C->INTR) & INTR_RX) != 0) {
// Setup pointer address register
pointer = PTR_RCV | PTR_READ;
// Read status
OUTPORT16(&g_pLAN91C->PTR, pointer);
code = INPORT16(&g_pLAN91C->DATA);
pointer += sizeof(UINT16);
if ((code & (STAT_ALGNERR|STAT_BADCRC|STAT_LONG|STAT_SHORT)) == 0) {
// Get packet size
OUTPORT16(&g_pLAN91C->PTR, pointer);
length = (INPORT16(&g_pLAN91C->DATA) & 0x07FF) - 6;
pointer += sizeof(UINT16);
// Check packet size
if( length <= *pLength )
{
// Copy packet
count = length;
while (count > 1) {
OUTPORT16(&g_pLAN91C->PTR, pointer);
*(UINT16*)pos = INPORT16(&g_pLAN91C->DATA);
pointer += sizeof(UINT16);
pos += sizeof(UINT16);
count -= sizeof(UINT16);
}
// Get control word (which can contain last byte)
OUTPORT16(&g_pLAN91C->PTR, pointer);
code = INPORT16(&g_pLAN91C->DATA);
pointer += sizeof(UINT16);
if ((code & CTRL_ODD) != 0) {
length++;
*pos = (UINT8)code;
}
}
else
{
// Error getting the packet size
OALMSGS(OAL_ERROR, (L"ERROR: LAN91CGetFrame: packet size (%d) > than buf len (%d)\r\n", length, *pLength ));
length = 0;
bErr = TRUE;
}
}
// Release the memory for the received frame
switch (GET_CHIP_ID(g_chipRevision)) {
case CHIP_ID_LAN91C111:
OUTPORT16(&g_pLAN91C->MMUCR, MMUCR_111_REM_REL_RX);
break;
default:
OUTPORT16(&g_pLAN91C->MMUCR, MMUCR_REM_REL_TOP);
}
while ((INPORT16(&g_pLAN91C->MMUCR) & MMUCR_BUSY) != 0);
// If error, break
if( bErr ) break;
// If length is non zero we get a packet
if (length > 0) break;
}
*pLength = (UINT16)length;
return (*pLength);
}
//------------------------------------------------------------------------------
VOID LAN91CEnableInts()
{
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"+LAN91CEnableInts\r\n"));
// Only enable receive interrupts (we poll for Tx completion)
OUTPORT16(&g_pLAN91C->BANKSEL, 2);
OUTPORT16(&g_pLAN91C->INTR, INTR_RX_MASK);
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-LAN91CEnableInts\r\n"));
}
//------------------------------------------------------------------------------
VOID LAN91CDisableInts()
{
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"+LAN91CDisableInts\r\n"));
// Disable all interrupts
OUTPORT16(&g_pLAN91C->BANKSEL, 2);
OUTPORT16(&g_pLAN91C->INTR, 0);
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-LAN91CDisableInts\r\n"));
}
//------------------------------------------------------------------------------
VOID LAN91CCurrentPacketFilter(UINT32 filter)
{
UINT16 rcr = RCR_RXEN|RCR_STRIP_CRC;
OALMSGS(OAL_ETHER&&OAL_FUNC, (
L"+LAN91CCurrentPacketFilter(0x%08x)\r\n", filter
));
if ((filter & PACKET_TYPE_ALL_MULTICAST) != 0) rcr |= RCR_ALMUL;
if ((filter & PACKET_TYPE_PROMISCUOUS) != 0) rcr |= RCR_PRMS;
OUTPORT16(&g_pLAN91C->BANKSEL, 0);
OUTPORT16(&g_pLAN91C->RCR, rcr);
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-LAN91CCurrentPacketFilter\r\n"));
}
//------------------------------------------------------------------------------
BOOL LAN91CMulticastList(UINT8 *pAddresses, UINT32 count)
{
UINT32 crc, i;
UINT16 h[4];
OALMSGS(OAL_ETHER&&OAL_FUNC, (
L"+LAN91CMulticastList(0x%08x, %d)\r\n", pAddresses, count
));
// Calculate hash bits
h[0] = h[1] = h[2] = h[3] = 0;
for (i = 0; i < count; i++) {
crc = Crc(pAddresses);
h[crc >> 30] |= 1 << ((crc >> 26) & 0x0F);
pAddresses += 6;
}
// Write it to hardware
OUTPORT16(&g_pLAN91C->BANKSEL, 3);
OUTPORT16(&g_pLAN91C->MT[0], h[0]);
OUTPORT16(&g_pLAN91C->MT[1], h[1]);
OUTPORT16(&g_pLAN91C->MT[2], h[2]);
OUTPORT16(&g_pLAN91C->MT[3], h[3]);
OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-LAN91CMulticastList(rc = 1)\r\n"));
return TRUE;
}
//------------------------------------------------------------------------------
UINT32 Crc(UINT8 *pAddress)
{
UINT32 crc, carry;
UINT32 i, j;
UINT8 uc;
crc = 0xFFFFFFFF;
for (i = 0; i < 6; i++) {
uc = pAddress[i];
for (j = 0; j < 8; j++) {
carry = ((crc & 0x80000000) ? 1 : 0) ^ (uc & 0x01);
crc <<= 1;
uc >>= 1;
if (carry) crc = (crc ^ 0x04c11db6) | carry;
}
}
return crc;
}
//------------------------------------------------------------------------------
static VOID PhyWrite(UINT8 PHYaddr, UINT8 PHYreg, UINT16 PHYdata)
{
INT32 i;
UINT16 mask;
UINT16 mii_reg;
UINT8 bits[65];
INT32 clk_idx = 0;
// 32 consecutive ones on MDO to establish sync.
//
for (i = 0; i < 32; ++i)
{
bits[clk_idx++] = MGMT_MDOE | MGMT_MDO;
}
// Start code <01>.
//
bits[clk_idx++] = MGMT_MDOE;
bits[clk_idx++] = MGMT_MDOE | MGMT_MDO;
// Write command <01>.
//
bits[clk_idx++] = MGMT_MDOE;
bits[clk_idx++] = MGMT_MDOE | MGMT_MDO;
// Output the PHY address, msb first.
//
mask = (UINT8)0x10;
for (i = 0; i < 5; ++i)
{
if (PHYaddr & mask)
bits[clk_idx++] = MGMT_MDOE | MGMT_MDO;
else
bits[clk_idx++] = MGMT_MDOE;
// Shift to next lowest bit.
mask >>= 1;
}
// Output the PHY register number, msb first.
//
mask = (UINT8)0x10;
for (i = 0; i < 5; ++i)
{
if (PHYreg & mask)
bits[clk_idx++] = MGMT_MDOE | MGMT_MDO;
else
bits[clk_idx++] = MGMT_MDOE;
// Shift to next lowest bit.
mask >>= 1;
}
// Tristate and turnaround (2 bit times).
//
bits[clk_idx++] = 0;
bits[clk_idx++] = 0;
// Write out 16 bits of data, msb first.
//
mask = 0x8000;
for (i = 0; i < 16; ++i)
{
if (PHYdata & mask)
bits[clk_idx++] = MGMT_MDOE | MGMT_MDO;
else
bits[clk_idx++] = MGMT_MDOE;
// Shift to next lowest bit.
mask >>= 1;
}
// Final clock bit (tristate).
//
bits[clk_idx++] = 0;
// Select bank 3.
//
OUTPORT16(&g_pLAN91C->BANKSEL, 3);
// Get the current MII register value.
//
mii_reg = INPORT16(&g_pLAN91C->MGMT);
// Turn off all MII Interface bits.
//
mii_reg &= ~(MGMT_MDOE | MGMT_MCLK |
MGMT_MDI | MGMT_MDO);
// Clock all cycles.
//
for (i = 0; i < sizeof bits; ++i)
{
// Clock Low - output data.
//
OUTPORT16(&g_pLAN91C->MGMT, mii_reg | bits[i]);
OALStall(50);
// Clock Hi - input data.
//
OUTPORT16(&g_pLAN91C->MGMT, (UINT16)(mii_reg | bits[i] | MGMT_MCLK));
OALStall(50);
bits[i] |= INPORT16(&g_pLAN91C->MGMT) & MGMT_MDI;
}
// Return to idle state. Set clock to low, data to low, and output tristated.
//
OUTPORT16(&g_pLAN91C->MGMT, mii_reg);
OALStall(50);
}
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -