www.pudn.com > S3c2410bsp.zip > ne2000End.c


/* ne2000End.c - NE2000 END network interface driver */

#include "copyright_wrs.h"

#include "vxWorks.h"
#include "endLib.h"			/* Common END structures. */
#include "etherMultiLib.h"
#include "netLib.h"
#include "cacheLib.h"
#include "lstLib.h"			/* Needed to maintain protocol list. */
#include "iv.h"
#include "stdlib.h"
#include "sysLib.h"
#include "intLib.h"
#include "taskLib.h"
#include "ne2000End.h"		
#include "s3c2410x.h"

#include "wrSbcArm9.h"


#define NE2000_ALL_INTS    (IM_OVWE | IM_TXEE | IM_RXEE | IM_PTXE | IM_PRXE)
/*#define NE2000_ALL_INTS    (IM_PTXE | IM_PRXE)*/


#define CRC32_POLYNOMIAL		0x04c11db7


/* Configuration items */

#define END_SPEED		10000000

#define NE2000_DEV_NAME		"ene"
#define NE2000_DEV_NAME_LEN	4

#ifndef SYS_INT_CONNECT
#define SYS_INT_CONNECT(pDrvCtrl,rtn,arg,pResult) \
	{ \
	IMPORT STATUS intConnect(); \
	*pResult = intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (pDrvCtrl->ivec), \
			     rtn, (int)arg); \
	}
#endif


#ifndef SYS_INT_DISCONNECT
#define SYS_INT_DISCONNECT(pDrvCtrl,rtn,arg,pResult) \
	{ \
	*pResult = OK; /* HELP: need a real routine */ \
	}
#endif

#ifndef SYS_INT_ENABLE
#define SYS_INT_ENABLE(pDrvCtrl) \
	{ \
	IMPORT STATUS intEnable(); \
	intEnable (pDrvCtrl->ilevel); \
	}
#endif


#ifndef SYS_ENET_ADDR_GET
#define SYS_ENET_ADDR_GET(pDevice) \
	ne2000EnetAddrGet(pDevice)
#endif


#if     (CPU_FAMILY == I80X86)


#ifndef SYS_OUT_CHAR
#define SYS_OUT_CHAR(pDrvCtrl,addr,value) \
	sysOutByte((pDrvCtrl)->base + (int) (addr),(char) (value))
#endif

#ifndef SYS_IN_CHAR
#define SYS_IN_CHAR(pDrvCtrl,addr,pData) \
	(*(pData) = (UCHAR) sysInByte((pDrvCtrl)->base + (int) (addr)))
#endif

#ifndef SYS_IN_WORD_STRING
#define SYS_IN_WORD_STRING(pDrvCtrl,addr,pData,len) \
	(sysInWordString ((pDrvCtrl)->base + (int) (addr), (short *)(pData), \
			  (len)))
#endif

#ifndef SYS_OUT_WORD_STRING
#define SYS_OUT_WORD_STRING(pDrvCtrl,addr,pData,len) \
	(sysOutWordString ((pDrvCtrl)->base + (int) (addr), (short *)(pData), \
			   (len)))
#endif

#else /* #if     (CPU_FAMILY == I80X86) */

#ifndef SYS_OUT_CHAR
#define SYS_OUT_CHAR(pDrvCtrl,addr,value) \
    	sysOutByte((pDrvCtrl)->base + (UINT) (addr), (value))
#endif

#ifndef SYS_IN_CHAR
#define SYS_IN_CHAR(pDrvCtrl,addr,pData) \
    	(*(pData) = (UCHAR) sysInByte((pDrvCtrl)->base + (UINT) (addr)))
#endif

#ifndef SYS_IN_WORD_STRING
#define SYS_IN_WORD_STRING(pDrvCtrl,addr,pData,len) \
    	(sysInWordString ((pDrvCtrl)->base + (UINT) (addr),  \
			  (UINT16 *)(pData), (len)))
#endif

#ifndef SYS_OUT_WORD_STRING
#define SYS_OUT_WORD_STRING(pDrvCtrl,addr,pData,len) \
    	(sysOutWordString ((pDrvCtrl)->base + (UINT) (addr), \
			   (UINT16 *) (pData), (len)))
#endif

#endif /* #if     (CPU_FAMILY == I80X86) */

/* A shortcut for getting the hardware address from the MIB II stuff. */

#define END_HADDR(pEnd)	\
		((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)

#define END_HADDR_LEN(pEnd) \
		((pEnd)->mib2Tbl.ifPhysAddress.addrLength)


/* Statistics we gather from the NE2000 */

typedef struct
    {
    UINT collisions;
    UINT crcs;
    UINT aligns;
    UINT missed;
    UINT overruns;
    UINT disabled;
    UINT deferring;
    UINT underruns;
    UINT aborts;
    UINT outofwindow;
    UINT heartbeats;
    UINT badPacket;
    UINT shortPacket;
    UINT tnoerror;
    UINT rnoerror;
    UINT terror;
    UINT rerror;
    UINT overwrite;
    UINT wrapped;
    UINT interrupts;
    UINT reset;
    UINT strayint;
    UINT jabber;
    } NE2000_STAT;

typedef struct ne2000_device
    {
    END_OBJ		endObj;		
    END_ERR		lastError;	
    int			lastIntError;	
    int			unit;		
    int			ivec;		
    int			ilevel;		
    int			byteAccess;
    int			usePromEnetAddr;
    ULONG		base;		
    int			offset;		
	#ifdef _USE_SND_DMA_
    char		packetBuf [SAVE_SND_NUM][NE2000_BUFSIZ];	/* long-aligned */
	int 		packetLen[SAVE_SND_NUM];	
	#else
	char		packetBuf[NE2000_BUFSIZ];
	#endif
    volatile long	flags;		
    volatile UCHAR	current;	
    volatile ULONG	imask;		
    volatile NE2000_STAT stats;		
    UCHAR		enetAddr[6];	
    UCHAR		mcastFilter[8];	
    UCHAR		nextPacket;	
    CL_POOL_ID		clPoolId;
    int                 configRegA;     
    int                 configRegB;    

	#ifdef _USE_SND_DMA_
	int useHead;
	int bufCount;
	int freeHead;
	#endif
	#ifdef _USE_RECV_DMA_
	char 		recvMapBuf[RECV_PAGE_NUM][RECV_PAGE_SIZE];
	int 		nextMapPage;
	#endif
	
} NE2000END_DEVICE;


NE2000END_DEVICE *gpDeviceCtrl = NULL;

struct macinfo
{ char ipadrinfo[50];
	char netmaskinfo[50];
	char gatewayinfo[50];
	ULONG netmaskshowinfo;
	UCHAR macshowinfo[6];
	int dhcpflag;
  int bootpflag;
};
struct macinfo MAC_INFO;


/* Definitions for the flags field */

#define END_PROMISCUOUS_FLAG	0x01
#define END_RECV_HANDLING_FLAG	0x02
#define END_TX_IN_PROGRESS	0x04
#define END_TX_BLOCKED		0x08
#define END_POLLING		0x10
#define END_OVERWRITE		0x20
#define END_OVERWRITE2		0x40

/***** DEBUG MACROS *****/

#undef DEBUG


#ifdef DEBUG
#   include "stdio.h"
#   include "logLib.h"
    int endDebug = 1;
#   define ENDLOGMSG(x) \
	do { \
	    if (endDebug) \
		logMsg x; \
	   } while (0)
#else
#   define ENDLOGMSG(x)
#endif /* ENDDEBUG */

/***** LOCALS *****/

/* imports */

IMPORT char ne2000EnetAddr[];
IMPORT int endMultiLstCnt (END_OBJ *);

LOCAL void	ne2000Int (NE2000END_DEVICE* pDrvCtrl);
LOCAL void	ne2000HandleRcvInt (NE2000END_DEVICE* pDrvCtrl);
LOCAL void	ne2000Config (NE2000END_DEVICE* pDrvCtrl,
			      int intEnable);
LOCAL void	ne2000OverwriteRecover (NE2000END_DEVICE* pDrvCtrl,
					UCHAR cmdStatus);
LOCAL int	ne2000PacketGet (NE2000END_DEVICE* pDrvCtrl, char *pData);
LOCAL void	ne2000AddrFilterSet (NE2000END_DEVICE* pDrvCtrl);
LOCAL UINT32 	ne2000CrcWork (UINT8 inChar, UINT32 inCrc);
LOCAL void	ne2000EnetAddrGet (NE2000END_DEVICE* pDrvCtrl);
LOCAL UCHAR	ne2000GetCurr (NE2000END_DEVICE* pDrvCtrl);
LOCAL void	ne2000DataIn (NE2000END_DEVICE* pDrvCtrl, int eneAddress,
			      int len, char* pData);
LOCAL void	ne2000DataOut (NE2000END_DEVICE* pDrvCtrl, char* pData,
			       int len, int eneAddress);
LOCAL STATUS	ne2000Parse (NE2000END_DEVICE* pDrvCtrl, char* initString);
LOCAL STATUS	ne2000MemInit (NE2000END_DEVICE* pDrvCtrl);
LOCAL STATUS	ne2000PollStart (NE2000END_DEVICE* pDrvCtrl);
LOCAL STATUS	ne2000PollStop (NE2000END_DEVICE* pDrvCtrl);


/* END Specific interfaces. */

/* This is the only externally visible interface. */

END_OBJ * 	ne2000EndLoad (char* initString, void *pBSP);

LOCAL STATUS	ne2000Start (void* pCookie);
LOCAL STATUS	ne2000Stop (void* pCookie);
LOCAL STATUS	ne2000Unload (void *pCookie);
LOCAL int	ne2000Ioctl (void *pCookie, int cmd, caddr_t data);
LOCAL STATUS	ne2000Send (void *pCookie, M_BLK_ID pBuf);
LOCAL STATUS	ne2000MCastAdd (void *pCookie, char* pAddress);
LOCAL STATUS	ne2000MCastDel (void *pCookie, char* pAddress);
LOCAL STATUS	ne2000MCastGet (void *pCookie, MULTI_TABLE* pTable);
LOCAL STATUS	ne2000PollSend (void *pCookie, M_BLK_ID pBuf);
LOCAL STATUS	ne2000PollRecv (void *pCookie, M_BLK_ID pBuf);


#define U32 unsigned int

void ne2000DmaInit();

#ifdef _USE_SND_DMA_
void ne2000DmaSendInt();
void ne2000DmaSend(NE2000END_DEVICE* pDrvCtrl ,int eneAddress);
#else
void ne2000DmaSendInt();
void ne2000DmaSend(NE2000END_DEVICE* pDev , char *srcBuf , int sndLen);
#endif

#ifdef _USE_RECV_DMA_
void ne2000DmaRecvInt();
void ne2000DmaRecv(NE2000END_DEVICE *pDrvCtrl,int eneAddress,int len);
#endif

void ne2000OpenRecvIntLog();

LOCAL NET_FUNCS ne2000FuncTable =
    {
    (FUNCPTR) ne2000Start,	
    (FUNCPTR) ne2000Stop,	
    (FUNCPTR) ne2000Unload,	
    (FUNCPTR) ne2000Ioctl,	
    (FUNCPTR) ne2000Send,	
    (FUNCPTR) ne2000MCastAdd,				
    (FUNCPTR) ne2000MCastDel,					
    (FUNCPTR) ne2000MCastGet,					
    (FUNCPTR) ne2000PollSend,	
    (FUNCPTR) ne2000PollRecv,	
    endEtherAddressForm, 
    (FUNCPTR) endEtherPacketDataGet, 
    (FUNCPTR) endEtherPacketAddrGet  
    };

int				dmaReadyFlag =TRUE;
int				recvIntLog = FALSE;

/******************************************************************************
*
*
* RETURNS: An END object pointer or NULL on error.
*/

END_OBJ* ne2000EndLoad
    (
    char* initString,		
    void* pBSP			
    )
    {
    NE2000END_DEVICE 	*pDrvCtrl;
    int 		level;
    UCHAR		regVal;

#ifdef DEBUG
    printf ("ne2000EndLoad(%s)\n", initString);
    printf ("\tinitString '%s'\n", initString ? initString : "");
    printf ("\tpBSP       '%s'\n", pBSP ? pBSP : "");
#endif
    if (initString == NULL)
        return (NULL);

    if (initString[0] == '\0')
        {
        bcopy((char *)NE2000_DEV_NAME, initString, NE2000_DEV_NAME_LEN);
        return (NULL);
        }

    pDrvCtrl = (NE2000END_DEVICE *) calloc (sizeof(NE2000END_DEVICE), 1);
    if (pDrvCtrl == NULL)
	goto errorExit;


    if (ne2000Parse (pDrvCtrl, initString) == ERROR)
	goto errorExit;


    if (pDrvCtrl->configRegA != 0)
        {

        level = intLock ();

        SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_PAGE0);
        SYS_IN_CHAR (pDrvCtrl, ENE_RBCR0, ®Val);
        SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, pDrvCtrl->configRegA);

        intUnlock (level);
        }                 

    if (pDrvCtrl->configRegB != 0)
        {

        level = intLock ();

        SYS_IN_CHAR (pDrvCtrl, ENE_RBCR1, ®Val);
        SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, pDrvCtrl->configRegB);

        intUnlock (level);
        }         


    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_STOP);


    if (pDrvCtrl->byteAccess)
	SYS_OUT_CHAR (pDrvCtrl, ENE_DCON, DCON_BSIZE1 | DCON_BUS_8
			| DCON_LOOPBK_OFF);
    else
	SYS_OUT_CHAR (pDrvCtrl, ENE_DCON, DCON_BSIZE1 | DCON_BUS16 
			| DCON_LOOPBK_OFF);

    SYS_ENET_ADDR_GET (pDrvCtrl);


    if (END_OBJ_INIT (&pDrvCtrl->endObj, (DEV_OBJ *)pDrvCtrl, NE2000_DEV_NAME,
		      pDrvCtrl->unit, &ne2000FuncTable,
		      "ne2000 Enhanced Network Driver") == ERROR)
	goto errorExit;


    if (END_MIB_INIT (&pDrvCtrl->endObj, M2_ifType_ethernet_csmacd,
		      &pDrvCtrl->enetAddr[0], 6, ETHERMTU,
                      END_SPEED) == ERROR)
	goto errorExit;

    if (ne2000MemInit (pDrvCtrl) == ERROR)
	goto errorExit;

    END_OBJ_READY (&pDrvCtrl->endObj,
		    IFF_NOTRAILERS | IFF_MULTICAST | IFF_BROADCAST);

	#ifdef _USE_SND_DMA_
	pDrvCtrl->useHead = 0x5a;
	pDrvCtrl->freeHead = 0;
	pDrvCtrl->bufCount = SAVE_SND_NUM;
	#endif

	gpDeviceCtrl = pDrvCtrl;

    return (&pDrvCtrl->endObj);

