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

📄 ether82557.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
miir(Ctlr* ctlr, int phyadd, int regadd){	int mcr, timo;	csr32w(ctlr, Mcr, MDIread|(phyadd<<21)|(regadd<<16));	mcr = 0;	for(timo = 64; timo; timo--){		mcr = csr32r(ctlr, Mcr);		if(mcr & MDIready)			break;		microdelay(1);	}	if(mcr & MDIready)		return mcr & 0xFFFF;	return -1;}static intmiiw(Ctlr* ctlr, int phyadd, int regadd, int data){	int mcr, timo;	csr32w(ctlr, Mcr, MDIwrite|(phyadd<<21)|(regadd<<16)|(data & 0xFFFF));	mcr = 0;	for(timo = 64; timo; timo--){		mcr = csr32r(ctlr, Mcr);		if(mcr & MDIready)			break;		microdelay(1);	}	if(mcr & MDIready)		return 0;	return -1;}static inthy93c46r(Ctlr* ctlr, int r){	int data, i, op, size;	/*	 * Hyundai HY93C46 or equivalent serial EEPROM.	 * This sequence for reading a 16-bit register 'r'	 * in the EEPROM is taken straight from Section	 * 3.3.4.2 of the Intel 82557 User's Guide.	 */reread:	csr16w(ctlr, Ecr, EEcs);	op = EEstart|EEread;	for(i = 2; i >= 0; i--){		data = (((op>>i) & 0x01)<<2)|EEcs;		csr16w(ctlr, Ecr, data);		csr16w(ctlr, Ecr, data|EEsk);		microdelay(1);		csr16w(ctlr, Ecr, data);		microdelay(1);	}	/*	 * First time through must work out the EEPROM size.	 */	if((size = ctlr->eepromsz) == 0)		size = 8;	for(size = size-1; size >= 0; size--){		data = (((r>>size) & 0x01)<<2)|EEcs;		csr16w(ctlr, Ecr, data);		csr16w(ctlr, Ecr, data|EEsk);		delay(1);		csr16w(ctlr, Ecr, data);		microdelay(1);		if(!(csr16r(ctlr, Ecr) & EEdo))			break;	}	data = 0;	for(i = 15; i >= 0; i--){		csr16w(ctlr, Ecr, EEcs|EEsk);		microdelay(1);		if(csr16r(ctlr, Ecr) & EEdo)			data |= (1<<i);		csr16w(ctlr, Ecr, EEcs);		microdelay(1);	}	csr16w(ctlr, Ecr, 0);	if(ctlr->eepromsz == 0){		ctlr->eepromsz = 8-size;		ctlr->eeprom = malloc((1<<ctlr->eepromsz)*sizeof(ushort));		goto reread;	}	return data;}static voidi82557pci(void){	Pcidev *p;	Ctlr *ctlr;	p = nil;	while(p = pcimatch(p, 0x8086, 0)){		switch(p->did){		default:			continue;		case 0x1031:		/* Intel 82562EM */		case 0x1050:		/* Intel 82562EZ */		case 0x1039:		/* Intel 82801BD PRO/100 VE */		case 0x103A:		/* Intel 82562 PRO/100 VE */		case 0x1064:		/* Intel 82562 PRO/100 VE */		case 0x2449:		/* Intel 82562ET */		case 0x1209:		/* Intel 82559ER */		case 0x1229:		/* Intel 8255[789] */		case 0x1030:		/* Intel 82559 InBusiness 10/100  */			break;		}		/*		 * bar[0] is the memory-mapped register address (4KB),		 * bar[1] is the I/O port register address (32 bytes) and		 * bar[2] is for the flash ROM (1MB).		 */		ctlr = malloc(sizeof(Ctlr));		ctlr->port = p->mem[1].bar & ~0x01;		ctlr->pcidev = p;		if(ctlrhead != nil)			ctlrtail->next = ctlr;		else			ctlrhead = ctlr;		ctlrtail = ctlr;		pcisetbme(p);	}}static voiddetach(Ether* ether){	Ctlr *ctlr;	ctlr = ether->ctlr;	csr32w(ctlr, Port, 0);	delay(1);	while(csr8r(ctlr, CommandR))		;}static intscanphy(Ctlr* ctlr){	int i, oui, x;	for(i = 0; i < 32; i++){		if((oui = miir(ctlr, i, 2)) == -1 || oui == 0 || oui == 0xFFFF)			continue;		oui <<= 6;		x = miir(ctlr, i, 3);		oui |= x>>10;		//print("phy%d: oui %uX reg1 %uX\n", i, oui, miir(ctlr, i, 1));		if(oui == 0xAA00)			ctlr->eeprom[6] = 0x07<<8;		else if(oui == 0x80017){			if(x & 0x01)				ctlr->eeprom[6] = 0x0A<<8;			else				ctlr->eeprom[6] = 0x04<<8;		}		return i;	}	return -1;}inti82557reset(Ether* ether){	int anar, anlpar, bmcr, bmsr, force, i, phyaddr, x;	unsigned short sum;	Block *bp;	uchar ea[Eaddrlen];	Ctlr *ctlr;	Cb *cb;	if(ctlrhead == nil)		i82557pci();	/*	 * Any adapter matches if no ether->port is supplied,	 * otherwise the ports must match.	 */	for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){		if(ctlr->active)			continue;		if(ether->port == 0 || ether->port == ctlr->port){			ctlr->active = 1;			break;		}	}	if(ctlr == nil)		return -1;	/*	 * Initialise the Ctlr structure.	 * Perform a software reset after which need to ensure busmastering	 * is still enabled. The EtherExpress PRO/100B appears to leave	 * the PCI configuration alone (see the 'To do' list above) so punt	 * for now.	 * Load the RUB and CUB registers for linear addressing (0).	 */	ether->ctlr = ctlr;	ether->port = ctlr->port;	ether->irq = ctlr->pcidev->intl;	ether->tbdf = ctlr->pcidev->tbdf;	ctlr->ctlrno = ether->ctlrno;	ctlr->type = ether->type;	csr32w(ctlr, Port, 0);	delay(1);	while(csr8r(ctlr, CommandR))		;	csr32w(ctlr, Pointer, 0);	csr8w(ctlr, CommandR, LoadRUB);	while(csr8r(ctlr, CommandR))		;	csr8w(ctlr, CommandR, LoadCUB);	/*	 * Initialise the action and receive frame areas.	 */	ctlrinit(ctlr);	/*	 * Read the EEPROM.	 * Do a dummy read first to get the size	 * and allocate ctlr->eeprom.	 */	hy93c46r(ctlr, 0);	sum = 0;	for(i = 0; i < (1<<ctlr->eepromsz); i++){		x = hy93c46r(ctlr, i);		ctlr->eeprom[i] = x;		sum += x;	}	if(sum != 0xBABA)		print("#l%d: EEPROM checksum - 0x%4.4uX\n", ether->ctlrno, sum);	/*	 * Eeprom[6] indicates whether there is a PHY and whether	 * it's not 10Mb-only, in which case use the given PHY address	 * to set any PHY specific options and determine the speed.	 * Unfortunately, sometimes the EEPROM is blank except for	 * the ether address and checksum; in this case look at the	 * controller type and if it's am 82558 or 82559 it has an	 * embedded PHY so scan for that.	 * If no PHY, assume 82503 (serial) operation.	 */	if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000))		phyaddr = ctlr->eeprom[6] & 0x00FF;	else	switch(ctlr->pcidev->rid){	case 0x01:			/* 82557 A-step */	case 0x02:			/* 82557 B-step */	case 0x03:			/* 82557 C-step */	default:		phyaddr = -1;		break;	case 0x04:			/* 82558 A-step */	case 0x05:			/* 82558 B-step */	case 0x06:			/* 82559 A-step */	case 0x07:			/* 82559 B-step */	case 0x08:			/* 82559 C-step */	case 0x09:			/* 82559ER A-step */		phyaddr = scanphy(ctlr);		break;	}	if(phyaddr >= 0){		/*		 * Resolve the highest common ability of the two		 * link partners. In descending order:		 *	0x0100		100BASE-TX Full Duplex		 *	0x0200		100BASE-T4		 *	0x0080		100BASE-TX		 *	0x0040		10BASE-T Full Duplex		 *	0x0020		10BASE-T		 */		anar = miir(ctlr, phyaddr, 0x04);		anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0;		anar &= anlpar;		bmcr = 0;		if(anar & 0x380)			bmcr = 0x2000;		if(anar & 0x0140)			bmcr |= 0x0100;		switch((ctlr->eeprom[6]>>8) & 0x001F){		case 0x04:				/* DP83840 */		case 0x0A:				/* DP83840A */			/*			 * The DP83840[A] requires some tweaking for			 * reliable operation.			 * The manual says bit 10 should be unconditionally			 * set although it supposedly only affects full-duplex			 * operation (an & 0x0140).			 */			x = miir(ctlr, phyaddr, 0x17) & ~0x0520;			x |= 0x0420;			for(i = 0; i < ether->nopt; i++){				if(cistrcmp(ether->opt[i], "congestioncontrol"))					continue;				x |= 0x0100;				break;			}			miiw(ctlr, phyaddr, 0x17, x);			/*			 * If the link partner can't autonegotiate, determine			 * the speed from elsewhere.			 */			if(anlpar == 0){				miir(ctlr, phyaddr, 0x01);				bmsr = miir(ctlr, phyaddr, 0x01);				x = miir(ctlr, phyaddr, 0x19);				if((bmsr & 0x0004) && !(x & 0x0040))					bmcr = 0x2000;			}			break;		case 0x07:				/* Intel 82555 */			/*			 * Auto-negotiation may fail if the other end is			 * a DP83840A and the cable is short.			 */			bmsr = miir(ctlr, phyaddr, 0x01);			if((miir(ctlr, phyaddr, 0) & 0x1000) && !(bmsr & 0x0020)){				miiw(ctlr, phyaddr, 0x1A, 0x2010);				x = miir(ctlr, phyaddr, 0);				miiw(ctlr, phyaddr, 0, 0x0200|x);				for(i = 0; i < 3000; i++){					delay(1);					if(miir(ctlr, phyaddr, 0x01) & 0x0020)						break;				}				miiw(ctlr, phyaddr, 0x1A, 0x2000);									anar = miir(ctlr, phyaddr, 0x04);				anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0;				anar &= anlpar;				bmcr = 0;				if(anar & 0x380)					bmcr = 0x2000;				if(anar & 0x0140)					bmcr |= 0x0100;			}			break;		}		/*		 * Force speed and duplex if no auto-negotiation.		 */		if(anlpar == 0){			force = 0;			for(i = 0; i < ether->nopt; i++){				if(cistrcmp(ether->opt[i], "fullduplex") == 0){					force = 1;					bmcr |= 0x0100;					ctlr->configdata[19] |= 0x40;				}				else if(cistrcmp(ether->opt[i], "speed") == 0){					force = 1;					x = strtol(&ether->opt[i][6], 0, 0);					if(x == 10)						bmcr &= ~0x2000;					else if(x == 100)						bmcr |= 0x2000;					else						force = 0;				}			}			if(force)				miiw(ctlr, phyaddr, 0x00, bmcr);		}		ctlr->configdata[8] = 1;		ctlr->configdata[15] &= ~0x80;	}	else{		ctlr->configdata[8] = 0;		ctlr->configdata[15] |= 0x80;	}	/*	 * Load the chip configuration	 */	configure(ether, 0);	/*	 * Check if the adapter's station address is to be overridden.	 * If not, read it from the EEPROM and set in ether->ea prior to loading	 * the station address with the Individual Address Setup command.	 */	memset(ea, 0, Eaddrlen);	if(memcmp(ea, ether->ea, Eaddrlen) == 0){		for(i = 0; i < Eaddrlen/2; i++){			x = ctlr->eeprom[i];			ether->ea[2*i] = x & 0xFF;			ether->ea[2*i+1] = (x>>8) & 0xFF;		}	}	bp = allocb(sizeof(Cb));	cb = (Cb*)bp->rp;	bp->wp += sizeof(Cb);	cb->command = CbIAS;	cb->link = NullPointer;	memmove(cb->data, ether->ea, Eaddrlen);	action(ctlr, bp);	/*	 * Linkage to the generic ethernet driver.	 */	ether->attach = attach;	ether->transmit = transmit;	ether->interrupt = interrupt;	ether->detach = detach;	return 0;}

⌨️ 快捷键说明

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