www.pudn.com > 860bsp.rar > motCpmEnd.c


/* motCpmEnd.c - END style Motorola MC68EN360/MPC800 network interface driver */ 
 
/* Copyright 1997-1999 Wind River Systems, Inc. */ 
#include "copyright_wrs.h" 
 
/* 
modification history 
-------------------- 
01x,29mar99,dat  SPR 26119, documentation, usage of .bS/.bE 
01w,26nov98,dbt  removed splimp() and splx() calls in motCmpEndIoctl 
		 (SPR #23528). Added a missing netMblkClChainFree() call. 
01v,22sep98,dat  added Didier's fix for system-mode transitions. (SPR 22325) 
		 removed warnings. 
01u,09sep98,n_s  removed promiscous mode filter from motCpmEndPollReceive ().  
                 spr 21143. 
01t,28aug98,dat  chg'd all names from motCmp to motCpm. 
01s,21aug98,n_s  removed promiscous mode filter from motCmpRecv (). spr 21143. 
01r,30jun98,cn   changed include file motCmpEnd.h to motCpmEnd.h 
01q,22jun98,cn   added support for PPC800-series Ethernet Controller. 
01p,11dec97,kbw  making man page edits 
01o,08dec97,gnn  END code review fixes. 
01n,19oct97,vin	 moved swapping of loaned buffer before END_RCV_RTN_CALL 
01m,17oct97,vin  removed extra free. 
01l,07oct97,vin  MTU size to ETHER_MTU. 
01k,03oct97,gnn  fixed SPR 8988, memory leak 
01j,25sep97,gnn  SENS beta feedback fixes 
01i,24sep97,vin  added clBlk related calls 
01h,03sep97,gnn  fixed a crashing bug under heavy load 
01g,25aug97,gnn  changes due to new netPool routines. 
01f,22aug97,gnn  changes due to new buffering scheme. 
01e,12aug97,gnn  changes necessitated by MUX/END update. 
01d,15may97,map  fixed intr event ack (scce) handling (SPR# 8580). 
01c,18apr97,gnn  fixed a bug in the receive code. 
01b,09apr97,gnn  updated buffer handling code to follow new MUX level 
                 requirements. 
01a,15feb97,dbt	 modified if_qu.c to END style.	 
*/ 
 
/* 
This module implements the Motorola MC68EN360 QUICC as well as the MPC821 and 
MPC860 Power-QUICC Ethernet Enhanced network interface driver. 
 
All the above mentioned microprocessors feature a number of Serial  
Communication Controllers (SCC) that support different serial protocols 
including IEEE 802.3 and Ethernet CSMA-CD. As a result, when the Ethernet 
mode of a SCC is selected, by properly programming its general Mode Register 
(GSMR), they can implement the full set of media access control and channel 
interface functions those protocol require. However, while the MC68EN360  
QUICC and the MPC860 Power-QUICC support up to four SCCs per unit, the  
MPC821 only includes two on-chip SCCs. 
 
This driver is designed to support the Ethernet mode of a SCC residing on the 
CPM processor core, no matter which among the MC68EN360 QUICC or any of the  
PPC800 Series. In fact, the major differences among these processors, as far 
as the driver is concerned, are to be found in the mapping of the internal  
Dual-Port RAM. The driver is generic in the sense that it does not care 
which SCC is being used. In addition, it poses no constraint on the number  
of individual units that may be used per board. However, this number should 
be specified in the bsp through the macro MAX_SCC_CHANNELS. The default value 
for this macro in the driver is 4. 
 
To achieve these goals, the driver requires several target-specific values 
provided as an input string to the load routine. It also requires some  
external support routines.  These target-specific values and the external  
support routines are described below. 
 
This network interface driver does not include support for trailer protocols 
or data chaining.  However, buffer loaning has been implemented in an effort  
to boost performance.  
 
This driver maintains cache coherency by allocating buffer space using  
the cacheDmaMalloc() routine.  This is provided for boards whose host 
processor use data cache space, e.g. the MPC800 Series. Altough the  
MC68EN360 does not have cache memory, it may be used in a particular  
configuration: 'MC68EN360 in 040 companion mode' where that is attached 
to processors that may cache memory. However, due to a lack of suitable  
hardware, the multiple unit support and '040 companion mode support have  
not been tested. 
 
BOARD LAYOUT 
This device is on-chip.  No jumpering diagram is necessary. 
 
EXTERNAL INTERFACE 
This driver provides the standard END external interface.  The only external  
interface is the motCpmEndLoad() routine.  The parameters are passed  
into the motCpmEndLoad() function as a single colon-delimited string. 
The motCpmEndLoad() function uses strtok() to parse the string, which it  
expects to be of the following format: 
 
:::::: 
: :  
 
TARGET-SPECIFIC PARAMETERS 
 
.IP  
A convenient holdover from the former model.  This parameter is used only 
in the string name for the driver. 
 
.IP  
Indicates the address at which the host processor presents its internal  
memory (also known as the dual ported RAM base address). With this address,  
and the SCC number (see below), the driver is able to compute the location  
of the SCC parameter RAM and the SCC register map, and, ultimately, to  
program the SCC for proper operations. This parameter should point to the  
internal memory of the processor where the SCC physically resides. This  
location might not necessarily be the Dual-Port RAM of the microprocessor  
configured as master on the target board. 
 
.IP  
This driver configures the host processor to generate hardware interrupts 
for various events within the device. The interrupt-vector offset 
parameter is used to connect the driver's ISR to the interrupt through 
a call to the VxWorks system function intConnect(). 
 
.IP  
This driver is written to support multiple individual device units. 
Thus, the multiple units supported by this driver can reside on different  
chips or on different SCCs within a single host processor. This parameter  
is used to explicitly state which SCC is being used (SCC1 is most commonly  
used, thus this parameter most often equals "1"). 
 
.IP " and " 
Specify the number of transmit and receive buffer descriptors (BDs).  
Each buffer descriptor resides in 8 bytes of the processor's dual-ported  
RAM space, and each one points to a 1520 byte buffer in regular RAM.   
There must be a minimum of two transmit and two receive BDs. There is  
no maximum, although more than a certain amount does not speed up the  
driver and wastes valuable dual-ported RAM space. If any of these parameters 
is "NULL", a default value of "32" BDs is used. 
 
.IP " and " 
Indicate the base location of the transmit and receive buffer descriptors  
(BDs). They are offsets, in bytes, from the base address of the host 
processor's internal memory (see above). Each BD takes up 8 bytes of 
dual-ported RAM, and it is the user's responsibility to ensure that all 
specified BDs fit within dual-ported RAM. This includes any other 
BDs the target board might be using, including other SCCs, SMCs, and the 
SPI device. There is no default for these parameters.  They must be 
provided by the user. 
 
.IP   
Tells the driver that space for the transmit and receive buffers need not  
be allocated but should be taken from a cache-coherent private memory space  
provided by the user at the given address.  The user should be aware that  
memory used for buffers must be 4-byte aligned and non-cacheable.  All the  
buffers must fit in the given memory space.  No checking is performed.   
This includes all transmit and receive buffers (see above).  Each buffer  
is 1520 bytes.  If this parameter is "NONE", space for buffers is obtained  
by calling cacheDmaMalloc() in motCpmEndLoad(). 
.LP 
 
EXTERNAL SUPPORT REQUIREMENTS 
This driver requires three external support functions: 
.IP sysXxxEnetEnable() 
.LP 
This is either sys360EnetEnable() or sysCpmEnetEnable(), based on the  
actual host processor being used. See below for the actual prototypes. 
This routine is expected to handle any target-specific functions needed  
to enable the Ethernet controller. These functions typically include  
enabling the Transmit Enable signal (TENA) and connecting the transmit  
and receive clocks to the SCC. This routine is expected to return OK on  
success, or ERROR. The driver calls this routine, once per unit, from the  
motCpmEndLoad() routine. 
.IP sysXxxEnetDisable() 
.LP 
This is either sys360EnetDisable() or sysCpmEnetDisable(), based on the  
actual host processor being used. See below for the actual prototypes. 
This routine is expected to handle any target-specific functions required  
to disable the Ethernet controller. This usually involves disabling the  
Transmit Enable (TENA) signal.  This routine is expected to return OK on  
success, or ERROR. The driver calls this routine from the motCpmEndStop()  
routine each time a unit is disabled. 
.IP sysXxxEnetAddrGet() 
.LP 
This is either sys360EnetAddrGet() or sysCpmEnetAddrGet(), based on the  
actual host processor being used. See below for the actual prototypes. 
The driver expects this routine to provide the six-byte Ethernet hardware  
address that is used by this unit.  This routine must copy the six-byte  
address to the space provided by .  This routine is expected to  
return OK on success, or ERROR.  The driver calls this routine, once per  
unit, from the motCpmEndLoad() routine. 
.LP 
In the case of the CPU32, the prototypes of the above mentioned support 
routines are as follows: 
.CS 
    STATUS sys360EnetEnable (int unit, UINT32 regBase) 
    void sys360EnetDisable (int unit, UINT32 regBase) 
    STATUS sys360EnetAddrGet (int unit, u_char * addr) 
.CE 
.LP 
In the case of the PPC860, the prototypes of the above mentioned support 
routines are as follows: 
.CS 
    STATUS sysCpmEnetEnable (int unit) 
    void sysCpmEnetDisable (int unit) 
    STATUS sysCpmEnetAddrGet (int unit, UINT8 * addr) 
.CE 
.LP 
 
SYSTEM RESOURCE USAGE 
When implemented, this driver requires the following system resources: 
 
    - one mutual exclusion semaphore 
    - one interrupt vector 
    - 0 bytes in the initialized data section (data) 
    - 1272 bytes in the uninitialized data section (BSS) 
  
The data and BSS sections are quoted for the CPU32 architecture and could 
vary for other architectures.  The code size (text) varies greatly between 
architectures, and is therefore not quoted here. 
 
If the driver allocates the memory to share with the Ethernet device unit, 
it does so by calling the cacheDmaMalloc() routine.  For the default case 
of 32 transmit buffers, 32 receive buffers, and 16 loaner buffers (this is not 
configurable), the total size requested is 121,600 bytes.  If a non-cacheable  
memory region is provided by the user, the size of this region should be this  
amount, unless the user has specified a different number of transmit or  
receive BDs. 
 
This driver can operate only if this memory region is non-cacheable 
or if the hardware implements bus snooping.  The driver cannot maintain 
cache coherency for the device because the buffers are asynchronously 
modified by both the driver and the device, and these fields might share  
the same cache line.  Additionally, the chip's dual-ported RAM must be 
declared as non-cacheable memory where applicable (for example, when attached 
to a 68040 processor). For more information, see the 
.I "Motorola MC68EN360 User's Manual", 
.I "Motorola MPC860 User's Manual", 
.I "Motorola MPC821 User's Manual" 
 
INTERNAL 
This driver contains conditional compilation switch DEBUG. 
If defined, adds debug output routines.  Output is further 
selectable at run-time via the motCpmDebug global variable. 
*/ 
 
/* includes */ 
 
#include "vxWorks.h" 
#include "iv.h" 
#include "taskLib.h" 
#include "memLib.h" 
#include "ioctl.h" 
#include "net/mbuf.h" 
#include "net/protosw.h" 
#include "socket.h" 
#include "errno.h" 
#include "errnoLib.h" 
#include "net/unixLib.h" 
#include "net/route.h" 
#include "net/if_subr.h" 
#include "cacheLib.h" 
#include "stdio.h" 
#include "intLib.h" 
#include "logLib.h" 
#include "netLib.h" 
#include "iosLib.h" 
#include "drv/netif/netifDev.h" 
 
#include "drv/end/motCpmEnd.h" 
 
#include "net/if.h" 
#include "netinet/in.h" 
#include "netinet/in_systm.h" 
#include "netinet/in_var.h" 
#include "netinet/ip.h" 
#include "netinet/if_ether.h" 
#include "etherLib.h" 
#include "etherMultiLib.h" 
#include "end.h" 
#include "semLib.h" 
 
#undef END_MACROS 
 
#include "endLib.h" 
#include "lstLib.h" 
#include "netBufLib.h" 
 
/* defines */ 
 
