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 */