tlan.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,212 行 · 第 1/5 页

C
2,212
字号
	err = 0;	for ( i = 0;  i < 6 ; i++ )		err |= TLan_EeReadByte( dev,					(u8) priv->adapter->addrOfs + i,					(u8 *) &dev->dev_addr[i] );	if ( err ) {		printk(KERN_ERR "TLAN: %s: Error reading MAC from eeprom: %d\n",			dev->name,			err );	}	dev->addr_len = 6;	netif_carrier_off(dev);	/* Device methods */	dev->open = &TLan_Open;	dev->hard_start_xmit = &TLan_StartTx;	dev->stop = &TLan_Close;	dev->get_stats = &TLan_GetStats;	dev->set_multicast_list = &TLan_SetMulticastList;	dev->do_ioctl = &TLan_ioctl;#ifdef CONFIG_NET_POLL_CONTROLLER	dev->poll_controller = &TLan_Poll;#endif	dev->tx_timeout = &TLan_tx_timeout;	dev->watchdog_timeo = TX_TIMEOUT;	return 0;} /* TLan_Init */	/***************************************************************	 *	TLan_Open	 *	 *	Returns:	 *		0 on success, error code otherwise.	 *	Parms:	 *		dev	Structure of device to be opened.	 *	 *	This routine puts the driver and TLAN adapter in a	 *	state where it is ready to send and receive packets.	 *	It allocates the IRQ, resets and brings the adapter	 *	out of reset, and allows interrupts.  It also delays	 *	the startup for autonegotiation or sends a Rx GO	 *	command to the adapter, as appropriate.	 *	 **************************************************************/static int TLan_Open( struct net_device *dev ){	TLanPrivateInfo	*priv = dev->priv;	int		err;		priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION );	err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );		if ( err ) {		printk(KERN_ERR "TLAN:  Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );		return err;	}		init_timer(&priv->timer);	netif_start_queue(dev);		/* NOTE: It might not be necessary to read the stats before a			 reset if you don't care what the values are.	*/	TLan_ResetLists( dev );	TLan_ReadAndClearStats( dev, TLAN_IGNORE );	TLan_ResetAdapter( dev );	TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened.  TLAN Chip Rev: %x\n", dev->name, priv->tlanRev );	return 0;} /* TLan_Open */	/**************************************************************	 *	TLan_ioctl	 *		 *	Returns:	 *		0 on success, error code otherwise	 *	Params:	 *		dev	structure of device to receive ioctl.	 *			 *		rq	ifreq structure to hold userspace data.	 *	 *		cmd	ioctl command.	 *	 *	 *************************************************************/static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	TLanPrivateInfo *priv = dev->priv;	struct mii_ioctl_data *data = if_mii(rq);	u32 phy   = priv->phy[priv->phyNum];		if (!priv->phyOnline)		return -EAGAIN;	switch(cmd) {	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */			data->phy_id = phy;	case SIOCGMIIREG:		/* Read MII PHY register. */			TLan_MiiReadReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, &data->val_out);			return 0;			case SIOCSMIIREG:		/* Write MII PHY register. */			if (!capable(CAP_NET_ADMIN))				return -EPERM;			TLan_MiiWriteReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);			return 0;		default:			return -EOPNOTSUPP;	}} /* tlan_ioctl */	/***************************************************************	 * 	TLan_tx_timeout	 *	 * 	Returns: nothing	 *	 * 	Params:	 * 		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_FreeLists( dev );	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 = dev->priv;	TLanList	*tail_list;	dma_addr_t	tail_list_phys;	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;	tail_list_phys = priv->txListDMA + sizeof(TLanList) * 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 = pci_map_single(priv->pciDev, skb->data, skb->len, PCI_DMA_TODEVICE);		TLan_StoreSKB(tail_list, 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 = TLanPadBufferDMA;	} 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;		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Starting TX on buffer %d\n", priv->txTail );		outl( tail_list_phys, dev->base_addr + TLAN_CH_PARM );		outl( TLAN_HC_GO, 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 = tail_list_phys;		} else {			( priv->txList + ( priv->txTail - 1 ) )->forward = tail_list_phys;		}	}	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 irqreturn_t 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 = dev_id;	priv = 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);	return IRQ_HANDLED;} /* 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 = dev->priv;	netif_stop_queue(dev);	priv->neg_be_verbose = 0;	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 = 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 ) );

⌨️ 快捷键说明

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