#define ENET_ADDR_SIZE	0x6	/* size of Ethernet src/dest addresses */ 
#define TX_BD_MIN	2	/* minimum number of Tx buffer descriptors */ 
#define TX_BD_MAX	128	/* maximum number of Tx buffer descriptors */ 
#define RX_BD_MIN	2	/* minimum number of Rx buffer descriptors */ 
#define TX_BD_DEFAULT	0x20	/* default number of Tx buffer descriptors */ 
#define RX_BD_DEFAULT	0x20	/* default number of Rx buffer descriptors */ 
#define FRAME_MAX	0x05ee	/* maximum frame size */ 
#define FRAME_MAX_AL	0x0650/*0x05f0*/	/* maximum frame size, 4 byte alligned */ 
#define FRAME_MIN	0x0040	/* minimum frame size */ 
#define LENGTH_MIN_FBUF	9	/* min. size of the first buffer in a frame */ 
#define SPEED		10000000/* ethernet speed */ 
#define L_POOL		0x10	/* number of Rx loaner buffers in pool */ 
BOOL send1=0,send2=0,send3=0,send4=0,send5=0,send6=0,send7=0,send8=0,send9=0,send10=0,send11=0; 
BOOL rev1=0,rev2=0,rev3=0,rev4=0,rev5=0; 
void printfonoff_rev(BOOL a,BOOL b,BOOL c,BOOL d,BOOL e); 
void printfonoff_send(BOOL a,BOOL b,BOOL c,BOOL d,BOOL e,BOOL f,BOOL g,BOOL k,BOOL m,BOOL n,BOOL l); 
 
/* 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) 
 
#ifndef SYS_INT_CONNECT 
#define SYS_INT_CONNECT(pFunc, arg, pRet)                         	    \ 
{                                                                           \ 
*pRet = (intConnect) (INUM_TO_IVEC (pDrvCtrl->ivec),			    \ 
		      (pFunc), (int) (arg));                         	    \ 
} 
#endif /* SYS_INT_CONNECT */ 
 
#define MOT_CPM_DEBUG	/* debug support */ 
 
int motCpmDebug = 0; 
 
#ifdef MOT_CPM_DEBUG 
#define MOTCPMLOGMSG(x) \ 
	if (motCpmDebug) \ 
	    { \ 
	    logMsg x; \ 
	    } 
#else 
#define MOTCPMLOGMSG(x) 
#endif /* MOT_CPM_DEBUG */ 
 
/* typedefs */ 
 
/* Ethernet header */ 
 
typedef struct free_args 
    { 
    void* arg1; 
    void* arg2; 
    } FREE_ARGS; 
 
typedef struct end_ctrl	/* END_CTRL */ 
    { 
    END_OBJ		endObject;	/* base class */ 
    UINT32		regBase;	/* register/DPR base address */ 
    SCC_ETHER_DEV	ether;		/* ETHERNET SCC device */ 
    int			txBdIndexC;	/* current tx buffer descriptor index */ 
    UINT32		bufBase;	/* address of memory pool; */ 
					/* NONE = malloc it */ 
    int			unit;		/* unit number */ 
    int			ivec;		/* interrupt vector */ 
    BOOL		polling;	/* polling mode */ 
    BOOL		txCleaning;	/* cleaning queue */ 
    u_char *		txBuf;		/* transmit buffer */ 
    u_char *		rxBuf;		/* receive buffer */ 
    BOOL		txStop;		/* emergency stop output */ 
    FUNCPTR		freeRtn[TX_BD_MAX];	/* Array of free routines. */ 
    FREE_ARGS		freeData[TX_BD_MAX];	/* Array of free arguments */ 
    CL_POOL_ID  	pClPoolId;      /* for the free routines. */ 
    BOOL		txBlocked;	/* flag for implementing flow control */ 
    } END_CTRL; 
 
typedef struct { 
    int		unit;		/* unit number */ 
    UINT32 	motCpmAddr;	/* base address of processor internal mem */ 
    int		ivec;		/* interrupt vector */ 
    int		sccNum;		/* Serial Communication Controler number */ 
    int		txBdNum;	/* number of transmit buffer descriptors */ 
    int		rxBdNum;	/* number of receive buffer descriptors */ 
    UINT32	txBdBase;	/* transmit buffer descriptor offset */ 
    UINT32	rxBdBase;	/* receive buffer descriptor offset */ 
    UINT32	bufBase;	/* address of memory pool; NONE = malloc it */ 
    } END_PARM; 
 
/* globals */ 
 
/* locals */ 
 
M_CL_CONFIG motMclBlkConfig = 	/* network mbuf configuration table */ 
    { 
    /*  
    no. mBlks		no. clBlks	memArea		memSize 
    -----------		----------	-------		------- 
    */ 
    0, 			0, 		NULL, 		0 
    }; 
 
CL_DESC motClDescTbl [] = 	/* network cluster pool configuration table */ 
    { 
    /*  
    clusterSize		num		memArea		memSize 
    -----------		----		-------		------- 
    */ 
    {FRAME_MAX_AL,	0,		NULL,		0} 
    };  
 
int motClDescTblNumEnt = (NELEMENTS(motClDescTbl)); 
 
NET_POOL motCpmNetPool; 
 
LOCAL END_CTRL drvCtrl[MAX_SCC_CHANNELS];	/* array of driver control */ 
 
/* forward declarations */ 
 
#ifdef __STDC__ 
 
LOCAL STATUS    motCpmInitParse (END_PARM *pEndParm, char *initString); 
LOCAL STATUS    motCpmInitMem (END_CTRL *pDrvCtrl); 
LOCAL void	motCpmRecv (END_CTRL *pDrvCtrl, SCC_BUF * pRxBd); 
LOCAL void      motCpmIntr (END_CTRL *pDrvCtrl); 
LOCAL void 	motCpmReset (END_CTRL * pDrvCtrl); 
LOCAL void 	motCpmMCastFilterSet (END_CTRL * pDrvCtrl, char * pAddress); 
LOCAL void 	motCpmMCastConfig (END_CTRL * pDrvCtrl); 
LOCAL void 	motCpmTxRestart (END_CTRL * pDrvCtrl); 
LOCAL void 	motCpmHandleInt (END_CTRL * pDrvCtrl); 
LOCAL void 	motCpmCleanTxBdQueue (END_CTRL * pDrvCtrl); 
LOCAL STATUS 	motCpmRestart (END_CTRL * pDrvCtrl); 
LOCAL void	motCpmCleanRxBd (END_CTRL * pDrvCtrl, SCC_BUF * pRxBd); 
 
 
/* END Specific interfaces. */ 
 
END_OBJ *       motCpmEndLoad1 (char *initString); 
LOCAL STATUS    motCpmEndStart(END_CTRL *pDrvCtrl); 
LOCAL int       motCpmEndIoctl (END_CTRL *pDrvCtrl, int cmd, caddr_t data); 
LOCAL STATUS    motCpmEndSend (END_CTRL *pDrvCtrl, M_BLK_ID pBuf); 
LOCAL STATUS    motCpmEndMCastAddrAdd (END_CTRL *pDrvCtrl, char* pAddress); 
LOCAL STATUS    motCpmEndMCastAddrDel (END_CTRL *pDrvCtrl, char* pAddress); 
LOCAL STATUS    motCpmEndMCastAddrGet (END_CTRL *pDrvCtrl, 
					MULTI_TABLE *pTable); 
LOCAL STATUS    motCpmEndPollSend (END_CTRL *pDrvCtrl, M_BLK_ID pBuf); 
LOCAL STATUS    motCpmEndPollReceive (END_CTRL *pDrvCtrl, M_BLK_ID pBuf); 
LOCAL STATUS    motCpmEndPollStart (END_CTRL *pDrvCtrl); 
LOCAL STATUS    motCpmEndPollStop (END_CTRL *pDrvCtrl); 
LOCAL STATUS 	motCpmEndUnload (END_CTRL *pDrvCtrl); 
LOCAL STATUS 	motCpmEndStop (END_CTRL *pDrvCtrl); 
 
#else  /* __STDC__ */ 
 
LOCAL STATUS    motCpmInitParse (); 
LOCAL STATUS    motCpmInitMem (); 
LOCAL void	motCpmRecv (); 
LOCAL void      motCpmIntr (); 
LOCAL void 	motCpmReset (); 
LOCAL void 	motCpmMCastFilterSet (); 
LOCAL void 	motCpmMCastConfig (); 
LOCAL void 	motCpmTxRestart (); 
LOCAL void 	motCpmHandleInt (); 
LOCAL void 	motCpmCleanTxBdQueue (); 
LOCAL STATUS 	motCpmRestart (); 
LOCAL void	motCpmCleanRxBd (); 
 
/* END Specific interfaces. */ 
 
END_OBJ *       motCpmEndLoad1 (); 
LOCAL STATUS    motCpmEndStart (); 
LOCAL int       motCpmEndIoctl (); 
LOCAL STATUS    motCpmEndSend (); 
LOCAL STATUS    motCpmEndMCastAddrAdd (); 
LOCAL STATUS    motCpmEndMCastAddrDel (); 
LOCAL STATUS    motCpmEndMCastAddrGet (); 
LOCAL STATUS    motCpmEndPollSend (); 
LOCAL STATUS    motCpmEndPollReceive (); 
LOCAL STATUS    motCpmEndPollStart (); 
LOCAL STATUS    motCpmEndPollStop (); 
LOCAL STATUS 	motCpmEndUnload (); 
LOCAL STATUS 	motCpmEndStop (); 
 
#endif  /* __STDC__ */ 
 
/* 
 * Define the device function table.  This is static across all driver 
 * instances. 
 */ 
 
LOCAL NET_FUNCS netFuncs = 
    { 
    (FUNCPTR)motCpmEndStart,		/* start func. */ 
    (FUNCPTR)motCpmEndStop,		/* stop func. */ 
    (FUNCPTR)motCpmEndUnload,		/* unload func. */ 
    (FUNCPTR)motCpmEndIoctl,		/* ioctl func. */ 
    (FUNCPTR)motCpmEndSend,		/* send func. */ 
    (FUNCPTR)motCpmEndMCastAddrAdd,	/* multicast add func. */ 
    (FUNCPTR)motCpmEndMCastAddrDel,	/* multicast delete func. */ 
    (FUNCPTR)motCpmEndMCastAddrGet,	/* multicast get fun. */ 
    (FUNCPTR)motCpmEndPollSend,		/* polling send func. */ 
    (FUNCPTR)motCpmEndPollReceive,	/* polling receive func.  */ 
    endEtherAddressForm,          	/* Put address info into a packet.  */ 
    endEtherPacketDataGet,        	/* Get a pointer to packet data. */ 
    endEtherPacketAddrGet         	/* Get packet addresses. */ 
    }; 
 
/******************************************************************************* 
* 
* motCpmEndLoad - initialize the driver and device 
* 
* This routine initializes the driver and the device to the operational state. 
* All of the device specific parameters are passed in the , which 
* is of the following format: 
* 
* :::::::: 
  
*  
* The parameters of this string are individually described in the 'motCpmEnd'  
* man page. 
* 
* The SCC shares a region of memory with the driver.  The caller of  
* this routine can specify the address of a non-cacheable memory region with 
* .  Or, if this parameter is "NONE", the driver obtains this 
* memory region by making calls to cacheDmaMalloc().  Non-cacheable memory  
* space is important whenever the host processor uses cache memory. 
* This is also the case when the MC68EN360 is operating in companion 
* mode and is attached to a processor with cache memory. 
* 
* After non-cacheable memory is obtained, this routine divides up the 
* memory between the various buffer descriptors (BDs).  The number 
* of BDs can be specified by  and , or if "NULL", a 
* default value of 32 BDs will be used.  An additional number of buffers are 
* reserved as receive loaner buffers.  The number of loaner buffers is 
* a default number of 16. 
* 
* The user must specify the location of the transmit and receive BDs in 
* the processor's dual ported RAM.   and  give the 
* offsets from  for the base of the BD rings.  Each BD uses  
* 8 bytes. Care must be taken so that the specified locations for Ethernet  
* BDs do not conflict with other dual ported RAM structures. 
* 
* Multiple individual device units are supported by this driver.  Device 
* units can reside on different chips, or could be on different SCCs 
* within a single processor. The  parameter is used to explicitly 
* state which SCC is being used. SCC1 is most commonly used, thus this 
* parameter most often equals "1". 
* 
* Before this routine returns, it connects up the interrupt vector . 
* 
* RETURNS: An END object pointer or NULL on error. 
* 
* SEE ALSO: 
* .I "Motorola MC68EN360 User's Manual", 
* .I "Motorola MPC860 User's Manual", 
* .I "Motorola MPC821 User's Manual" 
*/ 
 