errorExit:
    if (pDrvCtrl != NULL)
	free ((char *)pDrvCtrl);

    return (NULL);
    }

/******************************************************************************
* RETURNS: OK or ERROR for invalid arguments.
*/

LOCAL STATUS ne2000Parse
    (
    NE2000END_DEVICE * pDrvCtrl,
    char * initString
    )
    {
    char*	tok;
    char*	holder = NULL;

    tok = strtok_r (initString, ":", &holder);
    if (tok == NULL)
	return (ERROR);
    pDrvCtrl->unit = atoi (tok);


    tok = strtok_r (NULL, ":", &holder);
    if (tok == NULL)
	return (ERROR);
    pDrvCtrl->base = strtoul (tok, NULL, 16);


    tok = strtok_r (NULL, ":", &holder);
    if (tok == NULL)
	return (ERROR);
    pDrvCtrl->ivec = strtoul (tok, NULL, 16);


    tok = strtok_r (NULL, ":", &holder);
    if (tok == NULL)
	return (ERROR);
    pDrvCtrl->ilevel = strtoul (tok, NULL, 16);


    tok = strtok_r (NULL, ":", &holder);
    if (tok == NULL)
	return (ERROR);
    pDrvCtrl->byteAccess = atoi (tok);


    tok = strtok_r (NULL, ":", &holder);
    if (tok == NULL)
	return (ERROR);
    pDrvCtrl->usePromEnetAddr = atoi (tok);


    tok = strtok_r (NULL, ":", &holder);
    if (tok == NULL)
	return (ERROR);
    pDrvCtrl->offset = strtoul (tok, NULL, 16);

   
    pDrvCtrl->configRegA = 0;

    tok = strtok_r (NULL, ":", &holder);
    if (tok != NULL)
        pDrvCtrl->configRegA = strtoul (tok, NULL, 16);

   
    pDrvCtrl->configRegB = 0;

    tok = strtok_r (NULL, ":", &holder);
    if (tok != NULL)
        pDrvCtrl->configRegB = strtoul (tok, NULL, 16);

    return (OK);
    }

/*******************************************************************************
* RETURNS: OK or ERROR.
*/

LOCAL STATUS ne2000MemInit
    (
    NE2000END_DEVICE * pDrvCtrl	
    )
    {
    M_CL_CONFIG	eneMclBlkConfig;
    CL_DESC	clDesc;                      /* cluster description */

    bzero ((char *)&eneMclBlkConfig, sizeof(eneMclBlkConfig));
    bzero ((char *)&clDesc, sizeof(clDesc));

    clDesc.clNum   = 128;
    clDesc.clSize  = NE2000_BUFSIZ;	/* allow for alignment */
    clDesc.memSize = ((clDesc.clNum * (clDesc.clSize + 8)) + 4);

    eneMclBlkConfig.mBlkNum  = 64 * 4;
    eneMclBlkConfig.clBlkNum = clDesc.clNum;

    eneMclBlkConfig.memSize =
      (eneMclBlkConfig.mBlkNum * (MSIZE + sizeof (long)))
      + (eneMclBlkConfig.clBlkNum * (CL_BLK_SZ + sizeof (long)));
    eneMclBlkConfig.memArea = (char *) memalign(sizeof (long),
						eneMclBlkConfig.memSize);
    if (eneMclBlkConfig.memArea == NULL)
        return (ERROR);

    clDesc.memArea = (char *) malloc (clDesc.memSize);
    if (clDesc.memArea == NULL)
	return (ERROR);

    pDrvCtrl->endObj.pNetPool = (NET_POOL_ID) malloc (sizeof(NET_POOL));
    if (pDrvCtrl->endObj.pNetPool == NULL)
        return (ERROR);

    if (netPoolInit (pDrvCtrl->endObj.pNetPool, &eneMclBlkConfig,
                     &clDesc, 1, NULL) == ERROR)
        return (ERROR);

    pDrvCtrl->clPoolId = clPoolIdGet (pDrvCtrl->endObj.pNetPool,
				      NE2000_BUFSIZ, FALSE);

    return (OK);
    }

/*******************************************************************************
*/

