📄 tlan.c
字号:
} /* TLan_EeSendStart */ /*************************************************************** * TLan_EeSendByte * * Returns: * If the correct ack was received, 0, otherwise 1 * Parms: io_base The IO port base address for the * TLAN device with the EEPROM to * use. * data The 8 bits of information to * send to the EEPROM. * stop If TLAN_EEPROM_STOP is passed, a * stop cycle is sent after the * byte is sent after the ack is * read. * * This function sends a byte on the serial EEPROM line, * driving the clock to send each bit. The function then * reverses transmission direction and reads an acknowledge * bit. * **************************************************************/static int TLan_EeSendByte( u16 io_base, u8 data, int stop ){ int err; u8 place; u16 sio; outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; /* Assume clock is low, tx is enabled; */ for ( place = 0x80; place != 0; place >>= 1 ) { if ( place & data ) TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); else TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); } TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); err = TLan_GetBit( TLAN_NET_SIO_EDATA, sio ); TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); if ( ( ! err ) && stop ) { TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */ TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); } return ( err );} /* TLan_EeSendByte */ /*************************************************************** * TLan_EeReceiveByte * * Returns: * Nothing * Parms: * io_base The IO port base address for the * TLAN device with the EEPROM to * use. * data An address to a char to hold the * data sent from the EEPROM. * stop If TLAN_EEPROM_STOP is passed, a * stop cycle is sent after the * byte is received, and no ack is * sent. * * This function receives 8 bits of data from the EEPROM * over the serial link. It then sends and ack bit, or no * ack and a stop bit. This function is used to retrieve * data after the address of a byte in the EEPROM has been * sent. * **************************************************************/static void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop ){ u8 place; u16 sio; outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; *data = 0; /* Assume clock is low, tx is enabled; */ TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); for ( place = 0x80; place; place >>= 1 ) { TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); if ( TLan_GetBit( TLAN_NET_SIO_EDATA, sio ) ) *data |= place; TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); } TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); if ( ! stop ) { TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* Ack = 0 */ TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); } else { TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); /* No ack = 1 (?) */ TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */ TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); }} /* TLan_EeReceiveByte */ /*************************************************************** * TLan_EeReadByte * * Returns: * No error = 0, else, the stage at which the error * occurred. * Parms: * io_base The IO port base address for the * TLAN device with the EEPROM to * use. * ee_addr The address of the byte in the * EEPROM whose contents are to be * retrieved. * data An address to a char to hold the * data obtained from the EEPROM. * * This function reads a byte of information from an byte * cell in the EEPROM. * **************************************************************/static int TLan_EeReadByte( u16 io_base, u8 ee_addr, u8 *data ){ int err; unsigned long flags = 0; int ret=0; TLan_EeSendStart( io_base ); err = TLan_EeSendByte( io_base, 0xA0, TLAN_EEPROM_ACK ); if (err) { ret=1; goto fail; } err = TLan_EeSendByte( io_base, ee_addr, TLAN_EEPROM_ACK ); if (err) { ret=2; goto fail; } TLan_EeSendStart( io_base ); err = TLan_EeSendByte( io_base, 0xA1, TLAN_EEPROM_ACK ); if (err) { ret=3; goto fail; } TLan_EeReceiveByte( io_base, data, TLAN_EEPROM_STOP );fail: return ret;} /* TLan_EeReadByte */#if 0/* Not yet converted from Linux driver *//*********************************************************************************************************************************************************** ThunderLAN Driver PHY Layer Routines***********************************************************************************************************************************************************/ /********************************************************************* * TLan_PhyPrint * * Returns: * Nothing * Parms: * dev A pointer to the device structure of the * TLAN device having the PHYs to be detailed. * * This function prints the registers a PHY (aka tranceiver). * ********************************************************************/void TLan_PhyPrint( struct net_device *dev ){ TLanPrivateInfo *priv = dev->priv; u16 i, data0, data1, data2, data3, phy; phy = priv->phy[priv->phyNum]; if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) { printk( "TLAN: Device %s, Unmanaged PHY.\n", dev->name ); } else if ( phy <= TLAN_PHY_MAX_ADDR ) { printk( "TLAN: Device %s, PHY 0x%02x.\n", dev->name, phy ); printk( "TLAN: Off. +0 +1 +2 +3 \n" ); for ( i = 0; i < 0x20; i+= 4 ) { printk( "TLAN: 0x%02x", i ); TLan_MiiReadReg( dev, phy, i, &data0 ); printk( " 0x%04hx", data0 ); TLan_MiiReadReg( dev, phy, i + 1, &data1 ); printk( " 0x%04hx", data1 ); TLan_MiiReadReg( dev, phy, i + 2, &data2 ); printk( " 0x%04hx", data2 ); TLan_MiiReadReg( dev, phy, i + 3, &data3 ); printk( " 0x%04hx\n", data3 ); } } else { printk( "TLAN: Device %s, Invalid PHY.\n", dev->name ); }} /* TLan_PhyPrint */ /********************************************************************* * TLan_PhyDetect * * Returns: * Nothing * Parms: * dev A pointer to the device structure of the adapter * for which the PHY needs determined. * * So far I've found that adapters which have external PHYs * may also use the internal PHY for part of the functionality. * (eg, AUI/Thinnet). This function finds out if this TLAN * chip has an internal PHY, and then finds the first external * PHY (starting from address 0) if it exists). * ********************************************************************/void TLan_PhyDetect( struct net_device *dev ){ TLanPrivateInfo *priv = dev->priv; u16 control; u16 hi; u16 lo; u32 phy; if ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) { priv->phyNum = 0xFFFF; return; } TLan_MiiReadReg( dev, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi ); if ( hi != 0xFFFF ) { priv->phy[0] = TLAN_PHY_MAX_ADDR; } else { priv->phy[0] = TLAN_PHY_NONE; } priv->phy[1] = TLAN_PHY_NONE; for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) { TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &control ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &hi ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &lo ); if ( ( control != 0xFFFF ) || ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) { TLAN_DBG( TLAN_DEBUG_GNRL, "PHY found at %02x %04x %04x %04x\n", phy, control, hi, lo ); if ( ( priv->phy[1] == TLAN_PHY_NONE ) && ( phy != TLAN_PHY_MAX_ADDR ) ) { priv->phy[1] = phy; } } } if ( priv->phy[1] != TLAN_PHY_NONE ) { priv->phyNum = 1; } else if ( priv->phy[0] != TLAN_PHY_NONE ) { priv->phyNum = 0; } else { printk( "TLAN: Cannot initialize device, no PHY was found!\n" ); }} /* TLan_PhyDetect */void TLan_PhyPowerDown( struct net_device *dev ){ TLanPrivateInfo *priv = dev->priv; u16 value; TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering down PHY(s).\n", dev->name ); value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE; TLan_MiiSync( dev->base_addr ); TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value ); if ( ( priv->phyNum == 0 ) && ( priv->phy[1] != TLAN_PHY_NONE ) && ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) { TLan_MiiSync( dev->base_addr ); TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value ); } /* Wait for 50 ms and powerup * This is abitrary. It is intended to make sure the * tranceiver settles. */ TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_PUP );} /* TLan_PhyPowerDown */void TLan_PhyPowerUp( struct net_device *dev ){ TLanPrivateInfo *priv = dev->priv; u16 value; TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering up PHY.\n", dev->name ); TLan_MiiSync( dev->base_addr ); value = MII_GC_LOOPBK; TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value ); TLan_MiiSync(dev->base_addr); /* Wait for 500 ms and reset the * tranceiver. The TLAN docs say both 50 ms and * 500 ms, so do the longer, just in case. */ TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_RESET );} /* TLan_PhyPowerUp */void TLan_PhyReset( struct net_device *dev ){ TLanPrivateInfo *priv = dev->priv; u16 phy; u16 value; phy = priv->phy[priv->phyNum]; TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Reseting PHY.\n", dev->name ); TLan_MiiSync( dev->base_addr ); value = MII_GC_LOOPBK | MII_GC_RESET; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, value ); TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value ); while ( value & MII_GC_RESET ) { TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &value ); } /* Wait for 500 ms and initialize. * I don't remember why I wait this long. * I've changed this to 50ms, as it seems long enough. */ TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_START_LINK );} /* TLan_PhyReset */void TLan_PhyStartLink( struct net_device *dev ){ TLanPrivateInfo *priv = dev->priv; u16 ability; u16 control; u16 data; u16 phy; u16 status; u16 tctl; phy = priv->phy[priv->phyNum]; TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Trying to activate link.\n", dev->name ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &ability ); if ( ( status & MII_GS_AUTONEG ) && ( ! priv->aui ) ) { ability = status >> 11; if ( priv->speed == TLAN_SPEED_10 && priv->duplex == TLAN_DUPLEX_HALF) { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000); } else if ( priv->speed == TLAN_SPEED_10 && priv->duplex == TLAN_DUPLEX_FULL) { priv->tlanFullDuplex = TRUE; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0100); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_HALF) { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2000); } else if ( priv->speed == TLAN_SPEED_100 && priv->duplex == TLAN_DUPLEX_FULL) { priv->tlanFullDuplex = TRUE; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100); } else { /* Set Auto-Neg advertisement */ TLan_MiiWriteReg( dev, phy, MII_AN_ADV, (ability << 5) | 1); /* Enablee Auto-Neg */ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 ); /* Restart Auto-Neg */ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 ); /* Wait for 4 sec for autonegotiation * to complete. The max spec time is less than this * but the card need additional time to start AN. * .5 sec should be plenty extra. */ printk( "TLAN: %s: Starting autonegotiation.\n", dev->name ); TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN ); return; } } if ( ( priv->aui ) && ( priv->phyNum != 0 ) ) { priv->phyNum = 0; data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data ); TLan_SetTimer( dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN ); return; } else if ( priv->phyNum == 0 ) { TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl ); if ( priv->aui ) { tctl |= TLAN_TC_AUISEL; } else { tctl &= ~TLAN_TC_AUISEL; control = 0; if ( priv->duplex == TLAN_DUPLEX_FULL ) { control |= MII_GC_DUPLEX;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -