if_lan91cxx.c
字号:
stat = CYG_LE16_TO_CPU(stat); len = get_data(sc); len = CYG_LE16_TO_CPU(len) - 6; // minus header/footer words#endif#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);#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 voidlan91cxx_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; rxd_t *data=NULL, 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)); val = get_data(sc); // packet length (minus header/footer)#ifdef LAN91CXX_32BIT_RX val = CYG_LE32_TO_CPU(val); plen = (val >> 16) - 6;#else val = CYG_LE16_TO_CPU(val); plen = get_data(sc); plen = CYG_LE16_TO_CPU(plen) - 6;#endif if( LAN91CXX_RX_STATUS_IS_ODD(cpd,val) ) plen++; for (i = 0; i < sg_len; i++) { data = (rxd_t *)sg_list[i].buf; mlen = sg_list[i].len; CYG_ASSERT(0 == (mlen & (sizeof(*data) - 1)) || (i == (sg_len-1)), "odd length");#if DEBUG & 1 db_printf("%s : mlen %x, plen %x\n", __FUNCTION__, mlen, plen);#endif if (data) { while (mlen >= sizeof(*data)) { *data++ = get_data(sc); mlen -= sizeof(*data); plen -= sizeof(*data); } } else { // must actively discard ie. read it from the chip anyway. while (mlen >= sizeof(*data)) { (void)get_data(sc); mlen -= sizeof(*data); plen -= sizeof(*data); } } } val = get_data(sc); // Read control word (and potential data) unconditionally#ifdef LAN91CXX_32BIT_RX val = CYG_LE32_TO_CPU(val); if (plen & 2) { if (data) *(cyg_uint16 *)data = val & 0xffff; cp = (unsigned char *)data + 2; val >>= 16; mlen -= 2; } else#else val = CYG_LE16_TO_CPU(val);#endif 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 %x (expected %x)\n", val, cpd->rxpacket); else db_printf("#####Rx packet freed %x (expected %x)\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 voidlan91cxx_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 } else if (event & LAN91CXX_INTERRUPT_EPH_INT) { // ethernet protocol handler failures } else if (event & LAN91CXX_INTERRUPT_RX_OVRN_INT) { // receive overrun } else if (event & LAN91CXX_INTERRUPT_ALLOC_INT) { // allocation interrupt } 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_LAN91C111static cyg_uint16lan91cxx_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]); HAL_DELAY_US(50); // Clock Hi - input data put_reg(sc, LAN91CXX_MGMT, mii_reg | bits[i] | LAN91CXX_MGMT_MCLK); HAL_DELAY_US(50); bits[i] |= get_reg(sc, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI; } // Return to idle state put_reg(sc, LAN91CXX_MGMT, mii_reg); HAL_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 voidlan91cxx_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]); HAL_DELAY_US(50); // Clock Hi - input data put_reg(sc, LAN91CXX_MGMT, mii_reg | bits[i] | LAN91CXX_MGMT_MCLK); HAL_DELAY_US(50);// bits[i] |= get_reg(sc, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI; } // Return to idle state put_reg(sc, LAN91CXX_MGMT, mii_reg); HAL_DELAY_US(50);}#endif // LAN91CXX_IS_LAN91C111// EOF if_lan91cxx.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -