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

📄 smc9194.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	int i;	int remainder;	int lines;	printk("Packet of length %d \n", length );	lines = length / 16;	remainder = length % 16;	for ( i = 0; i < lines ; i ++ ) {		int cur;		for ( cur = 0; cur < 8; cur ++ ) {			byte a, b;			a = *(buf ++ );			b = *(buf ++ );			printk("%02x%02x ", a, b );		}		printk("\n");	}	for ( i = 0; i < remainder/2 ; i++ ) {		byte a, b;		a = *(buf ++ );		b = *(buf ++ );		printk("%02x%02x ", a, b );	}	printk("\n");#endif}#endif/* * Open and Initialize the board * * Set up everything, reset the card, etc .. * */static int smc_open(struct net_device *dev){	int	ioaddr = dev->base_addr;	int	i;	/* used to set hw ethernet address */	/* clear out all the junk that was put here before... */	memset(dev->priv, 0, sizeof(struct smc_local));	/* reset the hardware */	smc_reset( ioaddr );	smc_enable( ioaddr );	/* Select which interface to use */	SMC_SELECT_BANK( 1 );	if ( dev->if_port == 1 ) {		outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT,			ioaddr + CONFIG );	}	else if ( dev->if_port == 2 ) {		outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT,			ioaddr + CONFIG );	}	/*  		According to Becker, I have to set the hardware address		at this point, because the (l)user can set it with an		ioctl.  Easily done...	*/	SMC_SELECT_BANK( 1 );	for ( i = 0; i < 6; i += 2 ) {		word	address;		address = dev->dev_addr[ i + 1 ] << 8 ;		address  |= dev->dev_addr[ i ];		outw( address, ioaddr + ADDR0 + i );	}	netif_start_queue(dev);	return 0;}/*-------------------------------------------------------- . Called by the kernel to send a packet out into the void . of the net.  This routine is largely based on . skeleton.c, from Becker. .--------------------------------------------------------*/static void smc_timeout(struct net_device *dev){	/* If we get here, some higher level has decided we are broken.	   There should really be a "kick me" function call instead. */	printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n",		tx_done(dev) ? "IRQ conflict" :		"network cable problem");	/* "kick" the adaptor */	smc_reset( dev->base_addr );	smc_enable( dev->base_addr );	dev->trans_start = jiffies;	/* clear anything saved */	((struct smc_local *)dev->priv)->saved_skb = NULL;	netif_wake_queue(dev);}/*------------------------------------------------------------- . . 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){	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 )			dev->stats.multicast++;		skb = dev_alloc_skb( packet_length + 5);		if ( skb == NULL ) {			printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n");			dev->stats.rx_dropped++;			goto done;		}		/*		 ! This should work without alignment, but it could be		 ! in the worse case		*/		skb_reserve( skb, 2 );   /* 16 bit alignment */		data = skb_put( skb, packet_length);#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 ));		insw(ioaddr + DATA_1 , data, packet_length >> 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		skb->protocol = eth_type_trans(skb, dev );		netif_rx(skb);		dev->last_rx = jiffies;		dev->stats.rx_packets++;		dev->stats.rx_bytes += packet_length;	} else {		/* error ... */		dev->stats.rx_errors++;		if ( status & RS_ALGNERR )  dev->stats.rx_frame_errors++;		if ( status & (RS_TOOSHORT | RS_TOOLONG ) )			dev->stats.rx_length_errors++;		if ( status & RS_BADCRC)	dev->stats.rx_crc_errors++;	}done:	/*  error or good, tell the card to get rid of this packet */	outw( MC_RELEASE, ioaddr + MMU_CMD );}/************************************************************************* . 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 = netdev_priv(dev);	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 ));	dev->stats.tx_errors++;	if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++;	if ( tx_status & TS_LATCOL  ) {		printk(KERN_DEBUG CARDNAME			": Late collision occurred on last xmit.\n");		dev->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;}/*-------------------------------------------------------------------- . . This is the main routine of the driver, to handle the device when . it needs some attention. . . So: .   first, save state of the chipset .   branch off into routines to handle each case, and acknowledge .	    each to the interrupt register .   and finally restore state. . ---------------------------------------------------------------------*/static irqreturn_t smc_interrupt(int irq, void * dev_id){	struct net_device *dev 	= dev_id;	int ioaddr 		= dev->base_addr;	struct smc_local *lp = netdev_priv(dev);	byte	status;	word	card_stats;	byte	mask;	int	timeout;	/* state registers */	word	saved_bank;	word	saved_pointer;	int handled = 0;	PRINTK3((CARDNAME": SMC interrupt started \n"));	saved_bank = inw( ioaddr + BANK_SELECT );	SMC_SELECT_BANK(2);	saved_pointer = inw( ioaddr + POINTER );	mask = inb( ioaddr + INT_MASK );	/* clear all interrupts */	outb( 0, ioaddr + INT_MASK );	/* set a timeout value, so I don't stay here forever */	timeout = 4;	PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask ));	do {		/* read the status flag, and mask it */		status = inb( ioaddr + INTERRUPT ) & mask;		if (!status )			break;		handled = 1;		PRINTK3((KERN_WARNING CARDNAME			": Handling interrupt status %x \n", status ));		if (status & IM_RCV_INT) {			/* Got a packet(s). */			PRINTK2((KERN_WARNING CARDNAME				": Receive Interrupt\n"));			smc_rcv(dev);		} 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 */			dev->stats.collisions += card_stats & 0xF;			card_stats >>= 4;			/* multiple collisions */			dev->stats.collisions += card_stats & 0xF;			/* these are for when linux supports these statistics */			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;			dev->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 */			netif_wake_queue(dev);			PRINTK2((CARDNAME": Handoff done successfully.\n"));		} else if (status & IM_RX_OVRN_INT ) {			dev->stats.rx_errors++;			dev->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 );	PRINTK3((CARDNAME ": Interrupt done\n"));	return IRQ_RETVAL(handled);}/*---------------------------------------------------- . 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);	/* clear everything */	smc_shutdown( dev->base_addr );	/* Update the statistics here. */	return 0;}/*----------------------------------------------------------- . 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){	short ioaddr = dev->base_addr;	SMC_SELECT_BANK(0);	if ( dev->flags & IFF_PROMISC )		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	*/	else if (dev->flags & IFF_ALLMULTI)		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. */	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 );	}	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 struct net_device *devSMC9194;MODULE_LICENSE("GPL");module_param(io, int, 0);module_param(irq, int, 0);module_param(ifport, int, 0);MODULE_PARM_DESC(io, "SMC 99194 I/O base address");MODULE_PARM_DESC(irq, "SMC 99194 IRQ number");MODULE_PARM_DESC(ifport, "SMC 99194 interface port (0-default, 1-TP, 2-AUI)");int __init init_module(void){	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 = smc_init(-1);	if (IS_ERR(devSMC9194))		return PTR_ERR(devSMC9194);	return 0;}void __exit cleanup_module(void){	unregister_netdev(devSMC9194);	free_irq(devSMC9194->irq, devSMC9194);	release_region(devSMC9194->base_addr, SMC_IO_EXTENT);	free_netdev(devSMC9194);}#endif /* MODULE */

⌨️ 快捷键说明

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