END_OBJ *motCpmEndLoad1 
    ( 
    char *      initString      /* parameter string */ 
    ) 
    { 
    END_PARM    endParm;        /* parameters from initString */ 
    END_CTRL    *pDrvCtrl;	/* pointer to END_CTRL structure */ 
    int         scc; 
    UINT32	motCpmAddr; 
    u_char	enetAddr[ENET_ADDR_SIZE]; 
    int         retVal; 
 
    MOTCPMLOGMSG(("motCpmEndLoad1 \n", 0, 0, 0, 0, 0, 0)); 
 
    if (initString == NULL) 
        return (NULL); 
     
    if (initString[0] == NULL) 
        { 
        bcopy((char *)MOT_DEV_NAME, initString, MOT_DEV_NAME_LEN); 
        return (0); 
        } 
 
    /* Parse InitString */ 
 
    if (motCpmInitParse (&endParm, initString) == ERROR) 
	return (NULL); 
 
    /* Sanity check -- unit number */ 
 
    if (endParm.unit < 0 || endParm.unit >= MAX_SCC_CHANNELS) 
	return (NULL); 
 
    /* Sanity check -- scc number */ 
 
    if ((endParm.sccNum < 1) || (endParm.sccNum > 4)) 
	return (NULL); 
 
    if (endParm.txBdBase == endParm.rxBdBase) 
	return (NULL); 
 
    pDrvCtrl = & drvCtrl [endParm.unit]; 
 
    /* Check if we are already attached */ 
 
    if (pDrvCtrl->endObject.attached == TRUE) 
	return (&pDrvCtrl->endObject); 
 
    /* use default number of buffer descriptors if user did not specify */ 
 
    if (endParm.txBdNum == NULL) 
	endParm.txBdNum = TX_BD_DEFAULT; 
    if (endParm.rxBdNum == NULL) 
    	endParm.rxBdNum = RX_BD_DEFAULT; 
 
    /* must be at least two transmit and receive buffer descriptors */ 
 
    endParm.txBdNum = max (TX_BD_MIN, endParm.txBdNum); 
    endParm.rxBdNum = max (RX_BD_MIN, endParm.rxBdNum); 
 
    /* Initialize parameters */ 
 
    pDrvCtrl->regBase		= endParm.motCpmAddr; 
    pDrvCtrl->bufBase		= endParm.bufBase; 
    pDrvCtrl->unit		= endParm.unit; 
    pDrvCtrl->ivec		= endParm.ivec; 
    pDrvCtrl->ether.sccNum	= endParm.sccNum; 
    pDrvCtrl->ether.txBdNum	= endParm.txBdNum; 
    pDrvCtrl->ether.rxBdNum	= endParm.rxBdNum; 
    pDrvCtrl->ether.txBdBase	= (SCC_BUF *) (endParm.motCpmAddr +  
						(endParm.txBdBase & 0xffff)); 
    pDrvCtrl->ether.rxBdBase	= (SCC_BUF *) (endParm.motCpmAddr +  
						(endParm.rxBdBase & 0xffff)); 
    pDrvCtrl->ether.txBufSize	= FRAME_MAX_AL; 
    pDrvCtrl->ether.rxBufSize	= FRAME_MAX_AL; 
    pDrvCtrl->txBdIndexC	= 0; 
 
    /* derive SCC dependent variables */ 
 
    scc = pDrvCtrl->ether.sccNum - 1; 
 
    motCpmAddr = pDrvCtrl->regBase; 
 
    pDrvCtrl->ether.pScc    = (SCC *) ((UINT32) CPM_DPR_SCC1(motCpmAddr) + 
				       (scc * 0x100)); 
    pDrvCtrl->ether.pSccReg = (SCC_REG *)  
				((UINT32) CPM_GSMR_L1(motCpmAddr) + ( 
				 scc * 0x20)); 
    pDrvCtrl->ether.intMask = CPM_CIMR_SCC4 << (3 - scc); 
 
    /* endObject initializations */ 
 
    if (END_OBJ_INIT (&pDrvCtrl->endObject, (void *)pDrvCtrl, MOT_DEV_NAME, 
                      pDrvCtrl->unit, &netFuncs, 
                      END_OBJ_STRING) == ERROR) 
	return (NULL); 
 
    /* memory initialization */ 
 
    if (motCpmInitMem (pDrvCtrl) == ERROR) 
	return (NULL); 
 
    /* reset the chip */ 
 
    motCpmReset (pDrvCtrl); 
 
    /* connect the interrupt handler motCpmIntr() */ 
 
    SYS_INT_CONNECT ((VOIDFUNCPTR) motCpmIntr, (int) pDrvCtrl, &retVal); 
    if (retVal == ERROR) 
        return (NULL); 
  
    /* Get our enet addr */ 
 
    SYS_ENET_ADDR_GET (enetAddr); 
 
    MOTCPMLOGMSG(("motCpmEndLoad1 ADDR: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \n",  
		(int) enetAddr[0], (int) enetAddr[1], (int) enetAddr[2],  
		(int) enetAddr[3], (int) enetAddr[4], (int) enetAddr[5])); 
 
    /* Initialize MIB2 entries */ 
 
    if (END_MIB_INIT (&pDrvCtrl->endObject, M2_ifType_ethernet_csmacd, 
                      enetAddr, 6, ETHERMTU, SPEED) == ERROR) 
	    return (NULL); 
 
    /* Mark the device ready */ 
    /* IFF_SCAT is not defined by default */ 
 
    END_OBJ_READY (&pDrvCtrl->endObject, 
		 IFF_NOTRAILERS | IFF_BROADCAST | IFF_MULTICAST); 
 
    /* Successful return */ 
 
    return (&pDrvCtrl->endObject); 
    } 
 
/******************************************************************************* 
* 
* motCpmInitParse - parse parameter values from initString 
* 
* Parse the input string.  Fill in values in the driver control structure. 
* 
* The initialization string format is: 
* .CS 
*    "unit:motCpmAddr:ivec:sccNum:txBdNum:rxBdNum:txBdBase:rxBdBase:bufBase" 
* .CE 
* 
* .IP  
* Device unit number, a small integer. 
* .IP  
* base address of processor internal mem  
* .IP  
* Interrupt vector number 
* .IP  
* SCC number used. 
* .IP  
* number of transmit buffer descriptors; NULL = default	 
* .IP  
* number of receive buffer descriptors; NULL = default 
* .IP  
* transmit buffer descriptor offset 
* .IP  
* receive buffer descriptor offset 
* .IP  
* address of memory pool; NONE = malloc it 
* .LP 
* 
* RETURNS: OK or ERROR for invalid arguments. 
*/ 
 
LOCAL STATUS motCpmInitParse 
    ( 
    END_PARM    *pEndParm,	/* structure to fill in with parameters */ 
    char        *initString	/* init string */ 
    ) 
    { 
    char *      tok;            /* an initString token */ 
    char *	holder=NULL;    /* points to initString fragment beyond tok */ 
    char * 	initStringBuff; 
 
    initStringBuff = malloc(strlen(initString) + 1); 
    if (initStringBuff == NULL) 
        return (ERROR); 
 
    strcpy (initStringBuff, initString); 
 
    tok = strtok_r(initStringBuff, ":", &holder); 
    if (tok == NULL) 
        { 
        free(initStringBuff); 
	return ERROR; 
        } 
    pEndParm->unit = atoi(tok); 
 
    tok = strtok_r(NULL, ":", &holder); 
    if (tok == NULL) 
        { 
        free(initStringBuff); 
	return ERROR; 
        } 
    pEndParm->motCpmAddr = strtoul (tok, NULL, 16); 
 
    tok = strtok_r(NULL, ":", &holder); 
    if (tok == NULL) 
        { 
        free(initStringBuff); 
	return ERROR; 
        } 
    pEndParm->ivec = strtoul (tok, NULL, 16); 
 
    tok = strtok_r(NULL, ":", &holder); 
    if (tok == NULL) 
        { 
        free(initStringBuff); 
	return ERROR; 
        } 
    pEndParm->sccNum = atoi (tok); 
 
    tok = strtok_r(NULL, ":", &holder); 
    if (tok == NULL) 
        { 
        free(initStringBuff); 
	return ERROR; 
        } 
    pEndParm->txBdNum = strtoul (tok, NULL, 16); 
 
    tok = strtok_r(NULL, ":", &holder); 
    if (tok == NULL) 
        { 
        free(initStringBuff); 
	return ERROR; 
        } 
    pEndParm->rxBdNum = strtoul (tok, NULL, 16); 
 
    tok = strtok_r(NULL, ":", &holder); 
    if (tok == NULL) 
        { 
        free(initStringBuff); 
	return ERROR; 
        } 
    pEndParm->txBdBase = strtoul (tok, NULL, 16); 
    /*pEndParm->txBdBase = 0x2800;*/ 
     
    tok = strtok_r(NULL, ":", &holder); 
    if (tok == NULL) 
        { 
        free(initStringBuff); 
	return ERROR; 
        } 
   pEndParm->rxBdBase = strtoul (tok, NULL, 16); 
    /*pEndParm->rxBdBase = 0x2900;*/ 
     
    tok = strtok_r(NULL, ":", &holder); 
    if (tok == NULL) 
        { 
        free(initStringBuff); 
	return ERROR; 
        } 
    pEndParm->bufBase = strtoul (tok, NULL, 16); 
 
    MOTCPMLOGMSG(("unit = %d, motCpmAddr = 0x%x, ivec = 0x%x, sccNum = 0x%x\n", 
		pEndParm->unit, pEndParm->motCpmAddr, pEndParm->ivec,  
		pEndParm->sccNum, 0, 0)); 
    MOTCPMLOGMSG(("txBdNum = 0x%x, rxBdNum = 0x%x, txBdBase = 0x%x\n", 
		pEndParm->txBdNum, pEndParm->rxBdNum, pEndParm->txBdBase,  
		0, 0, 0)); 
    MOTCPMLOGMSG(("rxBdBase  = 0x%x, bufBase = %d\n", pEndParm->rxBdBase,  
		pEndParm->bufBase, 0, 0, 0, 0)); 
 
    free(initStringBuff); 
    return OK; 
    } 
 
/******************************************************************************* 
* 
* motCpmInitMem - initialize memory  
* 
* Using data in the control structure, setup and initialize the memory 
* areas needed.  If the memory address is not already specified, then allocate 
* cache safe memory. 
* 
* RETURNS: OK or ERROR. 
* 
*/ 
 
