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

📄 tlan.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
	head_list = priv->txList + priv->txHead;	while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {		ack++;		if ( ! bbuf ) {			dev_kfree_skb_any( (struct sk_buff *) head_list->buffer[9].address );			head_list->buffer[9].address = 0;		}			if ( tmpCStat & TLAN_CSTAT_EOC )			eoc = 1;					priv->stats.tx_bytes += head_list->frameSize;		head_list->cStat = TLAN_CSTAT_UNUSED;		netif_start_queue(dev);				CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS ); 		head_list = priv->txList + priv->txHead;	}	if (!ack)		printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n");		if ( eoc ) {		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Handling TX EOC (Head=%d Tail=%d)\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;		}	}		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;		}	}	return ack;} /* TLan_HandleTxEOF */	/***************************************************************	 *	TLan_HandleStatOverflow	 *	 *	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 ){	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 activity LED.	 *	 **************************************************************/u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ){	TLanPrivateInfo	*priv = dev->priv;	u32		ack = 0;	int		eoc = 0;	u8		*head_buffer;	TLanList	*head_list;	struct sk_buff	*skb;	TLanList	*tail_list;	void		*t;	u32		frameSize;	u16		tmpCStat;	TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );	head_list = priv->rxList + priv->rxHead;		while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {		frameSize = head_list->frameSize;		ack++;		if (tmpCStat & TLAN_CSTAT_EOC)			eoc = 1;				if (bbuf) {			skb = dev_alloc_skb(frameSize + 7);			if (skb == NULL)				printk(KERN_INFO "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, frameSize);						priv->stats.rx_bytes += head_list->frameSize;				memcpy( t, head_buffer, 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;				skb_trim( skb, frameSize );				priv->stats.rx_bytes += 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[8].address = (u32) 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->cStat = 0;		tail_list = priv->rxList + priv->rxTail;		tail_list->forward = virt_to_bus( head_list );		CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS );		CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS );		head_list = priv->rxList + priv->rxHead;	}	if (!ack)		printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n");		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 ){	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 = 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 ) {			netif_stop_queue(dev);			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 = 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 ) {		netif_stop_queue( dev );		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 );				queue_task(&priv->tlan_tqueue, &tq_immediate);		mark_bh(IMMEDIATE_BH);				netif_wake_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 = dev->priv;	TLanList	*head_list;	u32		ack = 1;	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

⌨️ 快捷键说明

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