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

📄 etherelnk3.c

📁 著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是bell实验室开发的Unix后继者。
💻 C
📖 第 1 页 / 共 3 页
字号:
		tcmadapter(port, irq, BUSUNKNOWN);	}}static voidtcm5XXeisa(void){	ushort x;	int irq, port, slot;	/*	 * Check if this is an EISA machine.	 * If not, nothing to do.	 */	if(strncmp((char*)(KZERO|0xFFFD9), "EISA", 4))		return;	/*	 * Continue through the EISA slots looking for a match on both	 * 3COM as the manufacturer and 3C579-* or 3C59[27]-* as the product.	 * If an adapter is found, select window 0, enable it and clear	 * out any lingering status and interrupts.	 */	for(slot = 1; slot < MaxEISA; slot++){		port = slot*0x1000;		if(ins(port+0xC80+ManufacturerID) != 0x6D50)			continue;		x = ins(port+0xC80+ProductID);		if((x & 0xF0FF) != 0x9050 && (x & 0xFF00) != 0x5900)			continue;		COMMAND(port, SelectRegisterWindow, Wsetup);		outs(port+ConfigControl, Ena);		txrxreset(port);		COMMAND(port, AcknowledgeInterrupt, 0xFF);		irq = (ins(port+ResourceConfig)>>12) & 0x0F;		tcmadapter(port, irq, BUSUNKNOWN);	}}static voidtcm59Xpci(void){	Pcidev *p;	int irq, port;	p = nil;	while(p = pcimatch(p, 0x10B7, 0)){		port = p->mem[0].bar & ~0x01;		irq = p->intl;		COMMAND(port, GlobalReset, 0);		while(STATUS(port) & commandInProgress)			;		tcmadapter(port, irq, p->tbdf);	}}static char* tcmpcmcia[] = {	"3C589",			/* 3COM 589[ABCD] */	"3C562",			/* 3COM 562 */	"589E",				/* 3COM Megahertz 589E */	nil,};static inttcm5XXpcmcia(Ether* ether){	int i;	for(i = 0; tcmpcmcia[i] != nil; i++){		if(!cistrcmp(ether->type, tcmpcmcia[i]))			return ether->port;	}	return 0;}static voidsetxcvr(int port, int xcvr, int is9){	int x;	if(is9){		COMMAND(port, SelectRegisterWindow, Wsetup);		x = ins(port+AddressConfig) & ~xcvrMask9;		x |= (xcvr>>20)<<14;		outs(port+AddressConfig, x);	}	else{		COMMAND(port, SelectRegisterWindow, Wfifo);		x = inl(port+InternalConfig) & ~xcvrMask;		x |= xcvr;		outl(port+InternalConfig, x);	}	txrxreset(port);}static voidsetfullduplex(int port){	int x;	COMMAND(port, SelectRegisterWindow, Wfifo);	x = ins(port+MacControl);	outs(port+MacControl, fullDuplexEnable|x);	txrxreset(port);}static intmiimdi(int port, int n){	int data, i;	/*	 * Read n bits from the MII Management Register.	 */	data = 0;	for(i = n-1; i >= 0; i--){		if(ins(port) & mgmtData)			data |= (1<<i);		microdelay(1);		outs(port, mgmtClk);		microdelay(1);		outs(port, 0);		microdelay(1);	}	return data;}static voidmiimdo(int port, int bits, int n){	int i, mdo;	/*	 * Write n bits to the MII Management Register.	 */	for(i = n-1; i >= 0; i--){		if(bits & (1<<i))			mdo = mgmtDir|mgmtData;		else			mdo = mgmtDir;		outs(port, mdo);		microdelay(1);		outs(port, mdo|mgmtClk);		microdelay(1);		outs(port, mdo);		microdelay(1);	}}static intmiir(int port, int phyad, int regad){	int data, w;	w = (STATUS(port)>>13) & 0x07;	COMMAND(port, SelectRegisterWindow, Wdiagnostic);	port += PhysicalMgmt;	/*	 * Preamble;	 * ST+OP+PHYAD+REGAD;	 * TA + 16 data bits.	 */	miimdo(port, 0xFFFFFFFF, 32);	miimdo(port, 0x1800|(phyad<<5)|regad, 14);	data = miimdi(port, 18);	port -= PhysicalMgmt;	COMMAND(port, SelectRegisterWindow, w);	if(data & 0x10000)		return -1;	return data & 0xFFFF;}static intautoselect(int port, int is9){	int media, x;	/*	 * Pathetic attempt at automatic media selection.	 * Really just to get the Fast Etherlink 10BASE-T/100BASE-TX	 * cards operational.	 * It's a bonus if it works for anything else.	 */	if(is9){		COMMAND(port, SelectRegisterWindow, Wsetup);		x = ins(port+ConfigControl);		media = 0;		if(x & base10TAvailable9)			media |= base10TAvailable;		if(x & coaxAvailable9)			media |= coaxAvailable;		if(x & auiAvailable9)			media |= auiAvailable;	}	else{		COMMAND(port, SelectRegisterWindow, Wfifo);		media = ins(port+ResetOptions);	}	if(media & miiConnector)		return xcvrMii;	if(media & baseTXAvailable){		/*		 * Must have InternalConfig register.		 */		setxcvr(port, xcvr100BaseTX, is9);		COMMAND(port, SelectRegisterWindow, Wdiagnostic);		x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);		outs(port+MediaStatus, linkBeatEnable|x);		delay(10);		if(ins(port+MediaStatus) & linkBeatDetect)			return xcvr100BaseTX;		outs(port+MediaStatus, x);	}	if(media & base10TAvailable){		setxcvr(port, xcvr10BaseT, is9);		COMMAND(port, SelectRegisterWindow, Wdiagnostic);		x = ins(port+MediaStatus) & ~dcConverterEnabled;		outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x);		delay(10);		if(ins(port+MediaStatus) & linkBeatDetect)			return xcvr10BaseT;		outs(port+MediaStatus, x);	}	/*	 * Botch.	 */	return autoSelect;}static inteepromdata(int port, int offset){	COMMAND(port, SelectRegisterWindow, Wsetup);	while(EEPROMBUSY(port))		;	EEPROMCMD(port, EepromReadRegister, offset);	while(EEPROMBUSY(port))		;	return EEPROMDATA(port);}intelnk3reset(Ether* ether){	int anar, anlpar, busmaster, did, i, phyaddr, phystat, port, rxearly, rxstatus9, timeo, x, xcvr;	Block *bp, **bpp;	Adapter *ap;	uchar ea[Eaddrlen];	Ctlr *ctlr;	static int scandone;	/*	 * Scan for adapter on PCI, EISA and finally	 * using the little ISA configuration dance.	 */	if(scandone == 0){		tcm59Xpci();		tcm5XXeisa();		tcm509isa();		scandone = 1;	}	/*	 * Any adapter matches if no ether->port is supplied,	 * otherwise the ports must match.	 */	port = 0;	bpp = &adapter;	for(bp = *bpp; bp; bp = bp->next){		ap = (Adapter*)bp->rp;		if(ether->port == 0 || ether->port == ap->port){			port = ap->port;			ether->irq = ap->irq;			ether->tbdf = ap->tbdf;			*bpp = bp->next;			freeb(bp);			break;		}		bpp = &bp->next;	}	if(port == 0 && (port = tcm5XXpcmcia(ether)) == 0)		return -1;	/*	 * Read the DeviceID from the EEPROM, it's at offset 0x03,	 * and do something depending on capabilities.	 */	switch(did = eepromdata(port, 0x03)){	case 0x9000:	case 0x9001:	case 0x9005:	case 0x9050:	case 0x9051:	case 0x9055:		if(BUSTYPE(ether->tbdf) != BusPCI)			goto buggery;		busmaster = 2;		goto vortex;	case 0x5900:	case 0x5920:	case 0x5950:	case 0x5951:	case 0x5952:	case 0x5970:	case 0x5971:	case 0x5972:		busmaster = 0;	vortex:		COMMAND(port, SelectRegisterWindow, Wfifo);		xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask);		rxearly = 8188;		rxstatus9 = 0;		break;	buggery:	default:		busmaster = 0;		COMMAND(port, SelectRegisterWindow, Wsetup);		x = ins(port+AddressConfig);		xcvr = ((x & xcvrMask9)>>14)<<20;		if(x & autoSelect9)			xcvr |= autoSelect;		rxearly = 2044;		rxstatus9 = 1;		break;	}	USED(did);	/*	 * 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 in Wstation. The EEPROM returns 16-bits at a time.	 */	memset(ea, 0, Eaddrlen);	if(memcmp(ea, ether->ea, Eaddrlen) == 0){if(debug) print("copy eaddr from eeprom...");		for(i = 0; i < Eaddrlen/2; i++){			x = eepromdata(port, i);			ether->ea[2*i] = x>>8;			ether->ea[2*i+1] = x;		}	}	COMMAND(port, SelectRegisterWindow, Wstation);	for(i = 0; i < Eaddrlen; i++)		outb(port+i, ether->ea[i]);	/*	 * Enable the transceiver if necessary.	 *//* * forgive me, but i am weak */if(did == 0x9055)    xcvr = xcvrMii;else	if(xcvr & autoSelect)		xcvr = autoselect(port, rxstatus9);	switch(xcvr){	case xcvrMii:		/*		 * Quick hack.		 */		phyaddr = 24;		for(timeo = 0; timeo < 30; timeo++){			phystat = miir(port, phyaddr, 0x01);			if(phystat & 0x20)				break;			delay(100);		}		anar = miir(port, phyaddr, 0x04);		anlpar = miir(port, phyaddr, 0x05) & 0x03E0;		anar &= anlpar;		for(i = 0; i < ether->nopt; i++){			if(cistrcmp(ether->opt[i], "fullduplex") == 0)				anar |= 0x0100;			else if(cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)				anar |= 0x0100;			else if(cistrcmp(ether->opt[i], "force100") == 0)				anar |= 0x0080;		}		if(anar & 0x0100)		/* 100BASE-TXFD */			setfullduplex(port);		else if(anar & 0x0200)		/* 100BASE-T4 */			;		else if(anar & 0x0080)		/* 100BASE-TX */			;		else if(anar & 0x0040)		/* 10BASE-TFD */			setfullduplex(port);		else				/* 10BASE-T */			;	case xcvr100BaseTX:	case xcvr100BaseFX:		COMMAND(port, SelectRegisterWindow, Wfifo);		x = inl(port+InternalConfig) & ~ramPartitionMask;		outl(port+InternalConfig, x|ramPartition1to1);		COMMAND(port, SelectRegisterWindow, Wdiagnostic);		x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable);		x |= linkBeatEnable;		outs(port+MediaStatus, x);		break;	case xcvr10BaseT:		/*		 * Enable Link Beat and Jabber to start the		 * transceiver.		 */		COMMAND(port, SelectRegisterWindow, Wdiagnostic);		x = ins(port+MediaStatus) & ~dcConverterEnabled;		x |= linkBeatEnable|jabberGuardEnable;		outs(port+MediaStatus, x);		if((did & 0xFF00) == 0x5900)			busmaster = 0;		break;	case xcvr10Base2:		COMMAND(port, SelectRegisterWindow, Wdiagnostic);		x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable);		outs(port+MediaStatus, x);		/*		 * Start the DC-DC converter.		 * Wait > 800 microseconds.		 */		COMMAND(port, EnableDcConverter, 0);		delay(1);		break;	}	/*	 * Wop is the normal operating register set.	 * The 3C59[0257] adapters allow access to more than one register window	 * at a time, but there are situations where switching still needs to be	 * done, so just do it.	 * Clear out any lingering Tx status.	 */	COMMAND(port, SelectRegisterWindow, Wop);	while(inb(port+TxStatus))		outb(port+TxStatus, 0);	/*	 * Allocate a controller structure and start	 * to initialise it.	 */	ether->ctlr = malloc(sizeof(Ctlr));	ctlr = ether->ctlr;	memset(ctlr, 0, sizeof(Ctlr));	ctlr->busmaster = busmaster;	ctlr->xcvr = xcvr;	ctlr->rxstatus9 = rxstatus9;	ctlr->rxearly = rxearly;	if(rxearly >= 2048)		ctlr->ts = 2;	/*	 * Allocate any receive buffers.	 */	if(ctlr->busmaster == 2){		/*		 * 10MUpldBug.		 * Disabling is too severe, can use receive busmastering at		 * 100Mbps OK, but how to tell which rate is actually being used -		 * the 3c905 always seems to have dataRate100 set?		 * Believe the bug doesn't apply if upRxEarlyEnable is set		 * and the threshold is set such that uploads won't start		 * until the whole packet has been received.		 */		x = eepromdata(port, 0x0F);		if(!(x & 0x01))			outl(port+PktStatus, upRxEarlyEnable);		ctlr->nup = Nup;		ctlr->ndn = Ndn;		init905(ctlr);		outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256));	}	/*	 * Set a base TxStartThresh which will be incremented	 * if any txUnderrun errors occur and ensure no RxEarly	 * interrupts happen.	 */	ctlr->txthreshold = ETHERMAXTU/2;	COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts);	COMMAND(port, SetRxEarlyThresh, rxearly>>ctlr->ts);	/*	 * Set up the software configuration.	 */	ether->port = port;	ether->attach = attach;	ether->transmit = transmit;	ether->interrupt = interrupt;	ether->detach = detach;	return 0;}

⌨️ 快捷键说明

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