LOCAL int ne2000Ioctl
    (
    void*	pCookie,	
    int		cmd,
    caddr_t	data
    )
    {
    int error = 0;
    long value;
    NE2000END_DEVICE* pDrvCtrl = (NE2000END_DEVICE *) pCookie;

	ENDLOGMSG (("into ne2000Ioctl.\n", 0, 0, 0, 0, 0, 0));

    switch ((UINT) cmd)
        {
        case EIOCSADDR:
	    if (data == NULL)
		return (EINVAL);
            bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->endObj),
		   END_HADDR_LEN(&pDrvCtrl->endObj));
			ENDLOGMSG (("ne2000Ioctl set phy addr.\n", 0, 0, 0, 0, 0, 0));
            break;

        case EIOCGADDR:
	    if (data == NULL)
		return (EINVAL);
            bcopy ((char *)END_HADDR(&pDrvCtrl->endObj), (char *)data,
		   END_HADDR_LEN(&pDrvCtrl->endObj));
			ENDLOGMSG (("ne2000Ioctl get phy addr.\n", 0, 0, 0, 0, 0, 0));
            break;

        case EIOCSFLAGS:
	    value = (long)data;
	    if (value < 0)
		{
		value = -value;
		value--;
		END_FLAGS_CLR (&pDrvCtrl->endObj, value);
		}
	    else
		END_FLAGS_SET (&pDrvCtrl->endObj, value);
		ENDLOGMSG (("ne2000Ioctl set flag.\n", 0, 0, 0, 0, 0, 0));

	    ne2000Config (pDrvCtrl, TRUE);
            break;

        case EIOCGFLAGS:
	    *(int *)data = END_FLAGS_GET(&pDrvCtrl->endObj);
		ENDLOGMSG (("ne2000Ioctl get phy addr.\n", 0, 0, 0, 0, 0, 0));
            break;

	case EIOCPOLLSTART:
	    ne2000PollStart (pDrvCtrl);
		ENDLOGMSG (("ne2000Ioctl pool start.\n", 0, 0, 0, 0, 0, 0));
	    break;

	case EIOCPOLLSTOP:
	    ne2000PollStop (pDrvCtrl);
		ENDLOGMSG (("ne2000Ioctl pool stop.\n", 0, 0, 0, 0, 0, 0));
	    break;

        case EIOCGMIB2:
            if (data == NULL)
                return (EINVAL);
            bcopy((char *)&pDrvCtrl->endObj.mib2Tbl, (char *)data,
                  sizeof(pDrvCtrl->endObj.mib2Tbl));
			ENDLOGMSG (("ne2000Ioctl get mib table.\n", 0, 0, 0, 0, 0, 0));
            break;

        case EIOCGFBUF:
            if (data == NULL)
                return (EINVAL);
			ENDLOGMSG (("ne2000Ioctl get buffer.\n", 0, 0, 0, 0, 0, 0));
            break;

        default:
            error = EINVAL;
			ENDLOGMSG (("ne2000Ioctl do nothing.\n", 0, 0, 0, 0, 0, 0));
        }

    return (error);
    }

/*******************************************************************************
*
* ne2000Start - start the device
*
*
* RETURNS: OK or ERROR
*
*/

LOCAL STATUS ne2000Start
    (
    void*	pCookie
    )
    {
    UCHAR	rxFilter;		/* receiver configuration */
#ifdef DEBUG
    static buf [256];
#endif
    STATUS result;
    NE2000END_DEVICE* pDrvCtrl = (NE2000END_DEVICE *) pCookie;

    SYS_INT_CONNECT (pDrvCtrl, ne2000Int, (int)pDrvCtrl, &result);
    if (result == ERROR)
	return (ERROR);

	#ifdef _USE_RECV_DMA_
    pDrvCtrl->imask = 0;
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);

	if (END_MULTI_LST_CNT(&pDrvCtrl->endObj) > 0)
		ne2000AddrFilterSet (pDrvCtrl);

    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_STOP);

    if (pDrvCtrl->byteAccess)
	SYS_OUT_CHAR (pDrvCtrl, ENE_DCON, DCON_BSIZE1 | DCON_BUS_8 
			| DCON_LOOPBK_OFF);
    else
	SYS_OUT_CHAR (pDrvCtrl, ENE_DCON, DCON_BSIZE1 | DCON_BUS16 
			| DCON_LOOPBK_OFF);


	SYS_ENET_ADDR_GET (pDrvCtrl);


    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, 0x00);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, 0x00);

    rxFilter = RCON_BROAD;

    if (END_MULTI_LST_CNT(&pDrvCtrl->endObj) > 0)
	{
	rxFilter |= RCON_GROUP;
	}
    ENDLOGMSG (("\tMulticast mode %s\n",
	    (rxFilter & RCON_GROUP) ? "on" : "off",
	    0, 0, 0, 0, 0));

    if (END_FLAGS_GET(&pDrvCtrl->endObj) & IFF_PROMISC)
	{
	rxFilter |= RCON_PROM;
	}


	ENDLOGMSG (("\tPromiscuous mode %s\n",
	    (rxFilter & RCON_PROM) ? "on" : "off",
	    0, 0, 0, 0, 0));

    ENDLOGMSG (("\tsetting rxFilter = 0x%x\n", rxFilter,2,3,4,5,6));

    SYS_OUT_CHAR (pDrvCtrl, ENE_RCON, rxFilter);


    SYS_OUT_CHAR (pDrvCtrl, ENE_TCON, TCON_LB1);

    SYS_OUT_CHAR (pDrvCtrl, ENE_RSTART, NE2000_PSTART);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RSTOP, NE2000_PSTOP);
    SYS_OUT_CHAR (pDrvCtrl, ENE_BOUND, NE2000_PSTART);

    SYS_OUT_CHAR (pDrvCtrl, ENE_INTSTAT, (char)0xff);

	pDrvCtrl->imask = 0;
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);


    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_PAGE1 | CMD_STOP);


    SYS_OUT_CHAR (pDrvCtrl, ENE_STA0, pDrvCtrl->enetAddr[0]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_STA1, pDrvCtrl->enetAddr[1]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_STA2, pDrvCtrl->enetAddr[2]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_STA3, pDrvCtrl->enetAddr[3]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_STA4, pDrvCtrl->enetAddr[4]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_STA5, pDrvCtrl->enetAddr[5]);

    ENDLOGMSG (("enet addr %02x:%02x:%02x:%02x:%02x:%02x\n",
		pDrvCtrl->enetAddr[0] & 0xff,
		pDrvCtrl->enetAddr[1] & 0xff,
		pDrvCtrl->enetAddr[2] & 0xff,
		pDrvCtrl->enetAddr[3] & 0xff,
		pDrvCtrl->enetAddr[4] & 0xff,
		pDrvCtrl->enetAddr[5] & 0xff));



    ne2000AddrFilterSet (pDrvCtrl);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR0, pDrvCtrl->mcastFilter[0]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR1, pDrvCtrl->mcastFilter[1]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR2, pDrvCtrl->mcastFilter[2]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR3, pDrvCtrl->mcastFilter[3]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR4, pDrvCtrl->mcastFilter[4]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR5, pDrvCtrl->mcastFilter[5]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR6, pDrvCtrl->mcastFilter[6]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR7, pDrvCtrl->mcastFilter[7]);


#ifdef DEBUG
   ENDLOGMSG ((("Setting multicast addresses to:\n"),1,2,3,4,5,6));
    sprintf(buf, "enet mcast %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
	    pDrvCtrl->mcastFilter[0] & 0xff,
	    pDrvCtrl->mcastFilter[1] & 0xff,
	    pDrvCtrl->mcastFilter[2] & 0xff,
	    pDrvCtrl->mcastFilter[3] & 0xff,
	    pDrvCtrl->mcastFilter[4] & 0xff,
	    pDrvCtrl->mcastFilter[5] & 0xff,
	    pDrvCtrl->mcastFilter[6] & 0xff,
	    pDrvCtrl->mcastFilter[7] & 0xff);
    ENDLOGMSG (((buf),1,2,3,4,5,6));
#endif /* DEBUG */

	#endif
    END_FLAGS_SET (&pDrvCtrl->endObj, (IFF_UP | IFF_RUNNING));

	#ifdef _USE_RECV_DMA_
    SYS_OUT_CHAR (pDrvCtrl, ENE_CURR, NE2000_PSTART + 1);
    pDrvCtrl->nextPacket = NE2000_PSTART + 1;

    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START);


    SYS_OUT_CHAR (pDrvCtrl, ENE_TCON, TCON_NORMAL);


	#endif
	pDrvCtrl->imask = (pDrvCtrl->flags & END_POLLING) ? 0 : NE2000_ALL_INTS;
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
    SYS_INT_ENABLE (pDrvCtrl);

	ne2000DmaInit();

    return (OK);
    }

/******************************************************************************
*
* ne2000Config - reconfigure the interface under us.
*
*
* NOMANUAL
*/
LOCAL void ne2000Config
    (
    NE2000END_DEVICE *pDrvCtrl,
    BOOL	      intEnable		
    )
    {
    UCHAR	rxFilter;		
#ifdef DEBUG
    static buf [256];
#endif

    ENDLOGMSG (("ne2000Config: enter (intEnable=%d)\n",
		intEnable, 0, 0, 0, 0, 0));

    pDrvCtrl->imask = 0;
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);


    if (END_MULTI_LST_CNT(&pDrvCtrl->endObj) > 0)
		ne2000AddrFilterSet (pDrvCtrl);

    pDrvCtrl->flags &= (END_POLLING | END_OVERWRITE | END_OVERWRITE2);

    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_STOP);

    if (pDrvCtrl->byteAccess)
	SYS_OUT_CHAR (pDrvCtrl, ENE_DCON, DCON_BSIZE1 | DCON_BUS_8 
			| DCON_LOOPBK_OFF);
    else
	SYS_OUT_CHAR (pDrvCtrl, ENE_DCON, DCON_BSIZE1 | DCON_BUS16 
			| DCON_LOOPBK_OFF);

    SYS_ENET_ADDR_GET (pDrvCtrl);


    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, 0x00);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, 0x00);
    rxFilter = RCON_BROAD;


    if (END_MULTI_LST_CNT(&pDrvCtrl->endObj) > 0)
	{
	rxFilter |= RCON_GROUP;
	}
    ENDLOGMSG (("\tMulticast mode %s\n",
	    (rxFilter & RCON_GROUP) ? "on" : "off",
	    0, 0, 0, 0, 0));


    if (END_FLAGS_GET(&pDrvCtrl->endObj) & IFF_PROMISC)
	{
	rxFilter |= RCON_PROM;
	}
    ENDLOGMSG (("\tPromiscuous mode %s\n",
	    (rxFilter & RCON_PROM) ? "on" : "off",
	    0, 0, 0, 0, 0));

    ENDLOGMSG (("\tsetting rxFilter = 0x%x\n", rxFilter,2,3,4,5,6));

    SYS_OUT_CHAR (pDrvCtrl, ENE_RCON, rxFilter);


    SYS_OUT_CHAR (pDrvCtrl, ENE_TCON, TCON_LB1);


    SYS_OUT_CHAR (pDrvCtrl, ENE_RSTART, NE2000_PSTART);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RSTOP, NE2000_PSTOP);
    SYS_OUT_CHAR (pDrvCtrl, ENE_BOUND, NE2000_PSTART);


    SYS_OUT_CHAR (pDrvCtrl, ENE_INTSTAT, (char)0xff);


    pDrvCtrl->imask = 0;
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);


    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_PAGE1 | CMD_STOP);


    SYS_OUT_CHAR (pDrvCtrl, ENE_STA0, pDrvCtrl->enetAddr[0]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_STA1, pDrvCtrl->enetAddr[1]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_STA2, pDrvCtrl->enetAddr[2]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_STA3, pDrvCtrl->enetAddr[3]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_STA4, pDrvCtrl->enetAddr[4]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_STA5, pDrvCtrl->enetAddr[5]);

    ENDLOGMSG (("enet addr %02x:%02x:%02x:%02x:%02x:%02x\n",
		pDrvCtrl->enetAddr[0] & 0xff,
		pDrvCtrl->enetAddr[1] & 0xff,
		pDrvCtrl->enetAddr[2] & 0xff,
		pDrvCtrl->enetAddr[3] & 0xff,
		pDrvCtrl->enetAddr[4] & 0xff,
		pDrvCtrl->enetAddr[5] & 0xff));



    ne2000AddrFilterSet (pDrvCtrl);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR0, pDrvCtrl->mcastFilter[0]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR1, pDrvCtrl->mcastFilter[1]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR2, pDrvCtrl->mcastFilter[2]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR3, pDrvCtrl->mcastFilter[3]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR4, pDrvCtrl->mcastFilter[4]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR5, pDrvCtrl->mcastFilter[5]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR6, pDrvCtrl->mcastFilter[6]);
    SYS_OUT_CHAR (pDrvCtrl, ENE_MAR7, pDrvCtrl->mcastFilter[7]);


