www.pudn.com > tcpipstack.rar > SED.C


/*  
 * Ethernet Driver. 
 * A Very Simple set of ethernet driver primitives. The ethernet (3com Mbus) 
 * interface is controlled by busy-waiting, the application is handed the 
 * location of on-board packet buffers, and allowed to fill in the 
 * transmit buffer directly. The interface is entirely blocking. 
 *  
 * Written March, 1986 by Geoffrey Cooper 
 * 
 * Copyright (C) 1986, IMAGEN Corporation 
 * "This code may be duplicated in whole or in part provided that [1] there 
 * is no commercial gain involved in the duplication, and [2] that this 
 * copyright notice is preserved on all copies. Any other duplication 
 * requires written notice of the author." 
 *  
 
|===================================================================| 
|  The author of this code hereby licenses all duplication and/or   | 
|  modification of this code, in whole or in part, consistent with  | 
|  the terms of the GNU Library General Public License.             | 
|              - Geoffrey H. Cooper 10/29/97                        | 
|===================================================================| 
 
|===================================================================| 
|  My changes can be considered public domain.  Geof's statement    | 
|  will cover everything.                                           | 
|              - Rick Rodman 09/02/97                               | 
|===================================================================| 
 
 * Primitives: 
 * sed_Init() -- Initialize the package 
 * sed_FormatPacket( destEAddr ) => location of transmit buffer 
 * sed_Send( pkLength ) -- send the packet that is in the transmit buffer 
 * sed_Receive( recBufLocation ) -- enable receiving packets. 
 * sed_IsPacket() => location of packet in receive buffer 
 * sed_CheckPacket( recBufLocation, expectedType ) 
 * 
 * Global Variables: 
 *	local_ethernet_address -- Ethernet address of this host. 
 *	broadcast_ethernet_address -- Ethernet broadcast address. 
 */ 
 
#include "tinytcp.h" 
#include "sed.h" 
 
#define en10pages		((en10size) >> pageshift) 
 
static	Byte *		sed_va;		/* virtual address of ethernet card */ 
 
/* globals referenced in ARP.C */ 
 
	struct Ethernet_Address	local_ethernet_address; 
					/* local ethernet address */ 
 
	struct Ethernet_Address	broadcast_ethernet_address; 
					/* Ethernet broadcast address */ 
static	BOOL		sed_respondARPreq; 
					/* controls responses to ARP req's */ 
static	char		bufAinUse, bufBinUse; 
					/* tell whether bufs are in use */ 
 
/*  
 * Initialize the Ethernet Interface, and this package. Enable input on 
 * both buffers. 
 */ 
int sed_Init( Void ) { 
	int		recState; 
	int		i; 
 
	recState = 7;					/* == mine + broad - errors */ 
 
	/* Map the Ethernet Interface in, and initialize sed_va */ 
	sed_va = ( Byte * )SED3CVA;		/* our virtual addr */ 
 
	/* Map memory for 3Com board (must be 8k boundary) */ 
	/* INSERT CODE HERE */ 
 
	/* map_ethernet_board(); */ 
 
	/* Reset the Ethernet controller */ 
	MECSR(sed_va) = RESET; 
	for (i=0; i<10; i++);		/* delay a bit... */ 
 
	/* just copy on-board ROM to on-board RAM, to use std. address */ 
 
	Move( ( Byte * ) MEAROM(sed_va), ( Byte * ) local_ethernet_address, 6 ); 
	Move( ( Byte * ) local_ethernet_address, ( Byte * ) MEARAM( sed_va ), 6 ); 
	 
	MECSR(sed_va) |= AMSW;		/* and tell board we did it */ 
 
	/* 
	* and initialize the exported variable which gives the Eth broadcast 
	* address, for everyone else to use.  
	*/ 
	for( i = 0; i < 3; i++ ) broadcast_ethernet_address[ i ] = 0xFFFF; 
	 
	/* accept packets addressed for us and broadcast packets */ 
 
	MECSR(sed_va) = (MECSR(sed_va)&~PA) | recState; 
 
	/* declare both buffers in use... */ 
	bufAinUse = bufBinUse = True; 
	return 1; 
} 
 
/* ----- deinit the interface --------------------------------------- */ 
 
int sed_Deinit( void ) { 
	/* do nothing */ 
	return 1; 
} 
 
/*  
 * Format an ethernet header in the transmit buffer, and say where it is. 
 * Note that because of the way the 3Com interface works, we need to know 
 * how long the packet is before we know where to put it. The solution is 
 * that we format the packet at the BEGINNING of the transmit buffer, and 
 * later copy it (carefully) to where it belongs. Another hack would be 
 * to be inefficient about the size of the packet to be sent (always send 
 * a larger ethernet packet than you need to, but copying should be ok for 
 * now. 
 */ 
