📄 lan91c11x.c
字号:
if (packet_num & LAN_FIFOPORT_RCVFIFO_EMPTY)
{
if (EtherVerbose)
printf("lan91c11x WARNING: nothing on rx FIFO. \n");
return 0;
}
// definitely got a packet
EtherRFRAMECnt++;
// tell the lan91c11x to move the received packet to the
// data area so we can process it
lan91c11x_wr(LAN_PTR, LAN_PTR_RCV
| LAN_PTR_AUTOINC
| LAN_PTR_READ);
for(i = 0; i < 100; i++); /* delay necessary between POINTER */
/* and DATA access. */
rfsw = lan91c11x_rd(LAN_DATA1); /* Receive frame status word */
count = lan91c11x_rd(LAN_DATA1); /* Byte count. */
if (count < 16)
{
if (EtherVerbose)
printf("lan91c11x Invalid receive count = 0x%04x, Status Word = 0x%04x.\n", count, rfsw);
return 0;
}
count &= 0x7ff; /* Upper 5 bits are reserved. */
count -= 4; /* Deduct for RFSW and ByteCount */
if (!(rfsw & LAN_RFSW_ODD_LEN)) /* Deduct for CTRL byte and possibly */
pktsize = count - 2; /* one more because len != odd. */
else
pktsize = count - 1;
data = (ushort *)pktbuf; // we do 16-bit reads
if (count >= 1600)
{
if (EtherVerbose)
printf("lan91c11x geteinbuf() overflow (cnt=0x%04x)\n",count);
enreset();
eninit();
return 0; // no packets available
}
// retreive the receieve packet
if (count & 1) count++;
while(count > 0)
{
*data++ = lan91c11x_rd(LAN_DATA1);
count -= 2;
}
// tell the lan91c11x to release the memory used by this packet
lan91c11x_wr(LAN_MMU_CMD, LAN_MMU_CMD_RMRELRXFRAME);
// check the frame for errors and update the appropriate counters
if (rfsw & (LAN_RFSW_ALGN_ERR
| LAN_RFSW_BADCRC
| LAN_RFSW_TOOLNG
| LAN_RFSW_TOOSHORT))
{
if (rfsw & LAN_RFSW_ALGN_ERR) {
EtherALGNERRCnt++;
if (EtherVerbose)
printf("Frame alignment error!\n");
}
if (rfsw & LAN_RFSW_BADCRC) {
EtherBADCRCCnt++;
if (EtherVerbose)
printf("Bad CRC!\n");
}
if (rfsw & LAN_RFSW_TOOLNG) {
EtherTOOLONGCnt++;
if (EtherVerbose)
printf("Frame too long!\n");
}
if (rfsw & LAN_RFSW_TOOLNG) {
EtherTOOSHORTCnt++;
if (EtherVerbose)
printf("Frame too short!\n");
}
return(-1);
}
processPACKET((struct ether_header *)pktbuf, pktsize);
if (EtherVerbose == SHOW_ALL){
printf("lan91c11x: Receive Packet Complete.\n");
}
return count;
} // if RCV_INT
return 0;
}
void
lan91c11x_show_stats(void)
{
ushort status;
printf("Receiver overrun errors: %d\n",EtherRXOVRNCnt);
printf("Alignment errors: %d\n",EtherALGNERRCnt);
printf("Bad CRC errors: %d\n",EtherBADCRCCnt);
printf("Packet too long errors: %d\n",EtherTOOLONGCnt);
printf("Packet too short errors: %d\n",EtherTOOSHORTCnt);
printf("Wait-for-alloc timeouts: %d\n",EtherWFATMTCnt);
status = lan91c11x_phy(PHY_INT, 0, 0);
printf("Link: %dBaseT %s duplex\n",
status & PHY_INT_SPDDET ? 100 : 10,
status & PHY_INT_DPLXDET ? "full" : "half");
}
//--------------------------------------------------------------------------
// lan91c11x_phy()
//
// This function reads or writes a register in the lan91c11x PHY
//
ushort lan91c11x_phy(uchar phyreg, ushort phydata, int phy_dir)
{
int i;
ushort mask;
ushort bits[64]; // array to hold the writes to the LAN_MGMT Register
int clk_idx = 0;
int input_idx = 0;
// 32 consecutive ones on MDO to establish sync
for (i = 0; i < 32; ++i)
bits[clk_idx++] = LAN_MGMT_MDOE | LAN_MGMT_MDO;
// Start code <01>
bits[clk_idx++] = LAN_MGMT_MDOE;
bits[clk_idx++] = LAN_MGMT_MDOE | LAN_MGMT_MDO;
if (phy_dir == 0) // read
{
// Read command <10>
bits[clk_idx++] = LAN_MGMT_MDOE | LAN_MGMT_MDO;
bits[clk_idx++] = LAN_MGMT_MDOE;
}
else
{
// Write command <01>
bits[clk_idx++] = LAN_MGMT_MDOE;
bits[clk_idx++] = LAN_MGMT_MDOE | LAN_MGMT_MDO;
}
// Output the PHY address, msb first - Internal PHY is address 0
for (i = 0; i < 5; ++i)
{
bits[clk_idx++] = LAN_MGMT_MDOE;
}
// Output the phy register number, msb first
mask = 0x10;
for (i = 0; i < 5; ++i)
{
if (phyreg & mask)
bits[clk_idx++] = LAN_MGMT_MDOE | LAN_MGMT_MDO;
else
bits[clk_idx++] = LAN_MGMT_MDOE;
// Shift to next lowest bit
mask >>= 1;
}
if (phy_dir == 0) // read
{
// 1 extra bit time for turnaround
bits[clk_idx++] = 0;
// Input starts at this bit time
input_idx = clk_idx;
// Will input 16 bits
for (i = 0; i < 16; ++i)
bits[clk_idx++] = 0;
}
else // write
{
// 2 extra bit times for turnaround
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++] = LAN_MGMT_MDOE | LAN_MGMT_MDO;
else
bits[clk_idx++] = LAN_MGMT_MDOE;
// Shift to next lowest bit
mask >>= 1;
}
} // else write
// Final clock bit
bits[clk_idx++] = 0;
// Turn off all MII Interface bits
lan91c11x_wr(LAN_MGMT, lan91c11x_rd(LAN_MGMT) & 0xfff0);
// Clock all 64 cycles
for (i = 0; i < sizeof bits; ++i)
{
// Clock Low - output data
lan91c11x_wr(LAN_MGMT, bits[i]);
monDelay(2);
// Clock Hi - input data
lan91c11x_wr(LAN_MGMT, bits[i] | LAN_MGMT_MCLK);
monDelay(2);
bits[i] |= lan91c11x_rd(LAN_MGMT) & LAN_MGMT_MDI;
}
// Return to idle state
// Set clock to low, data to low, and output tristated
lan91c11x_wr(LAN_MGMT, lan91c11x_rd(LAN_MGMT) & 0xfff0);
monDelay(2);
if (phy_dir == 0) // read
{
// Recover input data
phydata = 0;
for (i = 0; i < 16; ++i)
{
phydata <<= 1;
if (bits[input_idx++] & LAN_MGMT_MDI)
phydata |= 0x0001;
}
if (EtherVerbose == SHOW_ALL)
{
printf("Read lan91c11x_phy_register(): phyreg=%x,phydata=%x\n",
phyreg, phydata);
}
} // if read
else // write
{
if (EtherVerbose == SHOW_ALL)
{
printf("Wrote lan91c11x_phy_register(): phyreg=%x,phydata=%x\n",
phyreg, phydata);
}
}
return(phydata);
}
//--------------------------------------------------------------------------
// lan91c11x_phy()
//
// This function configures the lan91c11x PHY using autonegotiation
//
int lan91c11x_phy_cfg()
{
int timeout;
ushort my_phy_caps; // My PHY capabilities
ushort my_ad_caps; // My Advertised capabilities
ushort status = 0;
// Reset the PHY, setting all other bits to zero
lan91c11x_phy(PHY_CNTL, PHY_CNTL_RST, 1);
// Wait for the reset to complete, or time out
timeout = 3000; // Wait up to 3 seconds
while (timeout--)
{
if (!(lan91c11x_phy(PHY_CNTL, 0, 0) & PHY_CNTL_RST)) break;
monDelay(2); // wait 2 millisec
}
if (timeout < 1)
{
printf("lan91c11x PHY Reset Timed Out!\n");
return -1;
}
// Copy our capabilities from PHY_STAT to PHY_AD
my_phy_caps = lan91c11x_phy(PHY_STAT, 0, 0);
my_ad_caps = PHY_AD_CSMA; // I am CSMA capable
if (my_phy_caps & PHY_STAT_CAP_T4)
my_ad_caps |= PHY_AD_T4;
if (my_phy_caps & PHY_STAT_CAP_TXF)
my_ad_caps |= PHY_AD_TX_FDX;
if (my_phy_caps & PHY_STAT_CAP_TXH)
my_ad_caps |= PHY_AD_TX_HDX;
if (my_phy_caps & PHY_STAT_CAP_TF)
my_ad_caps |= PHY_AD_10_FDX;
if (my_phy_caps & PHY_STAT_CAP_TH)
my_ad_caps |= PHY_AD_10_HDX;
lan91c11x_phy(PHY_AD, my_ad_caps, 1);
if (EtherVerbose)
printf("lan91c11x phy advertised caps=%x\n", my_ad_caps);
// Restart auto-negotiation process in order to advertise my caps
lan91c11x_phy(PHY_CNTL, (PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST), 1);
// Wait for the auto-negotiation to complete. This may take from
// 2 to 3 seconds.
timeout = 50;
while (timeout--)
{
status = lan91c11x_phy(PHY_STAT, 0, 0);
if (status & PHY_STAT_ANEG_ACK)
{
// auto-negotiate complete
break;
}
monDelay(2); // wait 2 millisec
// Restart auto-negotiation again if remote fault
if (status & PHY_STAT_REM_FLT)
{
printf("lan91c11x phy remote fault detected.\n");
// Restart auto-negotiation
printf("lan91c11x phy restarting auto-negotiation.\n");
lan91c11x_phy(PHY_CNTL, (PHY_CNTL_ANEG_EN
| PHY_CNTL_ANEG_RST
| PHY_CNTL_SPEED
| PHY_CNTL_DPLX), 1);
} // if remote fault
} // while autonegotiate
if (timeout < 1)
{
printf("lan91c11x phy auto-negotiate timed out.\n");
lan91c11x_phy(PHY_CNTL,0,1);
}
// Fail if we detected an auto-negotiate remote fault
if (status & PHY_STAT_REM_FLT)
{
printf("lan91c11x phy remote fault detected, aborting autonegotiate process.\n");
return -1;
}
// Display auto-negotiation results
status = lan91c11x_phy(PHY_INT, 0, 0);
if (EtherVerbose) {
if ( status & PHY_INT_SPDDET )
printf("lan91c11x phy Link Speed = 100BaseT\n");
else
printf("lan91c11x phy Link Speed = 10BaseT\n");
if ( status & PHY_INT_DPLXDET )
printf("lan91c11x phy Link Duplex = Full\n");
else
printf("lan91c11x phy Link Duplex = Half\n");
}
return 0;
}
#endif // INCLUDE_ETHERNET
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -