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 + -
显示快捷键?