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

📄 rtl8139.c

📁 Linux 2.2.x下的8129/8139网卡驱动程序源码
💻 C
📖 第 1 页 / 共 5 页
字号:
#if LINUX_VERSION_CODE > 0x20115MODULE_AUTHOR("Donald Becker <becker@scyld.com>");MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver");MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(multicast_filter_limit, "i");MODULE_PARM(max_interrupt_work, "i");MODULE_PARM(debug, "i");#endif#endifstatic int rtl8139cp_open(struct net_device *dev);static void rtl8139cp_init_ring(struct net_device *dev);static int rtl8139cp_start_xmit(struct sk_buff *skb, struct net_device *dev);static int rtl8139cp_rx(struct net_device *dev);static void rtl8139CP_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static int rtl8129_open(struct net_device *dev);static int read_eeprom(long ioaddr, int location, int addr_len);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 val);static void rtl8129_timer(unsigned long data);static void rtl8129_tx_timeout(struct net_device *dev);static void rtl8129_init_ring(struct net_device *dev);static int rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev);static int rtl8129_rx(struct net_device *dev);static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static int rtl8129_close(struct net_device *dev);static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static struct net_device_stats *rtl8129_get_stats(struct net_device *dev);static inline u32 ether_crc(int length, unsigned char *data);static void set_rx_mode(struct net_device *dev);/* A list of all installed RTL8129 devices, for removing the driver module. */static struct net_device *root_rtl8129_dev = NULL;static int CPFlag = 0;#ifndef MODULEint rtl8139_probe(struct net_device *dev){	static int did_version = 0;			/* Already printed version info. */	if (debug > 0  &&  did_version++ == 0)		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);	return pci_drv_register(&rtl8139_drv_id, dev);}#endifstatic void *rtl8139_probe1(struct pci_dev *pdev, void *init_dev,							long ioaddr, int irq, int chip_idx, int found_cnt){	struct net_device *dev;	struct rtl8129_private *np;	void *priv_mem;	int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0;	long tmp;	dev = init_etherdev(init_dev, 0);	tmp = inl(ioaddr + TxConfig);	tmp = ( (tmp&0x7c000000) + ( (tmp&0x00800000)<<2 ) )>>24;	if (tmp == CPlus8139Version){		pci_tbl[chip_idx].name = "Realtek RTL8139C+ Fast Ethernet";#ifndef FORCE_8139CP_TO_C_MODE		CPFlag=1;#else		printk(KERN_INFO "%s: %s Forced in C Mode\n", dev->name, pci_tbl[chip_idx].name);#endif	}	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",		   dev->name, pci_tbl[chip_idx].name, ioaddr, irq);	/* Bring the chip out of low-power mode. */	outb(0x00, ioaddr + Config1);	{		int addr_len = read_eeprom(ioaddr, 0, 8) == 0x8129 ? 8 : 6;		for (i = 0; i < 3; i++)			((u16 *)(dev->dev_addr))[i] =				le16_to_cpu(read_eeprom(ioaddr, i+7, addr_len));	}	for (i = 0; i < 5; i++)		printk("%2.2x:", dev->dev_addr[i]);	printk("%2.2x.\n", dev->dev_addr[i]);	/* Make certain elements e.g. descriptor lists are aligned. */	priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);	/* Check for the very unlikely case of no memory. */	if (priv_mem == NULL)		return NULL;	/* We do a request_region() to register /proc/ioports info. */	request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);	dev->base_addr = ioaddr;	dev->irq = irq;	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_rtl8129_dev;	root_rtl8129_dev = dev;	np->pci_dev = pdev;	np->chip_id = chip_idx;	np->drv_flags = pci_tbl[chip_idx].drv_flags;	/* Find the connected MII xcvrs.	   Doing this in open() would allow detecting external xcvrs later, but	   takes too much time. */	if (np->drv_flags & HAS_MII_XCVR) {		int phy, phy_idx;		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(np->phys);			 phy++) {			int mii_status = mdio_read(dev, phy, 1);			if (mii_status != 0xffff  && mii_status != 0x0000) {				np->phys[phy_idx++] = phy;				printk(KERN_INFO "%s: MII transceiver found at address %d.\n",					   dev->name, phy);			}		}		if (phy_idx == 0) {			printk(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "				   "transceiver.\n",				   dev->name);			np->phys[0] = -1;		}	} else		np->phys[0] = 32;	/* Put the chip into low-power mode. */	outb(Cfg9346_Unlock, ioaddr + Cfg9346);	outb(0x03, ioaddr + Config1);	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */	np->AutoNegoAbility = option&0xF;//////////////////////////////////////////////////////////////	if( CPFlag == 1 ){	   if (option > 0) {			switch(np->AutoNegoAbility){		case 1: outw(AutoNegoAbility10half, ioaddr + NWayAdvert); break;		case 2: outw(AutoNegoAbility10full, ioaddr + NWayAdvert); break;		case 4: outw(AutoNegoAbility100half, ioaddr + NWayAdvert); break;		case 8: outw(AutoNegoAbility100full, ioaddr + NWayAdvert); break;		default: break;		}		outw( AutoNegotiationEnable|AutoNegotiationRestart, ioaddr + BasicModeCtrl);		printk(KERN_INFO "%s: Forcing %dMbs %s-duplex operation.\n",			   dev->name,			   (option & 0x0C ? 100 : 10),			   (option & 0x0A ? "full" : "half"));	   }	   else{		outw( AutoNegoAbility10half | AutoNegoAbility10full 			| AutoNegoAbility100half | AutoNegoAbility100full, ioaddr + NWayAdvert);		outw( AutoNegotiationEnable|AutoNegotiationRestart, ioaddr + BasicModeCtrl);	   }	} //end of if(CPFlag==1)//////////////////////////////////////////////////////////////	/* The lower four bits are the media type. */	if (option > 0) {		np->full_duplex = (option & 0x210) ? 1 : 0;		np->default_port = option & 0xff;		if (np->default_port)			np->medialock = 1;	}	if (found_cnt < MAX_UNITS  &&  full_duplex[found_cnt] > 0)		np->full_duplex = full_duplex[found_cnt];	if (np->full_duplex) {		printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);		/* Changing the MII-advertised media because might prevent		   re-connection. */		np->duplex_lock = 1;	}	if (np->default_port && (CPFlag != 1)) {		printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",			   (option & 0x20 ? 100 : 10),			   (option & 0x10 ? "full" : "half"));		mdio_write(dev, np->phys[0], 0,				   ((option & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */				   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */	}	if(CPFlag == 1){		dev->open = &rtl8139cp_open;		dev->hard_start_xmit = &rtl8139cp_start_xmit;	}	else{		dev->open = &rtl8129_open;		dev->hard_start_xmit = &rtl8129_start_xmit;	}	/* The Rtl8129-specific entries in the device structure. */	dev->stop = &rtl8129_close;	dev->get_stats = &rtl8129_get_stats;	dev->set_multicast_list = &set_rx_mode;	dev->do_ioctl = &mii_ioctl;	return dev;}/* Serial EEPROM section. *//*  EEPROM_Ctrl bits. */#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */#define EE_CS			0x08	/* EEPROM chip select. */#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */#define EE_WRITE_0		0x00#define EE_WRITE_1		0x02#define EE_DATA_READ	0x01	/* EEPROM chip data out. */#define EE_ENB			(0x80 | EE_CS)/* Delay between EEPROM clock transitions.   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. */#define eeprom_delay()	inl(ee_addr)/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD	(5)#define EE_READ_CMD		(6)#define EE_ERASE_CMD	(7)static int read_eeprom(long ioaddr, int location, int addr_len){	int i;	unsigned retval = 0;	long ee_addr = ioaddr + Cfg9346;	int read_cmd = location | (EE_READ_CMD << addr_len);	outb(EE_ENB & ~EE_CS, ee_addr);	outb(EE_ENB, ee_addr);	/* Shift the read command bits out. */	for (i = 4 + addr_len; i >= 0; i--) {		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;		outb(EE_ENB | dataval, ee_addr);		eeprom_delay();		outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);		eeprom_delay();	}	outb(EE_ENB, ee_addr);	eeprom_delay();	for (i = 16; i > 0; i--) {		outb(EE_ENB | EE_SHIFT_CLK, ee_addr);		eeprom_delay();		retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);		outb(EE_ENB, ee_addr);		eeprom_delay();	}	/* Terminate the EEPROM access. */	outb(~EE_CS, ee_addr);	return retval;}/* MII serial management: mostly bogus for now. *//* Read and write the MII management registers using software-generated   serial MDIO protocol.   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually   met by back-to-back PCI I/O cycles, but we insert a delay to avoid   "overclocking" issues. */#define MDIO_DIR		0x80#define MDIO_DATA_OUT	0x04#define MDIO_DATA_IN	0x02#define MDIO_CLK		0x01#define MDIO_WRITE0 (MDIO_DIR)#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)#define mdio_delay()	inb(mdio_addr)static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert,								 NWayLPAR, NWayExpansion, 0 };/* Syncronize the MII management interface by shifting 32 one bits out. */static void mdio_sync(long mdio_addr){	int i;	for (i = 32; i >= 0; i--) {		outb(MDIO_WRITE1, mdio_addr);		mdio_delay();		outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr);		mdio_delay();	}	return;}static int mdio_read(struct net_device *dev, int phy_id, int location){	long mdio_addr = dev->base_addr + MII_SMI;	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;	int retval = 0;	int i;	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */		return location < 8 && mii_2_8139_map[location] ?			inw(dev->base_addr + mii_2_8139_map[location]) : 0;	}	mdio_sync(mdio_addr);	/* Shift the read command bits out. */	for (i = 15; i >= 0; i--) {		int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;		outb(MDIO_DIR | dataval, mdio_addr);		mdio_delay();		outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr);		mdio_delay();	}	/* Read the two transition, 16 data, and wire-idle bits. */	for (i = 19; i > 0; i--) {		outb(0, mdio_addr);		mdio_delay();		retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0);		outb(MDIO_CLK, mdio_addr);		mdio_delay();	}	return (retval>>1) & 0xffff;}static void mdio_write(struct net_device *dev, int phy_id, int location, int value){	long mdio_addr = dev->base_addr + MII_SMI;	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;	int i;	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */		if (location < 8  &&  mii_2_8139_map[location])			outw(value, dev->base_addr + mii_2_8139_map[location]);		return;	}	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;		outb(dataval, mdio_addr);		mdio_delay();		outb(dataval | MDIO_CLK, mdio_addr);		mdio_delay();	}	/* Clear out extra bits. */	for (i = 2; i > 0; i--) {		outb(0, mdio_addr);		mdio_delay();		outb(MDIO_CLK, mdio_addr);		mdio_delay();	}	return;}static int rtl8139cp_open(struct net_device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	int i;	u8 diff;	u32 txPhyAddr, rxPhyAddr;	if( !(inb(ioaddr + MediaStatus) & LINK_Status) )		printk(KERN_INFO 			"%s: Realtek RTL8139C+ Fast Ethernet: %sMbs %s-duplex operation Link OK\n",			dev->name,			inb(ioaddr + MediaStatus) & SPEED_10_Bit ? "10" : "100",			inw(ioaddr + BasicModeCtrl) & Duplex_Mode ? "full" : "half");//	else//		printk(KERN_INFO "%s: Realtek RTL8139C+ Fast Ethernet Link Failed!\n", dev->name);		/* Soft reset the chip. */	outb(CmdReset, ioaddr + ChipCmd);	MOD_INC_USE_COUNT;	if (request_irq(dev->irq, &rtl8139CP_interrupt, SA_SHIRQ, dev->name, dev)) {		MOD_DEC_USE_COUNT;		return -EAGAIN;	}	tp->txDescArrays= kmalloc(NUM_CP_TX_DESC*sizeof(struct CPlusTxDesc)+256 ,						  GFP_KERNEL);		if (tp->txDescArrays == NULL) {		printk(KERN_ERR "%s: Couldn't allocate a %d byte tx ring.\n",				   dev->name, NUM_CP_TX_DESC*sizeof(struct CPlusTxDesc));		MOD_DEC_USE_COUNT;		return -ENOMEM;	}		// Tx Desscriptor needs 256 bytes alignment;	txPhyAddr=virt_to_bus(tp->txDescArrays);	diff=txPhyAddr-((txPhyAddr >> 8)<< 8);	diff=256-diff;	txPhyAddr +=diff;	tp->txDescArray = (struct CPlusTxDesc *)(tp->txDescArrays + diff);	tp->rxDescArrays= kmalloc(NUM_CP_RX_DESC*sizeof(struct CPlusRxDesc)+256 ,						  GFP_KERNEL);		if (tp->rxDescArrays == NULL) {		printk(KERN_ERR "%s: Couldn't allocate a %d byte rx ring.\n",				   dev->name, NUM_CP_RX_DESC*sizeof(struct CPlusRxDesc));		MOD_DEC_USE_COUNT;		return -ENOMEM;	}		// Rx Desscriptor needs 256 bytes alignment;	rxPhyAddr=virt_to_bus(tp->rxDescArrays);

⌨️ 快捷键说明

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