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

📄 rtl8139.c

📁 44b0uclinux下的8319网卡芯片驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
			tp->stats.rx_errors++;			if (rx_status & (RxBadSymbol|RxBadAlign))				tp->stats.rx_frame_errors++;			if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++;			if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++;			/* Reset the receiver, based on RealTek recommendation. (Bug?) */			tp->cur_rx = 0;			outb(CmdTxEnb, ioaddr + ChipCmd);			/* A.C.: Reset the multicast list. */			set_rx_mode(dev);			outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);		} else {			/* Malloc up new buffer, compatible with net-2e. */			/* Omit the four octet CRC from the length. */			struct sk_buff *skb;			int pkt_size = rx_size - 4;			skb = dev_alloc_skb(pkt_size + 2);			if (skb == NULL) {				printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n",					   dev->name);				/* We should check that some rx space is free.				   If not, free one and mark stats->rx_dropped++. */				tp->stats.rx_dropped++;				break;			}			skb->dev = dev;			skb_reserve(skb, 2);	/* 16 byte align the IP fields. */			if (ring_offset + rx_size > tp->rx_buf_len) {				int semi_count = tp->rx_buf_len - ring_offset - 4;				/* This could presumably use two calls to copy_and_sum()? */				memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4],					   semi_count);				memcpy(skb_put(skb, pkt_size-semi_count), rx_ring,					   pkt_size-semi_count);				if (debug > 4) {					int i;					printk(KERN_DEBUG"%s:  Frame wrap @%d",						   dev->name, semi_count);					for (i = 0; i < 16; i++)						printk(" %2.2x", rx_ring[i]);					printk(".\n");					memset(rx_ring, 0xcc, 16);				}			} else {				eth_copy_and_sum(skb, &rx_ring[ring_offset + 4],								 pkt_size, 0);				skb_put(skb, pkt_size);			}			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);#if LINUX_VERSION_CODE > 0x20119			tp->stats.rx_bytes += pkt_size;#endif			tp->stats.rx_packets++;		}		cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;		outw(cur_rx - 16, ioaddr + RxBufPtr);	}	if (debug > 4)		printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x,"			   " free to %4.4x, Cmd %2.2x.\n",			   dev->name, cur_rx, inw(ioaddr + RxBufAddr),			   inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));	tp->cur_rx = cur_rx;	return 0;}static intrtl8129_close(struct net_device *dev){	long ioaddr = dev->base_addr;	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	int i;	netif_stop_tx_queue(dev);	if (debug > 1)		printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",			   dev->name, inw(ioaddr + IntrStatus));	/* Disable interrupts by clearing the interrupt mask. */	outw(0x0000, ioaddr + IntrMask);	/* Stop the chip's Tx and Rx DMA processes. */	outb(0x00, ioaddr + ChipCmd);	/* Update the error counts. */	tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);	outl(0, ioaddr + RxMissed);	del_timer(&tp->timer);	free_irq(dev->irq, dev);	for (i = 0; i < NUM_TX_DESC; i++) {		if (tp->tx_skbuff[i])			dev_free_skb(tp->tx_skbuff[i]);		tp->tx_skbuff[i] = 0;	}	kfree(tp->rx_ring);	tp->rx_ring = 0;	/* Green! Put the chip in low-power mode. */	outb(0xC0, ioaddr + Cfg9346);	outb(0x03, ioaddr + Config1);	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */	MOD_DEC_USE_COUNT;	return 0;}static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct rtl8129_private *np = (struct rtl8129_private *)dev->priv;	u16 *data = (u16 *)&rq->ifr_data;	switch(cmd) {	case SIOCGMIIPHY:		/* Get the address of the PHY in use. */		data[0] = np->phys[0] & 0x3f;		/* Fall Through */	case SIOCGMIIREG:		/* Read the specified MII register. */		data[3] = mdio_read(dev, data[0], data[1] & 0x1f);		return 0;	case SIOCSMIIREG:		/* Write the specified MII register */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		if (data[0] == np->phys[0]) {			u16 value = data[2];			switch (data[1]) {			case 0:				/* Check for autonegotiation on or reset. */				np->medialock = (value & 0x9000) ? 0 : 1;				if (np->medialock)					np->full_duplex = (value & 0x0100) ? 1 : 0;				break;			case 4: np->advertising = value; break;			}		}		mdio_write(dev, data[0], data[1] & 0x1f, data[2]);		return 0;	default:		return -EOPNOTSUPP;	}}static struct net_device_stats *rtl8129_get_stats(struct net_device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	if (netif_running(dev)) {		tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);		outl(0, ioaddr + RxMissed);	}	return &tp->stats;}/* Set or clear the multicast filter for this adaptor.   This routine is not state sensitive and need not be SMP locked. */static unsigned const ethernet_polynomial = 0x04c11db7U;static inline u32 ether_crc(int length, unsigned char *data){	int crc = -1;	while (--length >= 0) {		unsigned char current_octet = *data++;		int bit;		for (bit = 0; bit < 8; bit++, current_octet >>= 1)			crc = (crc << 1) ^				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);	}	return crc;}/* Bits in RxConfig. */enum rx_mode_bits {	AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,	AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,};static void set_rx_mode(struct net_device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	u32 mc_filter[2];		 /* Multicast hash filter */	int i, rx_mode;	if (debug > 3)		printk(KERN_DEBUG"%s:   set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",			   dev->name, dev->flags, inl(ioaddr + RxConfig));	/* Note: do not reorder, GCC is clever about common statements. */	if (dev->flags & IFF_PROMISC) {		/* Unconditionally log net taps. */		printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name);		rx_mode = AcceptBroadcast|AcceptMulticast|AcceptMyPhys|AcceptAllPhys;		mc_filter[1] = mc_filter[0] = 0xffffffff;	} else if ((dev->mc_count > multicast_filter_limit)			   || (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter perfectly -- accept all multicasts. */		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;		mc_filter[1] = mc_filter[0] = 0xffffffff;	} else {		struct dev_mc_list *mclist;		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;		mc_filter[1] = mc_filter[0] = 0;		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;			 i++, mclist = mclist->next)			set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);	}	/* We can safely update without stopping the chip. */	outl(tp->rx_config | rx_mode, ioaddr + RxConfig);	outl(mc_filter[0], ioaddr + MAR0 + 0);	outl(mc_filter[1], ioaddr + MAR0 + 4);	return;}static int rtl_pwr_event(void *dev_instance, int event){	struct net_device *dev = dev_instance;	struct rtl8129_private *np = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	if (debug > 1)		printk("%s: Handling power event %d.\n", dev->name, event);	switch(event) {	case DRV_ATTACH:		MOD_INC_USE_COUNT;		break;	case DRV_SUSPEND:		netif_device_detach(dev);		/* Disable interrupts, stop Tx and Rx. */		outw(0x0000, ioaddr + IntrMask);		outb(0x00, ioaddr + ChipCmd);		/* Update the error counts. */		np->stats.rx_missed_errors += inl(ioaddr + RxMissed);		outl(0, ioaddr + RxMissed);		break;	case DRV_RESUME:		netif_device_attach(dev);		rtl_hw_start(dev);		break;	case DRV_DETACH: {		struct net_device **devp, **next;		if (dev->flags & IFF_UP) {			dev_close(dev);			dev->flags &= ~(IFF_UP|IFF_RUNNING);		}		unregister_netdev(dev);		release_region(dev->base_addr, pci_tbl[np->chip_id].io_size);#ifndef USE_IO_OPS		iounmap((char *)dev->base_addr);#endif		for (devp = &root_rtl8129_dev; *devp; devp = next) {			next = &((struct rtl8129_private *)(*devp)->priv)->next_module;			if (*devp == dev) {				*devp = *next;				break;			}		}		if (np->priv_addr)			kfree(np->priv_addr);		kfree(dev);		MOD_DEC_USE_COUNT;		break;	}	}	return 0;}#ifdef CARDBUS#include <pcmcia/driver_ops.h>static dev_node_t *rtl8139_attach(dev_locator_t *loc){	struct net_device *dev;	u16 dev_id;	u32 pciaddr;	u8 bus, devfn, irq;	long hostaddr;	/* Note: the chip index should match the 8139B pci_tbl[] entry. */	int chip_idx = 2;	if (loc->bus != LOC_PCI) return NULL;	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;	printk(KERN_DEBUG "rtl8139_attach(bus %d, function %d)\n", bus, devfn);#ifdef USE_IO_OPS	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &pciaddr);	hostaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK;#else	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &pciaddr);	hostaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK,							 pci_tbl[chip_idx].io_size);#endif	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);	if (hostaddr == 0 || irq == 0) {		printk(KERN_ERR "The %s interface at %d/%d was not assigned an %s.\n"			   KERN_ERR "  It will not be activated.\n",			   pci_tbl[chip_idx].name, bus, devfn,			   hostaddr == 0 ? "address" : "IRQ");		return NULL;	}	dev = rtl8139_probe1(pci_find_slot(bus, devfn), NULL,						 hostaddr, irq, chip_idx, 0);	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 rtl8139_detach(dev_node_t *node){	struct net_device **devp, **next;	printk(KERN_INFO "rtl8139_detach(%s)\n", node->dev_name);	for (devp = &root_rtl8129_dev; *devp; devp = next) {		next = &((struct rtl8129_private *)(*devp)->priv)->next_module;		if (strcmp((*devp)->name, node->dev_name) == 0) break;	}	if (*devp) {		struct rtl8129_private *np =			(struct rtl8129_private *)(*devp)->priv;		unregister_netdev(*devp);		release_region((*devp)->base_addr, pci_tbl[np->chip_id].io_size);#ifndef USE_IO_OPS		iounmap((char *)(*devp)->base_addr);#endif		kfree(*devp);		if (np->priv_addr)			kfree(np->priv_addr);		*devp = *next;		kfree(node);		MOD_DEC_USE_COUNT;	}}struct driver_operations realtek_ops = {	"realtek_cb",	rtl8139_attach, /*rtl8139_suspend*/0, /*rtl8139_resume*/0, rtl8139_detach};#endif  /* Cardbus support */int rtl8139_init_module(void){	if (debug)					/* Emit version even if no cards detected. */		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);#ifdef CARDBUS	register_driver(&realtek_ops);	return 0;#else	return pci_drv_register(&rtl8139_drv_id, NULL);#endif}void rtl8139_cleanup_module(void){	struct net_device *next_dev;#ifdef CARDBUS	unregister_driver(&realtek_ops);#else	pci_drv_unregister(&rtl8139_drv_id);#endif	while (root_rtl8129_dev) {		struct rtl8129_private *np = (void *)(root_rtl8129_dev->priv);		unregister_netdev(root_rtl8129_dev);		release_region(root_rtl8129_dev->base_addr,					   pci_tbl[np->chip_id].io_size);#ifndef USE_IO_OPS		iounmap((char *)(root_rtl8129_dev->base_addr));#endif		next_dev = np->next_module;		if (np->priv_addr)			kfree(np->priv_addr);		kfree(root_rtl8129_dev);		root_rtl8129_dev = next_dev;	}}module_init(rtl8139_init_module);module_exit(rtl8139_cleanup_module);/* * Local variables: *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c rtl8139.c" *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -Wall -Wstrict-prototypes -O6 -c rtl8139.c -o realtek_cb.o -I/usr/src/pcmcia/include/" *  c-indent-level: 4 *  c-basic-offset: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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