3c509.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,663 行 · 第 1/3 页

C
1,663
字号
		}		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 int el3_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;}/** * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls * @dev: network interface on which out-of-band action is to be performed * @useraddr: userspace address to which data is to be read and returned * * Process the various commands of the SIOCETHTOOL interface. */static intnetdev_ethtool_ioctl (struct net_device *dev, void __user *useraddr){	u32 ethcmd;	struct el3_private *lp = netdev_priv(dev);	/* dev_ioctl() in ../../net/core/dev.c has already checked	   capable(CAP_NET_ADMIN), so don't bother with that here.  */	if (get_user(ethcmd, (u32 __user *)useraddr))		return -EFAULT;	switch (ethcmd) {	case ETHTOOL_GDRVINFO: {		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };		strcpy (info.driver, DRV_NAME);		strcpy (info.version, DRV_VERSION);		if (copy_to_user (useraddr, &info, sizeof (info)))			return -EFAULT;		return 0;	}	/* get settings */	case ETHTOOL_GSET: {		int ret;		struct ethtool_cmd ecmd = { ETHTOOL_GSET };		spin_lock_irq(&lp->lock);		ret = el3_netdev_get_ecmd(dev, &ecmd);		spin_unlock_irq(&lp->lock);		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))			return -EFAULT;		return ret;	}	/* set settings */	case ETHTOOL_SSET: {		int ret;		struct ethtool_cmd ecmd;		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))			return -EFAULT;		spin_lock_irq(&lp->lock);		ret = el3_netdev_set_ecmd(dev, &ecmd);		spin_unlock_irq(&lp->lock);		return ret;	}	/* get link status */	case ETHTOOL_GLINK: {		struct ethtool_value edata = { ETHTOOL_GLINK };		spin_lock_irq(&lp->lock);		edata.data = el3_link_ok(dev);		spin_unlock_irq(&lp->lock);		if (copy_to_user(useraddr, &edata, sizeof(edata)))			return -EFAULT;		return 0;	}	/* get message-level */	case ETHTOOL_GMSGLVL: {		struct ethtool_value edata = {ETHTOOL_GMSGLVL};		edata.data = el3_debug;		if (copy_to_user(useraddr, &edata, sizeof(edata)))			return -EFAULT;		return 0;	}	/* set message-level */	case ETHTOOL_SMSGLVL: {		struct ethtool_value edata;		if (copy_from_user(&edata, useraddr, sizeof(edata)))			return -EFAULT;		el3_debug = edata.data;		return 0;	}	default:		break;	}	return -EOPNOTSUPP;}/** * netdev_ioctl: Handle network interface ioctls * @dev: network interface on which out-of-band action is to be performed * @rq: user request data * @cmd: command issued by user * * Process the various out-of-band ioctls passed to this driver. */static intnetdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd){	int rc = 0;	switch (cmd) {	case SIOCETHTOOL:		rc = netdev_ethtool_ioctl(dev, rq->ifr_data);		break;	default:		rc = -EOPNOTSUPP;		break;	}	return rc;}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 CONFIG_PMstatic intel3_suspend(struct pm_dev *pdev){	unsigned long flags;	struct net_device *dev;	struct el3_private *lp;	int ioaddr;		if (!pdev && !pdev->data)		return -EINVAL;	dev = (struct net_device *)pdev->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 pm_dev *pdev){	unsigned long flags;	struct net_device *dev;	struct el3_private *lp;	int ioaddr;		if (!pdev && !pdev->data)		return -EINVAL;	dev = (struct net_device *)pdev->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;}static intel3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data){	switch (rqst) {		case PM_SUSPEND:			return el3_suspend(pdev);		case PM_RESUME:			return el3_resume(pdev);	}	return 0;}#endif /* CONFIG_PM *//* 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_PARM(debug,"i");MODULE_PARM(irq,"1-8i");MODULE_PARM(xcvr,"1-12i");MODULE_PARM(max_interrupt_work, "i");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_PARM(nopnp, "i");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){	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	if (eisa_driver_register (&el3_eisa_driver) < 0) {		eisa_driver_unregister (&el3_eisa_driver);	}#endif#ifdef CONFIG_MCA	mca_register_driver(&el3_mca_driver);#endif	return 0;}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 + =
减小字号Ctrl + -
显示快捷键?