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

📄 3c501.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	{		int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);		unsigned char *buf = skb->data;		lp->tx_pkt_start = gp_start;    		lp->collisions = 0;    		lp->stats.tx_bytes += skb->len;		/*		 *	Command mode with status cleared should [in theory]		 *	mean no more interrupts can be pending on the card.		 */		outb_p(AX_SYS, AX_CMD);		inb_p(RX_STATUS);		inb_p(TX_STATUS);		lp->loading = 1;		lp->txing = 1;		/*		 *	Turn interrupts back on while we spend a pleasant afternoon		 *	loading bytes into the board		 */		spin_unlock_irqrestore(&lp->lock, flags);				outw(0x00, RX_BUF_CLR);		/* Set rx packet area to 0. */		outw(gp_start, GP_LOW);		/* aim - packet will be loaded into buffer start */		outsb(DATAPORT,buf,skb->len);	/* load buffer (usual thing each byte increments the pointer) */		outw(gp_start, GP_LOW);		/* the board reuses the same register */			if(lp->loading != 2)		{			outb(AX_XMIT, AX_CMD);		/* fire ... Trigger xmit.  */			lp->loading=0;			dev->trans_start = jiffies;			if (el_debug > 2)				printk(" queued xmit.\n");			dev_kfree_skb (skb);			return 0;		}		/* A receive upset our load, despite our best efforts */		if(el_debug>2)			printk("%s: burped during tx load.\n", dev->name);		spin_lock_irqsave(&lp->lock, flags);	}	while(1);}/** * el_interrupt: * @irq: Interrupt number * @dev_id: The 3c501 that burped * @regs: Register data (surplus to our requirements) * * Handle the ether interface interrupts. The 3c501 needs a lot more  * hand holding than most cards. In paticular we get a transmit interrupt * with a collision error because the board firmware isnt capable of rewinding * its own transmit buffer pointers. It can however count to 16 for us. * * On the receive side the card is also very dumb. It has no buffering to * speak of. We simply pull the packet out of its PIO buffer (which is slow) * and queue it for the kernel. Then we reset the card for the next packet. * * We sometimes get suprise interrupts late both because the SMP IRQ delivery * is message passing and because the card sometimes seems to deliver late. I * think if it is part way through a receive and the mode is changed it carries * on receiving and sends us an interrupt. We have to band aid all these cases * to get a sensible 150kbytes/second performance. Even then you want a small * TCP window. */static void el_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct net_local *lp;	int ioaddr;	int axsr;			/* Aux. status reg. */	ioaddr = dev->base_addr;	lp = (struct net_local *)dev->priv;	spin_lock(&lp->lock);		/*	 *	What happened ?	 */	axsr = inb(AX_STATUS);	/*	 *	Log it	 */	if (el_debug > 3)		printk(KERN_DEBUG "%s: el_interrupt() aux=%#02x", dev->name, axsr);        if(lp->loading==1 && !lp->txing)        	printk(KERN_WARNING "%s: Inconsistent state loading while not in tx\n",        		dev->name);	if (lp->txing)	{    		/*    		 *	Board in transmit mode. May be loading. If we are    		 *	loading we shouldn't have got this.    		 */		int txsr = inb(TX_STATUS);		if(lp->loading==1)		{			if(el_debug > 2)			{				printk(KERN_DEBUG "%s: Interrupt while loading [", dev->name);				printk(" txsr=%02x gp=%04x rp=%04x]\n", txsr, inw(GP_LOW),inw(RX_LOW));			}			lp->loading=2;		/* Force a reload */			spin_unlock(&lp->lock);			return;		}		if (el_debug > 6)			printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW),inw(RX_LOW));		if ((axsr & 0x80) && (txsr & TX_READY) == 0)		{			/*			 *	FIXME: is there a logic to whether to keep on trying or			 *	reset immediately ?			 */			if(el_debug>1)				printk("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x"			  		" gp=%03x rp=%03x.\n", dev->name, txsr, axsr,			inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR));			lp->txing = 0;			netif_wake_queue(dev);		}		else if (txsr & TX_16COLLISIONS)		{			/*			 *	Timed out			 */			if (el_debug)				printk("%s: Transmit failed 16 times, Ethernet jammed?\n",dev->name);			outb(AX_SYS, AX_CMD);			lp->txing = 0;			lp->stats.tx_aborted_errors++;			netif_wake_queue(dev);		}		else if (txsr & TX_COLLISION)		{			/*			 *	Retrigger xmit.			 */			if (el_debug > 6)				printk(" retransmitting after a collision.\n");			/*			 *	Poor little chip can't reset its own start pointer			 */			outb(AX_SYS, AX_CMD);			outw(lp->tx_pkt_start, GP_LOW);			outb(AX_XMIT, AX_CMD);			lp->stats.collisions++;			spin_unlock(&lp->lock);			return;		}		else		{			/*			 *	It worked.. we will now fall through and receive			 */			lp->stats.tx_packets++;			if (el_debug > 6)				printk(" Tx succeeded %s\n",		       			(txsr & TX_RDY) ? "." : "but tx is busy!");			/*			 *	This is safe the interrupt is atomic WRT itself.			 */			lp->txing = 0;			netif_wake_queue(dev);	/* In case more to transmit */		}	}	else	{    		/*    		 *	In receive mode.    		 */		int rxsr = inb(RX_STATUS);		if (el_debug > 5)			printk(" rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS),inw(RX_LOW));		/*		 *	Just reading rx_status fixes most errors.		 */		if (rxsr & RX_MISSED)			lp->stats.rx_missed_errors++;		else if (rxsr & RX_RUNT)		{	/* Handled to avoid board lock-up. */			lp->stats.rx_length_errors++;			if (el_debug > 5)				printk(" runt.\n");		}		else if (rxsr & RX_GOOD)		{			/*			 *	Receive worked.			 */			el_receive(dev);		}		else		{			/*			 *	Nothing?  Something is broken!			 */			if (el_debug > 2)				printk("%s: No packet seen, rxsr=%02x **resetting 3c501***\n",					dev->name, rxsr);			el_reset(dev);		}		if (el_debug > 3)			printk(".\n");	}	/*	 *	Move into receive mode	 */	outb(AX_RX, AX_CMD);	outw(0x00, RX_BUF_CLR);	inb(RX_STATUS);		/* Be certain that interrupts are cleared. */	inb(TX_STATUS);	spin_unlock(&lp->lock);	return;}/** * el_receive: * @dev: Device to pull the packets from * * We have a good packet. Well, not really "good", just mostly not broken. * We must check everything to see if it is good. In paticular we occasionally * get wild packet sizes from the card. If the packet seems sane we PIO it * off the card and queue it for the protocol layers. */static void el_receive(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	int ioaddr = dev->base_addr;	int pkt_len;	struct sk_buff *skb;	pkt_len = inw(RX_LOW);	if (el_debug > 4)		printk(" el_receive %d.\n", pkt_len);	if ((pkt_len < 60)  ||  (pkt_len > 1536))	{		if (el_debug)			printk("%s: bogus packet, length=%d\n", dev->name, pkt_len);		lp->stats.rx_over_errors++;		return;	}	/*	 *	Command mode so we can empty the buffer	 */	outb(AX_SYS, AX_CMD);	skb = dev_alloc_skb(pkt_len+2);	/*	 *	Start of frame	 */	outw(0x00, GP_LOW);	if (skb == NULL)	{		printk("%s: Memory squeeze, dropping packet.\n", dev->name);		lp->stats.rx_dropped++;		return;	}	else	{    		skb_reserve(skb,2);	/* Force 16 byte alignment */		skb->dev = dev;		/*		 *	The read increments through the bytes. The interrupt		 *	handler will fix the pointer when it returns to		 *	receive mode.		 */		insb(DATAPORT, skb_put(skb,pkt_len), pkt_len);		skb->protocol=eth_type_trans(skb,dev);		netif_rx(skb);		lp->stats.rx_packets++;		lp->stats.rx_bytes+=pkt_len;	}	return;}/** * el_reset: Reset a 3c501 card * @dev: The 3c501 card about to get zapped * * Even resetting a 3c501 isnt simple. When you activate reset it loses all * its configuration. You must hold the lock when doing this. The function * cannot take the lock itself as it is callable from the irq handler. */static void  el_reset(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	int ioaddr = dev->base_addr;	if (el_debug> 2)		printk("3c501 reset...");	outb(AX_RESET, AX_CMD);		/* Reset the chip */	outb(AX_LOOP, AX_CMD);		/* Aux control, irq and loopback enabled */	{		int i;		for (i = 0; i < 6; i++)	/* Set the station address. */			outb(dev->dev_addr[i], ioaddr + i);	}	outw(0, RX_BUF_CLR);		/* Set rx packet area to 0. */	outb(TX_NORM, TX_CMD);		/* tx irq on done, collision */	outb(RX_NORM, RX_CMD);		/* Set Rx commands. */	inb(RX_STATUS);			/* Clear status. */	inb(TX_STATUS);	lp->txing = 0;}/** * el1_close: * @dev: 3c501 card to shut down * * Close a 3c501 card. The IFF_UP flag has been cleared by the user via * the SIOCSIFFLAGS ioctl. We stop any further transmissions being queued, * and then disable the interrupts. Finally we reset the chip. The effects * of the rest will be cleaned up by #el1_open. Always returns 0 indicating * a success. */ static int el1_close(struct net_device *dev){	int ioaddr = dev->base_addr;	if (el_debug > 2)		printk("%s: Shutting down Ethernet card at %#x.\n", dev->name, ioaddr);	netif_stop_queue(dev);		/*	 *	Free and disable the IRQ.	 */	free_irq(dev->irq, dev);	outb(AX_RESET, AX_CMD);		/* Reset the chip */	return 0;}/** * el1_get_stats: * @dev: The card to get the statistics for * * In smarter devices this function is needed to pull statistics off the * board itself. The 3c501 has no hardware statistics. We maintain them all * so they are by definition always up to date. * * Returns the statistics for the card from the card private data */ static struct net_device_stats *el1_get_stats(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	return &lp->stats;}/** * set_multicast_list: * @dev: The device to adjust * * Set or clear the multicast filter for this adaptor to use the best-effort  * filtering supported. The 3c501 supports only three modes of filtering. * It always receives broadcasts and packets for itself. You can choose to * optionally receive all packets, or all multicast packets on top of this. */static void set_multicast_list(struct net_device *dev){	int ioaddr = dev->base_addr;	if(dev->flags&IFF_PROMISC)	{		outb(RX_PROM, RX_CMD);		inb(RX_STATUS);	}	else if (dev->mc_list || dev->flags&IFF_ALLMULTI)	{		outb(RX_MULT, RX_CMD);	/* Multicast or all multicast is the same */		inb(RX_STATUS);		/* Clear status. */	}	else	{		outb(RX_NORM, RX_CMD);		inb(RX_STATUS);	}}#ifdef MODULEstatic struct net_device dev_3c501 = {	init:		el1_probe,	base_addr:	0x280,	irq:		5,};static int io=0x280;static int irq=5;MODULE_PARM(io, "i");MODULE_PARM(irq, "i");/** * init_module: * * When the driver is loaded as a module this function is called. We fake up * a device structure with the base I/O and interrupt set as if it was being * called from Space.c. This minimises the extra code that would otherwise * be required. * * Returns 0 for success or -EIO if a card is not found. Returning an error * here also causes the module to be unloaded */ int init_module(void){	dev_3c501.irq=irq;	dev_3c501.base_addr=io;	if (register_netdev(&dev_3c501) != 0)		return -EIO;	return 0;}/** * cleanup_module: *  * The module is being unloaded. We unhook our network device from the system * and then free up the resources we took when the card was found. */ void cleanup_module(void){	/*	 *	No need to check MOD_IN_USE, as sys_delete_module() checks.	 */	unregister_netdev(&dev_3c501);	/*	 *	Free up the private structure, or leak memory :-)	 */	kfree(dev_3c501.priv);	dev_3c501.priv = NULL;	/* gets re-allocated by el1_probe1 */	/*	 *	If we don't do this, we can't re-insmod it later.	 */	release_region(dev_3c501.base_addr, EL1_IO_EXTENT);}#endif /* MODULE *//* * Local variables: *  compile-command: "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer  -m486 -c -o 3c501.o 3c501.c" *  kept-new-versions: 5 * End: */

⌨️ 快捷键说明

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