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

📄 smc9194.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
		} else if (status & IM_TX_INT ) {			PRINTK2((KERN_WARNING CARDNAME				": TX ERROR handled\n"));			smc_tx(dev);			outb(IM_TX_INT, ioaddr + INTERRUPT );		} else if (status & IM_TX_EMPTY_INT ) {			/* update stats */			SMC_SELECT_BANK( 0 );			card_stats = inw( ioaddr + COUNTER );			/* 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 CARDNAME				": TX_BUFFER_EMPTY handled\n"));			outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT );			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 CARDNAME				": Allocation interrupt \n"));			/* 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 */			mark_bh( NET_BH );			PRINTK2((CARDNAME": Handoff done successfully.\n"));		} else if (status & IM_RX_OVRN_INT ) {			lp->stats.rx_errors++;			lp->stats.rx_fifo_errors++;			outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT );		} else if (status & IM_EPH_INT ) {			PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n"));		} else if (status & IM_ERCV_INT ) {			PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n"));			outb( IM_ERCV_INT, ioaddr + INTERRUPT );		}	} while ( timeout -- );	/* restore state register */	SMC_SELECT_BANK( 2 );	outb( mask, ioaddr + INT_MASK );	PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask ));	outw( saved_pointer, ioaddr + POINTER );	SMC_SELECT_BANK( saved_bank );	dev->interrupt = 0;	PRINTK3((CARDNAME ": Interrupt done\n"));	return;}/*------------------------------------------------------------- . . 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 device *dev){	struct smc_local *lp = (struct smc_local *)dev->priv;	int 	ioaddr = dev->base_addr;	int 	packet_number;	word	status;	word	packet_length;	/* assume bank 2 */	packet_number = inw( ioaddr + FIFO_PORTS );	if ( packet_number & FP_RXEMPTY ) {		/* we got called , but nothing was on the FIFO */		PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO. \n"));		/* don't need to restore anything */		return;	}	/*  start reading from the start of the packet */	outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER );	/* First two words are status and packet_length */	status 		= inw( ioaddr + DATA_1 );	packet_length 	= inw( ioaddr + DATA_1 );	packet_length &= 0x07ff;  /* mask off top bits */	PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length ));	/*	 . the packet length contains 3 extra words :	 . status, length, and an extra word with an odd byte .	*/	packet_length -= 6;	if ( !(status & RS_ERRORS ) ){		/* do stuff to make a new packet */		struct sk_buff  * skb;		byte		* data;		/* read one extra byte */		if ( status & RS_ODDFRAME )			packet_length++;		/* set multicast stats */		if ( status & RS_MULTICAST )			lp->stats.multicast++;#ifdef SUPPORT_OLD_KERNEL		skb = alloc_skb( packet_length + 5, GFP_ATOMIC );#else		skb = dev_alloc_skb( packet_length + 5);#endif		if ( skb == NULL ) {			printk(KERN_NOTICE CARDNAME			": Low memory, packet dropped.\n");			lp->stats.rx_dropped++;		}		/*		 ! This should work without alignment, but it could be		 ! in the worse case		*/#ifndef SUPPORT_OLD_KERNEL		/* TODO: Should I use 32bit alignment here ? */		skb_reserve( skb, 2 );   /* 16 bit alignment */#endif		skb->dev = dev;#ifdef SUPPORT_OLD_KERNEL		skb->len = packet_length;		data = skb->data;#else		data = skb_put( skb, packet_length);#endif#ifdef USE_32_BIT		/* 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  */		PRINTK3((" Reading %d dwords (and %d bytes) \n",			packet_length >> 2, packet_length & 3 ));		insl(ioaddr + DATA_1 , data, packet_length >> 2 );		/* read the left over bytes */		insb( ioaddr + DATA_1, data + (packet_length & 0xFFFFFC),			packet_length & 0x3  );#else		PRINTK3((" Reading %d words and %d byte(s) \n",			(packet_length >> 1 ), packet_length & 1 );		if ( packet_length & 1 )			*(data++) = inb( ioaddr + DATA_1 );		insw(ioaddr + DATA_1 , data, (packet_length + 1 ) >> 1);		if ( packet_length & 1 ) {			data += packet_length & ~1;			*((data++) = inb( ioaddr + DATA_1 );		}#endif#if	SMC_DEBUG > 2			print_packet( data, packet_length );#endif#ifndef SUPPORT_OLD_KERNEL		skb->protocol = eth_type_trans(skb, dev );#endif		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++;	}	/*  error or good, tell the card to get rid of this packet */	outw( MC_RELEASE, ioaddr + MMU_CMD );	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 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;	/* assume bank 2  */	saved_packet = inb( ioaddr + PNR_ARR );	packet_no = inw( ioaddr + FIFO_PORTS );	packet_no &= 0x7F;	/* select this as the packet to read from */	outb( packet_no, ioaddr + PNR_ARR );	/* read the first word from this packet */	outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER );	tx_status = inw( ioaddr + DATA_1 );	PRINTK3((CARDNAME": TX DONE STATUS: %4x \n", tx_status ));	lp->stats.tx_errors++;	if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++;	if ( tx_status & TS_LATCOL  ) {		printk(KERN_DEBUG CARDNAME			": Late collision occurred on last xmit.\n");		lp->stats.tx_window_errors++;	}#if 0		if ( tx_status & TS_16COL ) { ... }#endif	if ( tx_status & TS_SUCCESS ) {		printk(CARDNAME": Successful packet caused interrupt \n");	}	/* re-enable transmit */	SMC_SELECT_BANK( 0 );	outw( inw( ioaddr + TCR ) | TCR_ENABLE, ioaddr + TCR );	/* kill the packet */	SMC_SELECT_BANK( 2 );	outw( MC_FREEPKT, ioaddr + MMU_CMD );	/* one less packet waiting for me */	lp->packets_waiting--;	outb( saved_packet, ioaddr + PNR_ARR );	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 device *dev){	dev->tbusy = 1;	dev->start = 0;	/* clear everything */	smc_shutdown( dev->base_addr );	/* Update the statistics here. */#ifdef MODULE	MOD_DEC_USE_COUNT;#endif	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 device *dev) {	struct smc_local *lp = (struct smc_local *)dev->priv;	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*/#ifdef SUPPORT_OLD_KERNELstatic void smc_set_multicast_list( struct device * dev,			int num_addrs, void * addrs )#elsestatic void smc_set_multicast_list(struct device *dev)#endif{	short ioaddr = dev->base_addr;	SMC_SELECT_BANK(0);#ifdef  SUPPORT_OLD_KERNEL	if ( num_addrs < 0 )#else	if ( dev->flags & IFF_PROMISC )#endif		outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR );/* 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	*/#ifdef  SUPPORT_OLD_KERNEL	else if ( num_addrs > 20 )	/* arbitrary constant */#else	else if (dev->flags & IFF_ALLMULTI)#endif		outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR );	/* We just get all multicast packets even if we only want them	 . from one source.  This will be changed at some future	 . point. */#ifdef  SUPPORT_OLD_KERNEL	else if (num_addrs > 0 ) {/* the old kernel support will not have hardware multicast support. It would   involve more kludges, and make the multicast setting code even worse.   Instead, just use the ALMUL method.   This is reasonable, considering that   it is seldom used*/		outw( inw( ioaddr + RCR ) & ~RCR_PROMISC, ioaddr + RCR );		outw( inw( ioadddr + RCR ) | RCR_ALMUL, ioadddr + RCR );	}#else	else if (dev->mc_count )  {		/* support hardware multicasting */		/* be sure I get rid of flags I might have set */		outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),			ioaddr + RCR );		/* 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 );	}#endif	else  {		outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),			ioaddr + RCR );		/*		  since I'm disabling all multicast entirely, I need to		  clear the multicast list		*/		SMC_SELECT_BANK( 3 );		outw( 0, ioaddr + MULTICAST1 );		outw( 0, ioaddr + MULTICAST2 );		outw( 0, ioaddr + MULTICAST3 );		outw( 0, ioaddr + MULTICAST4 );	}}#ifdef MODULEstatic char devicename[9] = { 0, };static struct device devSMC9194 = {	devicename, /* device name is inserted by linux/drivers/net/net_init.c */	0, 0, 0, 0,	0, 0,  /* I/O address, IRQ */	0, 0, 0, NULL, smc_init };int io = 0;int irq = 0;int ifport = 0;MODULE_PARM(io, "i");MODULE_PARM(irq, "i");MODULE_PARM(ifport, "i");int init_module(void){	int result;	if (io == 0)		printk(KERN_WARNING		CARDNAME": You shouldn't use auto-probing with insmod!\n" );	/* copy the parameters from insmod into the device structure */	devSMC9194.base_addr = io;	devSMC9194.irq       = irq;	devSMC9194.if_port	= ifport;	if ((result = register_netdev(&devSMC9194)) != 0)		return result;	return 0;}void cleanup_module(void){	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	unregister_netdev(&devSMC9194);	free_irq(devSMC9194.irq, &devSMC9194);	release_region(devSMC9194.base_addr, SMC_IO_EXTENT);	if (devSMC9194.priv)		kfree_s(devSMC9194.priv, sizeof(struct smc_local));}#endif /* MODULE */

⌨️ 快捷键说明

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