if_lan91cxx.c
字号:
cpd->enaddr[1], cpd->enaddr[2], cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5] );#endif // DEBUG // Set up hardware address for (i = 0; i < sizeof(cpd->enaddr); i += 2) put_reg(sc, LAN91CXX_IA01+i/2, cpd->enaddr[i] | (cpd->enaddr[i+1] << 8));#else // not CYGINT_DEVS_ETH_SMSC_LAN91CXX_STATIC_ESA // Find ESA - check possible sources in sequence and stop when // one provides the ESA: // RedBoot option (via provide_esa) // Compile-time configuration // EEPROM if (NULL != cpd->provide_esa) { esa_configured = cpd->provide_esa(cpd);# if DEBUG & 8 if (esa_configured) db_printf("Got ESA from RedBoot option\n");# endif } if (!esa_configured && cpd->hardwired_esa) { // ESA is already set in cpd->esa[] esa_configured = true;# if DEBUG & 8 db_printf("Got ESA from cpd\n");# endif } if (esa_configured) { // Set up hardware address for (i = 0; i < sizeof(cpd->enaddr); i += 2) put_reg(sc, LAN91CXX_IA01+i/2, cpd->enaddr[i] | (cpd->enaddr[i+1] << 8)); } else { // Use the address from the serial EEPROM // Read out hardware address for (i = 0; i < sizeof(cpd->enaddr); i += 2) { unsigned short z = get_reg(sc, LAN91CXX_IA01+i/2 ); cpd->enaddr[i] = (unsigned char)(0xff & z); cpd->enaddr[i+1] = (unsigned char)(0xff & (z >> 8)); } esa_configured = true;# if DEBUG & 8 db_printf("Got ESA from eeprom\n");# endif }#if DEBUG & 9 db_printf("LAN91CXX - ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", cpd->enaddr[0], cpd->enaddr[1], cpd->enaddr[2], cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5] );#endif // DEBUG#endif // !CYGINT_DEVS_ETH_SMSC_LAN91CXX_STATIC_ESA // Initialize upper level driver (sc->funs->eth_drv->init)(sc, cpd->enaddr); return true;}static voidlan91cxx_stop(struct eth_drv_sc *sc){ struct lan91cxx_priv_data *cpd = (struct lan91cxx_priv_data *)sc->driver_private; DEBUG_FUNCTION(); CYG_ASSERT( cpd->within_send < 10, "stop: Excess send recursions" ); cpd->within_send++; // Complete any outstanding activity: if ( cpd->txbusy ) { cpd->txbusy = 0;#if DEBUG & 9 db_printf("LAN91CXX - Stopping, cleaning up pending TX\n" );#endif (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, 0); } // Reset chip put_reg(sc, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST); put_reg(sc, LAN91CXX_RCR, 0); cpd->txbusy = cpd->within_send = 0;}//// This function is called to "start up" the interface. It may be called// multiple times, even when the hardware is already running. It will be// called whenever something "hardware oriented" changes and should leave// the hardware ready to send/receive packets.//static voidlan91cxx_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags){ cyg_uint16 intr;#ifdef LAN91CXX_IS_LAN91C111 cyg_uint16 phy_ctl; int delay;#endif#ifdef CYGPKG_NET struct ifnet *ifp = &sc->sc_arpcom.ac_if;#endif DEBUG_FUNCTION();#ifdef LAN91CXX_IS_LAN91C111 HAL_DELAY_US(100000); // 91C111 Errata. Internal PHY comes up disabled. Must enable here. phy_ctl = lan91cxx_read_phy(sc, 0, LAN91CXX_PHY_CTRL); phy_ctl &= ~LAN91CXX_PHY_CTRL_MII_DIS; lan91cxx_write_phy(sc, 0, LAN91CXX_PHY_CTRL, phy_ctl); // Start auto-negotiation put_reg(sc, LAN91CXX_RPCR, LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK | LAN91CXX_RPCR_ANEG); // wait for auto-negotiation to finish. // give it ~5 seconds before giving up (no cable?) delay = 50; while (!(lan91cxx_read_phy(sc, 0, LAN91CXX_PHY_STAT) & 0x20)) { if (--delay <= 0) break; HAL_DELAY_US(100000); }#endif put_reg(sc, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu); put_reg(sc, LAN91CXX_INTERRUPT, 0); // disable interrupts intr = get_reg(sc, LAN91CXX_INTERRUPT); put_reg(sc, LAN91CXX_INTERRUPT, intr & // ack old interrupts (LAN91CXX_INTERRUPT_TX_INT | LAN91CXX_INTERRUPT_TX_EMPTY_INT | LAN91CXX_INTERRUPT_RX_OVRN_INT | LAN91CXX_INTERRUPT_ERCV_INT)); put_reg(sc, LAN91CXX_RCR, #ifdef RCR_HAS_ABORT_ENB // 91C96 does not - page 46. LAN91CXX_RCR_ABORT_ENB |#endif LAN91CXX_RCR_STRIP_CRC | LAN91CXX_RCR_RXEN | LAN91CXX_RCR_ALMUL); put_reg(sc, LAN91CXX_TCR, LAN91CXX_TCR_TXENA | LAN91CXX_TCR_PAD_EN); put_reg(sc, LAN91CXX_CONTROL, 0); put_reg(sc, LAN91CXX_INTERRUPT, // enable interrupts LAN91CXX_INTERRUPT_RCV_INT_M);#ifdef CYGPKG_NET if (( 0#ifdef ETH_DRV_FLAGS_PROMISC_MODE != (flags & ETH_DRV_FLAGS_PROMISC_MODE)#endif ) || (ifp->if_flags & IFF_PROMISC) ) { // Then we select promiscuous mode. unsigned short rcr; rcr = get_reg(sc, LAN91CXX_RCR ); rcr |= LAN91CXX_RCR_PRMS; put_reg(sc, LAN91CXX_RCR, rcr ); }#endif}//// This routine is called to perform special "control" opertions//static intlan91cxx_control(struct eth_drv_sc *sc, unsigned long key, void *data, int data_length){ unsigned char *esa = (unsigned char *)data; int i; unsigned short reg; struct lan91cxx_priv_data *cpd = (struct lan91cxx_priv_data *)sc->driver_private; DEBUG_FUNCTION(); switch (key) { case ETH_DRV_SET_MAC_ADDRESS:#if 9 & DEBUG db_printf("LAN91CXX - set ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", esa[0], esa[1], esa[2], esa[3], esa[4], esa[5] );#ifndef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_WRITE_EEPROM db_printf("*** PERMANENT EEPROM WRITE NOT ENABLED ***\n");#endif#endif // DEBUG#ifdef CYGSEM_DEVS_ETH_SMSC_LAN91CXX_WRITE_EEPROM // Only now can we command the chip to perform EEPROM writes: // select arbitrary writing to the EEPROM reg = get_reg(sc, LAN91CXX_CONTROL); reg |= LAN91CXX_CONTROL_EEPROM_SELECT; put_reg(sc, LAN91CXX_CONTROL, reg ); for (i = 0; i < sizeof(cpd->enaddr); i += 2) { int j; // Set the address register put_reg(sc, LAN91CXX_POINTER, LAN91CXX_ESA_EEPROM_OFFSET + i/2); // Poke the data put_reg(sc, LAN91CXX_GENERAL, esa[i] | (esa[i+1] << 8)); // Command the store reg = get_reg(sc, LAN91CXX_CONTROL); reg |= LAN91CXX_CONTROL_STORE; put_reg(sc, LAN91CXX_CONTROL, reg ); // and poll for completion for ( j = 1024 * 1024; 0 < j ; j-- ) { reg = get_reg(sc, LAN91CXX_CONTROL); if ( 0 == (reg & LAN91CXX_CONTROL_EEPROM_BUSY) ) break; } CYG_ASSERT( 0 < j, "EEPROM write timout!" ); } reg = get_reg(sc, LAN91CXX_CONTROL); CYG_ASSERT( 0 == (reg & LAN91CXX_CONTROL_EEPROM_BUSY), "EEPROM still busy!" ); // Clear the EEPROM selection bit reg &=~LAN91CXX_CONTROL_EEPROM_SELECT; put_reg(sc, LAN91CXX_CONTROL, reg ); // and check it "took" reg = get_reg(sc, LAN91CXX_CONTROL); CYG_ASSERT( 0 == (reg & LAN91CXX_CONTROL_EEPROM_SELECT), "EEPROM still selected!" ); // and command a complete reload reg |= LAN91CXX_CONTROL_RELOAD; put_reg(sc, LAN91CXX_CONTROL, reg ); for ( i = 1024 * 1024; 0 < i ; i-- ) { reg = get_reg(sc, LAN91CXX_CONTROL); if ( 0 == (reg & LAN91CXX_CONTROL_EEPROM_BUSY) ) break; } CYG_ASSERT( 0 < i, "EEPROM reload timout!" ); // Now extract the MAC address that is in the chip, and tell the // system about it. for (i = 0; i < sizeof(cpd->enaddr); i += 2) { unsigned short z = get_reg(sc, LAN91CXX_IA01+i/2 ); cpd->enaddr[i] = (unsigned char)(0xff & z); cpd->enaddr[i+1] = (unsigned char)(0xff & (z >> 8)); }#if DEBUG & 9 db_printf("LAN91CXX - eeprom new ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", cpd->enaddr[0], cpd->enaddr[1], cpd->enaddr[2], cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5] );#endif // DEBUG for (i = 0; i < sizeof(cpd->enaddr); i++ ) { CYG_ASSERT( esa[i] == cpd->enaddr[i], "ESA not written correctly" ); if ( esa[i] != cpd->enaddr[i] ) return 1; // the operation failed. }#else // not CYGSEM_DEVS_ETH_SMSC_LAN91CXX_WRITE_EEPROM // Whatever, we can write the MAC address into the interface info, // and the chip registers no problem. for ( i = 0; i < sizeof(cpd->enaddr); i++ ) cpd->enaddr[i] = esa[i]; for (i = 0; i < sizeof(cpd->enaddr); i += 2) { reg = cpd->enaddr[i] | (cpd->enaddr[i+1] << 8); put_reg(sc, LAN91CXX_IA01+i/2, reg ); }#endif // !CYGSEM_DEVS_ETH_SMSC_LAN91CXX_WRITE_EEPROM return 0;#ifdef ETH_DRV_GET_MAC_ADDRESS case ETH_DRV_GET_MAC_ADDRESS: // Extract the MAC address that is in the chip, and tell the // system about it. for (i = 0; i < sizeof(cpd->enaddr); i += 2) { unsigned short z = get_reg(sc, LAN91CXX_IA01+i/2 ); esa[i] = (unsigned char)(0xff & z); esa[i+1] = (unsigned char)(0xff & (z >> 8)); } return 0;#endif#ifdef ETH_DRV_GET_IF_STATS_UD case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE#endif // drop through#ifdef ETH_DRV_GET_IF_STATS case ETH_DRV_GET_IF_STATS:#endif#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD) { struct ether_drv_stats *p = (struct ether_drv_stats *)data; // Chipset entry is no longer supported; RFC1573. for ( i = 0; i < SNMP_CHIPSET_LEN; i++ ) p->snmp_chipset[i] = 0; // This perhaps should be a config opt, so you can make up your own // description, or supply it from the instantiation. strcpy( p->description, "SMSC LAN91Cxx" ); // CYG_ASSERT( 48 > strlen(p->description), "Description too long" ); reg = get_reg(sc, LAN91CXX_EPH_STATUS); if ((reg & LAN91CXX_STATUS_LINK_OK) == 0) { p->operational = 2; // LINK DOWN p->duplex = 1; // UNKNOWN p->speed = 0; } else { p->operational = 3; // LINK UP p->duplex = 2; // 2 = SIMPLEX, 3 = DUPLEX p->speed = 10 * 1000000; // it's only a 10Mbit device }#ifdef KEEP_STATISTICS { struct smsc_lan91cxx_stats *ps = &(cpd->stats); // Admit to it... p->supports_dot3 = true; p->tx_good = ps->tx_good ; p->tx_max_collisions = ps->tx_max_collisions ; p->tx_late_collisions = ps->tx_late_collisions ; p->tx_underrun = ps->tx_underrun ; p->tx_carrier_loss = ps->tx_carrier_loss ; p->tx_deferred = ps->tx_deferred ; p->tx_sqetesterrors = ps->tx_sqetesterrors ; p->tx_single_collisions = ps->tx_single_collisions; p->tx_mult_collisions = ps->tx_mult_collisions ; p->tx_total_collisions = ps->tx_total_collisions ; p->rx_good = ps->rx_good ; p->rx_crc_errors = ps->rx_crc_errors ; p->rx_align_errors = ps->rx_align_errors ; p->rx_resource_errors = ps->rx_resource_errors ; p->rx_overrun_errors = ps->rx_overrun_errors ; p->rx_collisions = ps->rx_collisions ; p->rx_short_frames = ps->rx_short_frames ; p->rx_too_long_frames = ps->rx_too_long_frames ; p->rx_symbol_errors = ps->rx_symbol_errors ; p->interrupts = ps->interrupts ; p->rx_count = ps->rx_count ; p->rx_deliver = ps->rx_deliver ; p->rx_resource = ps->rx_resource ; p->rx_restart = ps->rx_restart ; p->tx_count = ps->tx_count ; p->tx_complete = ps->tx_complete ; p->tx_dropped = ps->tx_dropped ; }#endif // KEEP_STATISTICS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -