⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tlan.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 *	 *	Returns:	 *		1	 *	Parms:	 *		dev		Device assigned the IRQ that was	 *				raised.	 *		host_int	The contents of the HOST_INT	 *				port.	 *	 *	This function handles the Statistics Overflow interrupt	 *	which means that one or more of the TLAN statistics	 *	registers has reached 1/2 capacity and needs to be read.	 *	 **************************************************************/u32 TLan_HandleStatOverflow( struct net_device *dev, u16 host_int ){	host_int = 0;	TLan_ReadAndClearStats( dev, TLAN_RECORD );	return 1;} /* TLan_HandleStatOverflow */	/***************************************************************	 *	TLan_HandleRxEOF	 *	 *	Returns:	 *		1	 *	Parms:	 *		dev		Device assigned the IRQ that was	 *				raised.	 *		host_int	The contents of the HOST_INT	 *				port.	 *	 *	This function handles the Rx EOF interrupt which	 *	indicates a frame has been received by the adapter from	 *	the net and the frame has been transferred to memory.	 *	The function determines the bounce buffer the frame has	 *	been loaded into, creates a new sk_buff big enough to	 *	hold the frame, and sends it to protocol stack.  It	 *	then resets the used buffer and appends it to the end	 *	of the list.  If the frame was the last in the Rx	 *	channel (EOC), the function restarts the receive channel	 *	by sending an Rx Go command to the adapter.  Then it	 *	activates/continues the the activity LED.	 *	 **************************************************************/u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ){	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;	u32		ack = 1;	int		eoc = 0;	u8		*head_buffer;	TLanList	*head_list;	struct sk_buff	*skb;	TLanList	*tail_list;	void		*t;	TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );	host_int = 0;	head_list = priv->rxList + priv->rxHead;	tail_list = priv->rxList + priv->rxTail;	if ( head_list->cStat & TLAN_CSTAT_EOC ) {		eoc = 1;	}	if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {		printk( "TLAN:  Received interrupt for uncompleted RX frame.\n" );	} else if ( bbuf ) {		skb = dev_alloc_skb( head_list->frameSize + 7 );		if ( skb == NULL ) { 			printk( "TLAN:  Couldn't allocate memory for received data.\n" );		} else {			head_buffer = priv->rxBuffer + ( priv->rxHead * TLAN_MAX_FRAME_SIZE );			skb->dev = dev;			skb_reserve( skb, 2 );			t = (void *) skb_put( skb, head_list->frameSize );			priv->stats.rx_bytes += head_list->frameSize;			memcpy( t, head_buffer, head_list->frameSize );			skb->protocol = eth_type_trans( skb, dev );			netif_rx( skb );		}	} else {		struct sk_buff *new_skb;				/*		 *	I changed the algorithm here. What we now do		 *	is allocate the new frame. If this fails we		 *	simply recycle the frame.		 */				new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );		if ( new_skb != NULL ) {			/* If this ever happened it would be a problem */			/* not any more - ac */			skb = (struct sk_buff *) head_list->buffer[9].address;			head_list->buffer[9].address = 0;			skb_trim( skb, head_list->frameSize );			priv->stats.rx_bytes += head_list->frameSize;			skb->protocol = eth_type_trans( skb, dev );			netif_rx( skb );				new_skb->dev = dev;			skb_reserve( new_skb, 2 );			t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE );			head_list->buffer[0].address = virt_to_bus( t );			head_list->buffer[9].address = (u32) new_skb;		}		else			printk(KERN_WARNING "TLAN:  Couldn't allocate memory for received data.\n" );	}	head_list->forward = 0;	head_list->frameSize = TLAN_MAX_FRAME_SIZE;	head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;	tail_list->forward = virt_to_bus( head_list );	CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS );	CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS );	if ( eoc ) { 		TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );		head_list = priv->rxList + priv->rxHead;		outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );		ack |= TLAN_HC_GO | TLAN_HC_RT;		priv->rxEocCount++;	}	if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {		TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );		if ( priv->timer.function == NULL )  {			priv->timer.function = &TLan_Timer;			priv->timer.data = (unsigned long) dev;			priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;			priv->timerSetAt = jiffies;			priv->timerType = TLAN_TIMER_ACTIVITY;			add_timer(&priv->timer);		} else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {			priv->timerSetAt = jiffies;		}	}	dev->last_rx = jiffies;	return ack;} /* TLan_HandleRxEOF */	/***************************************************************	 *	TLan_HandleDummy	 *	 *	Returns:	 *		1	 *	Parms:	 *		dev		Device assigned the IRQ that was	 *				raised.	 *		host_int	The contents of the HOST_INT	 *				port.	 *	 *	This function handles the Dummy interrupt, which is	 *	raised whenever a test interrupt is generated by setting	 *	the Req_Int bit of HOST_CMD to 1.	 *	 **************************************************************/u32 TLan_HandleDummy( struct net_device *dev, u16 host_int ){	host_int = 0;	printk( "TLAN:  Test interrupt on %s.\n", dev->name );	return 1;} /* TLan_HandleDummy */	/***************************************************************	 *	TLan_HandleTxEOC	 *	 *	Returns:	 *		1	 *	Parms:	 *		dev		Device assigned the IRQ that was	 *				raised.	 *		host_int	The contents of the HOST_INT	 *				port.	 *	 *	This driver is structured to determine EOC occurances by	 *	reading the CSTAT member of the list structure.  Tx EOC	 *	interrupts are disabled via the DIO INTDIS register.	 *	However, TLAN chips before revision 3.0 didn't have this	 *	functionality, so process EOC events if this is the	 *	case.	 *	 **************************************************************/u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int ){	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;	TLanList		*head_list;	u32				ack = 1;	host_int = 0;	if ( priv->tlanRev < 0x30 ) {		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail );		head_list = priv->txList + priv->txHead;		if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) {			outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );			ack |= TLAN_HC_GO;		} else {			priv->txInProgress = 0;		}	}	return ack;} /* TLan_HandleTxEOC */	/***************************************************************	 *	TLan_HandleStatusCheck	 *	 *	Returns:	 *		0 if Adapter check, 1 if Network Status check.	 *	Parms:	 *		dev		Device assigned the IRQ that was	 *				raised.	 *		host_int	The contents of the HOST_INT	 *				port.	 *	 *	This function handles Adapter Check/Network Status	 *	interrupts generated by the adapter.  It checks the	 *	vector in the HOST_INT register to determine if it is	 *	an Adapter Check interrupt.  If so, it resets the	 *	adapter.  Otherwise it clears the status registers	 *	and services the PHY.	 *	 **************************************************************/u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ){		TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;	u32		ack;	u32		error;	u8		net_sts;	u32		phy;	u16		tlphy_ctl;	u16		tlphy_sts;		ack = 1;	if ( host_int & TLAN_HI_IV_MASK ) {		error = inl( dev->base_addr + TLAN_CH_PARM );		printk( "TLAN:  %s: Adaptor Error = 0x%x\n", dev->name, error );		TLan_ReadAndClearStats( dev, TLAN_RECORD );		outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );		TLan_FreeLists( dev );		TLan_ResetLists( dev );		TLan_ResetAdapter( dev );		netif_start_queue(dev);		ack = 0;	} else {		TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Status Check\n", dev->name );		phy = priv->phy[priv->phyNum];		net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS );		if ( net_sts ) {			TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts );			TLAN_DBG( TLAN_DEBUG_GNRL, "%s:    Net_Sts = %x\n", dev->name, (unsigned) net_sts );		}		if ( ( net_sts & TLAN_NET_STS_MIRQ ) &&  ( priv->phyNum == 0 ) ) {			TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts );			TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl );        		if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {                		tlphy_ctl |= TLAN_TC_SWAPOL;                		TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);        		} else if ( ( tlphy_sts & TLAN_TS_POLOK ) && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {                		tlphy_ctl &= ~TLAN_TC_SWAPOL;                		TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);        		}			if (debug) {				TLan_PhyPrint( dev );					}		}	}	return ack;} /* TLan_HandleStatusCheck */	/***************************************************************	 *	TLan_HandleRxEOC	 *	 *	Returns:	 *		1	 *	Parms:	 *		dev		Device assigned the IRQ that was	 *				raised.	 *		host_int	The contents of the HOST_INT	 *				port.	 *	 *	This driver is structured to determine EOC occurances by	 *	reading the CSTAT member of the list structure.  Rx EOC	 *	interrupts are disabled via the DIO INTDIS register.	 *	However, TLAN chips before revision 3.0 didn't have this	 *	CSTAT member or a INTDIS register, so if this chip is	 *	pre-3.0, process EOC interrupts normally.	 *	 **************************************************************/u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int ){	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;	TLanList	*head_list;	u32		ack = 1;	host_int = 0;	if (  priv->tlanRev < 0x30 ) {		TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail );		head_list = priv->rxList + priv->rxHead;		outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );		ack |= TLAN_HC_GO | TLAN_HC_RT;		priv->rxEocCount++;	}	return ack;} /* TLan_HandleRxEOC *//***********************************************************************************************************************************************************	ThunderLAN Driver Timer Function***********************************************************************************************************************************************************/	/***************************************************************	 *	TLan_Timer	 *	 *	Returns:	 *		Nothing	 *	Parms:	 *		data	A value given to add timer when	 *			add_timer was called.	 *	 *	This function handles timed functionality for the	 *	TLAN driver.  The two current timer uses are for	 *	delaying for autonegotionation and driving the ACT LED.	 *	-	Autonegotiation requires being allowed about	 *		2 1/2 seconds before attempting to transmit a	 *		packet.  It would be a very bad thing to hang	 *		the kernel this long, so the driver doesn't	 *		allow transmission 'til after this time, for	 *		certain PHYs.  It would be much nicer if all	 *		PHYs were interrupt-capable like the internal	 *		PHY.	 *	-	The ACT LED, which shows adapter activity, is	 *		driven by the driver, and so must be left on	 *		for a short period to power up the LED so it	 *		can be seen.  This delay can be changed by	 *		changing the TLAN_TIMER_ACT_DELAY in tlan.h,	 *		if desired.  100 ms  produces a slightly	 *		sluggish response.	 *	 **************************************************************/void TLan_Timer( unsigned long data ){	struct net_device	*dev = (struct net_device *) data;	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;	u32		elapsed;	unsigned long	flags = 0;	priv->timer.function = NULL;	switch ( priv->timerType ) {#ifdef MONITOR				case TLAN_TIMER_LINK_BEAT:			TLan_PhyMonitor( dev );			break;#endif		case TLAN_TIMER_PHY_PDOWN:			TLan_PhyPowerDown( dev );			break;		case TLAN_TIMER_PHY_PUP:			TLan_PhyPowerUp( dev );			break;		case TLAN_TIMER_PHY_RESET:			TLan_PhyReset( dev );			break;		case TLAN_TIMER_PHY_START_LINK:			TLan_PhyStartLink( dev );			break;		case TLAN_TIMER_PHY_FINISH_AN:			TLan_PhyFinishAutoNeg( dev );			break;		case TLAN_TIMER_FINISH_RESET:			TLan_FinishReset( dev );			break;		case TLAN_TIMER_ACTIVITY:			spin_lock_irqsave(&priv->lock, flags);			if ( priv->timer.function == NULL ) {				elapsed = jiffies - priv->timerSetAt;				if ( elapsed >= TLAN_TIMER_ACT_DELAY ) {					TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );				} else  {					priv->timer.function = &TLan_Timer;					priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;					spin_unlock_irqrestore(&priv->lock, flags);					add_timer( &priv->timer );					break;				}			}			spin_unlock_irqrestore(&priv->lock, flags);			break;		default:			break;	}} /* TLan_Timer */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -