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

📄 tulip_core.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 4 页
字号:
	u16 *data = (u16 *)&rq->ifr_data;	int phy = tp->phys[0] & 0x1f;	long flags;	switch(cmd) {	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */		if (tp->mii_cnt)			data[0] = phy;		else if (tp->flags & HAS_NWAY)			data[0] = 32;		else if (tp->chip_id == COMET)			data[0] = 1;		else			return -ENODEV;	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */		if (data[0] == 32  &&  (tp->flags & HAS_NWAY)) {			int csr12 = inl(ioaddr + CSR12);			int csr14 = inl(ioaddr + CSR14);			switch (data[1]) {			case 0: {				data[3] = (csr14<<5) & 0x1000;				break; }			case 1:				data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)					+ (csr12&0x06 ? 0x04 : 0);				break;			case 4: {				data[3] = ((csr14>>9)&0x07C0) +					((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1;				break;			}			case 5: data[3] = csr12 >> 16; break;			default: data[3] = 0; break;			}		} else {			spin_lock_irqsave (&tp->lock, flags);			data[3] = tulip_mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);			spin_unlock_irqrestore (&tp->lock, flags);		}		return 0;	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		if (data[0] == 32  &&  (tp->flags & HAS_NWAY)) {			if (data[1] == 5)				tp->to_advertise = data[2];		} else {			spin_lock_irqsave (&tp->lock, flags);			tulip_mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);			spin_unlock_irqrestore(&tp->lock, flags);		}		return 0;	default:		return -EOPNOTSUPP;	}	return -EOPNOTSUPP;}/* 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. *//* 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;}#undef set_bit_le#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev){	struct tulip_private *tp = (struct tulip_private *)dev->priv;	u16 hash_table[32];	struct dev_mc_list *mclist;	int i;	u16 *eaddrs;	memset(hash_table, 0, sizeof(hash_table));	set_bit_le(255, hash_table); 			/* Broadcast entry */	/* This should work on big-endian machines as well. */	for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;	     i++, mclist = mclist->next) {		int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff;		set_bit_le(index, hash_table);		for (i = 0; i < 32; i++) {			*setup_frm++ = hash_table[i];			*setup_frm++ = hash_table[i];		}		setup_frm = &tp->setup_frame[13*6];	}	/* Fill the final entry with our physical address. */	eaddrs = (u16 *)dev->dev_addr;	*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];	*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];	*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];}static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev){	struct tulip_private *tp = (struct tulip_private *)dev->priv;	struct dev_mc_list *mclist;	int i;	u16 *eaddrs;	/* We have <= 14 addresses so we can use the wonderful	   16 address perfect filtering of the Tulip. */	for (i = 0, mclist = dev->mc_list; i < dev->mc_count;	     i++, mclist = mclist->next) {		eaddrs = (u16 *)mclist->dmi_addr;		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;	}	/* Fill the unused entries with the broadcast address. */	memset(setup_frm, 0xff, (15-i)*12);	setup_frm = &tp->setup_frame[15*6];	/* Fill the final entry with our physical address. */	eaddrs = (u16 *)dev->dev_addr;	*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];	*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];	*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];}static void set_rx_mode(struct net_device *dev){	struct tulip_private *tp = (struct tulip_private *)dev->priv;	long ioaddr = dev->base_addr;	int csr6;	DPRINTK("ENTER\n");	csr6 = inl(ioaddr + CSR6) & ~0x00D5;	tp->csr6 &= ~0x00D5;	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		tp->csr6 |= 0x00C0;		csr6 |= 0x00C0;		/* Unconditionally log net taps. */		printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);	} else if ((dev->mc_count > 1000)  ||  (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter well -- accept all multicasts. */		tp->csr6 |= 0x0080;		csr6 |= 0x0080;	} else	if (tp->flags & MC_HASH_ONLY) {		/* Some work-alikes have only a 64-entry hash filter table. */		/* Should verify correctness on big-endian/__powerpc__ */		struct dev_mc_list *mclist;		int i;		u32 mc_filter[2];		 /* Multicast hash filter */		if (dev->mc_count > 64) {		/* Arbitrary non-effective limit. */			tp->csr6 |= 0x0080;			csr6 |= 0x0080;		} else {			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);			if (tp->chip_id == AX88140) {				outl(2, ioaddr + CSR13);				outl(mc_filter[0], ioaddr + CSR14);				outl(3, ioaddr + CSR13);				outl(mc_filter[1], ioaddr + CSR14);			} else if (tp->chip_id == COMET) { /* Has a simple hash filter. */				outl(mc_filter[0], ioaddr + 0xAC);				outl(mc_filter[1], ioaddr + 0xB0);			}		}	} else {		unsigned long flags;		/* Note that only the low-address shortword of setup_frame is valid!		   The values are doubled for big-endian architectures. */		if (dev->mc_count > 14) { /* Must use a multicast hash table. */			build_setup_frame_hash(tp->setup_frame, dev);		} else {			build_setup_frame_perfect(tp->setup_frame, dev);		}		spin_lock_irqsave(&tp->lock, flags);		if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {			/* Same setup recently queued, we need not add it. */		} else {			u32 tx_flags = 0x08000000 | 192;			unsigned int entry;			int dummy = -1;			/* Now add this frame to the Tx list. */			entry = tp->cur_tx++ % TX_RING_SIZE;			if (entry != 0) {				/* Avoid a chip errata by prefixing a dummy entry. */				tp->tx_buffers[entry].skb = NULL;				tp->tx_buffers[entry].mapping = 0;				tp->tx_ring[entry].length =					(entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0;				tp->tx_ring[entry].buffer1 = 0;				/* Must set DescOwned later to avoid race with chip */				dummy = entry;				entry = tp->cur_tx++ % TX_RING_SIZE;			}			tp->tx_buffers[entry].skb = NULL;			tp->tx_buffers[entry].mapping =				pci_map_single(tp->pdev, tp->setup_frame,					       sizeof(tp->setup_frame),					       PCI_DMA_TODEVICE);			/* Put the setup frame on the Tx list. */			if (entry == TX_RING_SIZE-1)				tx_flags |= DESC_RING_WRAP;		/* Wrap ring. */			tp->tx_ring[entry].length = cpu_to_le32(tx_flags);			tp->tx_ring[entry].buffer1 =				cpu_to_le32(tp->tx_buffers[entry].mapping);			tp->tx_ring[entry].status = cpu_to_le32(DescOwned);			if (dummy >= 0)				tp->tx_ring[dummy].status = cpu_to_le32(DescOwned);			if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2)				netif_stop_queue(dev);			/* Trigger an immediate transmit demand. */			outl(0, ioaddr + CSR1);		}		spin_unlock_irqrestore(&tp->lock, flags);	}	/* Can someone explain to me what the OR here is supposed to accomplish???? */	tulip_outl_csr(tp, csr6 | 0x0000, CSR6);}static int __devinit tulip_init_one (struct pci_dev *pdev,				     const struct pci_device_id *ent){	static int did_version;			/* Already printed version info. */	struct tulip_private *tp;	/* See note below on the multiport cards. */	static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};	static int last_irq;	static int multiport_cnt;		/* For four-port boards w/one EEPROM */	u8 chip_rev;	int i, irq;	unsigned short sum;	u8 ee_data[EEPROM_SIZE];	struct net_device *dev;	long ioaddr;	static int board_idx = -1;	int chip_idx = ent->driver_data;	board_idx++;	if (tulip_debug > 0  &&  did_version++ == 0)		printk (KERN_INFO "%s", version);	/*	 *	Lan media wire a tulip chip to a wan interface. Needs a very	 *	different driver (lmc driver)	 */	         if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) {		printk (KERN_ERR PFX "skipping LMC card.\n");		return -ENODEV;	}		/*	 *	Early DM9100's need software CRC and the DMFE driver	 */	 	if (pdev->vendor == 0x1282 && pdev->device == 0x9100)	{		u32 dev_rev;		/* Read Chip revision */		pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev);		if(dev_rev < 0x02000030)		{			printk(KERN_ERR PFX "skipping early DM9100 with Crc bug (use dmfe)\n");			return -ENODEV;		}	}			/*	 *	Looks for early PCI chipsets where people report hangs 	 *	without the workarounds being on.	 */	 	/* Intel Saturn. Switch to 8 long words burst, 8 long word cache aligned 	   Aries might need this too. The Saturn errata are not pretty reading but	   thankfully its an old 486 chipset.	*/		if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, NULL))		csr0 = 0x00A04800;	/* The dreaded SiS496 486 chipset. Same workaround as above. */	if (pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, NULL))		csr0 = 0x00A04800;			/*	 *	And back to business	 */ 	i = pci_enable_device(pdev);	if (i) {		printk (KERN_ERR PFX			"Cannot enable tulip board #%d, aborting\n",			board_idx);		return i;	}	ioaddr = pci_resource_start (pdev, 0);	irq = pdev->irq;	/* init_etherdev ensures aligned and zeroed private structures */	dev = init_etherdev (NULL, sizeof (*tp));	if (!dev) {		printk (KERN_ERR PFX "ether device alloc failed, aborting\n");		return -ENOMEM;	}	if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {		printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) too small, "			"aborting\n", dev->name, pci_resource_len (pdev, 0),			pci_resource_start (pdev, 0));		goto err_out_free_netdev;	}	/* grab all resources from both PIO and MMIO regions, as we	 * don't want anyone else messing around with our hardware */	if (!request_region (pci_resource_start (pdev, 0),			     pci_resource_len (pdev, 0),			     dev->name)) {		printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) unavailable, "			"aborting\n", dev->name, pci_resource_len (pdev, 0),			pci_resource_start (pdev, 0));		goto err_out_free_netdev;	}	if (!request_mem_region (pci_resource_start (pdev, 1),				 pci_resource_len (pdev, 1),				 dev->name)) {		printk (KERN_ERR PFX "%s: MMIO region (0x%lx@0x%lx) unavailable, "			"aborting\n", dev->name, pci_resource_len (pdev, 1),			pci_resource_start (pdev, 1));		goto err_out_free_pio_res;	}	pci_set_master(pdev);	pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev);	/*	 * initialize priviate data structure 'tp'	 * it is zeroed and aligned in init_etherdev	 */	tp = dev->priv;	tp->rx_ring = pci_alloc_consistent(pdev,					   sizeof(struct tulip_rx_desc) * RX_RING_SIZE +					   sizeof(struct tulip_tx_desc) * TX_RING_SIZE,

⌨️ 快捷键说明

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