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

📄 3c509.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	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;			outw(RxDiscard, ioaddr + EL3_CMD);			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;			}		} else {			short pkt_len = rx_status & 0x7ff;			struct sk_buff *skb;			skb = dev_alloc_skb(pkt_len+5);			lp->stats.rx_bytes += pkt_len;			if (el3_debug > 4)				printk("Receiving packet size %d status %4.4x.\n",					   pkt_len, rx_status);			if (skb != NULL) {				skb_reserve(skb, 2);     /* Align IP on 16 byte */				/* 'skb->data' points to the start of sk_buff data area. */				insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len),					 (pkt_len + 3) >> 2);				outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */				skb->protocol = eth_type_trans(skb,dev);				netif_rx(skb);				dev->last_rx = jiffies;				lp->stats.rx_packets++;				continue;			}			outw(RxDiscard, ioaddr + EL3_CMD);			lp->stats.rx_dropped++;			if (el3_debug)				printk("%s: Couldn't allocate a sk_buff of size %d.\n",					   dev->name, pkt_len);		}		inw(ioaddr + EL3_STATUS); 				/* Delay. */		while (inw(ioaddr + EL3_STATUS) & 0x1000)			printk(KERN_DEBUG "	Waiting for 3c509 to discard packet, status %x.\n",				   inw(ioaddr + EL3_STATUS) );	}	return 0;}/* *     Set or clear the multicast filter for this adaptor. */static voidset_multicast_list(struct net_device *dev){	unsigned long flags;	struct el3_private *lp = netdev_priv(dev);	int ioaddr = dev->base_addr;	if (el3_debug > 1) {		static int old;		if (old != dev->mc_count) {			old = dev->mc_count;			printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count);		}	}	spin_lock_irqsave(&lp->lock, flags);	if (dev->flags&IFF_PROMISC) {		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,			 ioaddr + EL3_CMD);	}	else if (dev->mc_count || (dev->flags&IFF_ALLMULTI)) {		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD);	}	else		outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);	spin_unlock_irqrestore(&lp->lock, flags);}static intel3_close(struct net_device *dev){	int ioaddr = dev->base_addr;	struct el3_private *lp = netdev_priv(dev);	if (el3_debug > 2)		printk("%s: Shutting down ethercard.\n", dev->name);	el3_down(dev);	free_irq(dev->irq, dev);	/* Switching back to window 0 disables the IRQ. */	EL3WINDOW(0);	if (lp->type != EL3_EISA) {		/* But we explicitly zero the IRQ line select anyway. Don't do		 * it on EISA cards, it prevents the module from getting an		 * IRQ after unload+reload... */		outw(0x0f00, ioaddr + WN0_IRQ);	}	return 0;}static intel3_link_ok(struct net_device *dev){	int ioaddr = dev->base_addr;	u16 tmp;	EL3WINDOW(4);	tmp = inw(ioaddr + WN4_MEDIA);	EL3WINDOW(1);	return tmp & (1<<11);}static intel3_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd){	u16 tmp;	int ioaddr = dev->base_addr;	EL3WINDOW(0);	/* obtain current transceiver via WN4_MEDIA? */	tmp = inw(ioaddr + WN0_ADDR_CONF);	ecmd->transceiver = XCVR_INTERNAL;	switch (tmp >> 14) {	case 0:		ecmd->port = PORT_TP;		break;	case 1:		ecmd->port = PORT_AUI;		ecmd->transceiver = XCVR_EXTERNAL;		break;	case 3:		ecmd->port = PORT_BNC;	default:		break;	}	ecmd->duplex = DUPLEX_HALF;	ecmd->supported = 0;	tmp = inw(ioaddr + WN0_CONF_CTRL);	if (tmp & (1<<13))		ecmd->supported |= SUPPORTED_AUI;	if (tmp & (1<<12))		ecmd->supported |= SUPPORTED_BNC;	if (tmp & (1<<9)) {		ecmd->supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half |				SUPPORTED_10baseT_Full;	/* hmm... */		EL3WINDOW(4);		tmp = inw(ioaddr + WN4_NETDIAG);		if (tmp & FD_ENABLE)			ecmd->duplex = DUPLEX_FULL;	}	ecmd->speed = SPEED_10;	EL3WINDOW(1);	return 0;}static intel3_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd){	u16 tmp;	int ioaddr = dev->base_addr;	if (ecmd->speed != SPEED_10)		return -EINVAL;	if ((ecmd->duplex != DUPLEX_HALF) && (ecmd->duplex != DUPLEX_FULL))		return -EINVAL;	if ((ecmd->transceiver != XCVR_INTERNAL) && (ecmd->transceiver != XCVR_EXTERNAL))		return -EINVAL;	/* change XCVR type */	EL3WINDOW(0);	tmp = inw(ioaddr + WN0_ADDR_CONF);	switch (ecmd->port) {	case PORT_TP:		tmp &= ~(3<<14);		dev->if_port = 0;		break;	case PORT_AUI:		tmp |= (1<<14);		dev->if_port = 1;		break;	case PORT_BNC:		tmp |= (3<<14);		dev->if_port = 3;		break;	default:		return -EINVAL;	}	outw(tmp, ioaddr + WN0_ADDR_CONF);	if (dev->if_port == 3) {		/* fire up the DC-DC convertor if BNC gets enabled */		tmp = inw(ioaddr + WN0_ADDR_CONF);		if (tmp & (3 << 14)) {			outw(StartCoax, ioaddr + EL3_CMD);			udelay(800);		} else			return -EIO;	}	EL3WINDOW(4);	tmp = inw(ioaddr + WN4_NETDIAG);	if (ecmd->duplex == DUPLEX_FULL)		tmp |= FD_ENABLE;	else		tmp &= ~FD_ENABLE;	outw(tmp, ioaddr + WN4_NETDIAG);	EL3WINDOW(1);	return 0;}static void el3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){	strcpy(info->driver, DRV_NAME);	strcpy(info->version, DRV_VERSION);}static int el3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd){	struct el3_private *lp = netdev_priv(dev);	int ret;	spin_lock_irq(&lp->lock);	ret = el3_netdev_get_ecmd(dev, ecmd);	spin_unlock_irq(&lp->lock);	return ret;}static int el3_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd){	struct el3_private *lp = netdev_priv(dev);	int ret;	spin_lock_irq(&lp->lock);	ret = el3_netdev_set_ecmd(dev, ecmd);	spin_unlock_irq(&lp->lock);	return ret;}static u32 el3_get_link(struct net_device *dev){	struct el3_private *lp = netdev_priv(dev);	u32 ret;	spin_lock_irq(&lp->lock);	ret = el3_link_ok(dev);	spin_unlock_irq(&lp->lock);	return ret;}static u32 el3_get_msglevel(struct net_device *dev){	return el3_debug;}static void el3_set_msglevel(struct net_device *dev, u32 v){	el3_debug = v;}static const struct ethtool_ops ethtool_ops = {	.get_drvinfo = el3_get_drvinfo,	.get_settings = el3_get_settings,	.set_settings = el3_set_settings,	.get_link = el3_get_link,	.get_msglevel = el3_get_msglevel,	.set_msglevel = el3_set_msglevel,};static voidel3_down(struct net_device *dev){	int ioaddr = dev->base_addr;	netif_stop_queue(dev);	/* Turn off statistics ASAP.  We update lp->stats below. */	outw(StatsDisable, ioaddr + EL3_CMD);	/* Disable the receiver and transmitter. */	outw(RxDisable, ioaddr + EL3_CMD);	outw(TxDisable, ioaddr + EL3_CMD);	if (dev->if_port == 3)		/* Turn off thinnet power.  Green! */		outw(StopCoax, ioaddr + EL3_CMD);	else if (dev->if_port == 0) {		/* Disable link beat and jabber, if_port may change here next open(). */		EL3WINDOW(4);		outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);	}	outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);	update_stats(dev);}static voidel3_up(struct net_device *dev){	int i, sw_info, net_diag;	int ioaddr = dev->base_addr;	/* Activating the board required and does no harm otherwise */	outw(0x0001, ioaddr + 4);	/* Set the IRQ line. */	outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);	/* Set the station address in window 2 each time opened. */	EL3WINDOW(2);	for (i = 0; i < 6; i++)		outb(dev->dev_addr[i], ioaddr + i);	if ((dev->if_port & 0x03) == 3) /* BNC interface */		/* Start the thinnet transceiver. We should really wait 50ms...*/		outw(StartCoax, ioaddr + EL3_CMD);	else if ((dev->if_port & 0x03) == 0) { /* 10baseT interface */		/* Combine secondary sw_info word (the adapter level) and primary			sw_info word (duplex setting plus other useless bits) */		EL3WINDOW(0);		sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) |			(read_eeprom(ioaddr, 0x0d) & 0xBff0);		EL3WINDOW(4);		net_diag = inw(ioaddr + WN4_NETDIAG);		net_diag = (net_diag | FD_ENABLE); /* temporarily assume full-duplex will be set */		printk("%s: ", dev->name);		switch (dev->if_port & 0x0c) {			case 12:				/* force full-duplex mode if 3c5x9b */				if (sw_info & 0x000f) {					printk("Forcing 3c5x9b full-duplex mode");					break;				}			case 8:				/* set full-duplex mode based on eeprom config setting */				if ((sw_info & 0x000f) && (sw_info & 0x8000)) {					printk("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)");					break;				}			default:				/* xcvr=(0 || 4) OR user has an old 3c5x9 non "B" model */				printk("Setting 3c5x9/3c5x9B half-duplex mode");				net_diag = (net_diag & ~FD_ENABLE); /* disable full duplex */		}		outw(net_diag, ioaddr + WN4_NETDIAG);		printk(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info);		if (el3_debug > 3)			printk("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag);		/* Enable link beat and jabber check. */		outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA);	}	/* Switch to the stats window, and clear all stats by reading. */	outw(StatsDisable, ioaddr + EL3_CMD);	EL3WINDOW(6);	for (i = 0; i < 9; i++)		inb(ioaddr + i);	inw(ioaddr + 10);	inw(ioaddr + 12);	/* Switch to register set 1 for normal use. */	EL3WINDOW(1);	/* Accept b-case and phys addr only. */	outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */	/* Allow status bits to be seen. */	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);	/* Ack all pending events, and set active indicator mask. */	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,		 ioaddr + EL3_CMD);	outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull,		 ioaddr + EL3_CMD);	netif_start_queue(dev);}/* Power Management support functions */#ifdef EL3_SUSPENDstatic intel3_suspend(struct device *pdev, pm_message_t state){	unsigned long flags;	struct net_device *dev;	struct el3_private *lp;	int ioaddr;	dev = pdev->driver_data;	lp = netdev_priv(dev);	ioaddr = dev->base_addr;	spin_lock_irqsave(&lp->lock, flags);	if (netif_running(dev))		netif_device_detach(dev);	el3_down(dev);	outw(PowerDown, ioaddr + EL3_CMD);	spin_unlock_irqrestore(&lp->lock, flags);	return 0;}static intel3_resume(struct device *pdev){	unsigned long flags;	struct net_device *dev;	struct el3_private *lp;	int ioaddr;	dev = pdev->driver_data;	lp = netdev_priv(dev);	ioaddr = dev->base_addr;	spin_lock_irqsave(&lp->lock, flags);	outw(PowerUp, ioaddr + EL3_CMD);	el3_up(dev);	if (netif_running(dev))		netif_device_attach(dev);	spin_unlock_irqrestore(&lp->lock, flags);	return 0;}#endif /* EL3_SUSPEND *//* Parameters that may be passed into the module. */static int debug = -1;static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1};static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};module_param(debug,int, 0);module_param_array(irq, int, NULL, 0);module_param_array(xcvr, int, NULL, 0);module_param(max_interrupt_work, int, 0);MODULE_PARM_DESC(debug, "debug level (0-6)");MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");MODULE_PARM_DESC(xcvr,"transceiver(s) (0=internal, 1=external)");MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");#if defined(__ISAPNP__)module_param(nopnp, int, 0);MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);#endif	/* __ISAPNP__ */MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B) ISA/PnP ethernet driver");MODULE_LICENSE("GPL");static int __init el3_init_module(void){	int ret = 0;	el3_cards = 0;	if (debug >= 0)		el3_debug = debug;	el3_root_dev = NULL;	while (el3_probe(el3_cards) == 0) {		if (irq[el3_cards] > 1)			el3_root_dev->irq = irq[el3_cards];		if (xcvr[el3_cards] >= 0)			el3_root_dev->if_port = xcvr[el3_cards];		el3_cards++;	}#ifdef CONFIG_EISA	ret = eisa_driver_register(&el3_eisa_driver);#endif#ifdef CONFIG_MCA	{		int err = mca_register_driver(&el3_mca_driver);		if (ret == 0)			ret = err;	}#endif	return ret;}static void __exit el3_cleanup_module(void){	struct net_device *next_dev;	while (el3_root_dev) {		struct el3_private *lp = netdev_priv(el3_root_dev);		next_dev = lp->next_dev;		el3_common_remove (el3_root_dev);		el3_root_dev = next_dev;	}#ifdef CONFIG_EISA	eisa_driver_unregister (&el3_eisa_driver);#endif#ifdef CONFIG_MCA	mca_unregister_driver(&el3_mca_driver);#endif}module_init (el3_init_module);module_exit (el3_cleanup_module);

⌨️ 快捷键说明

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