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

📄 winbond-840.c

📁 Linux下各种网卡的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	unsigned int tx_q_bytes, tx_unq_bytes;	unsigned int tx_full:1;				/* The Tx queue is full. */	/* These values track of the transceiver/media in use. */	unsigned int full_duplex:1;			/* Full-duplex operation requested. */	unsigned int duplex_lock:1;	unsigned int medialock:1;			/* Do not sense media. */	unsigned int default_port;			/* Last dev->if_port value. */	/* Rx filter. */	u32 cur_rx_mode;	u32 rx_filter[2];	int multicast_filter_limit;	/* MII transceiver section. */	int mii_cnt;						/* MII device addresses. */	u16 advertising;					/* NWay media advertisement */	unsigned char phys[2];				/* MII device addresses. */};static int  eeprom_read(long ioaddr, int location);static int  mdio_read(struct net_device *dev, int phy_id, int location);static void mdio_write(struct net_device *dev, int phy_id, int location, int value);static int  netdev_open(struct net_device *dev);static void check_duplex(struct net_device *dev);static void netdev_timer(unsigned long data);static void tx_timeout(struct net_device *dev);static void init_ring(struct net_device *dev);static int  start_tx(struct sk_buff *skb, struct net_device *dev);static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);static void netdev_error(struct net_device *dev, int intr_status);static int  netdev_rx(struct net_device *dev);static void netdev_error(struct net_device *dev, int intr_status);static inline unsigned ether_crc(int length, unsigned char *data);static void set_rx_mode(struct net_device *dev);static struct net_device_stats *get_stats(struct net_device *dev);static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int  netdev_close(struct net_device *dev);/* A list of our installed devices, for removing the driver module. */static struct net_device *root_net_dev = NULL;static void *w840_probe1(struct pci_dev *pdev, void *init_dev,						 long ioaddr, int irq, int chip_idx, int card_idx){	struct net_device *dev;	struct netdev_private *np;	void *priv_mem;	int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;	dev = init_etherdev(init_dev, 0);	if (!dev)		return NULL;#if LINUX_VERSION_CODE < 0x20155	printk(KERN_INFO "%s: %s at 0x%lx, %2.2x:%2.2x",		   dev->name, pci_id_tbl[chip_idx].name, ioaddr,		   pci_bus_number(pdev), pci_devfn(pdev)>>3);#else	printk(KERN_INFO "%s: %s at 0x%lx, %2.2x:%2.2x",		   dev->name, pci_id_tbl[chip_idx].name, ioaddr,		   pdev->bus->number, pdev->devfn>>3);#endif	/* Warning: validate for big-endian machines. */	for (i = 0; i < 3; i++)		((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i));	for (i = 0; i < 5; i++)		printk("%2.2x:", dev->dev_addr[i]);	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);	priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);	/* Out of memory is very unlikely. */	if (priv_mem == NULL)		return NULL;#ifdef USE_IO_OPS	request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);#endif	/* Reset the chip to erase previous misconfiguration.	   No hold time required! */	writel(0x00000001, ioaddr + PCIBusCfg);	dev->base_addr = ioaddr;	dev->irq = irq;	/* The descriptor lists must be aligned. */	dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);	memset(np, 0, sizeof(*np));	np->priv_addr = priv_mem;	np->next_module = root_net_dev;	root_net_dev = dev;	np->pci_dev = pdev;	np->chip_id = chip_idx;	np->drv_flags = pci_id_tbl[chip_idx].drv_flags;	np->msg_level = (1 << debug) - 1;	np->rx_copybreak = rx_copybreak;	np->max_interrupt_work = max_interrupt_work;	np->multicast_filter_limit = multicast_filter_limit;	np->tx_ring_size = TX_RING_SIZE;	np->rx_ring_size = RX_RING_SIZE;	if (dev->mem_start)		option = dev->mem_start;	if ((card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)		|| (np->drv_flags & AlwaysFDX))		np->full_duplex = 1;	/* The chip-specific entries in the device structure. */	dev->open = &netdev_open;	dev->hard_start_xmit = &start_tx;	dev->stop = &netdev_close;	dev->get_stats = &get_stats;	dev->set_multicast_list = &set_rx_mode;	dev->do_ioctl = &mii_ioctl;	if (np->drv_flags & CanHaveMII) {		int phy, phy_idx = 0;		for (phy = 1; phy < 32 && phy_idx < 4; phy++) {			int mii_status = mdio_read(dev, phy, 1);			if (mii_status != 0xffff  &&  mii_status != 0x0000) {				np->phys[phy_idx++] = phy;				np->advertising = mdio_read(dev, phy, 4);				printk(KERN_INFO "%s: MII PHY found at address %d, status "					   "0x%4.4x advertising %4.4x.\n",					   dev->name, phy, mii_status, np->advertising);			}		}		np->mii_cnt = phy_idx;		if (phy_idx == 0) {			printk(KERN_WARNING "%s: MII PHY not found -- this device may "				   "not operate correctly.\n"				   KERN_WARNING "%s:  If this is a switch card, explicitly "				   "force full duplex on this interface.\n",				   dev->name, dev->name);			if (np->drv_flags & FDXOnNoMII) {				printk(KERN_INFO "%s:  Assuming a switch card, forcing full "					   "duplex.\n", dev->name);				np->full_duplex = np->duplex_lock = 1;			}		}	}	/* Allow forcing the media type. */	if (np->full_duplex) {		printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"			   " disabled.\n", dev->name);		np->duplex_lock = 1;	}	if (option > 0) {		if (option & 0x220)			np->full_duplex = 1;		np->default_port = option & 0x3ff;		if (np->default_port & 0x330) {			np->medialock = 1;			printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",				   (option & 0x300 ? 100 : 10),				   (np->full_duplex ? "full" : "half"));			if (np->mii_cnt)				mdio_write(dev, np->phys[0], 0,						   ((option & 0x300) ? 0x2000 : 0) | 	/* 100mbps? */						   (np->full_duplex ? 0x0100 : 0)); /* Full duplex? */		}	}	return dev;}/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.   The Winbond NIC uses serial bit streams generated by the host processor. *//* Delay between EEPROM clock transitions.   This "delay" is to force out buffered PCI writes. */#define eeprom_delay(ee_addr)	readl(ee_addr)enum EEPROM_Ctrl_Bits {	EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,	EE_ChipSelect=0x801, EE_DataIn=0x08,};/* The EEPROM commands always start with 01.. preamble bits.   Commands are prepended to the variable-length address. */enum EEPROM_Cmds {	EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),};static int eeprom_read(long addr, int location){	int i;	int retval = 0;	long ee_addr = addr + EECtrl;	int read_cmd = location | EE_ReadCmd;	writel(EE_ChipSelect, ee_addr);	/* Shift the read command bits out. */	for (i = 10; i >= 0; i--) {		short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;		writel(dataval, ee_addr);		eeprom_delay(ee_addr);		writel(dataval | EE_ShiftClk, ee_addr);		eeprom_delay(ee_addr);	}	writel(EE_ChipSelect, ee_addr);	eeprom_delay(ee_addr);	for (i = 16; i > 0; i--) {		writel(EE_ChipSelect | EE_ShiftClk, ee_addr);		eeprom_delay(ee_addr);		retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);		writel(EE_ChipSelect, ee_addr);		eeprom_delay(ee_addr);	}	/* Terminate the EEPROM access. */	writel(0, ee_addr);	return retval;}/*  MII transceiver control section.	Read and write the MII registers using software-generated serial	MDIO protocol.  See the MII specifications or DP83840A data sheet	for details.	The maximum data clock rate is 2.5 Mhz.	The timing is decoupled from the processor clock by flushing the write	from the CPU write buffer with a following read, and using PCI	transaction time. */#define mdio_in(mdio_addr) readl(mdio_addr)#define mdio_out(value, mdio_addr) writel(value, mdio_addr)#define mdio_delay(mdio_addr) readl(mdio_addr)/* Set iff a MII transceiver on any interface requires mdio preamble.   This only set with older tranceivers, so the extra   code size of a per-interface flag is not worthwhile. */static char mii_preamble_required = 1;#define MDIO_WRITE0 (MDIO_EnbOutput)#define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput)/* Generate the preamble required for initial synchronization and   a few older transceivers. */static void mdio_sync(long mdio_addr){	int bits = 32;	/* Establish sync by sending at least 32 logic ones. */	while (--bits >= 0) {		mdio_out(MDIO_WRITE1, mdio_addr);		mdio_delay(mdio_addr);		mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}}static int mdio_read(struct net_device *dev, int phy_id, int location){	long mdio_addr = dev->base_addr + MIICtrl;	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;	int i, retval = 0;	if (mii_preamble_required)		mdio_sync(mdio_addr);	/* Shift the read command bits out. */	for (i = 15; i >= 0; i--) {		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;		mdio_out(dataval, mdio_addr);		mdio_delay(mdio_addr);		mdio_out(dataval | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	/* Read the two transition, 16 data, and wire-idle bits. */	for (i = 20; i > 0; i--) {		mdio_out(MDIO_EnbIn, mdio_addr);		mdio_delay(mdio_addr);		retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_DataIn) ? 1 : 0);		mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	return (retval>>1) & 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int reg, int value){	long mdio_addr = dev->base_addr + MIICtrl;	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (reg<<18) | value;	int i;	if (mii_preamble_required)		mdio_sync(mdio_addr);	/* Shift the command bits out. */	for (i = 31; i >= 0; i--) {		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;		mdio_out(dataval, mdio_addr);		mdio_delay(mdio_addr);		mdio_out(dataval | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	/* Clear out extra bits. */	for (i = 2; i > 0; i--) {		mdio_out(MDIO_EnbIn, mdio_addr);		mdio_delay(mdio_addr);		mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	return;}static int netdev_open(struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	int i;	writel(0x00000001, ioaddr + PCIBusCfg);		/* Reset */	MOD_INC_USE_COUNT;	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {		MOD_DEC_USE_COUNT;		return -EAGAIN;	}	if (np->msg_level & NETIF_MSG_IFUP)		printk(KERN_DEBUG "%s: w89c840_open() irq %d.\n",			   dev->name, dev->irq);	init_ring(dev);	writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);	writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);	for (i = 0; i < 6; i++)		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);	/* Initialize other registers. */	np->csr0 = csr0;	writel(np->csr0, ioaddr + PCIBusCfg);	if (dev->if_port == 0)		dev->if_port = np->default_port;	writel(0, ioaddr + RxStartDemand);	np->csr6 = np->full_duplex ? 0x20022202 : 0x20022002;	check_duplex(dev);	set_rx_mode(dev);	netif_start_tx_queue(dev);	/* Clear and Enable interrupts by setting the interrupt mask.	   See enum intr_status_bits above for bit guide.	   We omit: TimerInt, IntrRxDied, IntrTxStopped	*/	writel(0x1A0F5, ioaddr + IntrStatus);	writel(0x1A0F5, ioaddr + IntrEnable);	if (np->msg_level & NETIF_MSG_IFUP)		printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name);	/* Set the timer to check for link beat. */	init_timer(&np->timer);	np->timer.expires = jiffies + 3*HZ;	np->timer.data = (unsigned long)dev;	np->timer.function = &netdev_timer;				/* timer handler */	add_timer(&np->timer);	return 0;}static void check_duplex(struct net_device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	int mii_reg5 = mdio_read(dev, np->phys[0], 5);	int negotiated =  mii_reg5 & np->advertising;	int duplex;	if (np->duplex_lock  ||  mii_reg5 == 0xffff)		return;	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;	if (np->full_duplex != duplex) {

⌨️ 快捷键说明

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