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

📄 smc91113.c

📁 SMSC lan91c113 uclinux driver source
💻 C
📖 第 1 页 / 共 5 页
字号:
		status = inb( ioaddr + INT_REG ) & mask;		if (!status )			break;		PRINTK3(KERN_WARNING "%s: Handling interrupt status %x \n",			dev->name, status);		if (status & IM_RCV_INT) {			/* Got a packet(s). */			PRINTK2(KERN_WARNING				"%s: Receive Interrupt\n", dev->name);			smc_rcv(dev);		} else if (status & IM_TX_INT ) {			PRINTK2(KERN_WARNING "%s: TX ERROR handled\n",				dev->name);			smc_tx(dev);			// Acknowledge the interrupt			outb(IM_TX_INT, ioaddr + INT_REG );		} else if (status & IM_TX_EMPTY_INT ) {			/* update stats */			SMC_SELECT_BANK( 0 );			card_stats = inw( ioaddr + COUNTER_REG );			/* single collisions */			lp->stats.collisions += card_stats & 0xF;			card_stats >>= 4;			/* multiple collisions */			lp->stats.collisions += card_stats & 0xF;			/* these are for when linux supports these statistics */#if 0			card_stats >>= 4;			/* deferred */			card_stats >>= 4;			/* excess deferred */#endif			SMC_SELECT_BANK( 2 );			PRINTK2(KERN_WARNING "%s: TX_BUFFER_EMPTY handled\n",				dev->name);			// Acknowledge the interrupt			outb( IM_TX_EMPTY_INT, ioaddr + INT_REG );			mask &= ~IM_TX_EMPTY_INT;			lp->stats.tx_packets += lp->packets_waiting;			lp->packets_waiting = 0;		} else if (status & IM_ALLOC_INT ) {			PRINTK2(KERN_DEBUG "%s: Allocation interrupt \n",				dev->name);			/* clear this interrupt so it doesn't happen again */			mask &= ~IM_ALLOC_INT;			smc_hardware_send_packet( dev );			/* enable xmit interrupts based on this */			mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );			/* and let the card send more packets to me */			netif_wake_queue(dev);			PRINTK2("%s: Handoff done successfully.\n",				dev->name);		} else if (status & IM_RX_OVRN_INT ) {			lp->stats.rx_errors++;			lp->stats.rx_fifo_errors++;			// Acknowledge the interrupt			outb( IM_RX_OVRN_INT, ioaddr + INT_REG );		} else if (status & IM_EPH_INT ) {			PRINTK("%s: UNSUPPORTED: EPH INTERRUPT \n",				dev->name);		} else if (status & IM_MDINT ) {			smc_phy_interrupt(dev);			// Acknowledge the interrupt			outb(IM_MDINT, ioaddr + INT_REG );		} else if (status & IM_ERCV_INT ) {			PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n",				dev->name);			// Acknowledge the interrupt			outb( IM_ERCV_INT, ioaddr + INT_REG );		}	} while ( timeout -- );	/* restore register states */	SMC_SELECT_BANK( 2 );	outb( mask, ioaddr + IM_REG );	PRINTK3( KERN_WARNING "%s: MASK is now %x \n", dev->name, mask);	outw( saved_pointer, ioaddr + PTR_REG );	SMC_SELECT_BANK( saved_bank );	//dev->interrupt = 0;	PRINTK3("%s: Interrupt done\n", dev->name);	return;}/*Qinwei : fix the problem when using insw(...)*/static void SMC_insw(r,b,l){    int __i ;     	unsigned short *__b2;        __b2 = (unsigned short *) b;      for (__i = 0; __i < l; __i++)     {          *(__b2 + __i) = inw(r);          inw(0x2000300);      };}/*Qinwei : fix the problem when using outsw(...)*/static void SMC_outsw(r,b,l){	    int __i;    unsigned short *__b2;     __b2 = (unsigned short *) b;     for (__i = 0; __i < l; __i++)     {         outw( *(__b2 + __i), r);    } }/*------------------------------------------------------------- . . smc_rcv -  receive a packet from the card . . There is ( at least ) a packet waiting to be read from . chip-memory. . . o Read the status . o If an error, record it . o otherwise, read in the packet --------------------------------------------------------------*/static void smc_rcv(struct net_device *dev){	struct smc_local *lp = (struct smc_local *)dev->priv;	int 	ioaddr = dev->base_addr;	int 	packet_number;	word	status;	word	packet_length;	PRINTK3("%s:smc_rcv\n", dev->name);	/* assume bank 2 */	packet_number = inw( ioaddr + RXFIFO_REG );	if ( packet_number & RXFIFO_REMPTY ) {		/* we got called , but nothing was on the FIFO */		PRINTK("%s: WARNING: smc_rcv with nothing on FIFO. \n",			dev->name);		/* don't need to restore anything */		return;	}	/*  start reading from the start of the packet */	outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + PTR_REG );	/* First two words are status and packet_length *///	status 		= inw( ioaddr + DATA_REG ); // Qinwei: it seems couldn't get the status???    status = RS_ODDFRAME;                   // So add this line.	packet_length 	= inw( ioaddr + DATA_REG );	packet_length &= 0x07ff;  /* mask off top bits */	PRINTK2("RCV: STATUS %4x LENGTH %4x\n", status, packet_length );	if ( !(status & RS_ERRORS ) ){		/* do stuff to make a new packet */		struct sk_buff  * skb;		byte		* data;		/* set multicast stats */		if ( status & RS_MULTICAST )			lp->stats.multicast++;		// Allocate enough memory for entire receive frame, to be safe		skb = dev_alloc_skb( packet_length );		/* Adjust for having already read the first two words */		packet_length -= 4;		if ( skb == NULL ) {			printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",				dev->name);			lp->stats.rx_dropped++;			goto done;		}		/*		 ! This should work without alignment, but it could be		 ! in the worse case		*/		/* TODO: Should I use 32bit alignment here ? */		skb_reserve( skb, 2 );   /* 16 bit alignment */		skb->dev = dev;		/* =>    ODD-BYTE ISSUE : The odd byte problem has been fixed in the LAN91C113 Rev B.		So we check if the Chip Revision, stored in smsc_local->ChipRev, is = 1.		If so then we increment the packet length only if RS_ODDFRAME is set.		If the Chip's revision is equal to 0, then we blindly increment the packet length		by 1, thus always assuming that the packet is odd length, leaving the higher layer		to decide the actual length.			-- Pramod		<= */		if ((9 == lp->ChipID) && (1 == lp->ChipRev))		{			if (status & RS_ODDFRAME)				data = skb_put( skb, packet_length + 1 );				else				data = skb_put( skb, packet_length);								}		else		{			// set odd length for bug in LAN91C113, REV A			// which never sets RS_ODDFRAME			data = skb_put( skb, packet_length + 1 );		}#ifdef USE_32_BIT		PRINTK3(" Reading %d dwords (and %d bytes) \n",			packet_length >> 2, packet_length & 3 );		/* QUESTION:  Like in the TX routine, do I want		   to send the DWORDs or the bytes first, or some		   mixture.  A mixture might improve already slow PIO		   performance  */		insl(ioaddr + DATA_REG , data, packet_length >> 2 );		/* read the left over bytes */		insb( ioaddr + DATA_REG, data + (packet_length & 0xFFFFFC),			packet_length & 0x3  ); #else		PRINTK3(" Reading %d words and %d byte(s) \n",			(packet_length >> 1 ), packet_length & 1 );//		insw(ioaddr + DATA_REG , data, packet_length >> 1); // Qinwei ???        SMC_insw(ioaddr + DATA_REG,data, packet_length >> 1);#endif // USE_32_BIT#if	SMC_DEBUG > 2		printk("Receiving Packet\n");		print_packet( data, packet_length );#endif		skb->protocol = eth_type_trans(skb, dev );		netif_rx(skb);		lp->stats.rx_packets++;	} else {		/* error ... */		lp->stats.rx_errors++;		if ( status & RS_ALGNERR )  lp->stats.rx_frame_errors++;		if ( status & (RS_TOOSHORT | RS_TOOLONG ) )			lp->stats.rx_length_errors++;		if ( status & RS_BADCRC)	lp->stats.rx_crc_errors++;	}	while ( inw( ioaddr + MMU_CMD_REG ) & MC_BUSY )		udelay(1); // Wait until not busydone:	/*  error or good, tell the card to get rid of this packet */	outw( MC_RELEASE, ioaddr + MMU_CMD_REG );	return;}/************************************************************************* . smc_tx . . Purpose:  Handle a transmit error message.   This will only be called .   when an error, because of the AUTO_RELEASE mode. . . Algorithm: .	Save pointer and packet no .	Get the packet no from the top of the queue .	check if it's valid ( if not, is this an error??? ) .	read the status word .	record the error .	( resend?  Not really, since we don't want old packets around ) .	Restore saved values ************************************************************************/static void smc_tx( struct net_device * dev ){	int	ioaddr = dev->base_addr;	struct smc_local *lp = (struct smc_local *)dev->priv;	byte saved_packet;	byte packet_no;	word tx_status;	PRINTK3("%s:smc_tx\n", dev->name);	/* assume bank 2  */	saved_packet = inb( ioaddr + PN_REG );	packet_no = inw( ioaddr + RXFIFO_REG );	packet_no &= 0x7F;	/* If the TX FIFO is empty then nothing to do */	if ( packet_no & TXFIFO_TEMPTY )		return;	/* select this as the packet to read from */	outb( packet_no, ioaddr + PN_REG );	/* read the first word (status word) from this packet */	outw( PTR_AUTOINC | PTR_READ, ioaddr + PTR_REG );	tx_status = inw( ioaddr + DATA_REG );	PRINTK3("%s: TX DONE STATUS: %4x \n", dev->name, tx_status);	lp->stats.tx_errors++;	if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++;	if ( tx_status & TS_LATCOL  ) {		printk(KERN_DEBUG			"%s: Late collision occurred on last xmit.\n",			dev->name);		lp->stats.tx_window_errors++;#ifdef CONFIG_SYSCTL				lp->ctl_forcol = 0; // Reset forced collsion#endif //CONFIG_SYSCTL	}#if 0	if ( tx_status & TS_16COL ) { ... }#endif	if ( tx_status & TS_SUCCESS ) {		printk("%s: Successful packet caused interrupt \n", dev->name);	}	/* re-enable transmit */	SMC_SELECT_BANK( 0 );	outw( inw( ioaddr + TCR_REG ) | TCR_ENABLE, ioaddr + TCR_REG );	/* kill the packet */	SMC_SELECT_BANK( 2 );	outw( MC_FREEPKT, ioaddr + MMU_CMD_REG );	/* one less packet waiting for me */	lp->packets_waiting--;	/* Don't change Packet Number Reg until busy bit is cleared */	/* Per LAN91C113 Spec, Page 50 */	while ( inw( ioaddr + MMU_CMD_REG ) & MC_BUSY );	outb( saved_packet, ioaddr + PN_REG );	return;}/*---------------------------------------------------- . smc_close . . this makes the board clean up everything that it can . and not talk to the outside world.   Caused by . an 'ifconfig ethX down' . -----------------------------------------------------*/static int smc_close(struct net_device *dev){	netif_stop_queue(dev);	//dev->start = 0;	PRINTK2("%s:smc_close\n", dev->name);#ifdef CONFIG_SYSCTL	smc_sysctl_unregister(dev);#endif /* CONFIG_SYSCTL */ 	/* clear everything */	smc_shutdown( dev->base_addr );    /*Qinwei: close the interupt */    disable_irq(dev->irq); 	return 0;}/*------------------------------------------------------------ . Get the current statistics. . This may be called with the card open or closed. .-------------------------------------------------------------*/static struct net_device_stats* smc_query_statistics(struct net_device *dev) {	struct smc_local *lp = (struct smc_local *)dev->priv;	PRINTK2("%s:smc_query_statistics\n", dev->name);	return &lp->stats;}/*----------------------------------------------------------- . smc_set_multicast_list . . This routine will, depending on the values passed to it, . either make it accept multicast packets, go into . promiscuous mode ( for TCPDUMP and cousins ) or accept . a select set of multicast packets*/static void smc_set_multicast_list(struct net_device *dev){	unsigned int ioaddr = dev->base_addr;	PRINTK2("%s:smc_set_multicast_list\n", dev->name);	SMC_SELECT_BANK(0);	if ( dev->flags & IFF_PROMISC )		{		PRINTK2("%s:smc_set_multicast_list:RCR_PRMS\n", dev->name);		outw( inw(ioaddr + RCR_REG ) | RCR_PRMS, ioaddr + RCR_REG );		}/* BUG?  I never disable promiscuous mode if multicasting was turned on.   Now, I turn off promiscuous mode, but I don't do anything to multicasting   when promiscuous mode is turned on.*/	/* Here, I am setting this to accept all multicast packets.	   I don't need to zero the multicast table, because the flag is	   checked before the table is	*/	else if (dev->flags & IFF_ALLMULTI)		{		outw( inw(ioaddr + RCR_REG ) | RCR_ALMUL, ioaddr + RCR_REG );		PRINTK2("%s:smc_set_multicast_list:RCR_ALMUL\n", dev->name);		}	/* We just get all multicast packets even if we only want them	 . from one source.  This will be changed at some future	 . point. */	else if (dev->mc_count )  {		/* support hardware multicasting */		/* be sure I get rid of flags I might have set */		outw( inw( ioaddr + RCR_REG ) & ~(RCR_PRMS | RCR_ALMUL),			ioaddr + RCR_REG );		/* NOTE: this has to set the bank, so make sure it is the		   last thing called.  The bank is set to zero at the top */		smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );	} else  {		PRINTK2("%s:smc_set_multicast_list:~(RCR_PRMS|RCR_ALMUL)\n",			dev->name);		outw( inw( ioaddr + RCR_REG ) & ~(RCR_PRMS | RCR_ALMUL),			ioaddr + RCR_REG );		/*		  since I'm disabling all multicast entirely, I need to		  clear the multicast list		*/		SMC_SELECT_BANK( 3 );		outw( 0, ioaddr + MCAST_REG1 );		outw( 0, ioaddr + MCAST_REG2 );		outw( 0, ioaddr + MCAST_REG3 );		outw( 0, ioaddr + MCAST_REG4 );	}}static struct net_device devSMC91113;/*------------------------------------------------------------ . Module initialization function .-------------------------------------------------------------*/int EV44b0_init_module(void){	int result;	PRINTK2("CARDNAME:init_module\n");	/* copy the parameters from insmod into the device structure */	devSMC91113.base_addr	= CONFIG_SMC91113_BASE;     // io base address 	devSMC91113.irq		    = CONFIG_SMC91113_IRQ;      // irq number	devSMC91113.dma		    = CONFIG_SMC91113_DMA;      // Use DMA field for nowait?	devSMC91113.init	    = smc_init;/* Kernel 2.4 Changes - Pramod */	if ((result = register_netdev(&devSMC91113)) != 0)	{	    printk("EV44B0 eth: Error %i registering device \"%s\"\n", result, devSMC91113.name);	    return -ENODEV;

⌨️ 快捷键说明

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