LOCAL STATUS motCpmInitMem/*wuta*/ 
    ( 
    END_CTRL *	pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    int		counter; 
    FUNCPTR 	allocFunc; 
    void *	pData; 
    char*	pTmpBuf; 
    int		numBuf; 
 
    /* Set up the structures to allow us to free data after sending it. */ 
#if 1 
    for (counter = 0; counter < pDrvCtrl->ether.txBdNum; counter++) 
	{ 
	pDrvCtrl->freeRtn[counter] = NULL; 
	pDrvCtrl->freeData[counter].arg1 = NULL; 
	pDrvCtrl->freeData[counter].arg2 = NULL; 
	} 
#endif 
 
    if (pDrvCtrl->bufBase == NONE) 
	{ 
	/* We must allocate memory for buffer descriptors */ 
 
	pData = NULL; 
	allocFunc = (FUNCPTR) cacheDmaMalloc; 
	} 
    else 
	{ 
	/* Memory for buffer descriptors is already allocated */ 
 
	pData = (void *) pDrvCtrl->bufBase; 
	allocFunc = NULL; 
	} 
 
    /*  
     * calculate the number of buffers we need : 
     * receive buffers + transmit buffers + loaner buffers (= L_POOL) 
     */ 
 
 /*   if ((pDrvCtrl->endObject.pNetPool = (NET_POOL) malloc (sizeof(NET_POOL))) == NULL) 
        return (ERROR);      /*wutao  ADD*/ 
	 
    numBuf = /*pDrvCtrl->ether.rxBdNum + pDrvCtrl->ether.txBdNum + L_POOL*/500; 
 
    /* Use the MUX's memory manager to get our buffers. */ 
 
    pDrvCtrl->endObject.pNetPool = &motCpmNetPool; 
 
    motClDescTbl[0].clNum 	= numBuf; 
    motClDescTbl[0].memSize 	= (numBuf * (FRAME_MAX_AL + sizeof (long))); 
 
    motMclBlkConfig.mBlkNum 	= 2 * numBuf; 
    motMclBlkConfig.clBlkNum 	= numBuf; 
    motMclBlkConfig.memSize 	= ((motMclBlkConfig.mBlkNum * 
                                    (MSIZE + sizeof (long))) + 
                                   (motMclBlkConfig.clBlkNum * 
                                    (CL_BLK_SZ + sizeof (long)))); 
 
    if ((motMclBlkConfig.memArea = (char *) memalign (sizeof (long), 
                                                      motMclBlkConfig.memSize)) 
        == NULL) 
        return (ERROR); 
 
    motClDescTbl[0].memArea = (char *) cacheDmaMalloc(motClDescTbl[0].memSize); 
    if ((int)motClDescTbl[0].memArea == NULL) 
        { 
        MOTCPMLOGMSG (( "system memory unavailable\n", 1, 2, 3, 4, 5, 6)); 
        return (ERROR); 
        } 
 
    if (netPoolInit(pDrvCtrl->endObject.pNetPool, &motMclBlkConfig, 
                    &motClDescTbl[0], motClDescTblNumEnt, NULL) == ERROR) 
                     
        { 
        MOTCPMLOGMSG(("Could not init buffering\n", 1, 2, 3, 4, 5, 6)); 
        return (ERROR); 
        } 
 
#if 1 
    /* Store the cluster pool id as others need it later. */ 
    pDrvCtrl->pClPoolId = clPoolIdGet(pDrvCtrl->endObject.pNetPool, 
                                      FRAME_MAX_AL, FALSE); 
    for (counter = 0; counter < pDrvCtrl->ether.rxBdNum; counter++) 
	{ 
        if ((pTmpBuf = (char *)netClusterGet(pDrvCtrl->endObject.pNetPool, 
                                             pDrvCtrl->pClPoolId)) == NULL) 
            { 
            return (ERROR); 
            } 
 
        pDrvCtrl->ether.rxBdBase[counter].dataPointer = (u_char *) pTmpBuf; 
	} 
 
  #endif 
   
    return (OK); 
    } 
 
/******************************************************************************* 
* 
* motCpmEndStart - start the device  
* 
* This function initializes the device and calls BSP functions to connect 
* interrupts and start the device running in interrupt mode. 
* 
* The complement of this routine is motCpmEndStop().  Once a unit is reset by 
* motCpmEndStop(), it may be re-initialized to a running state by this routine. 
*  
* RETURNS: OK if successful, otherwise ERROR. 
*/ 
 
LOCAL STATUS motCpmEndStart 
    ( 
    END_CTRL *	pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    int			counter; 
    u_char *		enetAddr; 
    ETHER_MULTI *	pCurr; 
 
    MOTCPMLOGMSG(("motCpmEndStart \n", 0, 0, 0, 0, 0, 0)); 
 
    /* initialize flag(s) */ 
 
    pDrvCtrl->polling = FALSE; 
    pDrvCtrl->txStop = FALSE; 
    pDrvCtrl->txCleaning = FALSE; 
    pDrvCtrl->txBlocked = FALSE; 
 
    /* set up transmit buffer descriptors */ 
 
    pDrvCtrl->ether.pScc->param.tbase = (UINT16) 
	((UINT32) pDrvCtrl->ether.txBdBase & 0xffff); 
    pDrvCtrl->ether.pScc->param.tbptr = (UINT16) 
	((UINT32) pDrvCtrl->ether.txBdBase & 0xffff); 
 
    pDrvCtrl->ether.txBdNext  = 0; 
 
    /* initialize each transmit buffer descriptor */ 
      
    for (counter = 0; counter < pDrvCtrl->ether.txBdNum; counter++) 
        pDrvCtrl->ether.txBdBase[counter].statusMode = SCC_ETHER_TX_BD_I | 
                                                       SCC_ETHER_TX_BD_PAD | 
                                                       SCC_ETHER_TX_BD_L | 
                                                       SCC_ETHER_TX_BD_TC; 
 
    /* set the last BD to wrap to the first */ 
 
    pDrvCtrl->ether.txBdBase[(counter - 1)].statusMode |= SCC_ETHER_TX_BD_W; 
 
    /* set up receive buffer descriptors */ 
 
    pDrvCtrl->ether.pScc->param.rbase = (UINT16) 
	((UINT32) pDrvCtrl->ether.rxBdBase & 0xffff); 
    pDrvCtrl->ether.pScc->param.rbptr = (UINT16) 
	((UINT32) pDrvCtrl->ether.rxBdBase & 0xffff); 
 
    pDrvCtrl->ether.rxBdNext  = 0; 
 
    /* initialize each receive buffer descriptor */ 
 
    for (counter = 0; counter < pDrvCtrl->ether.rxBdNum; counter++) 
        pDrvCtrl->ether.rxBdBase[counter].statusMode = SCC_ETHER_RX_BD_I | 
        					       SCC_ETHER_RX_BD_E; 
 
    /* set the last BD to wrap to the first */ 
 
    pDrvCtrl->ether.rxBdBase[(counter - 1)].statusMode |= SCC_ETHER_RX_BD_W; 
 
    /* set SCC attributes to Ethernet mode */ 
  
    pDrvCtrl->ether.pSccReg->gsmrl    = SCC_GSMRL_ETHERNET | SCC_GSMRL_TPP_10 | 
                                        SCC_GSMRL_TPL_48   | SCC_GSMRL_TCI; 
    pDrvCtrl->ether.pSccReg->gsmrh    = 0x0; 
 
    pDrvCtrl->ether.pSccReg->psmr     = SCC_ETHER_PSMR_CRC | 
					SCC_ETHER_PSMR_NIB_22; 
 
    if (END_FLAGS_GET(&pDrvCtrl->endObject) & IFF_PROMISC) 
        pDrvCtrl->ether.pSccReg->psmr |= SCC_ETHER_PSMR_PRO; 
  
    pDrvCtrl->ether.pSccReg->dsr      = 0xd555; 
    pDrvCtrl->ether.pScc->param.rfcr  = 0x18;      /* supervisor data access */ 
    pDrvCtrl->ether.pScc->param.tfcr  = 0x18;      /* supervisor data access */ 
    pDrvCtrl->ether.pScc->param.mrblr = FRAME_MAX_AL;  /* max rx buffer size */ 
 
    /* initialize parameter the SCC RAM */ 
  
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->c_pres	= 0xffffffff; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->c_mask	= 0xdebb20e3; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->crcec	= 0x00000000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->alec	= 0x00000000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->disfc	= 0x00000000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->pads	= 0x8888; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->ret_lim	= 0x000f; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->mflr	= FRAME_MAX; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->minflr	= FRAME_MIN; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->maxd1	= FRAME_MAX; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->maxd2	= FRAME_MAX; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr1	= 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr2	= 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr3	= 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr4	= 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->p_per	= 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr1	= 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr2	= 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr3	= 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr4	= 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_h	= 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_m	= 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_l	= 0x0000; 
 
    /* set the hardware Ethernet address of the board */ 
 
    enetAddr = END_HADDR(&pDrvCtrl->endObject); 
 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_h = 
        (enetAddr[5] << 8) + enetAddr[4]; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_m = 
        (enetAddr[3] << 8) + enetAddr[2]; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_l = 
        (enetAddr[1] << 8) + enetAddr[0]; 
 
    /* Set the multicast addresses */ 
 
    for (pCurr = END_MULTI_LST_FIRST(&pDrvCtrl->endObject); pCurr != NULL; 
			pCurr = (ETHER_MULTI *)lstNext(&pCurr->node)) 
	{ 
	/* add multicast address */ 
 
	motCpmMCastFilterSet (pDrvCtrl, pCurr->addr); 
	} 
 
    /* enable Ethernet interrupts */ 
 
    pDrvCtrl->ether.pSccReg->scce = 0xffff;		/* clr events */ 
 
    /* allow receive and transmit errors interrupts */ 
 
  pDrvCtrl->ether.pSccReg->sccm = SCC_ETHER_SCCX_RXF | SCC_ETHER_SCCX_TXE | 
				    SCC_ETHER_SCCX_TXB; 
	   
				   
 
    *CPM_CIMR(pDrvCtrl->regBase) |= pDrvCtrl->ether.intMask; 
 
    /* call the BSP to do any other initialization (e.g., connecting clocks) */ 
 
    SYS_ENET_ENABLE; 
 
    /* raise the interface flags - mark the device as up */ 
 
    END_FLAGS_SET (&pDrvCtrl->endObject, IFF_UP | IFF_RUNNING); 
 
    /* enable the transmitter */ 
 
    pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENT; 
 
    /* issue the restart transmitter command to the CP */ 
 
    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
    *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) | 
                                      CPM_CR_SCC_RESTART | CPM_CR_FLG; 
    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
 
    /* enable the receiver */ 
 
    pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENR; 
 
    return (OK); 
    } 
 
/******************************************************************************* 
* 
* motCpmEndStop - stop the device  
* 
* This routine marks the interface as down and resets the device.  This 
* includes disabling interrupts, stopping the transmitter and receiver, 
* and calling the bsp-specific LAN disable routine to do any target  
* specific disabling. 
* 
* The complement of this routine is motCpmEndStart().  Once a unit is  
* stop in this routine, it may be re-initialized to a running state by  
* motCpmEndStart(). 
* 
* RETURNS: OK or ERROR. 
*/ 
 
LOCAL STATUS motCpmEndStop 
    ( 
    END_CTRL *	pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    /* mark the driver as down */ 
 
    END_FLAGS_CLR (&pDrvCtrl->endObject, IFF_UP | IFF_RUNNING); 
 
    /* Reset the device */ 
 
    motCpmReset (pDrvCtrl); 
 
    return (OK); 
    } 
 
/****************************************************************************** 
* 
* motCpmEndUnload - unload a driver from the system 
* 
* This function first brings down the device, and then frees any 
* stuff that was allocated by the driver in the load function. 
* 
* RETURN : OK or ERROR 
*/ 
 
LOCAL STATUS motCpmEndUnload 
    ( 
    END_CTRL	*pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    END_OBJECT_UNLOAD (&pDrvCtrl->endObject); 
 
    return (OK); 
    } 
 
 
 
/******************************************************************************* 
* 
* motCpmEndSend - output packet to network interface device 
* 
* This routine() takes a M_BLK_ID and sends off the data in the M_BLK_ID. 
* The buffer must already have the addressing information properly installed 
* in it. This is done by a higher layer. The last arguments are a free 
* routine to be called when the device is done with the buffer and a pointer 
* to the argument to pass to the free routine. 
* 
* muxSend() calls this routine each time it wants to send a packet. 
* Errors are detected at interrupt level. 
* 
* RETURNS: OK or ERROR. 
*/ 
 