#ifdef DEBUG
   ENDLOGMSG ((("Setting multicast addresses to:\n"),1,2,3,4,5,6));
    sprintf(buf, "enet mcast %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
	    pDrvCtrl->mcastFilter[0] & 0xff,
	    pDrvCtrl->mcastFilter[1] & 0xff,
	    pDrvCtrl->mcastFilter[2] & 0xff,
	    pDrvCtrl->mcastFilter[3] & 0xff,
	    pDrvCtrl->mcastFilter[4] & 0xff,
	    pDrvCtrl->mcastFilter[5] & 0xff,
	    pDrvCtrl->mcastFilter[6] & 0xff,
	    pDrvCtrl->mcastFilter[7] & 0xff);
    ENDLOGMSG (((buf),1,2,3,4,5,6));
#endif /* DEBUG */

    SYS_OUT_CHAR (pDrvCtrl, ENE_CURR, NE2000_PSTART + 1);
    pDrvCtrl->nextPacket = NE2000_PSTART + 1;



    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START);


    SYS_OUT_CHAR (pDrvCtrl, ENE_TCON, TCON_NORMAL);

    ENDLOGMSG (("ne2000Config: done\n", 0, 0, 0, 0, 0, 0));

    pDrvCtrl->imask = ((pDrvCtrl->flags & END_POLLING) ? 0 : NE2000_ALL_INTS);

    if (intEnable)
	SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
    }

/*******************************************************************************
*/

LOCAL void ne2000OverwriteRecover
    (
    NE2000END_DEVICE  *pDrvCtrl,
    UCHAR cmdStatus
    )
    {
    UCHAR stat;
    BOOL  reSend;
	int recvLen = 0;

    ENDLOGMSG (("ne2000OverwriteRecover: enter (flags=%x, imask=%x)\n",
		pDrvCtrl->flags,pDrvCtrl->imask,0,0,0,0));

    if (!(pDrvCtrl->flags & END_OVERWRITE2))
	{
	ENDLOGMSG (("ne2000OverwriteRecover: bad flags\n",
		    0,0,0,0,0,0));
#ifdef DEBUG
	SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, 0);
	taskSuspend (0);
#else
	return;
#endif
	}

    taskDelay ((sysClkRateGet() + 624)/ 625);

    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, 0x00);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, 0x00);


    if ((cmdStatus & CMD_TXP) == 0)
        reSend = FALSE;
    else
    {
		SYS_IN_CHAR (pDrvCtrl, ENE_INTSTAT, &stat);
        if ((stat & (ISTAT_PTX | ISTAT_TXE)) == 0)
	    {
            reSend = TRUE;
	    }
        else
	    {
            reSend = FALSE;
	    }
    }

    SYS_OUT_CHAR (pDrvCtrl, ENE_TCON, TCON_LB1);

    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START);


    pDrvCtrl->flags &= ~END_OVERWRITE;
    pDrvCtrl->current = ne2000GetCurr (pDrvCtrl);
	

	#ifdef _USE_RECV_DMA_
	if(pDrvCtrl->current>= pDrvCtrl->nextPacket)
	{
		recvLen = (pDrvCtrl->current-pDrvCtrl->nextPacket)*RECV_PAGE_SIZE;
	}
	else
	{
		recvLen = ((NE2000_PSTOP-pDrvCtrl->nextPacket)+(pDrvCtrl->current-NE2000_PSTART))*RECV_PAGE_SIZE;
	}
	ne2000DmaRecv(pDrvCtrl , (((UINT)pDrvCtrl->nextPacket << 8) & 0x0000ffff) 
		 , recvLen);
	#else			
    ne2000HandleRcvInt (pDrvCtrl);
	#endif

    
}


/*******************************************************************************
*
*
* RETURNS: N/A.
*/

LOCAL void ne2000Int(NE2000END_DEVICE  *pDrvCtrl)
{
    UCHAR val;
    UCHAR intStat;
    UCHAR txStat;
    UCHAR rxStat;

    pDrvCtrl->stats.interrupts++;



    SYS_IN_CHAR (pDrvCtrl, ENE_INTSTAT, &intStat);
    intStat &= pDrvCtrl->imask;
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTSTAT, intStat);

    SYS_IN_CHAR (pDrvCtrl, ENE_TSTAT, &txStat);
    SYS_IN_CHAR (pDrvCtrl, ENE_RSTAT, &rxStat);

    ENDLOGMSG (("ne2000Int: intStat=%02x imask=%02x txStat=%02x rxStat=%02x\n",
		intStat, pDrvCtrl->imask, txStat, rxStat, 0, 0));
	if(TRUE == recvIntLog)
	{
		
		logMsg ("ne2000Int: intStat=%02x imask=%02x txStat=%02x rxStat=%02x\n", 
			intStat, pDrvCtrl->imask, txStat, rxStat, 0, 0);
	}

    SYS_IN_CHAR (pDrvCtrl, ENE_COLCNT, &val);
    pDrvCtrl->stats.collisions += val;
    SYS_IN_CHAR (pDrvCtrl, ENE_ALICNT, &val);
    pDrvCtrl->stats.aligns += val;
    SYS_IN_CHAR (pDrvCtrl, ENE_CRCCNT, &val);
    pDrvCtrl->stats.crcs += val;
    SYS_IN_CHAR (pDrvCtrl, ENE_MPCNT, &val);
    pDrvCtrl->stats.missed += val;



    if (intStat & ISTAT_OVW) /* Overwrite */
    {
		UCHAR cmdStat;
		UCHAR currNo ;
		UCHAR bnry ;


		currNo = ne2000GetCurr(pDrvCtrl);
		SYS_IN_CHAR (pDrvCtrl, ENE_BOUND , &bnry);

		END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
		if (!(pDrvCtrl->flags & END_OVERWRITE2))
		{
		    pDrvCtrl->flags |= (END_OVERWRITE | END_OVERWRITE2);
		    pDrvCtrl->lastError.errCode = END_ERR_WARN;
		    pDrvCtrl->lastError.pMesg = "Overwrite";
		    netJobAdd ((FUNCPTR) muxError, (int) &pDrvCtrl->endObj,
			       (int) &pDrvCtrl->lastError,
			       0, 0, 0);
		    pDrvCtrl->stats.overwrite++;
		    SYS_IN_CHAR (pDrvCtrl, ENE_COLCNT, &cmdStat);
		    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_STOP);
		    ENDLOGMSG (("ne2000Int: overwrite detected\n",
				0, 0, 0, 0, 0, 0));
		    netJobAdd ((FUNCPTR) ne2000OverwriteRecover, (int) pDrvCtrl,
				      cmdStat, 0, 0, 0);
		}
		pDrvCtrl->imask = 0;
		SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
		return;
    }

    if (intStat & ISTAT_RXE) /* Receive-error */
    {
		if (!pDrvCtrl->lastIntError)
		{
		    END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
		    pDrvCtrl->lastError.errCode = END_ERR_WARN;
		    pDrvCtrl->lastError.pMesg = "receive error";
		    netJobAdd ((FUNCPTR) muxError, (int) &pDrvCtrl->endObj,
			       (int) &pDrvCtrl->lastError,
			       0, 0, 0);
		}
		++pDrvCtrl->lastIntError;
	    pDrvCtrl->stats.rerror++;
	    if (rxStat & RSTAT_OVER)
	        pDrvCtrl->stats.overruns++;
	    if (rxStat & RSTAT_DIS)
	        pDrvCtrl->stats.disabled++;
	    if (rxStat & RSTAT_DFR)
	        pDrvCtrl->stats.deferring++;
    }
	
    if (intStat & ISTAT_TXE)    /* Transmit error-packet not sent */
    {
		if (!pDrvCtrl->lastIntError)
		{
		    END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS,  +1);
		    END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, -1);
		    pDrvCtrl->lastError.errCode = END_ERR_WARN;
		    pDrvCtrl->lastError.pMesg = "transmit error";
		    netJobAdd ((FUNCPTR) muxError, (int) &pDrvCtrl->endObj,
			       (int) &pDrvCtrl->lastError,
			       0, 0, 0);
		}
		++pDrvCtrl->lastIntError;
	    pDrvCtrl->stats.terror++;
	    if (txStat & TSTAT_ABORT)
	    {
	       pDrvCtrl->stats.aborts++;
	       pDrvCtrl->stats.collisions += 16;
	    }
	    if (txStat & TSTAT_UNDER)
	       pDrvCtrl->stats.underruns++;
    }

    if (intStat & ISTAT_PTX)    /* Transmit-packet sent */
    {
		END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
        if (txStat & TSTAT_CDH)
            pDrvCtrl->stats.heartbeats++;
        if (txStat & TSTAT_OWC)
            pDrvCtrl->stats.outofwindow++;
        if (txStat & TSTAT_PTX)
            pDrvCtrl->stats.tnoerror++;
    }

    if (!(intStat & (ISTAT_RXE | ISTAT_TXE)))
		pDrvCtrl->lastIntError = 0;

    if (intStat & ISTAT_PRX)
    {
    	int recvLen = 0;
	    pDrvCtrl->current = ne2000GetCurr (pDrvCtrl);
		ENDLOGMSG(("ne2000Int: input packet (flags=%x, current=%d)\n",
			   pDrvCtrl->flags, pDrvCtrl->current, 0, 0, 0, 0));
	    if (!(pDrvCtrl->flags & END_RECV_HANDLING_FLAG))
	    {
		    /* Disable RX int */
		    pDrvCtrl->imask &= ~IM_PRXE;
		    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);

	        pDrvCtrl->flags |= END_RECV_HANDLING_FLAG;

			#ifdef _USE_RECV_DMA_
			if(pDrvCtrl->current>= pDrvCtrl->nextPacket)
			{
				recvLen = (pDrvCtrl->current-pDrvCtrl->nextPacket)*RECV_PAGE_SIZE;
			}
			else
			{
				recvLen = ((NE2000_PSTOP-pDrvCtrl->nextPacket)+(pDrvCtrl->current-NE2000_PSTART))*RECV_PAGE_SIZE;
			}
			ne2000DmaRecv(pDrvCtrl , (((UINT)pDrvCtrl->nextPacket << 8) & 0x0000ffff) 
				 , recvLen);
			#else			
	        (void)netJobAdd ((FUNCPTR)ne2000HandleRcvInt, (int)pDrvCtrl,
	                     0,0,0,0);
			#endif
	    }
    }

    if ((intStat & (ISTAT_TXE | ISTAT_PTX)) != 0)
	{
		#ifndef _USE_SND_DMA_
		pDrvCtrl->flags &= ~END_TX_IN_PROGRESS;
		ENDLOGMSG (("ne2000Int: Tx complete, blocked=%d\n",
			    (pDrvCtrl->flags & END_TX_BLOCKED) ? 1 : 0,0,0,0,0,0));

		#else
		if(pDrvCtrl->bufCount< SAVE_SND_NUM)
		{
			ne2000DmaSend(pDrvCtrl , (NE2000_TSTART << 8));
		}
		else
		{
			pDrvCtrl->flags &= ~END_TX_IN_PROGRESS;
		}
		#endif
		if (pDrvCtrl->flags & END_TX_BLOCKED)
		{
		    pDrvCtrl->imask &= ~(IM_TXEE | IM_PTXE);
		    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);

		    pDrvCtrl->flags &= ~END_TX_BLOCKED;
		    netJobAdd ((FUNCPTR)muxTxRestart, (int)&pDrvCtrl->endObj,
			       0, 0, 0, 0);
		}
	}

    /* Flush the write pipe */

    CACHE_PIPE_FLUSH ();
}