Byte * sed_FormatPacket( destEAddr, ethType ) 
	Byte *destEAddr; int ethType; { 
	Byte *xMitBuf; 
	 
	xMitBuf = &(( Byte * ) MEXBUF(sed_va))[-0x800]; 
	Move( ( Byte * ) destEAddr, ( Byte * ) xMitBuf, 6 ); 
	Move( ( Byte * ) local_ethernet_address, ( Byte * )( xMitBuf + 6 ), 6 ); 
	*((short *)(xMitBuf+12)) = ethType; 
	return ( xMitBuf+14 ); 
} 
 
/* 
 * Send a packet out over the ethernet. The packet is sitting at the 
 * beginning of the transmit buffer. The routine returns when the 
 * packet has been successfully sent. 
 */ 
int sed_Send( pkLengthInBytes ) int pkLengthInBytes; { 
	Byte *	fromO, *toO; 
	int		pkLength, csr; 
 
	pkLengthInBytes += 14;		/* account for Ethernet header */ 
	pkLengthInBytes = (pkLengthInBytes + 1) & (~1); 
 
	if(pkLengthInBytes < E10P_MIN)  
		pkLengthInBytes = E10P_MIN; /* and min. ethernet len */ 
 
	/* and copy the packet where it belongs */ 
	pkLength = pkLengthInBytes; 
	fromO = &((Byte *)MEXBUF(sed_va))[-0x800] + pkLength; 
	toO = ((Byte *)MEXBUF(sed_va)); 
 
	while ( pkLength-- ) *--toO = *--fromO; 
	 
	/* send the packet */ 
	 
	MEXHDR(sed_va) = 2048 - pkLengthInBytes; 
	MECSR(sed_va) |= TBSW; 
 
	/* and wait until it has really been sent. */ 
 
	for (pkLength=0; pkLength < 15; pkLength++) { 
		while ( (! ((csr = MECSR(sed_va)) & JAM)) && (csr & TBSW) ) 
			; 
		if(csr & JAM ) { 
			/* Ethernet Collision detected... */ 
#ifdef DEBUG 
			printf("sed: JAM: MECSR=%x\n", csr); 
#endif 
			MEBACK( sed_va ) = ( Word ) clock_ValueRough(); 
			MECSR( sed_va ) |= JAM; 
		} else break; 
	} 
 
#ifdef DEBUG 
	if( pkLength == 15 ) 
		printf( "Go and Buy a New Ethernet Interface.\n" ); 
#endif 
 
	/* else we sent the packet ok. */ 
 
	return 1; 
} 
 
/*  
 * Enable the Ethernet interface to receive packets from the network. If 
 * the argument is zero, enable both buffers. If the argument is nonzero, 
 * take it as the address of the buffer to be enabled. 
 */ 
 
int sed_Receive( recBufLocation ) Byte *recBufLocation; { 
	Word enables = 0; 
 
	if(recBufLocation == 0) { 
		bufAinUse = False; 
		bufBinUse = False; 
		enables = (ABSW | BBSW); 
	} 
	recBufLocation -= 16; 
	if(recBufLocation == ((Byte *)MEAHDR(sed_va))) { 
		bufAinUse = False; 
		enables = ABSW; 
		} 
	if(recBufLocation == ((Byte *)MEBHDR(sed_va))) { 
		bufBinUse = False; 
		enables = BBSW; 
	} 
 
	MECSR (sed_va) |= enables; 
 
	return 1; 
} 
 
/*  
 * Test for the arrival of a packet on the Ethernet interface. The packet may 
 * arrive in either buffer A or buffer B; the location of the packet is 
 * returned. If no packet is returned withing 'timeout' milliseconds, 
 * then the routine returns zero. 
 *  
 * Note: ignores ethernet errors. may occasionally return something 
 * which was received in error. 
 */ 
 
Byte * sed_IsPacket() { 
	Byte *	pb; 
	 
	pb = 0; 
	if( ! bufAinUse && (MECSR(sed_va)&ABSW) == 0 )  
		pb = (Byte *)MEAHDR(sed_va); 
	if( ! pb && ! bufBinUse && (MECSR(sed_va)&BBSW) == 0 ) 
		pb = (Byte *)MEBHDR(sed_va); 
 
	if( pb ) { 
		if( ((Byte *)pb) == ((Byte *)MEAHDR(sed_va)) ) bufAinUse = 1; 
		else bufBinUse = 1; 
		pb += 16;					/* get past the ethernet header */ 
	} 
 
	return ( pb ); 
} 
 
/*  
 * Check to make sure that the packet that you received was the one that 
 * you expected to get. 
 */ 
int sed_CheckPacket( recBufLocation, expectedType ) 
	Word *recBufLocation; Word expectedType; { 
 
	int recHeader = recBufLocation[-8]; 
 
	if( (recHeader&R_ERROR) != 0 || 
		(recHeader&R_OFFSET) < E10P_MIN ) { 
		return ( -1 ); 
	} 
 
	if( recBufLocation[-1] != expectedType ) { 
		return 0; 
	} 
	return 1; 
} 
 
/* end of sed.c */