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

📄 etherelnk3.c

📁 著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是bell实验室开发的Unix后继者。
💻 C
📖 第 1 页 / 共 3 页
字号:
	 * Free any completed packets.	 */	pd = ctlr->dntail;	while(ctlr->dnq){		if(PADDR(&pd->np) == inl(port+DnListPtr))			break;		ctlr->dnq--;		pd = pd->next;	}	ctlr->dntail = pd;	stalled = 0;	while(ctlr->dnq < (ctlr->ndn-1)){		tb = &ether->tb[ether->ti];		if(tb->owner != Interface)			break;		pd = ctlr->dnhead->next;		pd->np = 0;		pd->control = dnIndicate|tb->len;		memmove(pd->vaddr, tb->pkt, tb->len);		pd->len = updnLastFrag|tb->len;		tb->owner = Host;		ether->ti = NEXT(ether->ti, ether->ntb);		if(stalled == 0 && ctlr->dnq && inl(port+DnListPtr)){			COMMAND(port, Stall, dnStall);			for(timeo = 100; (STATUS(port) & commandInProgress) && timeo; timeo--)				;			if(timeo == 0)				print("#l%d: dnstall %d\n", ether->ctlrno, timeo);			stalled = 1;		}		ctlr->dnhead->np = PADDR(&pd->np);		ctlr->dnhead->control &= ~dnIndicate;		ctlr->dnhead = pd;		if(ctlr->dnq == 0)			ctlr->dntail = pd;		ctlr->dnq++;	}	/*	 * If the adapter is not currently processing anything	 * and there is something on the queue, start it processing.	 */	if(inl(port+DnListPtr) == 0 && ctlr->dnq)		outl(port+DnListPtr, PADDR(&ctlr->dnhead->np));	if(stalled)		COMMAND(port, Stall, dnUnStall);}static voidtransmit(Ether* ether){	Ctlr *ctlr;	int port, w;	port = ether->port;	ctlr = ether->ctlr;	ilock(&ctlr->wlock);	if(ctlr->busmaster == 2)		txstart905(ether);	else{		w = (STATUS(port)>>13) & 0x07;		COMMAND(port, SelectRegisterWindow, Wop);		txstart(ether);		COMMAND(port, SelectRegisterWindow, w);	}	iunlock(&ctlr->wlock);}static voidreceive905(Ether* ether){	Ctlr *ctlr;	int len, port;	Pd *pd;	RingBuf *rb;	ctlr = ether->ctlr;	port = ether->port;	for(pd = ctlr->uphead; pd->control & upPktComplete; pd = pd->next){		if(!(pd->control & upError)){			rb = &ether->rb[ether->ri];			if(rb->owner == Interface){				len = pd->control & rxBytes;				rb->len = len;				memmove(rb->pkt, pd->vaddr, len);				rb->owner = Host;				ether->ri = NEXT(ether->ri, ether->nrb);			}		}		pd->control = 0;		COMMAND(port, Stall, upUnStall);	}	ctlr->uphead = pd;}static voidreceive(Ether* ether){	int len, port, rxstatus;	RingBuf *rb;	port = ether->port;	if(debug) print("receive...");	while(((rxstatus = ins(port+RxStatus)) & rxIncomplete) == 0){		/*		 * If there was an error, throw it away and continue.		 * The 3C5[078]9 has the error info in the status register		 * and the 3C59[0257] implement a separate RxError register.		 */		if((rxstatus & rxError) == 0){			/*			 * Packet received. Read it into the next free			 * ring buffer, if any. Must read len bytes padded			 * to a doubleword, can be picked out 32-bits at			 * a time. The CRC is already stripped off.			 */			rb = &ether->rb[ether->ri];			if(rb->owner == Interface){				len = (rxstatus & rxBytes9);				rb->len = len;				insl(port+Fifo, rb->pkt, HOWMANY(len, 4));				rb->owner = Host;				ether->ri = NEXT(ether->ri, ether->nrb);			}elseif(debug) print("toss...");		}elseif(debug) print("error...");		/*		 * All done, discard the packet.		 */		COMMAND(port, RxDiscard, 0);		while(STATUS(port) & commandInProgress)			;	}}static voidstatistics(Ether* ether){	Ctlr *ctlr;	int i, port, w;	ctlr = ether->ctlr;	port = ether->port;	/*	 * 3C59[27] require a read between a PIO write and	 * reading a statistics register.	 */	w = (STATUS(port)>>13) & 0x07;	COMMAND(port, SelectRegisterWindow, Wstatistics);	STATUS(port);	for(i = 0; i < 0x0A; i++)		inb(port+i);	ins(port+BytesRcvdOk);	ins(port+BytesXmittedOk);	switch(ctlr->xcvr){	case xcvrMii:	case xcvr100BaseTX:	case xcvr100BaseFX:		COMMAND(port, SelectRegisterWindow, Wdiagnostic);		STATUS(port);		inb(port+BadSSD);		break;	}	COMMAND(port, SelectRegisterWindow, w);}static voidinterrupt(Ureg*, void* arg){	Ether *ether;	int port, status, s, w, x;	Ctlr *ctlr;	ether = arg;	port = ether->port;	ctlr = ether->ctlr;	w = (STATUS(port)>>13) & 0x07;	COMMAND(port, SelectRegisterWindow, Wop);	while((status = STATUS(port)) & (interruptMask|interruptLatch)){		if(status & hostError){			/*			 * Adapter failure, try to find out why, reset if			 * necessary. What happens if Tx is active and a reset			 * occurs, need to retransmit? This probably isn't right.			 */			COMMAND(port, SelectRegisterWindow, Wdiagnostic);			x = ins(port+FifoDiagnostic);			COMMAND(port, SelectRegisterWindow, Wop);			print("elnk3#%d: status 0x%uX, diag 0x%uX\n",			    ether->ctlrno, status, x);			if(x & txOverrun){				if(ctlr->busmaster == 0)					COMMAND(port, TxReset, 0);				else					COMMAND(port, TxReset, (updnReset|dmaReset));				COMMAND(port, TxEnable, 0);			}			if(x & rxUnderrun){				/*				 * This shouldn't happen...				 * Reset the receiver and restore the filter and RxEarly				 * threshold before re-enabling.				 * Need to restart any busmastering?				 */				COMMAND(port, SelectRegisterWindow, Wstate);				s = (port+RxFilter) & 0x000F;				COMMAND(port, SelectRegisterWindow, Wop);				COMMAND(port, RxReset, 0);				while(STATUS(port) & commandInProgress)					;				COMMAND(port, SetRxFilter, s);				COMMAND(port, SetRxEarlyThresh, ctlr->rxearly>>ctlr->ts);				COMMAND(port, RxEnable, 0);			}			status &= ~hostError;		}		if(status & (transferInt|rxComplete)){			receive(ether);			status &= ~(transferInt|rxComplete);		}		if(status & (upComplete)){			COMMAND(port, AcknowledgeInterrupt, upComplete);			receive905(ether);			status &= ~upComplete;		}		if(status & txComplete){			/*			 * Pop the TxStatus stack, accumulating errors.			 * Adjust the TX start threshold if there was an underrun.			 * If there was a Jabber or Underrun error, reset			 * the transmitter, taking care not to reset the dma logic			 * as a busmaster receive may be in progress.			 * For all conditions enable the transmitter.			 */			s = 0;			do{				if(x = inb(port+TxStatus))					outb(port+TxStatus, 0);				s |= x;			}while(STATUS(port) & txComplete);			if(s & txUnderrun){				if(ctlr->busmaster == 2){					while(inl(port+PktStatus) & dnInProg)						;				}				COMMAND(port, SelectRegisterWindow, Wdiagnostic);				while(ins(port+MediaStatus) & txInProg)					;				COMMAND(port, SelectRegisterWindow, Wop);				if(ctlr->txthreshold < ETHERMAXTU)					ctlr->txthreshold += ETHERMINTU;			}			/*			 * According to the manual, maxCollisions does not require			 * a TxReset, merely a TxEnable. However, evidence points to			 * it being necessary on the 3C905. The jury is still out.			 * On busy or badly configured networks maxCollisions can			 * happen frequently enough for messages to be annoying so			 * keep quiet about them by popular request.			 */			if(s & (txJabber|txUnderrun|maxCollisions)){				if(ctlr->busmaster == 0)					COMMAND(port, TxReset, 0);				else					COMMAND(port, TxReset, (updnReset|dmaReset));				while(STATUS(port) & commandInProgress)					;				COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts);				if(ctlr->busmaster == 2){					outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256));					status |= dnComplete;				}			}			if(s & ~(txStatusComplete|maxCollisions))				print("#l%d: txstatus 0x%uX, threshold %d\n",			    		ether->ctlrno, s, ctlr->txthreshold);			COMMAND(port, TxEnable, 0);			status &= ~txComplete;			status |= txAvailable;		}		if(status & txAvailable){			COMMAND(port, AcknowledgeInterrupt, txAvailable);			txstart(ether);			status &= ~txAvailable;		}		if(status & dnComplete){			COMMAND(port, AcknowledgeInterrupt, dnComplete);			txstart905(ether);			status &= ~dnComplete;		}		if(status & updateStats){			statistics(ether);			status &= ~updateStats;		}		/*		 * Currently, this shouldn't happen.		 */		if(status & rxEarly){			COMMAND(port, AcknowledgeInterrupt, rxEarly);			status &= ~rxEarly;		}		/*		 * Panic if there are any interrupts not dealt with.		 */		if(status & interruptMask)			panic("elnk3#%d: interrupt mask 0x%uX\n", ether->ctlrno, status);		COMMAND(port, AcknowledgeInterrupt, interruptLatch);	}	COMMAND(port, SelectRegisterWindow, w);}static voidtxrxreset(int port){	COMMAND(port, TxReset, 0);	while(STATUS(port) & commandInProgress)		;	COMMAND(port, RxReset, 0);	while(STATUS(port) & commandInProgress)		;}static voiddetach(Ether* ether){	txrxreset(ether->port);}typedef struct Adapter {	int	port;	int	irq;	int	tbdf;} Adapter;static Block* adapter;static voidtcmadapter(int port, int irq, int tbdf){	Block *bp;	Adapter *ap;	bp = allocb(sizeof(Adapter));	ap = (Adapter*)bp->rp;	ap->port = port;	ap->irq = irq;	ap->tbdf = tbdf;	bp->next = adapter;	adapter = bp;}/* * Write two 0 bytes to identify the IDport and then reset the * ID sequence. Then send the ID sequence to the card to get * the card into command state. */static voididseq(void){	int i;	uchar al;	static int reset, untag;	/*	 * One time only:	 *	reset any adapters listening	 */	if(reset == 0){		outb(IDport, 0);		outb(IDport, 0);		outb(IDport, 0xC0);		delay(20);		reset = 1;	}	outb(IDport, 0);	outb(IDport, 0);	for(al = 0xFF, i = 0; i < 255; i++){		outb(IDport, al);		if(al & 0x80){			al <<= 1;			al ^= 0xCF;		}		else			al <<= 1;	}	/*	 * One time only:	 *	write ID sequence to get the attention of all adapters;	 *	untag all adapters.	 * If we do a global reset here on all adapters we'll confuse any	 * ISA cards configured for EISA mode.	 */	if(untag == 0){		outb(IDport, 0xD0);		untag = 1;	}}static ulongactivate(void){	int i;	ushort x, acr;	/*	 * Do the little configuration dance:	 *	 * 2. write the ID sequence to get to command state.	 */	idseq();	/*	 * 3. Read the Manufacturer ID from the EEPROM.	 *    This is done by writing the IDPort with 0x87 (0x80	 *    is the 'read EEPROM' command, 0x07 is the offset of	 *    the Manufacturer ID field in the EEPROM).	 *    The data comes back 1 bit at a time.	 *    We seem to need a delay here between reading the bits.	 *	 * If the ID doesn't match, there are no more adapters.	 */	outb(IDport, 0x87);	delay(20);	for(x = 0, i = 0; i < 16; i++){		delay(20);		x <<= 1;		x |= inb(IDport) & 0x01;	}	if(x != 0x6D50)		return 0;	/*	 * 3. Read the Address Configuration from the EEPROM.	 *    The Address Configuration field is at offset 0x08 in the EEPROM).	 */	outb(IDport, 0x88);	for(acr = 0, i = 0; i < 16; i++){		delay(20);		acr <<= 1;		acr |= inb(IDport) & 0x01;	}	return (acr & 0x1F)*0x10 + 0x200;}static voidtcm509isa(void){	int irq, port;	/*	 * Attempt to activate all adapters. If adapter is set for	 * EISA mode (0x3F0), tag it and ignore. Otherwise, activate	 * it fully.	 */	while(port = activate()){		/*		 * 6. Tag the adapter so it won't respond in future.		 */		outb(IDport, 0xD1);		if(port == 0x3F0)			continue;		/*		 * 6. Activate the adapter by writing the Activate command		 *    (0xFF).		 */		outb(IDport, 0xFF);		delay(20);		/*		 * 8. Can now talk to the adapter's I/O base addresses.		 *    Use the I/O base address from the acr just read.		 *		 *    Enable the adapter and clear out any lingering status		 *    and interrupts.		 */		while(STATUS(port) & commandInProgress)			;		COMMAND(port, SelectRegisterWindow, Wsetup);		outs(port+ConfigControl, Ena);		txrxreset(port);		COMMAND(port, AcknowledgeInterrupt, 0xFF);		irq = (ins(port+ResourceConfig)>>12) & 0x0F;

⌨️ 快捷键说明

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