/*******************************************************************************
*
* ne2000HandleRcvInt - task level interrupt service for input packets
*
* This routine is called at task level indirectly by the interrupt
* service routine to do any message received processing.
*
* RETURNS: N/A.
*/

LOCAL void ne2000HandleRcvInt
    (
    NE2000END_DEVICE *pDrvCtrl
    )
    {
    int oldLevel;
    char *pBuf;
	UCHAR currNo ;
	UCHAR bnry ;
	UCHAR stat;
	int errFlag = FALSE;


    ENDLOGMSG (("ne2000HandleRcvInt(%x): enter (flags=%x)\n",
		pDrvCtrl,pDrvCtrl->flags,0,0,0,0));
    pBuf = NULL;
    while ((pDrvCtrl->flags & END_RECV_HANDLING_FLAG) || (pDrvCtrl->flags &END_OVERWRITE2))
	{
		int	len;
		CL_BLK_ID	pClBlk;
		M_BLK_ID	pMblk;      /* MBLK to send upstream */

		SYS_IN_CHAR (pDrvCtrl, ENE_BOUND , &bnry);
		if (pDrvCtrl->nextPacket == pDrvCtrl->current)
		    break;

		if (pDrvCtrl->flags & END_OVERWRITE)
		    break;		

		if (!pBuf)
		{
		    pBuf = netClusterGet (pDrvCtrl->endObj.pNetPool,
					  pDrvCtrl->clPoolId);
		    if (!pBuf)
			{				
				errFlag = TRUE;
				break;
			}
		}
		len = ne2000PacketGet (pDrvCtrl, pBuf + pDrvCtrl->offset);
		if (len <= 0)
		{			
		    END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
			errFlag = TRUE;
		    break;
		}
		pMblk = mBlkGet (pDrvCtrl->endObj.pNetPool,
				 M_DONTWAIT, MT_DATA);
		if (!pMblk)
		{			
		    END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
			errFlag = TRUE;
		    break;
		}
		pClBlk = netClBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT);
		if (!pClBlk)
		{			
		    netMblkFree (pDrvCtrl->endObj.pNetPool, (M_BLK_ID)pMblk);
			errFlag = TRUE;
		    break;
		}
		netClBlkJoin (pClBlk, pBuf, NE2000_BUFSIZ, NULL, 0, 0, 0);

		netMblkClJoin (pMblk, pClBlk);

		pMblk->mBlkHdr.mFlags |= M_PKTHDR;
		pMblk->mBlkHdr.mLen    = len;
		pMblk->mBlkPktHdr.len  = len;
		pMblk->mBlkHdr.mData   += pDrvCtrl->offset;

		END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);

		END_RCV_RTN_CALL (&pDrvCtrl->endObj, pMblk);

		pBuf = NULL;
	}

    if (pBuf)
		netClFree (pDrvCtrl->endObj.pNetPool, (UCHAR *) pBuf);

    oldLevel = intLock ();
    pDrvCtrl->flags &= ~END_RECV_HANDLING_FLAG;
    pDrvCtrl->imask |= IM_PRXE;
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);

	if(pDrvCtrl->flags &END_OVERWRITE2 )
	{
		currNo = ne2000GetCurr(pDrvCtrl);
		SYS_IN_CHAR (pDrvCtrl, ENE_BOUND , &bnry);

		if(TRUE == errFlag)
		{
			if(NE2000_PSTART ==currNo )
			{
				bnry = NE2000_PSTOP-1;
			}
			else
			{
				bnry = currNo-1;
			}
			SYS_OUT_CHAR (pDrvCtrl, ENE_BOUND , bnry);
		}
	    SYS_IN_CHAR (pDrvCtrl, ENE_INTSTAT, &stat);
	    SYS_OUT_CHAR (pDrvCtrl, ENE_INTSTAT, stat);

	    SYS_OUT_CHAR (pDrvCtrl, ENE_TCON, 0x00);

	    pDrvCtrl->imask = NE2000_ALL_INTS;
	    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);

	    pDrvCtrl->flags &= ~END_OVERWRITE2;

	}


    intUnlock (oldLevel);
    }

/*******************************************************************************
*
* ne2000DataIn - input bytes from NE2000 memory
*
* NOMANUAL
*/

LOCAL void ne2000DataIn
    (
    NE2000END_DEVICE *	pDrvCtrl,
    int			eneAddress,
    int			len,
    char *		pData
    )
    {
    if (len == 0)
	{
		return;
	}

    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, 0);
    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR0, eneAddress & 0xff);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR1, eneAddress >> 8);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, len & 0xff);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, len >> 8);
    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_RREAD | CMD_START);

    SYS_IN_WORD_STRING (pDrvCtrl, ENE_DATA, pData, len/2);
    if (len & 1)
	SYS_IN_CHAR (pDrvCtrl, ENE_DATA, (pData + (len - 1)));
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
    }

/*******************************************************************************
*
* ne2000DataOut - output bytes to NE2000 memory
*
* NOMANUAL
*/


void ne2000DmaInit()
{	
	#ifdef _USE_SND_DMA_
	(void) intConnect (INUM_TO_IVEC(INT_VEC_DMA3),ne2000DmaSendInt, (int)0);
    intEnable (INT_LVL_DMA3); 
	#endif

	#ifdef _USE_RECV_DMA_
	(void) intConnect (INUM_TO_IVEC(INT_VEC_DMA0),ne2000DmaRecvInt, (int)0);
    intEnable (INT_LVL_DMA0); 
	#endif
}


#ifdef _USE_SND_DMA_