LOCAL STATUS motCpmEndSend123/*wut 2004.7.22modify*/ 
    ( 
    END_CTRL	*pDrvCtrl,	/* pointer to END_CTRL structure */ 
    M_BLK_ID    pMblk	/* Data to send */ 
    ) 
    { 
    int			length; 
    SCC_BUF *		pTxBd; 
    u_char *		pad; 
    char 	        *pBuf; 
    int 		oldLevel; 
    int                 s; 
     
    MOTCPMLOGMSG(("motCpmEndSend \n", 0, 0, 0, 0, 0, 0)); 
 
    if (pDrvCtrl->txBlocked) 
	{ 
	if(send1==1) 
	 MOTCPMLOGMSG(("motCpmEndSend1 \n", 0, 0, 0, 0, 0, 0)); 
        return (END_ERR_BLOCK); 
    	} 
     
    if (pDrvCtrl->polling) 
    	{ 
    	if(send2==1) 
    	MOTCPMLOGMSG(("motCpmEndSend2 \n", 0, 0, 0, 0, 0, 0)); 
	return (ERROR); 
    	} 
    /* gain exclusive access to the transmitter */ 
 
    END_TX_SEM_TAKE (&pDrvCtrl->endObject, WAIT_FOREVER); 
 
   
	 
       if((pMblk->mBlkPktHdr.len)<40) 
    	{ 
    	 END_TX_SEM_GIVE (&pDrvCtrl->endObject); 
	 MOTCPMLOGMSG(("pMblk->mBlkPktHdr.len)<40 \n", 0, 0, 0, 0, 0, 0)); 
	 return ERROR; 
    	} 
 
    /* get a free transmit frame descriptor */ 
    if(send3==1) 
    MOTCPMLOGMSG(("motCpmEndSend3 \n", 0, 0, 0, 0, 0, 0)); 
    pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->ether.txBdNext]; 
     
    /* check if a transmit buffer descriptor is available */ 
     
    if ((pTxBd->statusMode & SCC_ETHER_TX_BD_R) ||  
        (((pDrvCtrl->ether.txBdNext + 1) % pDrvCtrl->ether.txBdNum)  
         == pDrvCtrl->txBdIndexC)) 
        { 
        END_TX_SEM_GIVE (&pDrvCtrl->endObject); 
        s = intLock(); 
        pDrvCtrl->txBlocked = TRUE; 
        intUnlock(s); 
		if(send4==1) 
	 MOTCPMLOGMSG(("motCpmEndSend4 \n", 0, 0, 0, 0, 0, 0)); 
        return (END_ERR_BLOCK); 
        } 
 
    #if 1 
    pBuf = netClusterGet(pDrvCtrl->endObject.pNetPool, pDrvCtrl->pClPoolId); 
 
    if (pBuf == NULL) 
        { 
         END_TX_SEM_GIVE (&pDrvCtrl->endObject); 
	  netMblkClChainFree(pMblk);  
	  if(send5==1) 
	  MOTCPMLOGMSG(("motCpmEndSend5 \n", 0, 0, 0, 0, 0, 0)); 
         return (ERROR); 
        } 
 
    #endif	 
    length = netMblkToBufCopy (pMblk, (char *)pBuf, NULL); 
   
   /* length = pMblk->mBlkPktHdr.len;*/ 
 
   /* netMblkToBufCopy (pMblk, (u_char*)(pTxBd->dataPointer), NULL);*/ 
	 
   /* netMblkClChainFree(pMblk); */ 
    
   
	 
   pTxBd->dataPointer = (u_char *) pBuf; 
     
    /* padding mechanism in Rev A is buggy - do in software */ 
     
    if (length < FRAME_MIN) 
        { 
        pad = pTxBd->dataPointer + length; 
        for (; length != FRAME_MIN; length++, pad++) 
            *pad = 0x88; 
	 
        } 
     
    pTxBd->dataLength = length; 
     
	 
    oldLevel = intLock ();	/* disable ints during update */ 
     
    if (pTxBd->statusMode & SCC_ETHER_TX_BD_W) 
    	{ 
     
        pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD | 
            SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  | 
            SCC_ETHER_TX_BD_W | SCC_ETHER_TX_BD_R; 
    	} 
    else 
    	{  
    	 
        pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD | 
            SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  | 
            SCC_ETHER_TX_BD_R; 
    	} 
     
   pDrvCtrl->freeRtn[pDrvCtrl->ether.txBdNext] = (FUNCPTR) netClFree; 
 
  pDrvCtrl->freeData[pDrvCtrl->ether.txBdNext].arg1 = 
                              pDrvCtrl->endObject.pNetPool;    
  pDrvCtrl->freeData[pDrvCtrl->ether.txBdNext].arg2 =  pBuf; 
 
    /* incr BD count */ 
     
    pDrvCtrl->ether.txBdNext = (pDrvCtrl->ether.txBdNext + 1) % 
        pDrvCtrl->ether.txBdNum; 
     
    /* Unlock interrupts */ 
     
    intUnlock (oldLevel); 
   
    /* release semaphore */ 
 
	 
    END_TX_SEM_GIVE (&pDrvCtrl->endObject); 
 
    /* Bump the statistic counter. */ 
 
   netMblkClChainFree(pMblk);  
 
    END_ERR_ADD (&pDrvCtrl->endObject, MIB2_OUT_UCAST, +1); 
if(send6==1) 
    MOTCPMLOGMSG(("motCpmEndSend_Over \n", 0, 0, 0, 0, 0, 0));  
	 
    return (OK); 
    } 
 
/******************************************************************************* 
* 
* motCpmEndIoctl - network interface control routine 
* 
* This routine implements the network interface control functions. 
* It handles EIOCSIFADDR, EIOCGADDR, EIOCSFLAGS, EIOCGFLAGS, 
* EIOCPOLLSTART, EIOCPOLLSTOP, EIOCGMIB2 and EIOCGFBUF commands. 
* 
* RETURNS: OK if successful, otherwise EINVAL. 
*/ 
 
LOCAL int motCpmEndIoctl 
    ( 
    END_CTRL *	pDrvCtrl,	/* pointer to END_CTRL structure */ 
    int		cmd,		/* command to process */ 
    caddr_t	data		/* pointer to data */  
    ) 
    { 
    int         error   = 0;            /* error value */ 
    long 	value; 
    END_OBJ *	pEndObj	= &pDrvCtrl->endObject; 
 
    MOTCPMLOGMSG(("motCpmEndIoctl with command = 0x%x \n", cmd, 0, 0, 0, 0, 0)); 
 
    switch (cmd) 
        { 
	case EIOCSADDR: 
	    if (data == NULL) 
	    	error = EINVAL; 
	    bcopy ((char *)data, (char *)END_HADDR(pEndObj), 
			END_HADDR_LEN(pEndObj)); 
	    break; 
 
        case EIOCGADDR: 
	    if (data == NULL) 
	    	error = EINVAL; 
	     else 
	     	bcopy ((char *)END_HADDR(pEndObj), (char *)data, 
		 	END_HADDR_LEN(pEndObj)); 
	  	break; 
    
	case EIOCSFLAGS: 
	    value = (long) data; 
	    if (value < 0) 
		{ 
		value = -value; 
		value--; 
		END_FLAGS_CLR (pEndObj, value); 
		} 
	    else 
		END_FLAGS_SET (pEndObj, value); 
 
	    /* set promisc bit off flags */ 
 
	    if (END_FLAGS_GET(pEndObj) & IFF_PROMISC) 
		pDrvCtrl->ether.pSccReg->psmr |= SCC_ETHER_PSMR_PRO; 
	    else 
		pDrvCtrl->ether.pSccReg->psmr &= ~SCC_ETHER_PSMR_PRO; 
	    break; 
 
	case EIOCGFLAGS: 
	    if (data == NULL) 
		error = EINVAL; 
	    else 
	    	*(int *)data = END_FLAGS_GET(pEndObj); 
	    break; 
 
	case EIOCPOLLSTART: 
	    error = motCpmEndPollStart (pDrvCtrl); 
	    break; 
 
	case EIOCPOLLSTOP: 
	    error = motCpmEndPollStop (pDrvCtrl); 
	    break; 
 
	case EIOCGMIB2: 
	    if (data == NULL) 
	    	error = EINVAL; 
	    else 
		bcopy((char *)&pDrvCtrl->endObject.mib2Tbl, (char *)data, 
			sizeof(pDrvCtrl->endObject.mib2Tbl)); 
	    break; 
 
        case EIOCGFBUF: 
	    if (data == NULL) 
		error =  EINVAL; 
	    else 
		*(int *)data = LENGTH_MIN_FBUF; 
	    break; 
 
        default: 
            error = EINVAL; 
        } 
 
    return (error); 
    } 
 
/******************************************************************************* 
* 
* motCpmEndMCastAddrAdd - add a multicast address for the device 
* 
* This routine adds a multicast address to whatever the driver 
* is already listening for.  
* 
* To add an address in the processor group address hash filter, we use 
* the SET GROUP ADDRESS command. This command can be executed at any  
* time, regadless of whether the Ethernet channel is enabled. 
* 
* RETURNS : OK or ERROR 
*/ 
 
LOCAL STATUS motCpmEndMCastAddrAdd 
    ( 
    END_CTRL *  pDrvCtrl,	/* pointer to END_CTRL structure */ 
    char *      pAddr		/* Address to add to the table. */ 
    ) 
    { 
    STATUS error; 
 
    MOTCPMLOGMSG(("motCpmEndMCastAddrAdd %x:%x:%x:%x:%x:%x \n",  
		 pAddr[5], pAddr[4], pAddr[3],  
		 pAddr[2], pAddr[1], pAddr[0])); 
 
    error = etherMultiAdd (&pDrvCtrl->endObject.multiList, pAddr); 
 
    if (error == ENETRESET) 
	{ 
	pDrvCtrl->endObject.nMulti++; 
 
	/* Set the multicast address */ 
 
	motCpmMCastFilterSet (pDrvCtrl, pAddr); 
 
	error = OK; 
	} 
 
    return ((error == OK) ? OK : ERROR); 
    } 
 
/******************************************************************************* 
* 
* motCpmEndMCastAddrDel - delete a multicast address for the device 
* 
* This routine deletes a multicast address from the current list of 
* multicast addresses. 
* 
* RETURNS : OK or ERROR 
*/ 
 
LOCAL STATUS motCpmEndMCastAddrDel 
    ( 
    END_CTRL *  pDrvCtrl,	/* pointer to END_CTRL structure */ 
    char *      pAddr		/* Address to delete from the table. */ 
    ) 
    { 
    STATUS error; 
 
    MOTCPMLOGMSG(("motCpmEndMCastDel %x:%x:%x:%x:%x:%x \n",  
		 pAddr[5], pAddr[4], pAddr[3],  
		 pAddr[2], pAddr[1], pAddr[0])); 
 
    error = etherMultiDel (&pDrvCtrl->endObject.multiList, pAddr); 
 
    if (error == ENETRESET) 
	{ 
	pDrvCtrl->endObject.nMulti--; 
	motCpmMCastConfig (pDrvCtrl); 
	error = OK; 
	} 
 
    return ((error == OK) ? OK : ERROR); 
    } 
 
/******************************************************************************* 
* 
* motCpmEndMCastAddrGet - get the current multicast address list 
* 
* This routine returns the current multicast address list in  
* 
*/ 
 
LOCAL STATUS motCpmEndMCastAddrGet 
    ( 
    END_CTRL *  pDrvCtrl,	/* pointer to END_CTRL structure */ 
    MULTI_TABLE *pTable		/* table to fill in with addresses */ 
    ) 
    { 
    MOTCPMLOGMSG(("motCpmEndMCastAddrGet \n", 0, 0, 0, 0, 0, 0)); 
 
    return (etherMultiGet (&pDrvCtrl->endObject.multiList, pTable)); 
    } 
 
/******************************************************************************* 
* 
* motCpmEndPollStart - start polling mode 
* 
* This routine starts polling mode by disabling ethernet interrupts and 
* setting the polling flag in the END_CTRL stucture. 
* 
* It is necessary to empty transmit queue before entering polling mode 
* because M_BLK_ID free routine used in interrupt mode could be unusable  
* in this mode (could use kernel calls).  
* 
* RETURNS: OK or ERROR if already in polling mode. 
*/ 
 
