if_lan91cxx.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,486 行 · 第 1/4 页
C
1,486 行
0xff & (stat >> 8), cpd->rxpacket );
#endif
// There is an Rx Packet ready
cpd->rxpacket = 0xff & (stat >> 8);
// Read status and (word) length
put_reg(sc, LAN91CXX_POINTER, (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
LAN91CXX_POINTER_AUTO_INCR | 0x0000));
get_data_init(sc);
stat = get_data_short(sc);
len = get_data_short(sc);
len = len - 6; // minus header/footer words
#ifdef KEEP_STATISTICS
if ( stat & LAN91CXX_RX_STATUS_ALIGNERR ) INCR_STAT( rx_align_errors );
//if ( stat & LAN91CXX_RX_STATUS_BCAST ) INCR_STAT( );
if ( stat & LAN91CXX_RX_STATUS_BADCRC ) INCR_STAT( rx_crc_errors );
if ( stat & LAN91CXX_RX_STATUS_TOOLONG ) INCR_STAT( rx_too_long_frames );
if ( stat & LAN91CXX_RX_STATUS_TOOSHORT ) INCR_STAT( rx_short_frames );
//if ( stat & LAN91CXX_RX_STATUS_MCAST ) INCR_STAT( );
#endif // KEEP_STATISTICS
if ((stat & LAN91CXX_RX_STATUS_BAD) == 0) {
INCR_STAT( rx_good );
// Then it's OK
if( LAN91CXX_RX_STATUS_IS_ODD(cpd,stat) )
len++;
#if DEBUG & 1
db_printf("RxEvent good rx - stat: 0x%04x, len: 0x%04x\n", stat, len);
#endif
// Check for bogusly short packets; can happen in promisc mode:
// Asserted against and checked by upper layer driver.
#ifdef CYGPKG_NET
if ( len > sizeof( struct ether_header ) )
// then it is acceptable; offer the data to the network stack
#endif
(sc->funs->eth_drv->recv)(sc, len);
return;
}
// Not OK for one reason or another...
#if DEBUG & 1
db_printf("RxEvent - bad rx: stat: 0x%04x, len: 0x%04x\n", stat, len);
db_printf("PHY %2d: %04x\n",0,lan91cxx_read_phy( sc, 0, 0));
db_printf("PHY %2d: %04x\n",1,lan91cxx_read_phy( sc, 0, 1));
db_printf("PHY %2d: %04x\n",2,lan91cxx_read_phy( sc, 0, 2));
db_printf("PHY %2d: %04x\n",3,lan91cxx_read_phy( sc, 0, 3));
db_printf("PHY %2d: %04x\n",4,lan91cxx_read_phy( sc, 0, 4));
db_printf("PHY %2d: %04x\n",5,lan91cxx_read_phy( sc, 0, 5));
db_printf("PHY %2d: %04x\n",16,lan91cxx_read_phy( sc, 0, 16));
db_printf("PHY %2d: %04x\n",17,lan91cxx_read_phy( sc, 0, 17));
db_printf("PHY %2d: %04x\n",18,lan91cxx_read_phy( sc, 0, 18));
db_printf("PHY %2d: %04x\n",19,lan91cxx_read_phy( sc, 0, 19));
db_printf("PHY %2d: %04x\n",20,lan91cxx_read_phy( sc, 0, 20));
#endif
// Free packet
put_reg(sc, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
}
//
// This function is called as a result of the "eth_drv_recv()" call above.
// Its job is to actually fetch data for a packet from the hardware once
// memory buffers have been allocated for the packet. Note that the buffers
// may come in pieces, using a scatter-gather list. This allows for more
// efficient processing in the upper layers of the stack.
//
static void
lan91cxx_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
{
#if (4 & DEBUG) || defined(CYGPKG_INFRA_DEBUG) || \
defined(KEEP_STATISTICS) || defined(LAN91CXX_IS_LAN91C111)
struct lan91cxx_priv_data *cpd =
(struct lan91cxx_priv_data *)sc->driver_private;
#endif
int i;
short mlen=0, plen;
cyg_uint8 *data=NULL;
short val;
unsigned char *cp, cval;
DEBUG_FUNCTION();
INCR_STAT( rx_deliver );
put_reg(sc, LAN91CXX_POINTER, (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
LAN91CXX_POINTER_AUTO_INCR));
get_data_init(sc);
val = get_data_short(sc);
plen = get_data_short(sc);
plen = plen - 6;
for (i = 0; i < sg_len; i++) {
int clen;
data = (cyg_uint8 *)sg_list[i].buf;
mlen = sg_list[i].len;
clen = mlen;
if( clen > plen )
clen = plen;
#if DEBUG & 1
db_printf("%s : mlen 0x%04x plen 0x%04x clen 0x%04x\n", __FUNCTION__, mlen, plen, clen);
#endif
mlen -= clen;
plen -= clen;
if (data) {
while( clen > 0 ) {
*data++ = get_data_byte(sc);
clen--;
}
}
else { // must actively discard ie. read it from the chip anyway.
#if DEBUG & 1
db_printf("lan91cxx_recv: No data!!!!!\n");
#endif
while( clen > 0 ) {
(void)get_data_byte(sc);
clen--;
}
}
#if DEBUG & 1
diag_dump_buf( sg_list[i].buf, sg_list[i].len > 64 ? 64 : sg_list[i].len );
#endif
}
val = get_data_short(sc); // Read control word (and potential data) unconditionally
cp = (unsigned char *)data;
CYG_ASSERT(val & LAN91CXX_CONTROLBYTE_RX,
"Controlbyte is not for Rx");
CYG_ASSERT( (1 == mlen) == (0 != LAN91CXX_CONTROLBYTE_IS_ODD(cpd,val)),
"Controlbyte does not match");
if (data && (1 == mlen) && LAN91CXX_CONTROLBYTE_IS_ODD(cpd,val) ) {
cval = val & 0x00ff; // last byte contains data
*cp = cval;
}
val = get_reg(sc, LAN91CXX_FIFO_PORTS);
#if DEBUG & 4
if ( 0x8000 & val ) // Then the Rx FIFO is empty
db_printf("#####Rx packet NOT freed, stat is 0x%04x (expected 0x%04x)\n",
val, cpd->rxpacket);
else
db_printf("#####Rx packet freed 0x%04x (expected 0x%04x)\n",
0xff & (val >> 8), cpd->rxpacket );
#endif
CYG_ASSERT( (0xff & (val >> 8)) == cpd->rxpacket, "Unexpected rx packet" );
// Free packet
put_reg(sc, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
}
static void
lan91cxx_poll(struct eth_drv_sc *sc)
{
unsigned short event;
struct lan91cxx_priv_data *cpd =
(struct lan91cxx_priv_data *)sc->driver_private;
// DEBUG_FUNCTION();
while (1) {
cyg_drv_interrupt_acknowledge(cpd->interrupt);
// Get the (unmasked) requests
event = get_reg(sc, LAN91CXX_INTERRUPT);
event = event & (event >> 8) & 0xff;
if (0 == event)
break;
#if 0
if (event & LAN91CXX_INTERRUPT_ERCV_INT) {
// Early receive interrupt
db_printf("Early receive interrupt\n");
}
else if (event & LAN91CXX_INTERRUPT_EPH_INT) {
// ethernet protocol handler failures
db_printf("Ethernet protocol handler failures\n");
}
else if (event & LAN91CXX_INTERRUPT_RX_OVRN_INT) {
// receive overrun
db_printf("Receive overrun\n");
}
else if (event & LAN91CXX_INTERRUPT_ALLOC_INT) {
// allocation interrupt
db_printf("Allocation interrupt\n");
}
else
#endif
if (event & LAN91CXX_INTERRUPT_TX_SET) {
lan91cxx_TxEvent(sc, event);
}
if (event & LAN91CXX_INTERRUPT_RCV_INT) {
lan91cxx_RxEvent(sc);
}
if (event & ~(LAN91CXX_INTERRUPT_TX_SET | LAN91CXX_INTERRUPT_RCV_INT))
db_printf("%s: Unknown interrupt: 0x%04x\n",
__FUNCTION__, event);
}
}
#ifdef LAN91CXX_IS_LAN91C111
static cyg_uint16
lan91cxx_read_phy(struct eth_drv_sc *sc, cyg_uint8 phyaddr, cyg_uint8 phyreg)
{
int i, mask, input_idx, clk_idx = 0;
cyg_uint16 mii_reg, value;
cyg_uint8 bits[64];
// 32 consecutive ones on MDO to establish sync
for (i = 0; i < 32; ++i)
bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
// Start code <01>
bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
// Read command <10>
bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
// Output the PHY address, msb first
for (mask = 0x10; mask; mask >>= 1) {
if (phyaddr & mask)
bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
else
bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
}
// Output the phy register number, msb first
for (mask = 0x10; mask; mask >>= 1) {
if (phyreg & mask)
bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
else
bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
}
// Tristate and turnaround (1 bit times)
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;
// Final clock bit
bits[clk_idx++] = 0;
// Get the current MII register value
mii_reg = get_reg(sc, LAN91CXX_MGMT);
// Turn off all MII Interface bits
mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
// Clock all 64 cycles
for (i = 0; i < sizeof(bits); ++i) {
// Clock Low - output data
put_reg(sc, LAN91CXX_MGMT, mii_reg | bits[i]);
CYGACC_CALL_IF_DELAY_US(50);
// Clock Hi - input data
put_reg(sc, LAN91CXX_MGMT, mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
CYGACC_CALL_IF_DELAY_US(50);
bits[i] |= get_reg(sc, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
}
// Return to idle state
put_reg(sc, LAN91CXX_MGMT, mii_reg);
CYGACC_CALL_IF_DELAY_US(50);
// Recover input data
for (value = 0, i = 0; i < 16; ++i) {
value <<= 1;
if (bits[input_idx++] & LAN91CXX_MGMT_MDI)
value |= 1;
}
return value;
}
static void
lan91cxx_write_phy(struct eth_drv_sc *sc, cyg_uint8 phyaddr,
cyg_uint8 phyreg, cyg_uint16 value)
{
int i, mask, clk_idx = 0;
cyg_uint16 mii_reg;
cyg_uint8 bits[65];
// 32 consecutive ones on MDO to establish sync
for (i = 0; i < 32; ++i)
bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
// Start code <01>
bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
// Write command <01>
bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
// Output the PHY address, msb first
for (mask = 0x10; mask; mask >>= 1) {
if (phyaddr & mask)
bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
else
bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
}
// Output the phy register number, msb first
for (mask = 0x10; mask; mask >>= 1) {
if (phyreg & mask)
bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
else
bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
}
// Tristate and turnaround (2 bit times)
bits[clk_idx++] = 0;
bits[clk_idx++] = 0;
// Write out 16 bits of data, msb first
for (mask = 0x8000; mask; mask >>= 1) {
if (value & mask)
bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
else
bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
}
// Final clock bit (tristate)
bits[clk_idx++] = 0;
// Get the current MII register value
mii_reg = get_reg(sc, LAN91CXX_MGMT);
// Turn off all MII Interface bits
mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
// Clock all cycles
for (i = 0; i < sizeof(bits); ++i) {
// Clock Low - output data
put_reg(sc, LAN91CXX_MGMT, mii_reg | bits[i]);
CYGACC_CALL_IF_DELAY_US(50);
// Clock Hi - input data
put_reg(sc, LAN91CXX_MGMT, mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
CYGACC_CALL_IF_DELAY_US(50);
// bits[i] |= get_reg(sc, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
}
// Return to idle state
put_reg(sc, LAN91CXX_MGMT, mii_reg);
CYGACC_CALL_IF_DELAY_US(50);
}
#endif // LAN91CXX_IS_LAN91C111
// EOF if_lan91cxx.c
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?