void ne2000DmaSendInt()
{
	ENDLOGMSG (("into ne2000DmaSendInt.\n", 0, 0, 0, 0, 0, 0));

    SYS_OUT_CHAR (gpDeviceCtrl, ENE_TSTART, NE2000_TSTART);
    SYS_OUT_CHAR (gpDeviceCtrl, ENE_TCNTH, 
		gpDeviceCtrl->packetLen[gpDeviceCtrl->useHead] >> 8);
    SYS_OUT_CHAR (gpDeviceCtrl, ENE_TCNTL, 
		gpDeviceCtrl->packetLen[gpDeviceCtrl->useHead] & 0xff);
   
	if(gpDeviceCtrl->bufCount >=(SAVE_SND_NUM-1) )
	{
		gpDeviceCtrl->useHead = 0x5a;
		gpDeviceCtrl->bufCount = SAVE_SND_NUM;
	}
	else
	{
		if(gpDeviceCtrl->useHead >= (SAVE_SND_NUM-1))
		{
			gpDeviceCtrl->useHead = 0;
		}
		else
		{
			gpDeviceCtrl->useHead++;
		}
		gpDeviceCtrl->bufCount++;
	}

	CACHE_PIPE_FLUSH ();

	 SYS_OUT_CHAR (gpDeviceCtrl, ENE_CMD, CMD_TXP | CMD_START);


	
}
void ne2000DmaSend(NE2000END_DEVICE* pDrvCtrl , int eneAddress)
{
	char *sndBuf = NULL;
	int sndLen = 0;
	
	
	ENDLOGMSG (("into ne2000DmaSend.\n", 0, 0, 0, 0, 0, 0));

	sndBuf = pDrvCtrl->packetBuf[pDrvCtrl->useHead];
	sndLen = pDrvCtrl->packetLen[pDrvCtrl->useHead];
    if (sndLen == 0)
	{
		ENDLOGMSG (("ne2000DmaSend:send len is 0.\n", 0, 0, 0, 0, 0, 0));
        return;
	}

	if(rNE2000_DSTAT3 & 0xfffff)
	{
	  ENDLOGMSG (("ne2000DmaSend:dma can not op.\n", 0, 0, 0, 0, 0, 0));
	  return ;
	}

	pDrvCtrl->flags |= END_TX_IN_PROGRESS;

    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR0, eneAddress & 0xff);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR1, eneAddress >> 8);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, sndLen & 0xff);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, sndLen >> 8);
    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_RWRITE | CMD_START);
	
	
	rNE2000_DISRC3 = (int)sndBuf;
	rNE2000_DISRCC3 = (0x0<<1) + 0x0;
	rNE2000_DIDST3 = ((U32)(pDrvCtrl)->base+ (int)ENE_DATA);
	rNE2000_DIDSTC3 = (0x0<<1)+0x1;
	rNE2000_DCON3 = ((unsigned)1<<31)+(1<<30)+(1<<29)+(0<<28)+(1<<27)+(0<<23)+(1<<22)+(0<<20)+sndLen;/*((len-0x30)/2);*/

	rNE2000_DMASKTRIG3 = (0x0<<2) + (0x1<<1) + (0x1<<0);
	
		

}

#else
void ne2000DmaSendInt()
{
}

void ne2000DmaSend(NE2000END_DEVICE* pDev , char *srcBuf , int sndLen)
{
	
	if(rNE2000_DSTAT3 & 0xfffff)
	{
	  return ;
	}
	rNE2000_DISRC3 = (int)srcBuf;
	rNE2000_DISRCC3 = (0x0<<1) + 0x0;
	rNE2000_DIDST3 = ((U32)(pDev)->base+ (int)ENE_DATA);
	rNE2000_DIDSTC3 = (0x0<<1)+0x1;
	rNE2000_DCON3 = ((unsigned)1<<31)+(1<<30)+(1<<29)+(0<<28)+(1<<27)+(0<<23)+(1<<22)+(0<<20)+sndLen;/*((len-0x30)/2);*/

	rNE2000_DMASKTRIG3 = (0x0<<2) + (0x1<<1) + (0x1<<0);
	

}

#endif

#ifdef _USE_RECV_DMA_
void ne2000DmaRecvInt()
{
		
	gpDeviceCtrl->nextMapPage = 0;
	(void)netJobAdd ((FUNCPTR)ne2000HandleRcvInt, (int)gpDeviceCtrl,
	                     0,0,0,0);	

}

void ne2000DmaRecv(NE2000END_DEVICE *pDrvCtrl,int eneAddress,int	len)
{
	ENDLOGMSG (("into ne2000DmaRecv.\n", 0, 0, 0, 0, 0, 0));
    if (len == 0)
	{
		pDrvCtrl->flags &= ~END_RECV_HANDLING_FLAG;
		pDrvCtrl->imask |= IM_PRXE;
		    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
		return;
	}

    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, 0);
    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR0, eneAddress & 0xff);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR1, eneAddress >> 8);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, len & 0xff);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, len >> 8);
    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_RREAD | CMD_START);


	rNE2000_DISRC0 = ((U32)(pDrvCtrl)->base+ (int)ENE_DATA);		
	rNE2000_DISRCC0 = (0x0<<1) + 0x1;
	rNE2000_DIDST0 = ((U32)pDrvCtrl->recvMapBuf[0]);
	rNE2000_DIDSTC0 = (0x0<<1)+0x0;
	rNE2000_DCON0 = ((unsigned)1<<31)+(1<<30)+(1<<29)+(0<<28)+(1<<27)+(0<<23)+(1<<22)+(0<<20)+len;/*((len-0x30)/2);*/

	rNE2000_DMASKTRIG0 = (0x0<<2) + (0x1<<1) + (0x1<<0);


}

#endif

/*******************************************************************************
*
* ne2000OpenRecvIntLog - output bytes to NE2000 memory
*
* NOMANUAL
*/
void ne2000OpenRecvIntLog()
{
	recvIntLog = TRUE;
}

/*******************************************************************************
*
* ne2000DataOut - output bytes to NE2000 memory
*
* NOMANUAL
*/

LOCAL void ne2000DataOut
    (
    NE2000END_DEVICE *	pDrvCtrl,
    char *		pData,
    int			len,
    int			eneAddress
    )
    {
	ENDLOGMSG (("into ne2000DataOut.\n", 0, 0, 0, 0, 0, 0));
    if (len == 0)
        return;

    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, (char)0xff);
    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR0, eneAddress & 0xff);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR1, eneAddress >> 8);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, len & 0xff);
    SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, len >> 8);
    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_RWRITE | CMD_START);

	#ifndef _USE_SND_DMA_
	#ifndef _UNUSE_SND_DMA_
	ne2000DmaSend(pDrvCtrl , pData , len);
	#else
	SYS_OUT_WORD_STRING (pDrvCtrl, ENE_DATA, pData, len/2);
    if (len & 1)
        SYS_OUT_CHAR (pDrvCtrl, ENE_DATA, *(pData + (len - 1)));
	#endif
	#endif
	
    }

/*******************************************************************************
*
* RETURNS: OK or ERROR.
*/

LOCAL STATUS ne2000Send
    (
    void*	pCookie,	
    M_BLK_ID	pMblk		
    )
    {
    int		len;
    UCHAR	cmdStat;
	int level = 0;
    NE2000END_DEVICE* pDrvCtrl = (NE2000END_DEVICE *) pCookie;
    

	ENDLOGMSG (("ne2000Send: enter: (flags=%x, imask=%x)\n",
		pDrvCtrl->flags, pDrvCtrl->imask, 0, 0, 0, 0));

    if (pDrvCtrl->flags & (END_OVERWRITE | END_OVERWRITE2))
	{
		return (END_ERR_BLOCK);
	}	


    END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);

	#ifndef _USE_SND_DMA_
    pDrvCtrl->flags |= END_TX_BLOCKED;
	#endif
	

	#ifndef _USE_SND_DMA_
    if (pDrvCtrl->flags & END_TX_IN_PROGRESS)
	{
		int cnt;
		ENDLOGMSG (("ne2000Send: waiting for TX_IN_PROGRESS\n",
			    0,0,0,0,0,0));

		cnt = sysClkRateGet ();
		while ((pDrvCtrl->flags & END_TX_IN_PROGRESS) && (cnt-- > 0))
		{
		    taskDelay (1);
		}
	}
	#endif
	#ifndef _USE_SND_DMA_
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, 0);
    if (pDrvCtrl->flags & (END_OVERWRITE | END_OVERWRITE2))
	{
		ENDLOGMSG (("ne2000Send: overwrite detected (timeout)\n",
			    0, 0, 0, 0, 0, 0));
		pDrvCtrl->flags &= ~END_TX_BLOCKED;
		END_TX_SEM_GIVE (&pDrvCtrl->endObj);
		return (END_ERR_BLOCK);
	}
	#endif
	#ifndef _USE_SND_DMA_
    if (pDrvCtrl->flags & END_TX_IN_PROGRESS)
	{
	UCHAR tstat;

	SYS_IN_CHAR (pDrvCtrl, ENE_TSTAT, &tstat);
	SYS_IN_CHAR (pDrvCtrl, ENE_CMD, &cmdStat);
	ENDLOGMSG (("ne2000Send: timeout: flags=%x cmd=%02x stat=%02x\n",
		    pDrvCtrl->flags, cmdStat, tstat, 0, 0, 0));
	ne2000Config (pDrvCtrl, FALSE);
	}
	#endif


	#ifndef _USE_SND_DMA_

   len = netMblkToBufCopy (pMblk, pDrvCtrl->packetBuf, NULL);
	
    netMblkClChainFree (pMblk);
    len = max (len, ETHERSMALL);

	
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, 0x00);

	ne2000DataOut (pDrvCtrl, pDrvCtrl->packetBuf, len, (NE2000_TSTART << 8));
	
    
    CACHE_PIPE_FLUSH ();
    
    SYS_OUT_CHAR (pDrvCtrl, ENE_TSTART, NE2000_TSTART);
    SYS_OUT_CHAR (pDrvCtrl, ENE_TCNTH, len >> 8);
    SYS_OUT_CHAR (pDrvCtrl, ENE_TCNTL, len & 0xff);
    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_TXP | CMD_START);

    pDrvCtrl->flags |= END_TX_IN_PROGRESS;

    pDrvCtrl->imask |= (IM_TXEE | IM_PTXE);
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);

	#else
	level = intLock ();
	if(pDrvCtrl->bufCount>0)
	{
   		len = netMblkToBufCopy (pMblk, 
			pDrvCtrl->packetBuf[pDrvCtrl->freeHead], NULL);
		len = max (len, ETHERSMALL);
		pDrvCtrl->packetLen[pDrvCtrl->freeHead] = len;
		if(0x5a == pDrvCtrl->useHead )
		{
			pDrvCtrl->useHead = pDrvCtrl->freeHead;
		}
		if(pDrvCtrl->freeHead>= (SAVE_SND_NUM -1))
		{
			pDrvCtrl->freeHead =0;
		}
		else
		{
			pDrvCtrl->freeHead++;
		}
		pDrvCtrl->bufCount--;
		intUnlock(level);
	}
	else
	{
		intUnlock(level);
		return (END_ERR_BLOCK);
	}
	
    netMblkClChainFree (pMblk);
    

	if (!(pDrvCtrl->flags & END_TX_IN_PROGRESS))
	{
		ne2000DmaSend(pDrvCtrl , (NE2000_TSTART << 8));
	}
	#endif
	

    END_TX_SEM_GIVE (&pDrvCtrl->endObj);

    END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);


    ENDLOGMSG (("ne2000Send: done: imask=%02x\n",
		pDrvCtrl->imask, 0, 0, 0, 0, 0));
    return (OK);
    }

