📄 tlan.c
字号:
priv->tlanFullDuplex = TRUE; } if ( priv->speed == TLAN_SPEED_100 ) { control |= MII_GC_SPEEDSEL; } TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, control ); } TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tctl ); } /* Wait for 2 sec to give the tranceiver time * to establish link. */ TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_FINISH_RESET );} /* TLan_PhyStartLink */void TLan_PhyFinishAutoNeg( struct net_device *dev ){ TLanPrivateInfo *priv = dev->priv; u16 an_adv; u16 an_lpa; u16 data; u16 mode; u16 phy; u16 status; phy = priv->phy[priv->phyNum]; TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); udelay( 1000 ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); if ( ! ( status & MII_GS_AUTOCMPLT ) ) { /* Wait for 8 sec to give the process * more time. Perhaps we should fail after a while. */ if (!priv->neg_be_verbose++) { printk(KERN_INFO "TLAN: Giving autonegotiation more time.\n"); printk(KERN_INFO "TLAN: Please check that your adapter has\n"); printk(KERN_INFO "TLAN: been properly connected to a HUB or Switch.\n"); printk(KERN_INFO "TLAN: Trying to establish link in the background...\n"); } TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN ); return; } printk( "TLAN: %s: Autonegotiation complete.\n", dev->name ); TLan_MiiReadReg( dev, phy, MII_AN_ADV, &an_adv ); TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa ); mode = an_adv & an_lpa & 0x03E0; if ( mode & 0x0100 ) { priv->tlanFullDuplex = TRUE; } else if ( ! ( mode & 0x0080 ) && ( mode & 0x0040 ) ) { priv->tlanFullDuplex = TRUE; } if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( 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, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN ); return; } if ( priv->phyNum == 0 ) { if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || ( an_adv & an_lpa & 0x0040 ) ) { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB | MII_GC_DUPLEX ); printk( "TLAN: Starting internal PHY with FULL-DUPLEX\n" ); } else { TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB ); printk( "TLAN: Starting internal PHY with HALF-DUPLEX\n" ); } } /* Wait for 100 ms. No reason in partiticular. */ TLan_SetTimer( dev, (HZ/10), TLAN_TIMER_FINISH_RESET ); } /* TLan_PhyFinishAutoNeg */#ifdef MONITOR /********************************************************************* * * TLan_phyMonitor * * Returns: * None * * Params: * dev The device structure of this device. * * * This function monitors PHY condition by reading the status * register via the MII bus. This can be used to give info * about link changes (up/down), and possible switch to alternate * media. * * ******************************************************************/void TLan_PhyMonitor( struct net_device *dev ){ TLanPrivateInfo *priv = dev->priv; u16 phy; u16 phy_status; phy = priv->phy[priv->phyNum]; /* Get PHY status register */ TLan_MiiReadReg( dev, phy, MII_GEN_STS, &phy_status ); /* Check if link has been lost */ if (!(phy_status & MII_GS_LINK)) { if (priv->link) { priv->link = 0; printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name); dev->flags &= ~IFF_RUNNING; TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT ); return; } } /* Link restablished? */ if ((phy_status & MII_GS_LINK) && !priv->link) { priv->link = 1; printk(KERN_DEBUG "TLAN: %s has reestablished link\n", dev->name); dev->flags |= IFF_RUNNING; } /* Setup a new monitor */ TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT );} #endif /* MONITOR *//*********************************************************************************************************************************************************** ThunderLAN Driver MII Routines These routines are based on the information in Chap. 2 of the "ThunderLAN Programmer's Guide", pp. 15-24.***********************************************************************************************************************************************************/ /*************************************************************** * TLan_MiiReadReg * * Returns: * 0 if ack received ok * 1 otherwise. * * Parms: * dev The device structure containing * The io address and interrupt count * for this device. * phy The address of the PHY to be queried. * reg The register whose contents are to be * retreived. * val A pointer to a variable to store the * retrieved value. * * This function uses the TLAN's MII bus to retreive the contents * of a given register on a PHY. It sends the appropriate info * and then reads the 16-bit register value from the MII bus via * the TLAN SIO register. * **************************************************************/int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val ){ u8 nack; u16 sio, tmp; u32 i; int err; int minten; TLanPrivateInfo *priv = dev->priv; unsigned long flags = 0; err = FALSE; outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; if (!in_irq()) spin_lock_irqsave(&priv->lock, flags); TLan_MiiSync(dev->base_addr); minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio ); if ( minten ) TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio); TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Start ( 01b ) */ TLan_MiiSendData( dev->base_addr, 0x2, 2 ); /* Read ( 10b ) */ TLan_MiiSendData( dev->base_addr, phy, 5 ); /* Device # */ TLan_MiiSendData( dev->base_addr, reg, 5 ); /* Register # */ TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio); /* Change direction */ TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Clock Idle bit */ TLan_SetBit(TLAN_NET_SIO_MCLK, sio); TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Wait 300ns */ nack = TLan_GetBit(TLAN_NET_SIO_MDATA, sio); /* Check for ACK */ TLan_SetBit(TLAN_NET_SIO_MCLK, sio); /* Finish ACK */ if (nack) { /* No ACK, so fake it */ for (i = 0; i < 16; i++) { TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); TLan_SetBit(TLAN_NET_SIO_MCLK, sio); } tmp = 0xffff; err = TRUE; } else { /* ACK, so read data */ for (tmp = 0, i = 0x8000; i; i >>= 1) { TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); if (TLan_GetBit(TLAN_NET_SIO_MDATA, sio)) tmp |= i; TLan_SetBit(TLAN_NET_SIO_MCLK, sio); } } TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Idle cycle */ TLan_SetBit(TLAN_NET_SIO_MCLK, sio); if ( minten ) TLan_SetBit(TLAN_NET_SIO_MINTEN, sio); *val = tmp; if (!in_irq()) spin_unlock_irqrestore(&priv->lock, flags); return err;} /* TLan_MiiReadReg */ /*************************************************************** * TLan_MiiSendData * * Returns: * Nothing * Parms: * base_port The base IO port of the adapter in * question. * dev The address of the PHY to be queried. * data The value to be placed on the MII bus. * num_bits The number of bits in data that are to * be placed on the MII bus. * * This function sends on sequence of bits on the MII * configuration bus. * **************************************************************/void TLan_MiiSendData( u16 base_port, u32 data, unsigned num_bits ){ u16 sio; u32 i; if ( num_bits == 0 ) return; outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; TLan_SetBit( TLAN_NET_SIO_MTXEN, sio ); for ( i = ( 0x1 << ( num_bits - 1 ) ); i; i >>= 1 ) { TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); (void) TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); if ( data & i ) TLan_SetBit( TLAN_NET_SIO_MDATA, sio ); else TLan_ClearBit( TLAN_NET_SIO_MDATA, sio ); TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); (void) TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); }} /* TLan_MiiSendData */ /*************************************************************** * TLan_MiiSync * * Returns: * Nothing * Parms: * base_port The base IO port of the adapter in * question. * * This functions syncs all PHYs in terms of the MII configuration * bus. * **************************************************************/void TLan_MiiSync( u16 base_port ){ int i; u16 sio; outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; TLan_ClearBit( TLAN_NET_SIO_MTXEN, sio ); for ( i = 0; i < 32; i++ ) { TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); }} /* TLan_MiiSync */ /*************************************************************** * TLan_MiiWriteReg * * Returns: * Nothing * Parms: * dev The device structure for the device * to write to. * phy The address of the PHY to be written to. * reg The register whose contents are to be * written. * val The value to be written to the register. * * This function uses the TLAN's MII bus to write the contents of a * given register on a PHY. It sends the appropriate info and then * writes the 16-bit register value from the MII configuration bus * via the TLAN SIO register. * **************************************************************/void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val ){ u16 sio; int minten; unsigned long flags = 0; TLanPrivateInfo *priv = dev->priv; outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; if (!in_irq()) spin_lock_irqsave(&priv->lock, flags); TLan_MiiSync( dev->base_addr ); minten = TLan_GetBit( TLAN_NET_SIO_MINTEN, sio ); if ( minten ) TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio ); TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Start ( 01b ) */ TLan_MiiSendData( dev->base_addr, 0x1, 2 ); /* Write ( 01b ) */ TLan_MiiSendData( dev->base_addr, phy, 5 ); /* Device # */ TLan_MiiSendData( dev->base_addr, reg, 5 ); /* Register # */ TLan_MiiSendData( dev->base_addr, 0x2, 2 ); /* Send ACK */ TLan_MiiSendData( dev->base_addr, val, 16 ); /* Send Data */ TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); /* Idle cycle */ TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); if ( minten ) TLan_SetBit( TLAN_NET_SIO_MINTEN, sio ); if (!in_irq()) spin_unlock_irqrestore(&priv->lock, flags);} /* TLan_MiiWriteReg */#endif/**************************************************************************RESET - Reset adapter***************************************************************************/static void skel_reset(struct nic *nic){ /* put the card in its initial state */}/**************************************************************************POLL - Wait for a frame***************************************************************************/static int skel_poll(struct nic *nic){ /* return true if there's an ethernet packet ready to read */ /* nic->packet should contain data on return */ /* nic->packetlen should contain length of data */ return (0); /* initially as this is called to flush the input */}/**************************************************************************TRANSMIT - Transmit a frame***************************************************************************/static void skel_transmit( struct nic *nic, const char *d, /* Destination */ unsigned int t, /* Type */ unsigned int s, /* size */ const char *p) /* Packet */{ /* send the packet to destination */}/**************************************************************************DISABLE - Turn off ethernet interface***************************************************************************/static void skel_disable(struct nic *nic){}/**************************************************************************PROBE - Look for an adapter, this routine's visible to the outsideYou should omit the last argument struct pci_device * for a non-PCI NIC***************************************************************************/struct nic *tlan_probe(struct nic *nic, unsigned short *probe_addrs, struct pci_device *p)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -