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

📄 tlan.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 * 		dev	structure of device which timed out 	 * 			during transmit.	 *	 **************************************************************/static void TLan_tx_timeout(struct net_device *dev){		TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name);		/* Ok so we timed out, lets see what we can do about it...*/	TLan_ResetLists( dev );			TLan_ReadAndClearStats( dev, TLAN_IGNORE );	TLan_ResetAdapter( dev );	dev->trans_start = jiffies;	netif_wake_queue( dev );	}		/***************************************************************	 *	TLan_StartTx	 *  	 *	Returns:	 *		0 on success, non-zero on failure.	 *	Parms:	 *		skb	A pointer to the sk_buff containing the	 *			frame to be sent.	 *		dev	The device to send the data on.	 *	 *	This function adds a frame to the Tx list to be sent	 *	ASAP.  First it	verifies that the adapter is ready and	 *	there is room in the queue.  Then it sets up the next	 *	available list, copies the frame to the	corresponding	 *	buffer.  If the adapter Tx channel is idle, it gives	 *	the adapter a Tx Go command on the list, otherwise it	 *	sets the forward address of the previous list to point	 *	to this one.  Then it frees the sk_buff.	 *	 **************************************************************/static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ){	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;	TLanList	*tail_list;	u8		*tail_buffer;	int		pad;	unsigned long	flags;	if ( ! priv->phyOnline ) {		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  %s PHY is not ready\n", dev->name );		dev_kfree_skb_any(skb);		return 0;	}	tail_list = priv->txList + priv->txTail;	if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail );		netif_stop_queue(dev);		priv->txBusyCount++;		return 1;	}	tail_list->forward = 0;	if ( bbuf ) {		tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );		memcpy( tail_buffer, skb->data, skb->len );	} else {		tail_list->buffer[0].address = virt_to_bus( skb->data );		tail_list->buffer[9].address = (u32) skb;	}	pad = TLAN_MIN_FRAME_SIZE - skb->len;	if ( pad > 0 ) {		tail_list->frameSize = (u16) skb->len + pad;		tail_list->buffer[0].count = (u32) skb->len;		tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad;		tail_list->buffer[1].address = virt_to_bus( TLanPadBuffer );	} else {		tail_list->frameSize = (u16) skb->len;		tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len;		tail_list->buffer[1].count = 0;		tail_list->buffer[1].address = 0;	}	spin_lock_irqsave(&priv->lock, flags);	tail_list->cStat = TLAN_CSTAT_READY;	if ( ! priv->txInProgress ) {		priv->txInProgress = 1;		outw( 0x4, dev->base_addr + TLAN_HOST_INT );		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Starting TX on buffer %d\n", priv->txTail );		outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM );		outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD );	} else {		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Adding buffer %d to TX channel\n", priv->txTail );		if ( priv->txTail == 0 ) {			( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list );		} else {			( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list );		}	}	spin_unlock_irqrestore(&priv->lock, flags);	CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );	if ( bbuf )		dev_kfree_skb_any(skb);			dev->trans_start = jiffies;	return 0;} /* TLan_StartTx */	/***************************************************************	 *	TLan_HandleInterrupt	 *  	 *	Returns:		 *		Nothing	 *	Parms:	 *		irq	The line on which the interrupt	 *			occurred.	 *		dev_id	A pointer to the device assigned to	 *			this irq line.	 *		regs	???	 *	 *	This function handles an interrupt generated by its	 *	assigned TLAN adapter.  The function deactivates	 *	interrupts on its adapter, records the type of	 *	interrupt, executes the appropriate subhandler, and	 *	acknowdges the interrupt to the adapter (thus	 *	re-enabling adapter interrupts.	 *	 **************************************************************/static void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs){	u32		ack;	struct net_device	*dev;	u32		host_cmd;	u16		host_int;	int		type;	TLanPrivateInfo *priv;	dev = (struct net_device *) dev_id;	priv = (TLanPrivateInfo *) dev->priv;	spin_lock(&priv->lock);	host_int = inw( dev->base_addr + TLAN_HOST_INT );	outw( host_int, dev->base_addr + TLAN_HOST_INT );	type = ( host_int & TLAN_HI_IT_MASK ) >> 2;	ack = TLanIntVector[type]( dev, host_int );	if ( ack ) {		host_cmd = TLAN_HC_ACK | ack | ( type << 18 );		outl( host_cmd, dev->base_addr + TLAN_HOST_CMD );	}	spin_unlock(&priv->lock);} /* TLan_HandleInterrupts */	/***************************************************************	 *	TLan_Close	 *  	 * 	Returns:	 *		An error code.	 *	Parms:	 *		dev	The device structure of the device to	 *			close.	 *	 *	This function shuts down the adapter.  It records any	 *	stats, puts the adapter into reset state, deactivates	 *	its time as needed, and	frees the irq it is using.	 *	 **************************************************************/static int TLan_Close(struct net_device *dev){	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;	netif_stop_queue(dev);	TLan_ReadAndClearStats( dev, TLAN_RECORD );	outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );	if ( priv->timer.function != NULL ) {		del_timer_sync( &priv->timer );		priv->timer.function = NULL;	}		free_irq( dev->irq, dev );	TLan_FreeLists( dev );	TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name );	return 0;} /* TLan_Close */	/***************************************************************	 *	TLan_GetStats	 *  	 *	Returns:	 *		A pointer to the device's statistics structure.	 *	Parms:	 *		dev	The device structure to return the	 *			stats for.	 *	 *	This function updates the devices statistics by reading	 *	the TLAN chip's onboard registers.  Then it returns the	 *	address of the statistics structure.	 *	 **************************************************************/static struct net_device_stats *TLan_GetStats( struct net_device *dev ){	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;	int i;	/* Should only read stats if open ? */	TLan_ReadAndClearStats( dev, TLAN_RECORD );	TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  %s EOC count = %d\n", dev->name, priv->rxEocCount );	TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  %s Busy count = %d\n", dev->name, priv->txBusyCount );	if ( debug & TLAN_DEBUG_GNRL ) {		TLan_PrintDio( dev->base_addr );		TLan_PhyPrint( dev );			}	if ( debug & TLAN_DEBUG_LIST ) {		for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ )			TLan_PrintList( priv->rxList + i, "RX", i );		for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ )			TLan_PrintList( priv->txList + i, "TX", i );	}		return ( &( (TLanPrivateInfo *) dev->priv )->stats );} /* TLan_GetStats */	/***************************************************************	 *	TLan_SetMulticastList	 *  	 *	Returns:	 *		Nothing	 *	Parms:	 *		dev	The device structure to set the	 *			multicast list for.	 *	 *	This function sets the TLAN adaptor to various receive	 *	modes.  If the IFF_PROMISC flag is set, promiscuous	 *	mode is acitviated.  Otherwise,	promiscuous mode is	 *	turned off.  If the IFF_ALLMULTI flag is set, then	 *	the hash table is set to receive all group addresses.	 *	Otherwise, the first three multicast addresses are	 *	stored in AREG_1-3, and the rest are selected via the	 *	hash table, as necessary.	 *	 **************************************************************/static void TLan_SetMulticastList( struct net_device *dev ){		struct dev_mc_list	*dmi = dev->mc_list;	u32			hash1 = 0;	u32			hash2 = 0;	int			i;	u32			offset;	u8			tmp;	if ( dev->flags & IFF_PROMISC ) {		tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );		TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF );	} else {		tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );		TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF );		if ( dev->flags & IFF_ALLMULTI ) {			for ( i = 0; i < 3; i++ ) 				TLan_SetMac( dev, i + 1, NULL );			TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF );			TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF );		} else {			for ( i = 0; i < dev->mc_count; i++ ) {				if ( i < 3 ) {					TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr );				} else {					offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr );					if ( offset < 32 ) 						hash1 |= ( 1 << offset );					else						hash2 |= ( 1 << ( offset - 32 ) );				}				dmi = dmi->next;			}			for ( ; i < 3; i++ ) 				TLan_SetMac( dev, i + 1, NULL );			TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, hash1 );			TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, hash2 );		}	}} /* TLan_SetMulticastList *//***********************************************************************************************************************************************************        ThunderLAN Driver Interrupt Vectors and Table	Please see Chap. 4, "Interrupt Handling" of the "ThunderLAN	Programmer's Guide" for more informations on handling interrupts	generated by TLAN based adapters.  ***********************************************************************************************************************************************************/	/***************************************************************	 *	TLan_HandleInvalid	 *	 *	Returns:	 *		0	 *	Parms:	 *		dev		Device assigned the IRQ that was	 *				raised.	 *		host_int	The contents of the HOST_INT	 *				port.	 *	 *	This function handles invalid interrupts.  This should	 *	never happen unless some other adapter is trying to use	 *	the IRQ line assigned to the device.	 *	 **************************************************************/u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int ){	host_int = 0;	/* printk( "TLAN:  Invalid interrupt on %s.\n", dev->name ); */	return 0;} /* TLan_HandleInvalid */	/***************************************************************	 *	TLan_HandleTxEOF	 *	 *	Returns:	 *		1	 *	Parms:	 *		dev		Device assigned the IRQ that was	 *				raised.	 *		host_int	The contents of the HOST_INT	 *				port.	 *	 *	This function handles Tx EOF interrupts which are raised	 *	by the adapter when it has completed sending the	 *	contents of a buffer.  If detemines which list/buffer	 *	was completed and resets it.  If the buffer was the last	 *	in the channel (EOC), then the function checks to see if	 *	another buffer is ready to send, and if so, sends a Tx	 *	Go command.  Finally, the driver activates/continues the	 *	activity LED.	 *	 **************************************************************/u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ){	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;	int		eoc = 0;	TLanList	*head_list;	u32		ack = 1;	TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );	host_int = 0;	head_list = priv->txList + priv->txHead;	if ( ! bbuf ) {		dev_kfree_skb_irq( (struct sk_buff *) head_list->buffer[9].address );				head_list->buffer[9].address = 0;	}	if ( head_list->cStat & TLAN_CSTAT_EOC )		eoc = 1;	if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {		printk( "TLAN:  Received interrupt for uncompleted TX frame.\n" );	}	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 );	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

⌨️ 快捷键说明

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