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

📄 epic100.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
#ifndef final_version					if (epic_debug > 1)						printk("%s: Transmit error, Tx status %8.8x.\n",							   dev->name, txstatus);#endif					ep->stats.tx_errors++;					if (txstatus & 0x1050) ep->stats.tx_aborted_errors++;					if (txstatus & 0x0008) ep->stats.tx_carrier_errors++;					if (txstatus & 0x0040) ep->stats.tx_window_errors++;					if (txstatus & 0x0010) ep->stats.tx_fifo_errors++;#ifdef ETHER_STATS					if (txstatus & 0x1000) ep->stats.collisions16++;#endif				} else {#ifdef ETHER_STATS					if ((txstatus & 0x0002) != 0) ep->stats.tx_deferred++;#endif					ep->stats.collisions += (txstatus >> 8) & 15;					ep->stats.tx_packets++;				}				/* Free the original skb. */				DEV_FREE_SKB(ep->tx_skbuff[entry]);				ep->tx_skbuff[entry] = 0;			}#ifndef final_version			if (ep->cur_tx - dirty_tx > TX_RING_SIZE) {				printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",					   dev->name, dirty_tx, ep->cur_tx, ep->tx_full);				dirty_tx += TX_RING_SIZE;			}#endif			if (ep->tx_full && dev->tbusy				&& dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) {				/* The ring is no longer full, clear tbusy. */				ep->tx_full = 0;				clear_bit(0, (void*)&dev->tbusy);				mark_bh(NET_BH);			}			ep->dirty_tx = dirty_tx;		}		/* Check uncommon events all at once. */		if (status & (CntFull | TxUnderrun | RxOverflow |					  PCIBusErr170 | PCIBusErr175)) {			if (status == 0xffffffff) /* Chip failed or removed (CardBus). */				break;			/* Always update the error counts to avoid overhead later. */			ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);			ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);			ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);			if (status & TxUnderrun) { /* Tx FIFO underflow. */				ep->stats.tx_fifo_errors++;				outl(1536, ioaddr + TxThresh);				/* Restart the transmit process. */				outl(0x0080, ioaddr + COMMAND);			}			if (status & RxOverflow) {		/* Missed a Rx frame. */				ep->stats.rx_errors++;			}			if (status & PCIBusErr170) {				printk(KERN_ERR "%s: PCI Bus Error!  EPIC status %4.4x.\n",					   dev->name, status);				epic_pause(dev);				epic_restart(dev);			}			/* Clear all error sources. */			outl(status & 0x7f18, ioaddr + INTSTAT);		}		if (--boguscnt < 0) {			printk(KERN_ERR "%s: Too much work at interrupt, "				   "IntrStatus=0x%8.8x.\n",				   dev->name, status);			/* Clear all interrupt sources. */			outl(0x0001ffff, ioaddr + INTSTAT);			break;		}	} while (1);	if (epic_debug > 3)		printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n",			   dev->name, inl(ioaddr + INTSTAT));#if defined(__i386__)	clear_bit(0, (void*)&dev->interrupt);#else	dev->interrupt = 0;#endif	return;}static int epic_rx(struct device *dev){	struct epic_private *ep = (struct epic_private *)dev->priv;	int entry = ep->cur_rx % RX_RING_SIZE;	int work_done = 0;	if (epic_debug > 4)		printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry,			   ep->rx_ring[entry].status);	/* If we own the next entry, it's a new packet. Send it up. */	while (ep->rx_ring[entry].status >= 0  &&  ep->rx_skbuff[entry]) {		int status = ep->rx_ring[entry].status;		if (epic_debug > 4)			printk(KERN_DEBUG "  epic_rx() status was %8.8x.\n", status);		if (status & 0x2006) {			if (status & 0x2000) {				printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "					   "multiple buffers, status %4.4x!\n", dev->name, status);				ep->stats.rx_length_errors++;			} else if (status & 0x0006)				/* Rx Frame errors are counted in hardware. */				ep->stats.rx_errors++;		} else {			/* Malloc up new buffer, compatible with net-2e. */			/* Omit the four octet CRC from the length. */			short pkt_len = ep->rx_ring[entry].rxlength - 4;			struct sk_buff *skb;			/* Check if the packet is long enough to accept without copying			   to a minimally-sized skbuff. */			if (pkt_len < rx_copybreak				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {				skb->dev = dev;				skb_reserve(skb, 2);	/* 16 byte align the IP header */#if 1 /* USE_IP_COPYSUM */				eth_copy_and_sum(skb, bus_to_virt(ep->rx_ring[entry].bufaddr),								 pkt_len, 0);				skb_put(skb, pkt_len);#else				memcpy(skb_put(skb, pkt_len),					   bus_to_virt(ep->rx_ring[entry].bufaddr), pkt_len);#endif			} else {				skb_put(skb = ep->rx_skbuff[entry], pkt_len);				ep->rx_skbuff[entry] = NULL;			}			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);			ep->stats.rx_packets++;			/* rx_bytes counting -- Nolan Leake */			ep->stats.rx_bytes += pkt_len;		}		work_done++;		entry = (++ep->cur_rx) % RX_RING_SIZE;	}	/* Refill the Rx ring buffers. */	for (; ep->cur_rx - ep->dirty_rx > 0; ep->dirty_rx++) {		entry = ep->dirty_rx % RX_RING_SIZE;		if (ep->rx_skbuff[entry] == NULL) {			struct sk_buff *skb;			skb = ep->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);			if (skb == NULL)				break;			skb->dev = dev;			/* Mark as being used by this device. */			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */			ep->rx_ring[entry].bufaddr = virt_to_bus(skb->tail);			work_done++;		}		ep->rx_ring[entry].status = 0x8000;	}	return work_done;}static int epic_close(struct device *dev){	long ioaddr = dev->base_addr;	struct epic_private *ep = (struct epic_private *)dev->priv;	int i;	dev->start = 0;	dev->tbusy = 1;	if (epic_debug > 1)		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",			   dev->name, inl(ioaddr + INTSTAT));	/* Disable interrupts by clearing the interrupt mask. */	outl(0x00000000, ioaddr + INTMASK);	/* Stop the chip's Tx and Rx DMA processes. */	outw(0x0061, ioaddr + COMMAND);	/* Update the error counts. */	ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);	ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);	ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);	del_timer(&ep->timer);	free_irq(dev->irq, dev);	/* Free all the skbuffs in the Rx queue. */	for (i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb = ep->rx_skbuff[i];		ep->rx_skbuff[i] = 0;		ep->rx_ring[i].status = 0;		/* Not owned by Epic chip. */		ep->rx_ring[i].buflength = 0;		ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */		if (skb) {#if LINUX_VERSION_CODE < 0x20100			skb->free = 1;#endif			DEV_FREE_SKB(skb);		}	}	for (i = 0; i < TX_RING_SIZE; i++) {		if (ep->tx_skbuff[i])			DEV_FREE_SKB(ep->tx_skbuff[i]);		ep->tx_skbuff[i] = 0;	}	/* Green! Leave the chip in low-power mode. */	outl(0x0008, ioaddr + GENCTL);	MOD_DEC_USE_COUNT;	return 0;}static struct net_device_stats *epic_get_stats(struct device *dev){	struct epic_private *ep = (struct epic_private *)dev->priv;	long ioaddr = dev->base_addr;	if (dev->start) {		/* Update the error counts. */		ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);		ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);		ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);	}	return &ep->stats;}/* Set or clear the multicast filter for this adaptor.   Note that we only use exclusion around actually queueing the   new frame, not around filling ep->setup_frame.  This is non-deterministic   when re-entered but still correct. *//* The little-endian AUTODIN II ethernet CRC calculation.   N.B. Do not use for bulk data, use a table-based routine instead.   This is common code and should be moved to net/core/crc.c */static unsigned const ethernet_polynomial_le = 0xedb88320U;static inline unsigned ether_crc_le(int length, unsigned char *data){	unsigned int crc = 0xffffffff;	/* Initial value. */	while(--length >= 0) {		unsigned char current_octet = *data++;		int bit;		for (bit = 8; --bit >= 0; current_octet >>= 1) {			if ((crc ^ current_octet) & 1) {				crc >>= 1;				crc ^= ethernet_polynomial_le;			} else				crc >>= 1;		}	}	return crc;}static void set_rx_mode(struct device *dev){	long ioaddr = dev->base_addr;	struct epic_private *ep = (struct epic_private *)dev->priv;	unsigned char mc_filter[8];		 /* Multicast hash filter */	int i;	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		outl(0x002C, ioaddr + RxCtrl);		/* Unconditionally log net taps. */		printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);		memset(mc_filter, 0xff, sizeof(mc_filter));	} else if ((dev->mc_count > 0)  ||  (dev->flags & IFF_ALLMULTI)) {		/* There is apparently a chip bug, so the multicast filter		   is never enabled. */		/* Too many to filter perfectly -- accept all multicasts. */		memset(mc_filter, 0xff, sizeof(mc_filter));		outl(0x000C, ioaddr + RxCtrl);	} else if (dev->mc_count == 0) {		outl(0x0004, ioaddr + RxCtrl);		return;	} else {					/* Never executed, for now. */		struct dev_mc_list *mclist;		memset(mc_filter, 0, sizeof(mc_filter));		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;			 i++, mclist = mclist->next)			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,					mc_filter);	}	/* ToDo: perhaps we need to stop the Tx and Rx process here? */	if (memcmp(mc_filter, ep->mc_filter, sizeof(mc_filter))) {		for (i = 0; i < 4; i++)			outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4);		memcpy(ep->mc_filter, mc_filter, sizeof(mc_filter));	}	return;}static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd){	long ioaddr = dev->base_addr;	u16 *data = (u16 *)&rq->ifr_data;	switch(cmd) {	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */		data[0] = ((struct epic_private *)dev->priv)->phys[0] & 0x1f;		/* Fall Through */	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */		if (! dev->start) {			outl(0x0200, ioaddr + GENCTL);			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);		}		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);		if (! dev->start) {#ifdef notdef			outl(0x0008, ioaddr + GENCTL);			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);#endif		}		return 0;	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */		if (!suser())			return -EPERM;		if (! dev->start) {			outl(0x0200, ioaddr + GENCTL);			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);		}		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);		if (! dev->start) {#ifdef notdef			outl(0x0008, ioaddr + GENCTL);			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);#endif		}		return 0;	default:		return -EOPNOTSUPP;	}}#ifdef CARDBUS#include <pcmcia/driver_ops.h>static dev_node_t *epic_attach(dev_locator_t *loc){	struct device *dev;	u16 dev_id;	u32 io;	u8 bus, devfn, irq;	if (loc->bus != LOC_PCI) return NULL;	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;	printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n", bus, devfn);	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);	io &= ~3;	if (io == 0 || irq == 0) {		printk(KERN_ERR "The EPIC/C CardBus Ethernet interface was not "			   "assigned an %s.\n" KERN_ERR "  It will not be activated.\n",			   io == 0 ? "I/O address" : "IRQ");		return NULL;	}	dev = epic_probe1(bus, devfn, NULL, io, irq, 2, -1);	if (dev) {		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);		strcpy(node->dev_name, dev->name);		node->major = node->minor = 0;		node->next = NULL;		MOD_INC_USE_COUNT;		return node;	}	return NULL;}static void epic_suspend(dev_node_t *node){	struct device **devp, **next;	printk(KERN_INFO "epic_suspend(%s)\n", node->dev_name);	for (devp = &root_epic_dev; *devp; devp = next) {		next = &((struct epic_private *)(*devp)->priv)->next_module;		if (strcmp((*devp)->name, node->dev_name) == 0) break;	}	if (*devp) {		long ioaddr = (*devp)->base_addr;		epic_pause(*devp);		/* Put the chip into low-power mode. */		outl(0x0008, ioaddr + GENCTL);	}}static void epic_resume(dev_node_t *node){	struct device **devp, **next;	printk(KERN_INFO "epic_resume(%s)\n", node->dev_name);	for (devp = &root_epic_dev; *devp; devp = next) {		next = &((struct epic_private *)(*devp)->priv)->next_module;		if (strcmp((*devp)->name, node->dev_name) == 0) break;	}	if (*devp) {		epic_restart(*devp);	}}static void epic_detach(dev_node_t *node){	struct device **devp, **next;	printk(KERN_INFO "epic_detach(%s)\n", node->dev_name);	for (devp = &root_epic_dev; *devp; devp = next) {		next = &((struct epic_private *)(*devp)->priv)->next_module;		if (strcmp((*devp)->name, node->dev_name) == 0) break;	}	if (*devp) {		unregister_netdev(*devp);		kfree(*devp);		*devp = *next;		kfree(node);		MOD_DEC_USE_COUNT;	}}struct driver_operations epic_ops = {	"epic_cb", epic_attach, epic_suspend, epic_resume, epic_detach};#endif  /* Cardbus support */#ifdef MODULEint init_module(void){	if (epic_debug)		printk(KERN_INFO "%s", version);#ifdef CARDBUS	register_driver(&epic_ops);	return 0;#else	return epic100_probe(0);#endif}void cleanup_module(void){	struct device *next_dev;#ifdef CARDBUS	unregister_driver(&epic_ops);#endif	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	while (root_epic_dev) {		struct epic_private *ep = (struct epic_private *)root_epic_dev->priv;		next_dev = ep->next_module;		unregister_netdev(root_epic_dev);		release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE);		kfree(root_epic_dev);		root_epic_dev = next_dev;		kfree(ep);	}}#endif  /* MODULE *//* * Local variables: *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c -o epic_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/" *  c-indent-level: 4 *  c-basic-offset: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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