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

📄 3c509.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* Transmitter timeout, serious problems. */	if (dev->tbusy) {		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < 10)			return 1;		printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",			   dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS));		dev->trans_start = jiffies;		/* Issue TX_RESET and TX_START commands. */		outw(0x5800, ioaddr + EL3_CMD); /* TX_RESET */		outw(0x4800, ioaddr + EL3_CMD); /* TX_START */		dev->tbusy = 0;	}	if (skb == NULL) {		dev_tint(dev);		return 0;	}	/* Fill in the ethernet header. */	if (!skb->arp  &&  dev->rebuild_header(skb->data, dev)) {		skb->dev = dev;		arp_queue (skb);		return 0;	}	skb->arp=1;	if (skb->len <= 0)		return 0;	if (el3_debug > 4) {		printk("%s: el3_start_xmit(lenght = %ld) called, status %4.4x.\n",			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));	}#ifndef final_version	{	/* Error-checking code, delete for 1.00. */		ushort status = inw(ioaddr + EL3_STATUS);		if (status & 0x0001 		/* IRQ line active, missed one. */			&& inw(ioaddr + EL3_STATUS) & 1) { 			/* Make sure. */			printk("%s: Missed interrupt, status then %04x now %04x"				   "  Tx %2.2x Rx %4.4x.\n", dev->name, status,				   inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),				   inw(ioaddr + RX_STATUS));			outw(0x7800, ioaddr + EL3_CMD); /* Fake interrupt trigger. */			outw(0x6899, ioaddr + EL3_CMD); /* Ack IRQ */			outw(0x78ff, ioaddr + EL3_CMD); /* Set all status bits visible. */		}	}#endif	/* Avoid timer-based retransmission conflicts. */	if (set_bit(0, (void*)&dev->tbusy) != 0)		printk("%s: Transmitter access conflict.\n", dev->name);	else {		/* Put out the doubleword header... */		outw(skb->len, ioaddr + TX_FIFO);		outw(0x00, ioaddr + TX_FIFO);		/* ... and the packet rounded to a doubleword. */		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);			dev->trans_start = jiffies;		if (inw(ioaddr + TX_FREE) > 1536) {			dev->tbusy=0;		} else			/* Interrupt us when the FIFO has room for max-sized packet. */			outw(0x9000 + 1536, ioaddr + EL3_CMD);	}	if (skb->free)		kfree_skb (skb, FREE_WRITE);	/* Clear the Tx status stack. */	{		short tx_status;		int i = 4;		while (--i > 0	&&	(tx_status = inb(ioaddr + TX_STATUS)) > 0) {			if (el3_debug > 5)				printk("		Tx status %4.4x.\n", tx_status);			if (tx_status & 0x38) lp->stats.tx_aborted_errors++;			if (tx_status & 0x30) outw(0x5800, ioaddr + EL3_CMD);			if (tx_status & 0x3C) outw(0x4800, ioaddr + EL3_CMD);			outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */		}	}	return 0;}/* The EL3 interrupt handler. */static voidel3_interrupt(int reg_ptr){	int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);	struct device *dev = (struct device *)(irq2dev_map[irq]);	int ioaddr, status;	int i = 0;	if (dev == NULL) {		printk ("el3_interrupt(): irq %d for unknown device.\n", irq);		return;	}	if (dev->interrupt)		printk("%s: Re-entering the interrupt handler.\n", dev->name);	dev->interrupt = 1;	ioaddr = dev->base_addr;	status = inw(ioaddr + EL3_STATUS);	if (el3_debug > 4)		printk("%s: interrupt, status %4.4x.\n", dev->name, status);		while ((status = inw(ioaddr + EL3_STATUS)) & 0x01) {		if (status & 0x10)			el3_rx(dev);		if (status & 0x08) {			if (el3_debug > 5)				printk("	TX room bit was handled.\n");			/* There's room in the FIFO for a full-sized packet. */			outw(0x6808, ioaddr + EL3_CMD); /* Ack IRQ */			dev->tbusy = 0;			mark_bh(INET_BH);		}		if (status & 0x80)				/* Statistics full. */			update_stats(ioaddr, dev);				if (++i > 10) {			printk("%s: Infinite loop in interrupt, status %4.4x.\n",				   dev->name, status);			/* Clear all interrupts we have handled. */			outw(0x68FF, ioaddr + EL3_CMD);			break;		}		/* Acknowledge the IRQ. */		outw(0x6891, ioaddr + EL3_CMD); /* Ack IRQ */	}	if (el3_debug > 4) {		printk("%s: exiting interrupt, status %4.4x.\n", dev->name,			   inw(ioaddr + EL3_STATUS));	}		dev->interrupt = 0;	return;}static struct enet_statistics *el3_get_stats(struct device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	sti();	update_stats(dev->base_addr, dev);	cli();	return &lp->stats;}/*  Update statistics.  We change to register window 6, so this should be run	single-threaded if the device is active. This is expected to be a rare	operation, and it's simpler for the rest of the driver to assume that	window 1 is always valid rather than use a special window-state variable.	*/static void update_stats(int ioaddr, struct device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	if (el3_debug > 5)		printk("   Updating the statistics.\n");	/* Turn off statistics updates while reading. */	outw(0xB000, ioaddr + EL3_CMD);	/* Switch to the stats window, and read everything. */	EL3WINDOW(6);	lp->stats.tx_carrier_errors 	+= inb(ioaddr + 0);	lp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);	/* Multiple collisions. */	   	inb(ioaddr + 2);	lp->stats.collisions			+= inb(ioaddr + 3);	lp->stats.tx_window_errors		+= inb(ioaddr + 4);	lp->stats.rx_fifo_errors		+= inb(ioaddr + 5);	lp->stats.tx_packets			+= inb(ioaddr + 6);	lp->stats.rx_packets			+= inb(ioaddr + 7);	/* Tx deferrals */				inb(ioaddr + 8);	inw(ioaddr + 10);	/* Total Rx and Tx octets. */	inw(ioaddr + 12);	/* Back to window 1, and turn statistics back on. */	EL3WINDOW(1);	outw(0xA800, ioaddr + EL3_CMD);	return;}static intel3_rx(struct device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	int ioaddr = dev->base_addr;	short rx_status;	if (el3_debug > 5)		printk("	   In rx_packet(), status %4.4x, rx_status %4.4x.\n",			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));	while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) {		if (rx_status & 0x4000) { /* Error, update stats. */			short error = rx_status & 0x3800;			lp->stats.rx_errors++;			switch (error) {			case 0x0000:		lp->stats.rx_over_errors++; break;			case 0x0800:		lp->stats.rx_length_errors++; break;			case 0x1000:		lp->stats.rx_frame_errors++; break;			case 0x1800:		lp->stats.rx_length_errors++; break;			case 0x2000:		lp->stats.rx_frame_errors++; break;			case 0x2800:		lp->stats.rx_crc_errors++; break;			}		}		if ( (! (rx_status & 0x4000))			|| ! (rx_status & 0x1000)) { /* Dribble bits are OK. */			short pkt_len = rx_status & 0x7ff;			int sksize = sizeof(struct sk_buff) + pkt_len + 3;			struct sk_buff *skb;			skb = alloc_skb(sksize, GFP_ATOMIC);			if (el3_debug > 4)				printk("	   Receiving packet size %d status %4.4x.\n",					   pkt_len, rx_status);			if (skb != NULL) {				skb->mem_len = sksize;				skb->mem_addr = skb;				skb->len = pkt_len;				skb->dev = dev;				/* 'skb->data' points to the start of sk_buff data area. */				insl(ioaddr+RX_FIFO, skb->data,							(pkt_len + 3) >> 2);#ifdef HAVE_NETIF_RX				netif_rx(skb);				outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */				continue;#else				skb->lock = 0;				if (dev_rint((unsigned char *)skb, pkt_len,							 IN_SKBUFF,dev)== 0){					if (el3_debug > 6)						printk("	 dev_rint() happy, status %4.4x.\n",						inb(ioaddr + EL3_STATUS));					outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */					while (inw(ioaddr + EL3_STATUS) & 0x1000)					  printk("	Waiting for 3c509 to discard packet, status %x.\n",							 inw(ioaddr + EL3_STATUS) );					if (el3_debug > 6)						printk("	 discarded packet, status %4.4x.\n",						inb(ioaddr + EL3_STATUS));					continue;				} else {					printk("%s: receive buffers full.\n", dev->name);					kfree_s(skb, sksize);				}#endif			} else if (el3_debug)				printk("%s: Couldn't allocate a sk_buff of size %d.\n",					   dev->name, sksize);		}		lp->stats.rx_dropped++;		outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */		while (inw(ioaddr + EL3_STATUS) & 0x1000)		  printk("	Waiting for 3c509 to discard packet, status %x.\n",				 inw(ioaddr + EL3_STATUS) );	}	if (el3_debug > 5)		printk("	   Exiting rx_packet(), status %4.4x, rx_status %4.4x.\n",			   inw(ioaddr+EL3_STATUS), inw(ioaddr+8));	return 0;}#ifdef HAVE_MULTICAST/* Set or clear the multicast filter for this adaptor.   num_addrs == -1		Promiscuous mode, receive all packets   num_addrs == 0		Normal mode, clear multicast list   num_addrs > 0		Multicast mode, receive normal and MC packets, and do						best-effort filtering. */static voidset_multicast_list(struct device *dev, int num_addrs, void *addrs){	short ioaddr = dev->base_addr;	if (num_addrs > 0) {		outw(0x8007, ioaddr + EL3_CMD);	} else if (num_addrs < 0) {		outw(0x8008, ioaddr + EL3_CMD);	} else		outw(0x8005, ioaddr + EL3_CMD);}#endifstatic intel3_close(struct device *dev){	int ioaddr = dev->base_addr;	if (el3_debug > 2)		printk("%s: Shutting down ethercard.\n", dev->name);	dev->tbusy = 1;	dev->start = 0;	/* Turn off statistics.	 We update lp->stats below. */	outw(0xB000, ioaddr + EL3_CMD);	/* Disable the receiver and transmitter. */	outw(0x1800, ioaddr + EL3_CMD);	outw(0x5000, ioaddr + EL3_CMD);	if (dev->if_port == 3)		/* Turn off thinnet power. */		outw(0xb800, ioaddr + EL3_CMD);	else if (dev->if_port == 0) {		/* Disable link beat and jabber, if_port may change ere next open(). */		EL3WINDOW(4);		outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);	}	free_irq(dev->irq);	/* Switching back to window 0 disables the IRQ. */	EL3WINDOW(0);	/* But we explicitly zero the IRQ line select anyway. */	outw(0x0f00, ioaddr + 8);	irq2dev_map[dev->irq] = 0;	update_stats(ioaddr, dev);	return 0;}/* * Local variables: *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c509.c" *  version-control: t *  kept-new-versions: 5 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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