LOCAL STATUS motCpmEndPollStart 
    ( 
    END_CTRL    *pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    int 	intLevel; 
    int		txBdIndex; 
    SCC_BUF *	pTxBd; 
 
    MOTCPMLOGMSG(("motCpmEndPollStart \n", 0, 0, 0, 0, 0, 0)); 
 
    /* Lock interrupts */ 
 
    intLevel = intLock(); 
 
    /* clean transmit queue */ 
 
    txBdIndex = pDrvCtrl->txBdIndexC; 
 
    while (txBdIndex != pDrvCtrl->ether.txBdNext) 
	{ 
	pTxBd = & pDrvCtrl->ether.txBdBase[txBdIndex]; 
 
	/* Spin until frame buffer is sent */ 
 
	while (pTxBd->statusMode & SCC_ETHER_TX_BD_R) 
	    ; 
 
	/* Check for transmit errors */ 
 
	if (pTxBd->statusMode & (SCC_ETHER_TX_BD_RL | SCC_ETHER_TX_BD_UN | 
 				SCC_ETHER_TX_BD_CSL | SCC_ETHER_TX_BD_LC)) 
	    { 
	    /* An error has occured, restart the transmitter */ 
 
	    pDrvCtrl->txStop = TRUE; 
 
	    motCpmTxRestart (pDrvCtrl); 
	    } 
 
	/* increment txBdIndex */ 
 
	txBdIndex = (txBdIndex + 1) % pDrvCtrl->ether.txBdNum; 
	} 
     
    /* free all transmit buffer and update transmit queue */ 
 
    motCpmCleanTxBdQueue (pDrvCtrl); 
 
    /* Now, transmit queue is empty. We can enter polling mode. */ 
    /* mask off the receive and transmit interrupts */ 
     
    pDrvCtrl->ether.pSccReg->sccm = 0; 
 
    /* Set the polling flag */ 
 
    pDrvCtrl->polling = TRUE; 
 
    /* Unlock interrupts */ 
 
    intUnlock (intLevel); 
 
    return (OK); 
    } 
 
/******************************************************************************* 
* 
* motCpmEndPollStop - stop polling mode 
* 
* This routine stops polling mode by enabling ethernet interrupts and 
* resetting the polling flag in the END_CTRL structure. 
* 
* RETURNS: OK always 
*/ 
 
LOCAL STATUS motCpmEndPollStop 
    ( 
    END_CTRL    *pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    int         intLevel; 
 
    MOTCPMLOGMSG(("motCpmEndPollStop \n", 0, 0, 0, 0, 0, 0)); 
 
    /* lock interrupt  */ 
 
    intLevel = intLock(); 
 
    /* reset the SCC's interrupt status bit */ 
 
    *CPM_CISR(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask; 
 
    /* enable this SCC's interrupt */ 
 
    *CPM_CIMR(pDrvCtrl->regBase) |= pDrvCtrl->ether.intMask; 
 
    /* reset the status bits */ 
 
    pDrvCtrl->ether.pSccReg->scce = 0xffff; 
 
    /* enables the receive and transmit interrupts */ 
 
    
 
   pDrvCtrl->ether.pSccReg->sccm = SCC_ETHER_SCCX_RXF | SCC_ETHER_SCCX_TXE | 
				    SCC_ETHER_SCCX_TXB; 
 
    /* reset the polling flag */ 
 
    pDrvCtrl->polling = FALSE; 
 
    /* unlock interrupt  */ 
 
    intUnlock (intLevel); 
 
    return (OK); 
    } 
 
/****************************************************************************** 
* 
* motCpmEndPollSend - transmit a packet in polled mode 
* 
* This routine is called by a user to try and send a packet on the 
* device. It sends a packet directly on the network from the caller without 
* going through the normal processes of queuing a pacet on an output queue 
* and the waiting for the device to decide to transmit it. 
* 
* If it detects a transmission error, the restart command is issued. 
* 
* These routine should not call any kernel functions. 
* 
* RETURNS: OK or EAGAIN 
*/ 
 
/*LOCAL STATUS motCpmEndPollSend*/ 
LOCAL STATUS motCpmEndSend/*wut 2004.7.22modify*/ 
    ( 
    END_CTRL    *pDrvCtrl,	/* pointer to END_CTRL structure */ 
    M_BLK_ID    pMblk	/* data to send */ 
    ) 
    { 
    int		length; 
    int              oldLevel; 
    SCC_BUF *	pTxBd; 
    u_char *	pad; 
    char *	pBuf; 
	 
    if(send1==1) 
    MOTCPMLOGMSG(("motCpmEndSend_START \n", 0, 0, 0, 0, 0, 0)); 
 
 
 
    END_TX_SEM_TAKE (&pDrvCtrl->endObject, WAIT_FOREVER); 
 
    /* get a free transmit frame descriptor */ 
 
    pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->ether.txBdNext]; 
 
    /* check if a transmit buffer descriptor is available */ 
 
    if ((pTxBd->statusMode & SCC_ETHER_TX_BD_R) || 
	(((pDrvCtrl->ether.txBdNext + 1) % pDrvCtrl->ether.txBdNum) 
			== pDrvCtrl->txBdIndexC)) 
	{ 
	    END_TX_SEM_GIVE (&pDrvCtrl->endObject); 
	    if(send3==1) 
	    MOTCPMLOGMSG(("pTxBd->statusMode & SCC_ETHER_TX_BD_R \n", 0, 0, 0, 0, 0, 0)); 
	    motCpmCleanTxBdQueue (pDrvCtrl); 
	    return (EAGAIN); 
	} 
 
    /* fill the transmit frame descriptor */ 
     
   pBuf = netClusterGet (pDrvCtrl->endObject.pNetPool, pDrvCtrl->pClPoolId); 
	 
    if (pBuf == NULL) 
        { 
            END_TX_SEM_GIVE (&pDrvCtrl->endObject); 
            if(send4==1) 
            MOTCPMLOGMSG(("tran_pBuf == NULL \n", 0, 0, 0, 0, 0, 0)); 
	     netMblkClChainFree(pMblk); 	/*wutao*/ 
            return (ERROR); 
        } 
 
   length = netMblkToBufCopy (pMblk, (char *)pBuf, NULL); 
	 
    pTxBd->dataPointer = (u_char *) pBuf; 
 
    /* padding mechanism in Rev A is buggy - do in software */ 
 
    if (length < FRAME_MIN) 
	{ 
	pad = pTxBd->dataPointer + length; 
	for (; length != FRAME_MIN; length++, pad++) 
	    *pad = 0x88; 
	} 
 
    pTxBd->dataLength = length; 
 
    oldLevel = intLock ();	/* disable ints during update */ 
 
    if (pTxBd->statusMode & SCC_ETHER_TX_BD_W) 
	pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD | 
			    SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  | 
			    SCC_ETHER_TX_BD_W | SCC_ETHER_TX_BD_R; 
    else 
	pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD | 
			    SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  | 
			    SCC_ETHER_TX_BD_R; 
 
    /* incr BD count */ 
 
    pDrvCtrl->ether.txBdNext = (pDrvCtrl->ether.txBdNext + 1) % 
				pDrvCtrl->ether.txBdNum; 
 
 
    intUnlock (oldLevel); 
 
    /* Bump the statistic counter. */ 
 
    END_ERR_ADD (&pDrvCtrl->endObject, MIB2_OUT_UCAST, +1); 
 
    /* 
     * Spin until we've sent it. 
     */ 
 
    if(send5==1) 
            MOTCPMLOGMSG(("while no over \n", 0, 0, 0, 0, 0, 0)); 
	 
    while (pTxBd->statusMode & SCC_ETHER_TX_BD_R) 
	; 
 
    if (pTxBd->statusMode & (SCC_ETHER_TX_BD_RL | SCC_ETHER_TX_BD_UN | 
			    SCC_ETHER_TX_BD_CSL | SCC_ETHER_TX_BD_LC)) 
	{ 
	/* An error has occured, restart the transmitter */ 
 
	     
             	if(send6==1) 
             	MOTCPMLOGMSG(("pDrvCtrl->txStop = TRUE \n", 0, 0, 0, 0, 0, 0)); 
				 
 		motCpmTxRestart (pDrvCtrl); 
		motCpmCleanTxBdQueue (pDrvCtrl); 
		 
	 
	} 
 
    
     	netClFree (pDrvCtrl->endObject.pNetPool, pBuf); 
 
     	netMblkClChainFree(pMblk);  
 
 
    	pDrvCtrl->txBdIndexC = pDrvCtrl->ether.txBdNext; 
	if(send7==1) 
	MOTCPMLOGMSG(("tran_over \n", 0, 0, 0, 0, 0, 0)); 
	 
	END_TX_SEM_GIVE (&pDrvCtrl->endObject); 
	 
    	return (OK); 
    } 
 
/****************************************************************************** 
* 
* motCpmEndPollSend - transmit a packet in polled mode 
* 
* This routine is called by a user to try and send a packet on the 
* device. It sends a packet directly on the network from the caller without 
* going through the normal processes of queuing a pacet on an output queue 
* and the waiting for the device to decide to transmit it. 
* 
* If it detects a transmission error, the restart command is issued. 
* 
* These routine should not call any kernel functions. 
* 
* RETURNS: OK or EAGAIN 
*/ 
 
   LOCAL STATUS motCpmEndPollSend 
 
    ( 
    END_CTRL    *pDrvCtrl,	/* pointer to END_CTRL structure */ 
    M_BLK_ID    pMblk	/* data to send */ 
    ) 
    { 
    int		length; 
    SCC_BUF *	pTxBd; 
    u_char *	pad; 
    char *	pBuf; 
 
    MOTCPMLOGMSG(("motCpmEndPollSend \n", 0, 0, 0, 0, 0, 0)); 
 
    if (pDrvCtrl->txStop) 
	return (ERROR); 
 
    /* get a free transmit frame descriptor */ 
 
    pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->ether.txBdNext]; 
 
    /* check if a transmit buffer descriptor is available */ 
 
    if ((pTxBd->statusMode & SCC_ETHER_TX_BD_R) || 
	(((pDrvCtrl->ether.txBdNext + 1) % pDrvCtrl->ether.txBdNum) 
			== pDrvCtrl->txBdIndexC)) 
	{ 
	motCpmCleanTxBdQueue (pDrvCtrl); 
	return (EAGAIN); 
	} 
 
    /* fill the transmit frame descriptor */ 
     
    pBuf = netClusterGet (pDrvCtrl->endObject.pNetPool, pDrvCtrl->pClPoolId); 
    if (pBuf == NULL) 
        { 
        return (ERROR); 
        } 
 
    length = netMblkToBufCopy (pMblk, (char *)pBuf, NULL); 
 
    pTxBd->dataPointer = (u_char *) pBuf; 
 
    /* padding mechanism in Rev A is buggy - do in software */ 
 
    if (length < FRAME_MIN) 
	{ 
	pad = pTxBd->dataPointer + length; 
	for (; length != FRAME_MIN; length++, pad++) 
	    *pad = 0x88; 
	} 
 
    pTxBd->dataLength = length; 
 
    if (pTxBd->statusMode & SCC_ETHER_TX_BD_W) 
	pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD | 
			    SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  | 
			    SCC_ETHER_TX_BD_W | SCC_ETHER_TX_BD_R; 
    else 
	pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD | 
			    SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC  | 
			    SCC_ETHER_TX_BD_R; 
 
    /* incr BD count */ 
 
    pDrvCtrl->ether.txBdNext = (pDrvCtrl->ether.txBdNext + 1) % 
				pDrvCtrl->ether.txBdNum; 
 
    /* Bump the statistic counter. */ 
 
    END_ERR_ADD (&pDrvCtrl->endObject, MIB2_OUT_UCAST, +1); 
 
    /* 
     * Spin until we've sent it. 
     */ 
 
    while (pTxBd->statusMode & SCC_ETHER_TX_BD_R) 
	; 
 
    if (pTxBd->statusMode & (SCC_ETHER_TX_BD_RL | SCC_ETHER_TX_BD_UN | 
			    SCC_ETHER_TX_BD_CSL | SCC_ETHER_TX_BD_LC)) 
	{ 
	/* An error has occured, restart the transmitter */ 
 
	pDrvCtrl->txStop = TRUE; 
 
	motCpmTxRestart (pDrvCtrl); 
	} 
 
    /*  
     * we are allow to do this because transmit queue is empty when we 
     * start polling mode. 
     */ 
 
    netClFree (pDrvCtrl->endObject.pNetPool, pBuf); 
 
     netMblkClChainFree(pMblk);  
 
    pDrvCtrl->txBdIndexC = pDrvCtrl->ether.txBdNext; 
 
    return (OK); 
    } 
 
 