/*******************************************************************************
*
*
* RETURNS: ptr to next packet, or NULL if none ready.
*/

LOCAL int ne2000PacketGet
    (
    NE2000END_DEVICE	*pDrvCtrl,
    char		*pData
    )
    {
    UINT        packetSize;
    UCHAR	uppByteCnt;
    UINT8       tempPage;              
    UINT8       pageCount;             
    UINT        packetLen = 0;
    NE2000_HEADER  h;
	char tmpData[2048];
	int tmpDataLen = 0;

	ENDLOGMSG (("into ne2000PacketGet.\n", 0, 0, 0, 0, 0, 0));
	
    if (pDrvCtrl->nextPacket == pDrvCtrl->current)
		return (0);

	#ifdef _USE_RECV_DMA_
	memcpy(&h , pDrvCtrl->recvMapBuf[pDrvCtrl->nextMapPage] , sizeof (NE2000_HEADER));
	#else    
	ne2000DataIn (pDrvCtrl,
		  (((UINT)pDrvCtrl->nextPacket << 8) & 0x0000ffff),
		  sizeof (NE2000_HEADER), (char *) &h);	
	#endif

    if (h.next > pDrvCtrl->nextPacket)
	uppByteCnt = (UCHAR) (h.next - pDrvCtrl->nextPacket);
    else
	uppByteCnt = (UCHAR) ((NE2000_PSTOP - pDrvCtrl->nextPacket)
			      + (h.next - NE2000_PSTART));
    if (h.lowByteCnt > 0xfc)
	uppByteCnt -= 2;
    else
	uppByteCnt -= 1;
    h.uppByteCnt = uppByteCnt;


    packetSize = (((UINT)h.uppByteCnt << 8) + h.lowByteCnt) - 4;

    pageCount = (UCHAR) ((packetSize + 4 + sizeof (NE2000_HEADER)
			  + (ENE_PAGESIZE - 1)) / ENE_PAGESIZE);
    tempPage = (UCHAR) (pDrvCtrl->nextPacket + pageCount);
    if (tempPage >= NE2000_PSTOP)
	tempPage -= (NE2000_PSTOP - NE2000_PSTART);
    if ((h.next != tempPage) ||
	(h.next < NE2000_PSTART) || (h.next >= NE2000_PSTOP))
	{
	pDrvCtrl->stats.badPacket++;
	pDrvCtrl->stats.rerror++;
	if (!(pDrvCtrl->flags & (END_OVERWRITE|END_OVERWRITE2)))
	    ne2000Config (pDrvCtrl, TRUE);
	return (-1);
	}

    if (packetSize < 60)
	{
	pDrvCtrl->stats.shortPacket++;
	goto doneGet;
	}

    if (packetSize > NE2000_BUFSIZ)
	goto doneGet;

    if (h.rstat & RSTAT_PRX)
	{
	if (h.rstat & (RSTAT_DFR | RSTAT_DIS))
	    {
	    pDrvCtrl->stats.badPacket++;
	    pDrvCtrl->stats.rerror++;
	    goto doneGet;
	    }
	pDrvCtrl->stats.rnoerror++;
	}
    else
	{
	if (h.rstat & RSTAT_DFR)
	    pDrvCtrl->stats.jabber++;
	pDrvCtrl->stats.rerror++;
	goto doneGet;
	}

    packetLen = packetSize;

	#ifdef _USE_RECV_DMA_
	memcpy(pData , pDrvCtrl->recvMapBuf[pDrvCtrl->nextMapPage]+sizeof (NE2000_HEADER) , packetLen);
	#else
	tmpDataLen = ((packetLen+sizeof(NE2000_HEADER))/256+1)*256-sizeof(NE2000_HEADER);
    ne2000DataIn (pDrvCtrl,
		  ((UINT)pDrvCtrl->nextPacket << 8) + sizeof (NE2000_HEADER),
		  tmpDataLen,
		  tmpData);
	memcpy(pData , tmpData , packetLen);

	ENDLOGMSG (("into ne2000PacketGet.nextMapPage = %d:len = %d:tmplen = %d.\n", pDrvCtrl->nextPacket
			, tmpDataLen , packetLen, 0, 0, 0));
	#endif


doneGet:
	#ifdef _USE_RECV_DMA_	
	if( pDrvCtrl->nextPacket<= h.next)
	{
		pDrvCtrl->nextMapPage += (h.next-pDrvCtrl->nextPacket);
	}
	else
	{
		pDrvCtrl->nextMapPage += ((NE2000_PSTOP-pDrvCtrl->nextPacket)+
				(h.next-NE2000_PSTART));
	}
	#endif
    pDrvCtrl->nextPacket = h.next;
    SYS_OUT_CHAR (pDrvCtrl, ENE_BOUND,
		  (pDrvCtrl->nextPacket != NE2000_PSTART ?
		   pDrvCtrl->nextPacket - 1 : NE2000_PSTOP - 1));

    return (packetLen);
    }


/******************************************************************************
*
* device.
*/

LOCAL STATUS ne2000PollRecv
    (
    void*	pCookie,	
    M_BLK_ID	pMblk
    )
    {
    int len;
    NE2000END_DEVICE* pDrvCtrl = (NE2000END_DEVICE *) pCookie;

	ENDLOGMSG (("into ne2000PollRecv.\n", 0, 0, 0, 0, 0, 0));

    pDrvCtrl->current = ne2000GetCurr (pDrvCtrl);
    if (pDrvCtrl->nextPacket == pDrvCtrl->current)
        return ((STATUS) (EAGAIN));

    if ((pMblk->mBlkHdr.mLen < NE2000_BUFSIZ)
	|| !(pMblk->mBlkHdr.mFlags & M_EXT))
	{
        return ((STATUS) (EAGAIN));
	}

    ENDLOGMSG (("ne2000PollRecv: enter: imask=%02x\n",
		pDrvCtrl->imask, 0, 0, 0, 0, 0));

    len = ne2000PacketGet (pDrvCtrl, pMblk->mBlkHdr.mData + pDrvCtrl->offset);
    if (len <= 0)
        return ((STATUS) (EAGAIN));
    pMblk->mBlkHdr.mFlags |= M_PKTHDR;
    pMblk->mBlkHdr.mLen   = len;
    pMblk->mBlkPktHdr.len = len;
    pMblk->mBlkHdr.mData += pDrvCtrl->offset;

    ENDLOGMSG (("ne2000PollRecv: done: imask=%02x\n",
		pDrvCtrl->imask, 0, 0, 0, 0, 0));
    return (OK);
    }

/*******************************************************************************
*
* device.
*/

static STATUS ne2000PollSend
    (
    void*	pCookie,	
    M_BLK_ID	pMblk
    )
    {
    char *	pBuf;
    UCHAR	cmdStat;
    int		len;
    NE2000END_DEVICE* pDrvCtrl = (NE2000END_DEVICE *) pCookie;

    ENDLOGMSG (("ne2000PollSend: enter: imask=%x flags=%x\n",
		pDrvCtrl->imask, pDrvCtrl->flags, 0, 0, 0, 0));

    SYS_IN_CHAR (pDrvCtrl, ENE_CMD, &cmdStat);
    while (cmdStat & CMD_TXP)
	SYS_IN_CHAR (pDrvCtrl, ENE_DATA, &cmdStat);


	#ifdef	_USE_SND_DMA_
    pBuf = pDrvCtrl->packetBuf[0];
	#else
	pBuf = pDrvCtrl->packetBuf;
	#endif
    len = netMblkToBufCopy (pMblk, pBuf, NULL);
    len = max (len, ETHERSMALL);

	#ifdef _USE_SND_DMA_
	ne2000DataOut (pDrvCtrl, pDrvCtrl->packetBuf[0], len, (NE2000_TSTART << 8));
	#else
	ne2000DataOut (pDrvCtrl, pDrvCtrl->packetBuf, len, (NE2000_TSTART << 8));
	#endif

    CACHE_PIPE_FLUSH ();


    SYS_OUT_CHAR (pDrvCtrl, ENE_TSTART, NE2000_TSTART);
    SYS_OUT_CHAR (pDrvCtrl, ENE_TCNTH, len >> 8);
    SYS_OUT_CHAR (pDrvCtrl, ENE_TCNTL, len & 0xff);
    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_TXP | CMD_START);


    END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);


    CACHE_PIPE_FLUSH ();


    SYS_IN_CHAR (pDrvCtrl, ENE_CMD, &cmdStat);
    while (cmdStat & CMD_TXP)
	SYS_IN_CHAR (pDrvCtrl, ENE_CMD, &cmdStat);

    ENDLOGMSG (("ne2000PollSend: done: imask=%x flags=%x\n",
		pDrvCtrl->imask, pDrvCtrl->flags, 0, 0, 0, 0));

    return (OK);
    }

/*******************************************************************************
*
* ne2000PollStart - start polled mode operations
*
* RETURNS: OK or ERROR.
*/

