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

📄 xircom_tulip_cb.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 4 页
字号:
	for (i = 0; i < TX_RING_SIZE; i++) {		if (tp->tx_skbuff[i])			dev_kfree_skb(tp->tx_skbuff[i]);		tp->tx_skbuff[i] = 0;	}	tp->open = 0;	return 0;}static struct net_device_stats *xircom_get_stats(struct net_device *dev){	struct xircom_private *tp = dev->priv;	long ioaddr = dev->base_addr;	if (netif_device_present(dev))		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;	return &tp->stats;}static int xircom_ethtool_ioctl(struct net_device *dev, void *useraddr){	struct ethtool_cmd ecmd;	struct xircom_private *tp = dev->priv;	if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))		return -EFAULT;	switch (ecmd.cmd) {	case ETHTOOL_GSET:		ecmd.supported =			SUPPORTED_10baseT_Half |			SUPPORTED_10baseT_Full |			SUPPORTED_100baseT_Half |			SUPPORTED_100baseT_Full |			SUPPORTED_Autoneg |			SUPPORTED_MII;		ecmd.advertising = ADVERTISED_MII;		if (tp->advertising[0] & ADVERTISE_10HALF)			ecmd.advertising |= ADVERTISED_10baseT_Half;		if (tp->advertising[0] & ADVERTISE_10FULL)			ecmd.advertising |= ADVERTISED_10baseT_Full;		if (tp->advertising[0] & ADVERTISE_100HALF)			ecmd.advertising |= ADVERTISED_100baseT_Half;		if (tp->advertising[0] & ADVERTISE_100FULL)			ecmd.advertising |= ADVERTISED_100baseT_Full;		if (tp->autoneg) {			ecmd.advertising |= ADVERTISED_Autoneg;			ecmd.autoneg = AUTONEG_ENABLE;		} else			ecmd.autoneg = AUTONEG_DISABLE;		ecmd.port = PORT_MII;		ecmd.transceiver = XCVR_INTERNAL;		ecmd.phy_address = tp->phys[0];		ecmd.speed = tp->speed100 ? SPEED_100 : SPEED_10;		ecmd.duplex = tp->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;		ecmd.maxtxpkt = TX_RING_SIZE / 2;		ecmd.maxrxpkt = 0;		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))			return -EFAULT;		return 0;	case ETHTOOL_SSET: {		u16 autoneg, speed100, full_duplex;		autoneg = (ecmd.autoneg == AUTONEG_ENABLE);		speed100 = (ecmd.speed == SPEED_100);		full_duplex = (ecmd.duplex == DUPLEX_FULL);		tp->autoneg = autoneg;		if (speed100 != tp->speed100 ||		    full_duplex != tp->full_duplex) {			tp->speed100 = speed100;			tp->full_duplex = full_duplex;			/* change advertising bits */			tp->advertising[0] &= ~(ADVERTISE_10HALF |					     ADVERTISE_10FULL |					     ADVERTISE_100HALF |					     ADVERTISE_100FULL |					     ADVERTISE_100BASE4);			if (speed100) {				if (full_duplex)					tp->advertising[0] |= ADVERTISE_100FULL;				else					tp->advertising[0] |= ADVERTISE_100HALF;			} else {				if (full_duplex)					tp->advertising[0] |= ADVERTISE_10FULL;				else					tp->advertising[0] |= ADVERTISE_10HALF;			}		}		check_duplex(dev);		return 0;	}	case ETHTOOL_GDRVINFO: {		struct ethtool_drvinfo info;		memset(&info, 0, sizeof(info));		info.cmd = ecmd.cmd;		strcpy(info.driver, DRV_NAME);		strcpy(info.version, DRV_VERSION);		*info.fw_version = 0;		strcpy(info.bus_info, tp->pdev->slot_name);		if (copy_to_user(useraddr, &info, sizeof(info)))		       return -EFAULT;		return 0;	}	default:		return -EOPNOTSUPP;	}}/* Provide ioctl() calls to examine the MII xcvr state. */static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){	struct xircom_private *tp = dev->priv;	u16 *data = (u16 *)&rq->ifr_data;	int phy = tp->phys[0] & 0x1f;	long flags;	switch(cmd) {	case SIOCETHTOOL:		return xircom_ethtool_ioctl(dev, (void *) rq->ifr_data);	/* Legacy mii-diag interface */	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */		if (tp->mii_cnt)			data[0] = phy;		else			return -ENODEV;		return 0;	case SIOCGMIIREG:		/* Read MII PHY register. */	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */		save_flags(flags);		cli();		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);		restore_flags(flags);		return 0;	case SIOCSMIIREG:		/* Write MII PHY register. */	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		save_flags(flags);		cli();		if (data[0] == tp->phys[0]) {			u16 value = data[2];			switch (data[1]) {			case 0:				if (value & (BMCR_RESET | BMCR_ANENABLE))					/* Autonegotiation. */					tp->autoneg = 1;				else {					tp->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0;					tp->autoneg = 0;				}				break;			case 4:				tp->advertising[0] = value;				break;			}			check_duplex(dev);		}		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);		restore_flags(flags);		return 0;	default:		return -EOPNOTSUPP;	}	return -EOPNOTSUPP;}/* The little-endian AUTODIN32 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 u32 ether_crc_le(int length, unsigned char *data){	u32 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 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;}/* Set or clear the multicast filter for this adaptor.   Note that we only use exclusion around actually queueing the   new frame, not around filling tp->setup_frame.  This is non-deterministic   when re-entered but still correct. */static void set_rx_mode(struct net_device *dev){	struct xircom_private *tp = dev->priv;	struct dev_mc_list *mclist;	long ioaddr = dev->base_addr;	int csr6 = inl(ioaddr + CSR6);	u16 *eaddrs, *setup_frm;	u32 tx_flags;	int i;	tp->csr6 &= ~(AllMultiBit | PromiscBit | HashFilterBit);	csr6 &= ~(AllMultiBit | PromiscBit | HashFilterBit);	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		tp->csr6 |= PromiscBit;		csr6 |= PromiscBit;		goto out;	}	if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter well -- accept all multicasts. */		tp->csr6 |= AllMultiBit;		csr6 |= AllMultiBit;		goto out;	}	tx_flags = Tx1WholePkt | Tx1SetupPkt | PKT_SETUP_SZ;	/* Note that only the low-address shortword of setup_frame is valid! */	setup_frm = tp->setup_frame;	mclist = dev->mc_list;	/* Fill the first entry with our physical address. */	eaddrs = (u16 *)dev->dev_addr;	*setup_frm = cpu_to_le16(eaddrs[0]); setup_frm += 2;	*setup_frm = cpu_to_le16(eaddrs[1]); setup_frm += 2;	*setup_frm = cpu_to_le16(eaddrs[2]); setup_frm += 2;	if (dev->mc_count > 14) { /* Must use a multicast hash table. */		u32 *hash_table = (u32 *)(tp->setup_frame + 4 * 12);		u32 hash, hash2;		tx_flags |= Tx1HashSetup;		tp->csr6 |= HashFilterBit;		csr6 |= HashFilterBit;		/* Fill the unused 3 entries with the broadcast address.		   At least one entry *must* contain the broadcast address!!!*/		for (i = 0; i < 3; i++) {			*setup_frm = 0xffff; setup_frm += 2;			*setup_frm = 0xffff; setup_frm += 2;			*setup_frm = 0xffff; setup_frm += 2;		}		/* Truly brain-damaged hash filter layout */		/* XXX: not sure if I should take the last or the first 9 bits */		for (i = 0; i < dev->mc_count; i++, mclist = mclist->next) {			u32 *hptr;			hash = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff;			if (hash < 384) {				hash2 = hash + ((hash >> 4) << 4) +					((hash >> 5) << 5);			} else {				hash -= 384;				hash2 = 64 + hash + (hash >> 4) * 80;			}			hptr = &hash_table[hash2 & ~0x1f];			*hptr |= cpu_to_le32(1 << (hash2 & 0x1f));		}	} else {		/* We have <= 14 mcast addresses so we can use Xircom's		   wonderful 16-address perfect filter. */		for (i = 0; i < dev->mc_count; i++, mclist = mclist->next) {			eaddrs = (u16 *)mclist->dmi_addr;			*setup_frm = cpu_to_le16(eaddrs[0]); setup_frm += 2;			*setup_frm = cpu_to_le16(eaddrs[1]); setup_frm += 2;			*setup_frm = cpu_to_le16(eaddrs[2]); setup_frm += 2;		}		/* Fill the unused entries with the broadcast address.		   At least one entry *must* contain the broadcast address!!!*/		for (; i < 15; i++) {			*setup_frm = 0xffff; setup_frm += 2;			*setup_frm = 0xffff; setup_frm += 2;			*setup_frm = 0xffff; setup_frm += 2;		}	}	/* Now add this frame to the Tx list. */	if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {		/* Same setup recently queued, we need not add it. */		/* XXX: Huh? All it means is that the Tx list is full...*/	} else {		unsigned long flags;		unsigned int entry;		int dummy = -1;		save_flags(flags); cli();		entry = tp->cur_tx++ % TX_RING_SIZE;		if (entry != 0) {			/* Avoid a chip errata by prefixing a dummy entry. */			tp->tx_skbuff[entry] = 0;			tp->tx_ring[entry].length =				(entry == TX_RING_SIZE - 1) ? Tx1RingWrap : 0;			tp->tx_ring[entry].buffer1 = 0;			/* race with chip, set Tx0DescOwned later */			dummy = entry;			entry = tp->cur_tx++ % TX_RING_SIZE;		}		tp->tx_skbuff[entry] = 0;		/* Put the setup frame on the Tx list. */		if (entry == TX_RING_SIZE - 1)			tx_flags |= Tx1RingWrap;		/* Wrap ring. */		tp->tx_ring[entry].length = tx_flags;		tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);		tp->tx_ring[entry].status = Tx0DescOwned;		if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {			tp->tx_full = 1;			netif_stop_queue (dev);		}		if (dummy >= 0)			tp->tx_ring[dummy].status = Tx0DescOwned;		restore_flags(flags);		/* Trigger an immediate transmit demand. */		outl(0, ioaddr + CSR1);	}out:	outl_CSR6(csr6, ioaddr);}static struct pci_device_id xircom_pci_table[] __devinitdata = {  { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },  {0},};MODULE_DEVICE_TABLE(pci, xircom_pci_table);#ifdef CONFIG_PMstatic int xircom_suspend(struct pci_dev *pdev, u32 state){	struct net_device *dev = pci_get_drvdata(pdev);	struct xircom_private *tp = dev->priv;	printk(KERN_INFO "xircom_suspend(%s)\n", dev->name);	if (tp->open)		xircom_down(dev);	return 0;}static int xircom_resume(struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);	struct xircom_private *tp = dev->priv;	printk(KERN_INFO "xircom_resume(%s)\n", dev->name);	/* Bring the chip out of sleep mode.	   Caution: Snooze mode does not work with some boards! */	if (xircom_tbl[tp->chip_id].flags & HAS_ACPI)		pci_write_config_dword(tp->pdev, PCI_POWERMGMT, 0);	transceiver_voodoo(dev);	if (xircom_tbl[tp->chip_id].flags & HAS_MII)		check_duplex(dev);	if (tp->open)		xircom_up(dev);	return 0;}#endif /* CONFIG_PM */static void __devexit xircom_remove_one(struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);	printk(KERN_INFO "xircom_remove_one(%s)\n", dev->name);	unregister_netdev(dev);	pci_release_regions(pdev);	kfree(dev);	pci_set_drvdata(pdev, NULL);}static struct pci_driver xircom_driver = {	name:		DRV_NAME,	id_table:	xircom_pci_table,	probe:		xircom_init_one,	remove:		__devexit_p(xircom_remove_one),#ifdef CONFIG_PM	suspend:	xircom_suspend,	resume:		xircom_resume#endif /* CONFIG_PM */};static int __init xircom_init(void){/* when a module, this is printed whether or not devices are found in probe */#ifdef MODULE	printk(version);#endif	return pci_module_init(&xircom_driver);}static void __exit xircom_exit(void){	pci_unregister_driver(&xircom_driver);}module_init(xircom_init)module_exit(xircom_exit)/* * Local variables: *  c-indent-level: 4 *  c-basic-offset: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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