/******************************************************************************* 
* 
* motCpmEndPollReceive - receive a packet in polled mode 
* 
* This routine is called by a user to try and get a packet from the 
* device. It returns EAGAIN if no packet is available. The caller must 
* supply a M_BLK_ID with enough space to contain the receiving packet. If 
* enough buffer is not available then EAGAIN is returned. 
* 
* These routine should not call any kernel functions. 
* 
* RETURNS: OK or EAGAIN 
*/ 
 
LOCAL STATUS motCpmEndPollReceive 
    ( 
    END_CTRL    *pDrvCtrl,	/* pointer to END_CTRL structure */ 
    M_BLK_ID    pMblk 
    ) 
    { 
    SCC_BUF *	pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext]; 
    int		length; 
    int		status = EAGAIN; 
 
    MOTCPMLOGMSG(("motCpmEndPollReceive \n", 0, 0, 0, 0, 0, 0)); 
 
    /* if we have not received packets, leave immediatly */ 
 
    if (pRxBd->statusMode & SCC_ETHER_RX_BD_E) 
	return (EAGAIN); 
 
    /* check packets for errors */ 
 
    if (((pRxBd->statusMode & (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L)) 
			   == (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L)) 
       && !(pRxBd->statusMode & (SCC_ETHER_RX_BD_CL | 
				SCC_ETHER_RX_BD_OV | SCC_ETHER_RX_BD_CR | 
				SCC_ETHER_RX_BD_SH | SCC_ETHER_RX_BD_NO | 
				SCC_ETHER_RX_BD_LG))) 
	{ 
	/* adjust length to data only */ 
 
	length = pRxBd->dataLength; 
 
	if ((length - SIZEOF_ETHERHEADER) <= 0) 
	    { 
	    /* bump input error packet counter */ 
 
	    END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1); 
	    goto cleanRxBd; 
	    } 
 
	/*  
	 * Upper layer provides the buffer. 
         * If buffer is not large enough, we return. 
	 */ 
 
	/* copy data */ 
 
        if ((pMblk->mBlkHdr.mLen < length) || 
            (!(pMblk->mBlkHdr.mFlags & M_EXT))) 
            { 
            goto cleanRxBd; 
            } 
         
	bcopy ((char *) pRxBd->dataPointer, (char *)pMblk->mBlkHdr.mData, 
               length); 
	pMblk->mBlkHdr.mLen = length; 
	pMblk->mBlkPktHdr.len = length; 
	pMblk->mBlkHdr.mFlags |= M_PKTHDR; 
 
	/* bump input packet counter */ 
 
	END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_UCAST, +1); 
 
	status = OK; 
	} 
    else 
	{ 
	/* bump input error packet counter */ 
 
	END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1); 
	} 
 
cleanRxBd: 
    motCpmCleanRxBd (pDrvCtrl, pRxBd);	/* reset buffer descriptor as empty */ 
 
    return (status); 
    } 
 
/******************************************************************************* 
* 
* motCpmIntr - network interface interrupt handler 
* 
* This routine gets called at interrupt level. It handles work that  
* requires minimal processing. Interrupt processing that is more  
* extensive gets handled at task level. The network task, netTask(), is  
* provided for this function. Routines get added to the netTask() work  
* queue via the netJobAdd() command. 
* 
* RETURNS: N/A 
*/ 
 
LOCAL void motCpmIntr/*wut*/ 
    ( 
    END_CTRL *	pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    BOOL rxHandle = FALSE; 
    BOOL txbHandle = FALSE; 
     
    /* check for spurious interrupt -> initialized ? */ 
 
    if (!pDrvCtrl->endObject.attached) 
	{ 
        pDrvCtrl->ether.pSccReg->scce = 0xffff; 
 
        *CPM_CISR(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask; 
	return; 
	} 
 
    /* handle receive events */ 
 
    if ((pDrvCtrl->ether.pSccReg->sccm & SCC_ETHER_SCCX_RXF) && 
        (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_RXF)) 
	{ 
        (void) netJobAdd ((FUNCPTR) motCpmHandleInt, (int) pDrvCtrl,  
			  0, 0, 0, 0);  
 
	/* turn off receive interrupts for now - motCpmHandleIt turns back on */ 
 
        pDrvCtrl->ether.pSccReg->sccm &= ~SCC_ETHER_SCCX_RXF; 
	rxHandle = TRUE; 
        } 
 
    /* check for output errors */ 
 
    if (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_TXE) 
	{ 
	/* clean the transmit buffer descriptor queue */ 
	/* NOTE: HBC error not supported -> always RESTART Tx here */ 
	 
	if(send11==1) 
	MOTCPMLOGMSG(("netJobAdd (FUNCPTR) motCpmTxRestart\n", 0, 0, 0, 0, 0, 0)); 
 
	 if ( !pDrvCtrl->txCleaning) 
	 motCpmCleanTxBdQueue (pDrvCtrl); 
	  
	 pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXE; 
         
        (void) netJobAdd ((FUNCPTR) motCpmTxRestart, (int) pDrvCtrl,  
			  0, 0, 0, 0); 
 
	} 
 
    /* handle transmitter events - BD full condition -> ever happen ? */ 
 
    if ((pDrvCtrl->ether.pSccReg->sccm & SCC_ETHER_SCCX_TXB) && 
        (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_TXB)) 
	{ 
	txbHandle = TRUE; 
	} 
 
    /* check for input busy condition */ 
 
    if (pDrvCtrl->ether.pSccReg->scce & SCC_ETHER_SCCX_BSY) 
        pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_BSY;  
 
    /* acknowledge all other interrupts - ignore events */ 
 
    pDrvCtrl->ether.pSccReg->scce = (pDrvCtrl->ether.pSccReg->scce & 
				    ~(SCC_ETHER_SCCX_RXF | 
				      SCC_ETHER_SCCX_TXE | 
				      SCC_ETHER_SCCX_TXB | 
				      SCC_ETHER_SCCX_BSY)); 
 
    /*  
     * clean the transmit buffer descriptor queue if we have  
     * received a transmit interrupt and if we are not already 
     * cleaning this transmit queue. 
     */ 
 
  
 
       if ((txbHandle) && !pDrvCtrl->txCleaning)/*wutao*/ 
        { 
         if(send8==1) 
         	{ 
			 
	    		MOTCPMLOGMSG(("txbHandle=%d , pDrvCtrl->txCleaning=%d\n",  txbHandle, pDrvCtrl->txCleaning, 0, 0, 0,0)); 
		} 
    		motCpmCleanTxBdQueue (pDrvCtrl); 
 
 
        } 
 
    /* acknowledge interrupts */ 
 
    if (rxHandle) 
        pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_RXF;  
 
 
    if (txbHandle) 
        pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXB;  
 
 
    *CPM_CISR(pDrvCtrl->regBase) = pDrvCtrl->ether.intMask; 
 
    } 
 
/******************************************************************************* 
* 
* motCpmMCastFilterSet - set the group addres filter for a multicast addresse. 
* 
* To add an address in the processor group address hash filter, we use 
* the SET GROUP ADDRESS command. This command can be executed at any  
* time, regadless of whether the Ethernet channel is enabled. 
* 
* RETURNS : N/A  
* 
*/ 
 
LOCAL void motCpmMCastFilterSet 
    ( 
    END_CTRL *  pDrvCtrl,	/* pointer to END_CTRL structure */ 
    char *      pAddress        /* Address to delete from the table. */ 
    ) 
    { 
    MOTCPMLOGMSG(("motCpmMCastFilterSet \n", 0, 0, 0, 0, 0, 0)); 
 
    /* add multicast address */ 
 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_h = 
					(pAddress[5] << 8) + pAddress[4]; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_m = 
					(pAddress[3] << 8) + pAddress[2]; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_l = 
					(pAddress[1] << 8) + pAddress[0]; 
 
    /* issue the set group address command to the CP */ 
 
    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
 
    *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) | 
				       CPM_CR_SCC_SET_GROUP | 
				       CPM_CR_FLG; 
 
    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
    } 
 
/******************************************************************************* 
* 
* motCpmMCastConfig - reconfigure the interface under us. 
* 
* Reconfigure the interface changing the multicast interface list. 
* 
* In order to delete an address from the hash tabke, the Ethernet channel 
* should be disabled, the hash table registers should be cleared, and  
* the SET GROUP ADDRESS command must be executed for the remaining  
* desired addresses. This is required because the hash table may have mapped 
* multiple addresses to the same hash table bit. 
* 
* RETURNS : N/A  
*/ 
 
LOCAL void motCpmMCastConfig 
    ( 
    END_CTRL *  pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    ETHER_MULTI *	pCurr; 
 
    MOTCPMLOGMSG(("motCpmMCastConfig \n",0,0,0,0,0,0)); 
 
    /* disable the ethernet channel */ 
 
    motCpmReset (pDrvCtrl); 
 
    /* clear hash table group registers */ 
 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr1     = 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr2     = 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr3     = 0x0000; 
    ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr4     = 0x0000; 
 
    /* restore remaining addresses */ 
 
    for (pCurr = END_MULTI_LST_FIRST(&pDrvCtrl->endObject); pCurr != NULL; 
			pCurr = (ETHER_MULTI *)lstNext(&pCurr->node)) 
	{ 
	/* add multicast address */ 
	motCpmMCastFilterSet (pDrvCtrl, pCurr->addr); 
	} 
 
    /* restart the ethernet channel */ 
 
    motCpmRestart (pDrvCtrl); 
    } 
 
/******************************************************************************* 
* 
* motCpmRestart - network interface restart routine 
* 
* This routine restarts the device.  This includes enabling interrupts,  
* starting the transmitter and receiver, and calling the bsp-specific 
* LAN enable routine to do any target specific enabling. 
* 
* This routine follows the instructions in MC68EN360/MPC821 Users's Manual : 
* "Disabling the SCCs on the Fly" 
* 
* The complement of this routine is motCpmReset().  Once a unit is reset by 
* motCpmReset(), it may be re-initialized to a running state by this routine. 
* 
* RETURNS: N/A 
*/ 
 
LOCAL STATUS motCpmRestart 
    ( 
    END_CTRL * 	pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    /* enable Ethernet interrupts */ 
 
    *CPM_CIMR(pDrvCtrl->regBase) |= pDrvCtrl->ether.intMask; 
 
    /* call the BSP to do any other initialization (e.g., connecting clocks) */ 
 
    SYS_ENET_ENABLE; 
 
    /* enable the transmitter */ 
 
    pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENT; 
 
    /* issue the restart transmitter command to the CP */ 
 
    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
    *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) | 
				      CPM_CR_SCC_RESTART | 
				      CPM_CR_FLG; 
    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
 
    /* issue the enter hunt mode command to the CP */ 
 
    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
    *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) | 
				      CPM_CR_SCC_HUNT | 
				      CPM_CR_FLG; 
    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
 
    /* enable the receiver */ 
 
    pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENR; 
 
    return (OK); 
    } 
 
/******************************************************************************* 
* 
* motCpmReset - network interface reset routine 
* 
* This routine resets the device.  This includes disabling interrupts,  
* stopping the transmitter and receiver, and calling the bsp-specific 
* LAN disable routine to do any target specific disabling. 
* 
* This routine follows the instructions in MC68EN360/MPC821 Users's Manual : 
* "Disabling the SCCs on the Fly" 
* 
* The complements of this routine are motCpmEndStart() and motCpmRestart().   
* Once a unit is reset in this routine, it may be re-started with parameters 
* reinitialized with motCpmEndStart() or re-started with current parameteres  
* with  motCpmRestart(). 
* 
* RETURNS: N/A 
*/ 
 
LOCAL void motCpmReset 
    ( 
    END_CTRL * 	pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    int counter = 0xffff; 
 
    /* disable the SCC interrupts */ 
 
    *CPM_CIMR(pDrvCtrl->regBase) &= ~pDrvCtrl->ether.intMask; 
 
    /* issue the CP graceful stop command to the transmitter if necessary */ 
 
    if (pDrvCtrl->ether.pSccReg->gsmrl & SCC_GSMRL_ENT) 
	{ 
        while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
        *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) | 
                                          CPM_CR_SCC_GRSTOP | CPM_CR_FLG; 
        while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
 
        /* wait for graceful stop to register */ 
 
        while ((counter--) && (!(pDrvCtrl->ether.pSccReg->scce & 
			         SCC_ETHER_SCCX_GRA))); 
	} 
 
    /* disable the SCC receiver and transmitter */ 
 
    pDrvCtrl->ether.pSccReg->gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); 
 
    /* call the BSP to do any other disabling (e.g., *TENA) */ 
 
    SYS_ENET_DISABLE; 
 
    } 
 