LOCAL STATUS ne2000PollStart
    (
    NE2000END_DEVICE* pDrvCtrl
    )
    {
    int oldLevel;

    oldLevel = intLock ();
    ENDLOGMSG (("ne2000PollStart: imask=%x flags=%x\n",
		pDrvCtrl->imask, pDrvCtrl->flags, 0, 0, 0, 0));
    pDrvCtrl->flags |= END_POLLING;
    pDrvCtrl->imask = 0;
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);
    intUnlock (oldLevel);

    return (OK);
    }

/*******************************************************************************
*
* ne2000PollStop - stop polled mode operations
*
*
* RETURNS: OK or ERROR.
*/

LOCAL STATUS ne2000PollStop
    (
    NE2000END_DEVICE* pDrvCtrl
    )
    {
    int oldLevel;

    oldLevel = intLock ();
    pDrvCtrl->flags &= ~END_POLLING;
    pDrvCtrl->imask = NE2000_ALL_INTS;
    if (pDrvCtrl->flags & END_RECV_HANDLING_FLAG)
	pDrvCtrl->imask &= ~IM_PRXE;
    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);

    ENDLOGMSG (("ne2000PollStop: imask=%x flags=%x\n",
		pDrvCtrl->imask, pDrvCtrl->flags, 0, 0, 0, 0));
    intUnlock (oldLevel);
    return (OK);
    }

/******************************************************************************
*
* ne2000AddrFilterSet - set the address filter for multicast addresses
*
*
* NOMANUAL
*/
LOCAL void ne2000AddrFilterSet
    (
    NE2000END_DEVICE *pDrvCtrl
    )
    {
    int i;
    int eAddr;
    u_char enetChar;
    u_char *pCp;
    u_long crc;
    ETHER_MULTI* pCurr;

    ENDLOGMSG (("ne2000AddrFilterSet\n", 0, 0, 0, 0, 0, 0));

   
    for (i = 0; i < 8; ++i)
	pDrvCtrl->mcastFilter[i] = 0;

    for (pCurr = END_MULTI_LST_FIRST (&pDrvCtrl->endObj);
	 pCurr != NULL;
	 pCurr = END_MULTI_LST_NEXT(pCurr))
	{
	pCp = (unsigned char *)&pCurr->addr;

	crc = 0xffffffff; 


	for (eAddr = 0; eAddr < 6; eAddr++)
	    {
	    enetChar = *pCp++;
            crc = ne2000CrcWork (enetChar, crc);
	    }


	crc >>= 26;
	crc &= 0x3f;



	pDrvCtrl->mcastFilter[crc >> 3] |= (1 << (crc & 7));
	}
    }

/*****************************************************************************
*
* ne2000CrcWork - return CRC using a 32 bit polynomial
*
*
* NOMANUAL
*
*/

LOCAL UINT32 ne2000CrcWork
    (
    UINT8 inChar,
    UINT32 inCrc
    )
    {
    UINT8 work = 0;
    UINT8 wrap;
    int i;
     ENDLOGMSG (("into ne2000CrcWork.\n", 0, 0, 0, 0, 0, 0));

    for (i = 0; i < 8; i++)
        {
        wrap = (inCrc >> 31);
        inCrc <<= 1;
        work  = ((work << 1) | wrap) ^ inChar;
        if (work & 1)
            {
            inCrc ^= CRC32_POLYNOMIAL;
            }
         work >>= 1;
         inChar >>= 1;
         }
     return (inCrc);
     }


/*****************************************************************************
*
* ne2000MCastAdd - add a multicast address for the device
*
*/

LOCAL STATUS ne2000MCastAdd
    (
    void*	pCookie,	/* device ptr */
    char*	pAddress
    )
    {
    NE2000END_DEVICE* pDrvCtrl = (NE2000END_DEVICE *) pCookie;

    ENDLOGMSG (("ne2000MCastAdd - %02x:%02x:%02x:%02x:%02x:%02x\n",
		pAddress[0]&0xff, pAddress[1]&0xff, pAddress[2]&0xff,
		pAddress[3]&0xff, pAddress[4]&0xff, pAddress[5]&0xff));

    if (etherMultiAdd (&pDrvCtrl->endObj.multiList, pAddress) == ENETRESET)
	{
	}

    return (OK);
    }

/*****************************************************************************
*
* ne2000MCastDel - delete a multicast address for the device
*
*/

LOCAL STATUS ne2000MCastDel
    (
    void*	pCookie,	/* device ptr */
    char*	pAddress
    )
    {
    NE2000END_DEVICE* pDrvCtrl = (NE2000END_DEVICE *) pCookie;

    ENDLOGMSG (("ne2000MCastDel - %02x:%02x:%02x:%02x:%02x:%02x\n",
		pAddress[0]&0xff, pAddress[1]&0xff, pAddress[2]&0xff,
		pAddress[3]&0xff, pAddress[4]&0xff, pAddress[5]&0xff));

    if (etherMultiDel (&pDrvCtrl->endObj.multiList,
		       (char *)pAddress) == ENETRESET)
	{
	}

    return (OK);
    }

/*****************************************************************************
*
* ne2000MCastGet - get the multicast address list for the device
*
*/

LOCAL STATUS ne2000MCastGet
    (
    void*		pCookie,	/* device ptr */
    MULTI_TABLE*	pTable
    )
    {
    int error;
    NE2000END_DEVICE* pDrvCtrl = (NE2000END_DEVICE *) pCookie;

    ENDLOGMSG (("ne2000MCastGet\n", 0, 0, 0, 0, 0, 0));
    error = etherMultiGet (&pDrvCtrl->endObj.multiList, pTable);

    return (error);
    }

/******************************************************************************
*
* ne2000Stop - stop the device
*
* RETURNS: OK or ERROR
*/

LOCAL STATUS ne2000Stop
    (
    void *pCookie
    )
    {
    STATUS result = OK;
    NE2000END_DEVICE* pDrvCtrl;

	ENDLOGMSG (("into ne2000Stop.\n", 0, 0, 0, 0, 0, 0));

    pDrvCtrl = (NE2000END_DEVICE *) pCookie;


    END_FLAGS_CLR (&pDrvCtrl->endObj, IFF_UP | IFF_RUNNING);


    pDrvCtrl->imask = 0;

    SYS_OUT_CHAR (pDrvCtrl, ENE_INTMASK, pDrvCtrl->imask);


    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_STOP);

    ENDLOGMSG (("ne2000Stop\n", 0, 0, 0, 0, 0, 0));

    SYS_INT_DISCONNECT (pDrvCtrl, ne2000Int, (int)pDrvCtrl, &result);

    if (result == ERROR)
	ENDLOGMSG (("Could not disconnect interrupt!\n", 1, 2, 3, 4, 5, 6));

    return (result);
    }

/******************************************************************************
*
* ne2000Unload - unload a driver from the system
*
*/

LOCAL STATUS ne2000Unload
    (
    void *pCookie
    )
    {
    NE2000END_DEVICE* pDrvCtrl = (NE2000END_DEVICE *) pCookie;

    ENDLOGMSG (("ne2000Unload\n", 0, 0, 0, 0, 0, 0));

    END_OBJECT_UNLOAD (&pDrvCtrl->endObj); /* generic end unload functions */

    return (OK);
    }

/******************************************************************************
*
* ne2000EnetAddrGet - get enet address
*
* NOMANUAL
*/

LOCAL void ne2000EnetAddrGet
    (
    NE2000END_DEVICE* pDrvCtrl
    )
    {
    int i;

	ENDLOGMSG (("into ne2000EnetAddrGet.\n", 0, 0, 0, 0, 0, 0));

	    
	bcopyBytes ((char *) (0x7e000), &(MAC_INFO),sizeof(MAC_INFO));
	if ((MAC_INFO.macshowinfo[0] !=0)||(MAC_INFO.macshowinfo[1] !=0)||(MAC_INFO.macshowinfo[2] !=0)||(MAC_INFO.macshowinfo[3] !=0)||(MAC_INFO.macshowinfo[4] !=0)||(MAC_INFO.macshowinfo[5] !=0))
	{
	for (i = 0; i < 6; ++i)
		ne2000EnetAddr[i] = MAC_INFO.macshowinfo[i];
	}
	else
	{
			for (i = 0; i < 6; ++i)
						MAC_INFO.macshowinfo[i] = ne2000EnetAddr[i];
			SST39VF160_ChipProg(0x3F000,&(MAC_INFO),sizeof(MAC_INFO));
	}	


    if (pDrvCtrl->usePromEnetAddr)
	{
	SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_NODMA | CMD_PAGE0 | CMD_START);
	SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR0, NE2000_EADDR_LOC);
	SYS_OUT_CHAR (pDrvCtrl, ENE_RSAR1, NE2000_CONFIG_PAGE);
	SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR0, (EADDR_LEN * 2) & 0xff);
	SYS_OUT_CHAR (pDrvCtrl, ENE_RBCR1, (EADDR_LEN * 2) >> 8);
	SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_RREAD | CMD_START);

	for (i = 0; i < 6; ++i)
	    {
	    char ch;

	    SYS_IN_CHAR (pDrvCtrl, ENE_DATA, &pDrvCtrl->enetAddr[i]);
	    if (pDrvCtrl->byteAccess)
		SYS_IN_CHAR (pDrvCtrl, ENE_DATA, &ch);
	    }

	for (i = 0; i < 6; ++i)
	    if (pDrvCtrl->enetAddr[i])
		return;
	}

    for (i = 0; i < 6; ++i)
	pDrvCtrl->enetAddr[i] = ne2000EnetAddr[i];

    }

/******************************************************************************
*
* ne2000GetCurr - get current page
*
* RETURNS: current page that ENE is working on
*
* NOMANUAL
*/

LOCAL UCHAR ne2000GetCurr
    (
    NE2000END_DEVICE* pDrvCtrl
    )
    {
    UCHAR curr;

	ENDLOGMSG (("into ne2000GetCurr.\n", 0, 0, 0, 0, 0, 0));

    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_PAGE1);
    SYS_IN_CHAR (pDrvCtrl, ENE_CURR, &curr);
    SYS_OUT_CHAR (pDrvCtrl, ENE_CMD, CMD_PAGE0);

    return (curr);
    }