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

📄 smc91113.c

📁 SMSC lan91c113 uclinux driver source
💻 C
📖 第 1 页 / 共 5 页
字号:
static void smc_reset( struct net_device* dev ){	//struct smc_local *lp 	= (struct smc_local *)dev->priv;	unsigned int	ioaddr = dev->base_addr;	int temp = 0;	PRINTK2("%s:smc_reset\n", dev->name);	/* This resets the registers mostly to defaults, but doesn't	   affect EEPROM.  That seems unnecessary */	SMC_SELECT_BANK( 0 );	outw( RCR_SOFTRST, ioaddr + RCR_REG );    while(1) // now test the is reset ok?, if not ok, so we just change the status.    {        temp ++;        if ((inw(ioaddr + RCR_REG ) & RCR_SOFTRST) == 0)            break;        smc_wait_ms (10); /* Delay 10ms, try 5 times*/        if (temp >=5)        {            outw( (inw(ioaddr + RCR_REG ) & (~RCR_SOFTRST)) , ioaddr + RCR_REG );            break;        }    }	/* Setup the Configuration Register */	/* This is necessary because the CONFIG_REG is not affected */	/* by a soft reset */	SMC_SELECT_BANK( 1 );	outw( CONFIG_DEFAULT, ioaddr + CONFIG_REG);	/* Setup for fast accesses if requested */	/* If the card/system can't handle it then there will */	/* be no recovery except for a hard reset or power cycle */	if (dev->dma)		outw( inw( ioaddr + CONFIG_REG ) | CONFIG_NO_WAIT,			ioaddr + CONFIG_REG );#ifdef POWER_DOWN	/* Release from possible power-down state */	/* Configuration register is not affected by Soft Reset */	SMC_SELECT_BANK( 1 );	outw( inw( ioaddr + CONFIG_REG ) | CONFIG_EPH_POWER_EN,		ioaddr + CONFIG_REG  );#endif	SMC_SELECT_BANK( 0 );	/* this should pause enough for the chip to be happy */	mdelay(10);	/* Disable transmit and receive functionality */	outw( RCR_CLEAR, ioaddr + RCR_REG );	outw( TCR_CLEAR, ioaddr + TCR_REG );	/* set the control register to automatically	   release successfully transmitted packets, to make the best	   use out of our limited memory */	SMC_SELECT_BANK( 1 );	outw( inw( ioaddr + CTL_REG ) | CTL_AUTO_RELEASE , ioaddr + CTL_REG );	/* Reset the MMU */	SMC_SELECT_BANK( 2 );	outw( MC_RESET, ioaddr + MMU_CMD_REG );	/* Note:  It doesn't seem that waiting for the MMU busy is needed here,	   but this is a place where future chipsets _COULD_ break.  Be wary 	   of issuing another MMU command right after this */	while ( inw( ioaddr + MMU_CMD_REG ) & MC_BUSY ) /* Qinwei : I add waiting, for safe.*/		mdelay(1); // Wait until not busy	/* Disable all interrupts */	outb( 0, ioaddr + IM_REG );}/* . Function: smc_enable . Purpose: let the chip talk to the outside work . Method: .	1.  Enable the transmitter .	2.  Enable the receiver .	3.  Enable interrupts*/static void smc_enable( struct net_device *dev ){	unsigned int ioaddr 	= dev->base_addr;	struct smc_local *lp 	= (struct smc_local *)dev->priv;	PRINTK2("%s:smc_enable\n", dev->name);	SMC_SELECT_BANK( 0 );	/* see the header file for options in TCR/RCR DEFAULT*/	outw( lp->tcr_cur_mode, ioaddr + TCR_REG );	outw( lp->rcr_cur_mode, ioaddr + RCR_REG );	/* now, enable interrupts */	SMC_SELECT_BANK( 2 );	outb( SMC_INTERRUPT_MASK, ioaddr + IM_REG );}/* . Function: smc_shutdown . Purpose:  closes down the SMC91xxx chip. . Method: .	1. zero the interrupt mask .	2. clear the enable receive flag .	3. clear the enable xmit flags . . TODO: .   (1) maybe utilize power down mode. .	Why not yet?  Because while the chip will go into power down mode, .	the manual says that it will wake up in response to any I/O requests .	in the register space.   Empirical results do not show this working.*/static void smc_shutdown( int ioaddr ){	PRINTK2("CARDNAME:smc_shutdown\n");	/* no more interrupts for me */	SMC_SELECT_BANK( 2 );	outb( 0, ioaddr + IM_REG );	/* and tell the card to stay away from that nasty outside world */	SMC_SELECT_BANK( 0 );	outb( RCR_CLEAR, ioaddr + RCR_REG );	outb( TCR_CLEAR, ioaddr + TCR_REG );#ifdef POWER_DOWN	/* finally, shut the chip down */	SMC_SELECT_BANK( 1 );	outw( inw( ioaddr + CONFIG_REG ) & ~CONFIG_EPH_POWER_EN,		ioaddr + CONFIG_REG  );#endif}/* . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds ) . Purpose: .    This sets the internal hardware table to filter out unwanted multicast .    packets before they take up memory. . .    The SMC chip uses a hash table where the high 6 bits of the CRC of .    address are the offset into the table.  If that bit is 1, then the .    multicast packet is accepted.  Otherwise, it's dropped silently. . .    To use the 6 bits as an offset into the table, the high 3 bits are the .    number of the 8 bit register, while the low 3 bits are the bit within .    that register. . . This routine is based very heavily on the one provided by Peter Cammaert.*/static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) {	int			i;	unsigned char		multicast_table[ 8 ];	struct dev_mc_list	* cur_addr;	/* table for flipping the order of 3 bits */	unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };	PRINTK2("CARDNAME:smc_setmulticast\n");	/* start with a table of all zeros: reject all */	memset( multicast_table, 0, sizeof( multicast_table ) );	cur_addr = addrs;	for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next  ) {		int position;		/* do we have a pointer here? */		if ( !cur_addr )			break;		/* make sure this is a multicast address - shouldn't this		   be a given if we have it here ? */		if ( !( *cur_addr->dmi_addr & 1 ) )			continue;		/* only use the low order bits */		position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f;		/* do some messy swapping to put the bit in the right spot */		multicast_table[invert3[position&7]] |=					(1<<invert3[(position>>3)&7]);	}	/* now, the table can be loaded into the chipset */	SMC_SELECT_BANK( 3 );	for ( i = 0; i < 8 ; i++ ) {		outb( multicast_table[i], ioaddr + MCAST_REG1 + i );	}}/*  Finds the CRC32 of a set of bytes.  Again, from Peter Cammaert's code.*/static int crc32( char * s, int length ) {	/* indices */	int perByte;	int perBit;	/* crc polynomial for Ethernet */	const unsigned long poly = 0xedb88320;	/* crc value - preinitialized to all 1's */	unsigned long crc_value = 0xffffffff;	for ( perByte = 0; perByte < length; perByte ++ ) {		unsigned char	c;		c = *(s++);		for ( perBit = 0; perBit < 8; perBit++ ) {			crc_value = (crc_value>>1)^				(((crc_value^c)&0x01)?poly:0);			c >>= 1;		}	}	return	crc_value;}/* . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct device * ) . Purpose: .    Attempt to allocate memory for a packet, if chip-memory is not .    available, then tell the card to generate an interrupt when it .    is available. . . Algorithm: . . o	if the saved_skb is not currently null, then drop this packet .	on the floor.  This should never happen, because of TBUSY. . o	if the saved_skb is null, then replace it with the current packet, . o	See if I can sending it now. . o 	(NO): Enable interrupts and let the interrupt handler deal with it. . o	(YES):Send it now.*/static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ){	struct smc_local *lp 	= (struct smc_local *)dev->priv;	unsigned int ioaddr 	= dev->base_addr;	word 			length;	unsigned short 		numPages;	word			time_out;	word			status;	PRINTK3("%s:smc_wait_to_send_packet\n", dev->name);	if ( lp->saved_skb) {		/* THIS SHOULD NEVER HAPPEN. */		lp->stats.tx_aborted_errors++;//		printk("%s: sent packet while busy.\n",	dev->name);		return 1;	}	lp->saved_skb = skb;	length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;			/*	** The MMU wants the number of pages to be the number of 256 bytes	** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )	**	** The 91C113 ignores the size bits, but the code is left intact	** for backwards and future compatibility.	**	** Pkt size for allocating is data length +6 (for additional status	** words, length and ctl!)	**	** If odd size then last byte is included in this header.	*/	numPages =   ((length & 0xfffe) + 6);	numPages >>= 8; // Divide by 256	if (numPages > 7 ) {		printk("%s: Far too big packet error. \n", dev->name);		/* freeing the packet is a good thing here... but should		 . any packets of this size get down here?   */		dev_kfree_skb (skb);		lp->saved_skb = NULL;		/* this IS an error, but, i don't want the skb saved */		netif_wake_queue(dev);		return 0;	}	/* either way, a packet is waiting now */	lp->packets_waiting++;	/* now, try to allocate the memory */	SMC_SELECT_BANK( 2 );	outw( MC_ALLOC | numPages, ioaddr + MMU_CMD_REG );	/* 	. Performance Hack	. 	. wait a short amount of time.. if I can send a packet now, I send	. it now.  Otherwise, I enable an interrupt and wait for one to be	. available.	.	. I could have handled this a slightly different way, by checking to	. see if any memory was available in the FREE MEMORY register.  However,	. either way, I need to generate an allocation, and the allocation works	. no matter what, so I saw no point in checking free memory.	*/	time_out = MEMORY_WAIT_TIME;	do {		status = inb( ioaddr + INT_REG );		if ( status & IM_ALLOC_INT ) {			/* acknowledge the interrupt */			outb( IM_ALLOC_INT, ioaddr + INT_REG );  			break;		}   	} while ( -- time_out );   	if ( !time_out ) {		/* oh well, wait until the chip finds memory later */		SMC_ENABLE_INT( IM_ALLOC_INT );		/* Check the status bit one more time just in case */		/* it snuk in between the time we last checked it */		/* and when we set the interrupt bit */		status = inb( ioaddr + INT_REG );		if ( !(status & IM_ALLOC_INT) ) {      			PRINTK2("%s: memory allocation deferred. \n",				dev->name);			/* it's deferred, but I'll handle it later */      			return 0;			}		/* Looks like it did sneak in, so disable */		/* the interrupt */		SMC_DISABLE_INT( IM_ALLOC_INT );   	}	/* or YES! I can send the packet now.. */	smc_hardware_send_packet(dev);	netif_wake_queue(dev);	return 0;}/* . Function:  smc_hardware_send_packet(struct device * ) . Purpose: .	This sends the actual packet to the SMC9xxx chip. . . Algorithm: . 	First, see if a saved_skb is available. .		( this should NOT be called if there is no 'saved_skb' .	Now, find the packet number that the chip allocated .	Point the data pointers at it in memory .	Set the length word in the chip's memory .	Dump the packet to chip memory .	Check if a last byte is needed ( odd length packet ) .		if so, set the control flag right . 	Tell the card to send it .	Enable the transmit interrupt, so I know if it failed . 	Free the kernel data if I actually sent it.*/static void smc_hardware_send_packet( struct net_device * dev ){	struct smc_local *lp = (struct smc_local *)dev->priv;	byte	 		packet_no;	struct sk_buff * 	skb = lp->saved_skb;	word			length;	unsigned int	ioaddr;	byte			* buf;	PRINTK3("%s:smc_hardware_send_packet\n", dev->name);	ioaddr = dev->base_addr;	if ( !skb ) {		PRINTK("%s: In XMIT with no packet to send \n", dev->name);		return;	}	length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;	buf = skb->data;	/* If I get here, I _know_ there is a packet slot waiting for me */	packet_no = inb( ioaddr + AR_REG );	if ( packet_no & AR_FAILED ) {		/* or isn't there?  BAD CHIP! */		printk(KERN_DEBUG "%s: Memory allocation failed. \n",			dev->name);		dev_kfree_skb_any (skb);		lp->saved_skb = NULL;		netif_wake_queue(dev);		return;	}	/* we have a packet address, so tell the card to use it */	outb( packet_no, ioaddr + PN_REG );	/* point to the beginning of the packet */	outw( PTR_AUTOINC , ioaddr + PTR_REG );   	PRINTK3("%s: Trying to xmit packet of length %x\n",		dev->name, length);#if SMC_DEBUG > 2	printk("Transmitting Packet\n");	print_packet( buf, length );#endif	/* send the packet length ( +6 for status, length and ctl byte ) 	   and the status word ( set to zeros ) */#ifdef USE_32_BIT	outl(  (length +6 ) << 16 , ioaddr + DATA_REG );#else	outw( 0, ioaddr + DATA_REG );	/* send the packet length ( +6 for status words, length, and ctl*//*	outb( (length+6) & 0xFF,ioaddr + DATA_REG );	outb( (length+6) >> 8 , ioaddr + DATA_REG );*/ // Qinwei ?????	outw( (length+6), ioaddr + DATA_REG );#endif	/* send the actual data	 . I _think_ it's faster to send the longs first, and then	 . mop up by sending the last word.  It depends heavily 	 . on alignment, at least on the 486.  Maybe it would be 	 . a good idea to check which is optimal?  But that could take	 . almost as much time as is saved?	*/#ifdef USE_32_BIT	outsl(ioaddr + DATA_REG, buf,  length >> 2 );	if ( length & 0x2  )		outw(*((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_REG);#else	//outsw(ioaddr + DATA_REG , buf, (length ) >> 1); // Qinwei ???	SMC_outsw(ioaddr + DATA_REG,buf,(length ) >> 1);#endif // USE_32_BIT	/* Send the last byte, if there is one.   */	if ( (length & 1) == 0 ) {		outw( 0, ioaddr + DATA_REG );	} else {	    // Set odd bit in CONTROL BYTE	    outw( buf[length -1 ] | 0x2000, ioaddr + DATA_REG ); // Qinwei ???		/*outb( buf[length -1 ], ioaddr + DATA_REG );		outb( 0x20, ioaddr + DATA_REG); */	}	/* enable the interrupts */	SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) );	/* and let the chipset deal with it */	outw( MC_ENQUEUE , ioaddr + MMU_CMD_REG );	PRINTK2("%s: Sent packet of length %d \n", dev->name, length);	lp->saved_skb = NULL;	dev_kfree_skb_any (skb);	dev->trans_start = jiffies;	/* we can send another packet */	netif_wake_queue(dev);	return;}/*------------------------------------------------------------------------- | | smc_init( struct device * dev ) |   Input parameters: |	dev->base_addr == 0, try to find all possible locations |	dev->base_addr == 1, return failure code |	dev->base_addr == 2, always allocate space,  and return success |	dev->base_addr == <anything else>   this is the address to check | |   Output: |	0 --> there is a device |	anything else, error | ---------------------------------------------------------------------------*/

⌨️ 快捷键说明

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