/******************************************************************************* 
* 
* motCpmTxRestart - issue RESTART Tx command to the CP 
* 
* This routine issues a RESTART transmitter command to the CP.  It is 
* executed by netTask (motCpmIntr() did a netJobAdd).  motCpmIntr() cannot do 
* a RESTART directly because the CPM flag must be taken before a command 
* can be written.   
* 
* RETURNS: N/A 
*/ 
 
LOCAL void motCpmTxRestart 
    ( 
    END_CTRL *	pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    if(send10==1) 
    MOTCPMLOGMSG(("motCpmTxRestart \n", 0, 0, 0, 0, 0, 0)); 
 
    /* update error counter */ 
 
    END_ERR_ADD (&pDrvCtrl->endObject, MIB2_OUT_ERRS, +1); 
    END_ERR_ADD (&pDrvCtrl->endObject, MIB2_OUT_UCAST, -1); 
 
    /* restart transmitter */ 
 
    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
    *CPM_CPCR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) | 
                                      CPM_CR_SCC_RESTART | CPM_CR_FLG; 
    while (*CPM_CPCR(pDrvCtrl->regBase) & CPM_CR_FLG); 
 
    pDrvCtrl->txStop = FALSE; 
    } 
 
/******************************************************************************* 
* 
* motCpmHandleInt - task-level interrupt handler 
* 
* This is the task-level interrupt handler, which is called from  
* netTask(). motCpmIntr() gets input frames from the device and then calls  
* motCpmIntr() to process each frame. motCpmIntr() only gets called if no error 
* stats were reported in the buffer descriptor.  Data chaining is not 
* supported. 
* 
* This routine should be called with SCC receive interrupts masked so that 
* more netJobAdds of this routine are not performed by motCpmIntr(). 
* Receive interrupts are turned back on by this routine before exiting. 
* 
* RETURNS: N/A 
*/ 
 
LOCAL void motCpmHandleInt 
    ( 
    END_CTRL *	pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    SCC_BUF *	pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext]; 
 
    while (!(pRxBd->statusMode & SCC_ETHER_RX_BD_E)) 
        { 
        /* data chaining is not supported  - check all error conditions */ 
 
        if (((pRxBd->statusMode & (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L)) 
	                       == (SCC_ETHER_RX_BD_F  | SCC_ETHER_RX_BD_L)) 
	                      && !(pRxBd->statusMode & (SCC_ETHER_RX_BD_CL | 
		                   SCC_ETHER_RX_BD_OV | SCC_ETHER_RX_BD_CR | 
				   SCC_ETHER_RX_BD_SH | SCC_ETHER_RX_BD_NO | 
				   SCC_ETHER_RX_BD_LG))) 
            motCpmRecv (pDrvCtrl, pRxBd); 
        else 
	    { 
            END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1); 
 
	    /* reset buffer descriptor as empty */ 
 
	    motCpmCleanRxBd (pDrvCtrl, pRxBd); 
	    } 
 
        /* update receive buffer descriptor pointer */ 
 
        pRxBd = & pDrvCtrl->ether.rxBdBase[pDrvCtrl->ether.rxBdNext]; 
 
        /* clear Rx events */ 
 
        pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_RXF; 
        } 
 
    /* re-enable Rx interrupts */ 
 
    pDrvCtrl->ether.pSccReg->sccm |= SCC_ETHER_SCCX_RXF; 
    } 
 
/******************************************************************************* 
* 
* motCpmRecv - process an input frame 
* 
* This routine processes an input frame, then passes it up to the higher  
* level in a form it expects.  Buffer loaning, promiscuous mode are all  
* supported.  Trailer protocols is not supported. 
* 
* RETURNS: N/A 
*/ 
 
LOCAL void motCpmRecv  /*wut modify 2004.7.22*/ 
    ( 
    END_CTRL *	pDrvCtrl,	/* pointer to END_CTRL structure */ 
    SCC_BUF *	pRxBd		/* receive buffer descriptor */ 
    ) 
    {  
    M_BLK_ID	pMblk; 
    CL_BLK_ID	pClBlk; 
    char *	pNewCluster; 
 
    if (((pRxBd->dataLength - 4) - SIZEOF_ETHERHEADER) <= 0) 
	{  
        END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1); 
	motCpmCleanRxBd (pDrvCtrl, pRxBd);/* reset buffer descriptor as empty */ 
	return; 
	} 
	 
      if(rev1==1) 
      MOTCPMLOGMSG(("motCpmRecv_START\n", 0, 0, 0, 0, 0, 0)); 
 
   pNewCluster = netClusterGet (pDrvCtrl->endObject.pNetPool, 
                                 pDrvCtrl->pClPoolId); 
	 
   /* pNewCluster = netClusterGet (pDrvCtrl->endObject.pNetPool, 
                                 pDrvCtrl->endObject.pNetPool->clTbl[0]);*/ 
 
    if (pNewCluster == NULL) 
        {  
        if(rev2==1) 
         MOTCPMLOGMSG(("motCpm_REV_pNewCluster == NULL\n", 0, 0, 0, 0, 0, 0)); 
         END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1); 
	  motCpmCleanRxBd (pDrvCtrl, pRxBd);/* reset buffer descriptor as empty */ 
	  return; 
        } 
 
    if ((pClBlk = clBlkGet (pDrvCtrl->endObject.pNetPool, M_DONTWAIT)) 
        == NULL) 
        { 
         if(rev3==1) 
         MOTCPMLOGMSG(("motCpm_REV_pClBlk == NULL\n", 0, 0, 0, 0, 0, 0)); 
         netClFree (pDrvCtrl->endObject.pNetPool, pNewCluster); 
	  END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1); 
	  motCpmCleanRxBd (pDrvCtrl, pRxBd);/* reset buffer descriptor as empty */ 
         return; 
        } 
 
    if ((pMblk = mBlkGet(pDrvCtrl->endObject.pNetPool, 
                         M_DONTWAIT, MT_DATA)) == NULL) 
        { 
          if(rev4==1) 
         MOTCPMLOGMSG(("motCpm_REV_pMblk == NULL\n", 0, 0, 0, 0, 0, 0)); 
         netClBlkFree (pDrvCtrl->endObject.pNetPool, pClBlk);  
	  netClFree (pDrvCtrl->endObject.pNetPool, pNewCluster); 
         END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_ERRS, +1); 
	  motCpmCleanRxBd (pDrvCtrl, pRxBd);/* reset buffer descriptor as empty */ 
         return; 
        } 
 
 
    /* join the cluster block to the data buffer */ 
 
    netClBlkJoin (pClBlk, (char *) pRxBd->dataPointer, pRxBd->dataLength - 4, 
                  NULL, 0, 0, 0); 
 
    /* join the mBlk and cluster Block */ 
 
    netMblkClJoin (pMblk, pClBlk); 
 
    /* intialize the mBlk */ 
 
    pMblk->mBlkHdr.mLen 	= pRxBd->dataLength - 4; 
    pMblk->mBlkHdr.mFlags 	|= M_PKTHDR; 
    pMblk->mBlkPktHdr.len 	= pMblk->mBlkHdr.mLen; 
 
    /* update receive buffer descriptor data pointer */ 
 
    pRxBd->dataPointer = (char *) pNewCluster; 
 
    /*  
     * Reset buffer descriptor as empty 
     * It is neccessary to do this before sending up the packet to the 
     * protocol in case we switch to system mode.  
     */ 
 
    motCpmCleanRxBd (pDrvCtrl, pRxBd); 
 
    /* send up to protocol */ 
 
    if(rev5==1) 
    MOTCPMLOGMSG(("motCpm_REV_OVER\n", 0, 0, 0, 0, 0, 0)); 
 
    END_RCV_RTN_CALL (&pDrvCtrl->endObject, pMblk); 
 
    /* bump input packet counter */ 
 
    END_ERR_ADD (&pDrvCtrl->endObject, MIB2_IN_UCAST, +1); 
    } 
 
/******************************************************************************* 
* 
* motCpmCleanRxBd - reset receive buffer descriptor as empty 
* 
* This routine resets receive buffer descriptor as empty 
* 
* RETURNS: N/A 
*/ 
 
LOCAL void motCpmCleanRxBd 
    ( 
    END_CTRL *	pDrvCtrl,	/* pointer to END_CTRL structure */ 
    SCC_BUF *	pRxBd		/* receive buffer descriptor */ 
    ) 
    { 
    /* reset buffer descriptor as empty */ 
 
    if (pRxBd->statusMode & SCC_ETHER_RX_BD_W) 
	pRxBd->statusMode = SCC_ETHER_RX_BD_E | SCC_ETHER_RX_BD_I | 
			    SCC_ETHER_RX_BD_W; 
    else 
	pRxBd->statusMode = SCC_ETHER_RX_BD_E | SCC_ETHER_RX_BD_I; 
 
    /* incr BD count */ 
 
    pDrvCtrl->ether.rxBdNext = (pDrvCtrl->ether.rxBdNext + 1) % 
				pDrvCtrl->ether.rxBdNum; 
    } 
 
/******************************************************************************* 
* 
* motCpmCleanTxBdQueue - clean the transmit buffer descriptor queue 
* 
* This routine cleans the transmit buffer queue. It doesn't look for  
* transmission errors, this is done at interrupt level in motCpmIntr. 
* 
* RETURNS: N/A 
* 
*/ 
 
LOCAL void motCpmCleanTxBdQueue 
    ( 
    END_CTRL * 	pDrvCtrl	/* pointer to END_CTRL structure */ 
    ) 
    { 
    SCC_BUF * 	pTxBd; 
    int		oldLevel; 
    if(send9==1) 
    	{ 
    	/*if(pDrvCtrl->txStop = TRUE)*/ 
    	MOTCPMLOGMSG(("motCpmCleanTxBdQueue \n", 0, 0, 0, 0, 0, 0)); 
    	} 
 
    pDrvCtrl->txCleaning = TRUE; 
 
    while (pDrvCtrl->txBdIndexC != pDrvCtrl->ether.txBdNext) 
	{ 
	pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->txBdIndexC]; 
 
	/* if the data buffer has not been transmitted, don't touch it */ 
 
	if (pTxBd->statusMode & SCC_ETHER_TX_BD_R) 
	    break; 
 
	oldLevel = intLock(); 
 
	if (pDrvCtrl->freeRtn[pDrvCtrl->txBdIndexC] != NULL) 
	    { 
	    pDrvCtrl->freeRtn[pDrvCtrl->txBdIndexC] 
		    (pDrvCtrl->freeData[pDrvCtrl->txBdIndexC].arg1, 
		     pDrvCtrl->freeData[pDrvCtrl->txBdIndexC].arg2); 
	    pDrvCtrl->freeRtn[pDrvCtrl->txBdIndexC] = NULL; 
	    pDrvCtrl->freeData[pDrvCtrl->txBdIndexC].arg1 = NULL; 
	    pDrvCtrl->freeData[pDrvCtrl->txBdIndexC].arg2 = NULL; 
	    } 
 
	intUnlock(oldLevel); 
 
	/* incr txBdIndexC */ 
 
	pDrvCtrl->txBdIndexC = (pDrvCtrl->txBdIndexC + 1) % 
			       pDrvCtrl->ether.txBdNum; 
	} 
 
    pDrvCtrl->txCleaning = FALSE; 
    } 
void printfonoff_send(BOOL a,BOOL b,BOOL c,BOOL d,BOOL e,BOOL f,BOOL g,BOOL k,BOOL m,BOOL n,BOOL l) 
{ 
send1=a; 
send2=b; 
send3=c; 
send4=d; 
send5=e; 
send6=f; 
send7=g; 
send8=k; 
send9=m; 
send10=n; 
send11=l; 
} 
void printfonoff_rev(BOOL a,BOOL b,BOOL c,BOOL d,BOOL e) 
{ 
 rev1=a, 
 rev2=b, 
 rev3=c, 
 rev4=d, 
 rev5=e; 
} 
/* END OF FILE */