templateEnd.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:45k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* templateEnd.c - template Enhanced Network Driver (END) */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. /*
  4. TODO - Remove the template modification history and begin a new history
  5. starting with version 01a and growing the history upward with
  6. each revision.
  7. modification history
  8. --------------------
  9. 01y,14jun02,dat  Fixing diab warnings
  10. 01x,15may02,dat  Update comments about polled entry points
  11. 01w,03nov01,dat  buffer/cache updates
  12. 01v,24sep01,pai  merge from sustaining branch to Veloce (SPR# 70553).
  13. 01u,06jun01,pai  templateLoad corrected for two-pass algorithm (SPR# 67836)
  14. 01t,09mar01,dat  64473, MuxLib was free'ing the END_OBJ structure. Fixed the
  15.  load function for driver name response.
  16. 01s,29sep00,dat  removing PHYS_TO_VIRT translation
  17. 01r,20sep00,dat  SPR 32058, allow for alternate intConnect rtn
  18. 01q,28aug00,stv  corrected the handling of EIOCSFLAGS ioctl (SPR# 29423).
  19. 01p,02aug00,stv  removed netMblkClChainFree() in Pollsend routine (SPR# 32885).
  20. 01o,11jun00,ham  removed reference to etherLib.
  21. 01n,27jan00,dat  fixed use of NULL
  22. 01m,12dec00,pai  fixed SYS_ENET_ADDR_GET and SYS_INT_ENABLE definitions (SPR
  23.                  #62969).
  24. 01l,12dec00,pai  fixed various build errors (SPR #62962).
  25. 01k,12dec00,pai  merged in changes from HIT August Drivers Release.
  26. 01j,12oct99,dat  SPR 28492, fixed templateSend.
  27. 01i,29mar99,dat  documentation, SPR 26119. fixed .bS/.bE usage
  28. 01h,28feb99,pul  changed the prototype for END NET functions, to have END_OBJ
  29.  reference as the first argument rather than device object,
  30.  fix for SPR#24285
  31. 01g,17feb99,dat  documentation, removed beta warning
  32. 01f,29sep98,dat  Fixed problem in PollRx relating to SPR 22325.
  33. 01e,28sep98,dat  SPR 22325, system mode transition, plus fixed warnings
  34.  and template is now compilable (SPR 22204).
  35. 01d,17jul98,db   changed "holder" in templateParse from char** to char *.
  36.  fixed references to "holder" in templateParse(spr #21464).
  37. 01c,15oct97,gnn  revised to reflect the latest API changes.
  38. 01b,05may97,dat  added TODO's for documentation and macros.
  39. 01a,04feb97,gnn  written.
  40. */
  41. /*
  42. DESCRIPTION
  43. TODO - Describe the chip being used completely, even if it provides more
  44. features than ethernet.
  45. TODO - Describe the device's full ethernet capabilities, even if this driver
  46. doesn't or can't utilize all of them.  Describe the features that the driver
  47. does implement and any restrictions on their use.
  48. TODO - Describe all macros that can be used to customize this driver.  All
  49. accesses to chip registers should be done through redefineable macros.
  50. In this example driver the macros TEMPLATE_OUT_SHORT and TEMPLATE_IN_SHORT
  51. are sample macros to read/write data to a mock device.  If a device
  52. communicates through formatted control blocks in shared memory, the
  53. accesses to those control blocks should also be through redefinable
  54. macros.
  55. TODO - The following information describes the procedure an end user would
  56. follow to integrate this new END device into a new BSP.  The procedure 
  57. needs to be well documented.
  58. This driver is easily customized for a BSP by modifying global pointers
  59. to routines.  The routine pointers are declared below.  The code below
  60. indicates the default values for each routine as well.  By modifying
  61. these global pointer values, the BSP can change the behaviour of the driver.
  62. .CS
  63.     IMPORT STATUS (*templateIntConnectRtn) 
  64.             (int level, FUNCTPR pFunc, int arg);
  65.     IMPORT STATUS (*templateIntDisconnectRtn) 
  66.             (int level, FUNCTPR pFunc, int arg);
  67.     IMPORT STATUS (*templateIntEnableRtn) (int level);
  68.     IMPORT STATUS (*templateEnetAddrGetRtn)(int unit, char *pResult);
  69.     IMPORT STATUS (*templateOutShortRtn)(UINT addr, UINT value);
  70.     IMPORT STATUS (*templateInShortRtn)(UINT addr, USHORT *pData);
  71.     
  72.     templateIntConnectRtn = intConnect; /@ must not be NULL @/
  73.     templateIntDisconnectRtn = NULL;
  74.     templateIntEnableRtn = NULL;
  75.     templateEndAddrGetRtn = NULL;
  76.     templateOutShortRtn = NULL;
  77.     templateInShortRtn = NULL;
  78. .CE
  79. Excecpt for templateIntConnectRtn and templateIntEnableRtn, a NULL value
  80. will result in the driver taking a default action.  For the int disconnect
  81. function the default action is to do nothing at all.  For the short in and out
  82. routines, the default is to assume memory mapped device registers and to
  83. access them directly.  The default ethernet address get routine
  84. provides an invalid ethernet address of all zeros (0:0:0:0:0:0).
  85. If the BSP is willing to accept these default values no action at all
  86. is needed.  To change the default value, the BSP should create an appropriate
  87. routine and set the address into the global value before first use.  This
  88. would normally be done at function sysHwInit2() time.
  89. For Tornado 3.0 you need to pay attention to virtual physical address
  90. translations which are important.  Use the cache lib macros to to
  91. proper VIRT_TO_PHYS translation as part of generating the physical DMA
  92. address for the device.  Avoid the use of PHYS_TO_VIRT translation as
  93. it can be very time consuming.  If at all possible, the driver should
  94. cache the virtual address of each data buffer used for DMA.
  95. Prior to VxWorks AE 1.1, the muxLib function muxDevUnload() did a free
  96. of the actual END_OBJ structure that was malloc'd during the driver
  97. load routine.  Starting with VxWorks AE 1.1, this behaviour can be
  98. changed.  If the second argument to END_OBJ_INIT points to the END_OBJ
  99. then muxLib will free it during muxDevUnload.  If not, then muxDevUnload
  100. will not free the allocated space.  Under this situation, it is assumed
  101. that the driver unload routine has free'd the space itself.  This preserves
  102. backward compatibility with older drivers that always specified the second
  103. argument to END_OBJ_INIT() as a pointer to the END_OBJ structure.  This
  104. template has been changed to use the new behaviour instead.
  105. INCLUDES:
  106. end.h endLib.h etherMultiLib.h
  107. SEE ALSO: muxLib, endLib
  108. .I "Writing and Enhanced Network Driver"
  109. */
  110. /* includes */
  111. #include "vxWorks.h"
  112. #include "stdlib.h"
  113. #include "cacheLib.h"
  114. #include "intLib.h"
  115. #include "end.h" /* Common END structures. */
  116. #include "endLib.h"
  117. #include "lstLib.h" /* Needed to maintain protocol list. */
  118. #include "iv.h"
  119. #include "semLib.h"
  120. #include "logLib.h"
  121. #include "netLib.h"
  122. #include "stdio.h"
  123. #include "sysLib.h"
  124. #include "errno.h"
  125. #include "errnoLib.h"
  126. #include "memLib.h"
  127. #include "iosLib.h"
  128. #undef ETHER_MAP_IP_MULTICAST
  129. #include "etherMultiLib.h" /* multicast stuff. */
  130. #include "net/mbuf.h"
  131. #include "net/unixLib.h"
  132. #include "net/protosw.h"
  133. #include "net/systm.h"
  134. #include "net/if_subr.h"
  135. #include "net/route.h"
  136. #include "netinet/if_ether.h"
  137. #include "sys/socket.h"
  138. #include "sys/ioctl.h"
  139. #include "sys/times.h"
  140. IMPORT int endMultiLstCnt (END_OBJ* pEnd);
  141. /* defines */
  142. #define DRV_NAME "template"
  143. #define DRV_NAME_LEN (sizeof(DRV_NAME) + 1)
  144. /* Configuration items */
  145. #define END_BUFSIZ      (ETHERMTU + SIZEOF_ETHERHEADER + 6)
  146. #define EH_SIZE (14)
  147. #define END_SPEED_10M 10000000 /* 10Mbs */
  148. #define END_SPEED_100M 100000000 /* 100Mbs */
  149. #define END_SPEED       END_SPEED_10M
  150. /* Cache macros */
  151. #define END_CACHE_INVALIDATE(address, len) 
  152.         CACHE_DRV_INVALIDATE (pDrvCtrl->pCacheFuncs, (address), (len))
  153. #define END_CACHE_VIRT_TO_PHYS(address) 
  154.         CACHE_DRV_VIRT_TO_PHYS (pDrvCtrl->pCacheFuncs, (address))
  155. /*
  156.  * Default macro definitions for BSP interface.
  157.  * These macros can be redefined in a wrapper file, to generate
  158.  * a new module with an optimized interface.
  159.  */
  160. /* Macro to connect interrupt handler to vector */
  161. #ifndef SYS_INT_CONNECT
  162.     FUNCPTR templateIntConnectRtn = intConnect;
  163. #   define SYS_INT_CONNECT(pDrvCtrl,rtn,arg,pResult) 
  164. do { 
  165. *pResult = (*templateIntConnectRtn) ((VOIDFUNCPTR *) 
  166. INUM_TO_IVEC (pDrvCtrl->ivec), rtn, (int)arg); 
  167. } while (0)
  168. #endif
  169. /* Macro to disconnect interrupt handler from vector */
  170. #ifndef SYS_INT_DISCONNECT
  171.     STATUS (*templateIntDisconnectRtn) 
  172. (int level, FUNCPTR rtn, int arg) = NULL;
  173. #   define SYS_INT_DISCONNECT(pDrvCtrl,rtn,arg,pResult) 
  174. do { 
  175. if (templateIntDisconnectRtn != NULL) 
  176.     *pResult = (*templateIntDisconnectRtn)(pDrvCtrl->ivec, 
  177. rtn, (int)arg); 
  178. else 
  179.     *pResult = ERROR; 
  180. } while (0)
  181. #endif
  182. /* Macro to enable the appropriate interrupt level */
  183. #ifndef SYS_INT_ENABLE
  184.     STATUS (*templateIntEnableRtn)(int level) = NULL;
  185. #   define SYS_INT_ENABLE(pDrvCtrl) 
  186. do { 
  187.     if (templateIntEnableRtn != NULL) 
  188. (*templateIntEnableRtn) (pDrvCtrl->ilevel); 
  189. } while (0)
  190. #endif
  191. /* Macro to get the ethernet address from the BSP */
  192. #ifndef SYS_ENET_ADDR_GET
  193.     STATUS (*templateEnetAddrGetRtn)(int unit, char * pResult) = NULL;
  194. #   define SYS_ENET_ADDR_GET(pDevice) 
  195. do { 
  196. if (templateEnetAddrGetRtn == NULL) 
  197.     bzero ((char *)&pDevice->enetAddr, 6); 
  198. else 
  199.     (*templateEnetAddrGetRtn)(pDevice->unit, 
  200. (char *)&pDevice->enetAddr); 
  201. } while (0)
  202. #endif
  203. /*
  204.  * Macros to do a short (UINT16) access to the chip. Default
  205.  * assumes a normal memory mapped device.
  206.  */
  207. #ifndef TEMPLATE_OUT_SHORT
  208.     STATUS (*templateOutShortRtn)(UINT addr, UINT value) = NULL;
  209. #   define TEMPLATE_OUT_SHORT(pDrvCtrl,addr,value) 
  210. do { 
  211.     if (templateOutShortRtn == NULL) 
  212. (*(USHORT *)addr = value) 
  213.     else 
  214. (*templateOutShortRtn)((UINT)addr, (UINT)value) 
  215. } while (0)
  216. #endif
  217. #ifndef TEMPLATE_IN_SHORT
  218.     STATUS (*templateInShortRtn)(UINT addr, USHORT *pData) = NULL;
  219. #   define TEMPLATE_IN_SHORT(pDrvCtrl,addr,pData) 
  220. do { 
  221.     if (templateInShortRtn == NULL) 
  222. (*pData = *addr) 
  223.     else 
  224. (*templateInShortRtn)((UINT)addr, pData) 
  225. } while (0)
  226. #endif
  227. /* A shortcut for getting the hardware address from the MIB II stuff. */
  228. #define END_HADDR(pEnd)
  229. ((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
  230. #define END_HADDR_LEN(pEnd) 
  231. ((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
  232. /* typedefs */
  233. typedef struct
  234.     {
  235.     int len;
  236.     char * pData; /* data virtual address */
  237.     char * pPhys; /* dma physical address */
  238.     } PKT; /* A dummy DMA data packet */
  239. #define TEMPLATE_PKT_LEN_GET(pPkt) (((PKT *)pPkt)->len)
  240. #define TEMPLATE_PKT_VIRT_GET(pPkt) (((PKT *)pPkt)->pData)
  241. typedef struct rfd
  242.     {
  243.     PKT *  pPkt;
  244.     struct rfd * next;
  245.     } RFD; /* dummy rx frame descriptor */
  246. typedef struct free_args
  247.     {
  248.     void* arg1;
  249.     void* arg2;
  250.     } FREE_ARGS;
  251. /* The definition of the driver control structure */
  252. typedef struct end_device
  253.     {
  254.     END_OBJ     end; /* The class we inherit from. */
  255.     int unit; /* unit number */
  256.     int         ivec; /* interrupt vector */
  257.     int         ilevel; /* interrupt level */
  258.     char*       pShMem; /* real ptr to shared memory */
  259.     long flags; /* Our local flags. */
  260.     UCHAR enetAddr[6]; /* ethernet address */
  261.     CACHE_FUNCS* pCacheFuncs; /* cache function pointers */
  262.     FUNCPTR     freeRtn[128]; /* Array of free routines. */
  263.     struct free_args    freeData[128];  /* Array of free arguments */
  264. /* the free routines. */
  265.     CL_POOL_ID pClPoolId; /* cluster pool */
  266.     BOOL rxHandling; /* rcv task is scheduled */
  267.     } END_DEVICE;
  268. /*
  269.  * This will only work if there is only a single unit, for multiple
  270.  * unit device drivers these should be integrated into the END_DEVICE
  271.  * structure.
  272.  */
  273. M_CL_CONFIG templateMclBlkConfig =  /* network mbuf configuration table */
  274.     {
  275.     /*
  276.     no. mBlks no. clBlks memArea memSize
  277.     ----------- ---------- ------- -------
  278.     */
  279.     0,  0,  NULL,  0
  280.     };
  281. CL_DESC templateClDescTbl [] =  /* network cluster pool configuration table */
  282.     {
  283.     /*
  284.     clusterSize num memArea memSize
  285.     ----------- ---- ------- -------
  286.     */
  287.     {ETHERMTU + EH_SIZE + 2, 0, NULL, 0}
  288.     };
  289. int templateClDescTblNumEnt = (NELEMENTS(templateClDescTbl));
  290. /* Definitions for the flags field */
  291. #define TEMPLATE_PROMISCUOUS 0x1
  292. #define TEMPLATE_POLLING 0x2
  293. /* Status register bits, returned by templateStatusRead() */
  294. #define TEMPLATE_RINT 0x1 /* Rx interrupt pending */
  295. #define TEMPLATE_TINT 0x2 /* Tx interrupt pending */
  296. #define TEMPLATE_RXON 0x4 /* Rx on (enabled) */
  297. #define TEMPLATE_VALID_INT 0x3 /* Any valid interrupt pending */
  298. #define TEMPLATE_MIN_FBUF (1536) /* min first buffer size */
  299. /* DEBUG MACROS */
  300. #ifdef DEBUG
  301. #   define LOGMSG(x,a,b,c,d,e,f) 
  302. if (endDebug) 
  303.     { 
  304.     logMsg (x,a,b,c,d,e,f); 
  305.     }
  306. #else
  307. #   define LOGMSG(x,a,b,c,d,e,f)
  308. #endif /* ENDDEBUG */
  309. #undef DRV_DEBUG
  310. #ifdef DRV_DEBUG
  311. #define DRV_DEBUG_OFF 0x0000
  312. #define DRV_DEBUG_RX 0x0001
  313. #define DRV_DEBUG_TX 0x0002
  314. #define DRV_DEBUG_INT 0x0004
  315. #define DRV_DEBUG_POLL (DRV_DEBUG_POLL_RX | DRV_DEBUG_POLL_TX)
  316. #define DRV_DEBUG_POLL_RX 0x0008
  317. #define DRV_DEBUG_POLL_TX 0x0010
  318. #define DRV_DEBUG_LOAD 0x0020
  319. #define DRV_DEBUG_IOCTL 0x0040
  320. #define DRV_DEBUG_POLL_REDIR 0x10000
  321. #define DRV_DEBUG_LOG_NVRAM 0x20000
  322. int templateDebug = 0x00;
  323. int     templateTxInts=0;
  324. #define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)                        
  325. if (templateDebug & FLG)                                        
  326.             logMsg(X0, X1, X2, X3, X4, X5, X6);
  327. #define DRV_PRINT(FLG,X)                                                
  328. if (templateDebug & FLG) printf X;
  329. #else /*DRV_DEBUG*/
  330. #define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
  331. #define DRV_PRINT(DBG_SW,X)
  332. #endif /*DRV_DEBUG*/
  333. /* LOCALS */
  334. /* forward static functions */
  335. LOCAL void templateReset (END_DEVICE *pDrvCtrl);
  336. LOCAL void templateInt (END_DEVICE *pDrvCtrl);
  337. LOCAL void templateHandleRcvInt (END_DEVICE *pDrvCtrl);
  338. LOCAL STATUS templateRecv (END_DEVICE *pDrvCtrl, PKT* pData);
  339. LOCAL void templateConfig (END_DEVICE *pDrvCtrl);
  340. LOCAL UINT templateStatusRead (END_DEVICE *pDrvCtrl);
  341. /* END Specific interfaces. */
  342. /* This is the only externally visible interface. */
  343. END_OBJ*  templateLoad (char* initString);
  344. LOCAL STATUS templateStart (END_DEVICE* pDrvCtrl);
  345. LOCAL STATUS templateStop (END_DEVICE* pDrvCtrl);
  346. LOCAL int templateIoctl   (END_DEVICE* pDrvCtrl, int cmd, caddr_t data);
  347. LOCAL STATUS templateUnload (END_DEVICE* pDrvCtrl);
  348. LOCAL STATUS templateSend (END_DEVICE* pDrvCtrl, M_BLK_ID pBuf);
  349. LOCAL STATUS templateMCastAdd (END_DEVICE* pDrvCtrl, char* pAddress);
  350. LOCAL STATUS templateMCastDel (END_DEVICE* pDrvCtrl, char* pAddress);
  351. LOCAL STATUS templateMCastGet (END_DEVICE* pDrvCtrl,
  352.     MULTI_TABLE* pTable);
  353. LOCAL STATUS templatePollStart (END_DEVICE* pDrvCtrl);
  354. LOCAL STATUS templatePollStop (END_DEVICE* pDrvCtrl);
  355. LOCAL STATUS templatePollSend (END_DEVICE* pDrvCtrl, M_BLK_ID pBuf);
  356. LOCAL STATUS templatePollRcv (END_DEVICE* pDrvCtrl, M_BLK_ID pBuf);
  357. LOCAL void templateAddrFilterSet(END_DEVICE *pDrvCtrl);
  358. LOCAL STATUS templateParse ();
  359. LOCAL STATUS templateMemInit ();
  360. /*
  361.  * Declare our function table.  This is static across all device
  362.  * instances.
  363.  */
  364. LOCAL NET_FUNCS templateFuncTable =
  365.     {
  366.     (FUNCPTR) templateStart, /* Function to start the device. */
  367.     (FUNCPTR) templateStop, /* Function to stop the device. */
  368.     (FUNCPTR) templateUnload, /* Unloading function for the driver. */
  369.     (FUNCPTR) templateIoctl, /* Ioctl function for the driver. */
  370.     (FUNCPTR) templateSend, /* Send function for the driver. */
  371.     (FUNCPTR) templateMCastAdd, /* Multicast add function for the */
  372. /* driver. */
  373.     (FUNCPTR) templateMCastDel, /* Multicast delete function for */
  374. /* the driver. */
  375.     (FUNCPTR) templateMCastGet, /* Multicast retrieve function for */
  376. /* the driver. */
  377.     (FUNCPTR) templatePollSend, /* Polling send function */
  378.     (FUNCPTR) templatePollRcv, /* Polling receive function */
  379.     endEtherAddressForm, /* put address info into a NET_BUFFER */
  380.     endEtherPacketDataGet,   /* get pointer to data in NET_BUFFER */
  381.     endEtherPacketAddrGet   /* Get packet addresses. */
  382.     };
  383. /*******************************************************************************
  384. *
  385. * templateLoad - initialize the driver and device
  386. *
  387. * This routine initializes the driver and the device to the operational state.
  388. * All of the device specific parameters are passed in the initString.
  389. *
  390. * The string contains the target specific parameters like this:
  391. *
  392. * "register addr:int vector:int level:shmem addr:shmem size:shmem width"
  393. *
  394. * This routine can be called in two modes.  If it is called with an empty but
  395. * allocated string, it places the name of this device into the <initString>
  396. * and returns 0.
  397. *
  398. * If the string is allocated and not empty, the routine attempts to load
  399. * the driver using the values specified in the string.
  400. *
  401. * RETURNS: An END object pointer, or NULL on error, or 0 and the name of the
  402. * device if the <initString> was empty.
  403. */
  404. END_OBJ* templateLoad
  405.     (
  406.     char* initString /* String to be parsed by the driver. */
  407.     )
  408.     {
  409.     END_DEVICE  *pDrvCtrl;
  410.     DRV_LOG (DRV_DEBUG_LOAD, "Loading template...n", 1, 2, 3, 4, 5, 6);
  411.     if (initString == NULL)
  412.         {
  413.         DRV_LOG (DRV_DEBUG_LOAD, "templateLoad: NULL initStrrn",
  414. 0,0,0,0,0,0);
  415.         return NULL;
  416.         }
  417.     
  418.     if (initString[0] == EOS)
  419.         {
  420.         bcopy ((char *)DRV_NAME, initString, DRV_NAME_LEN);
  421.         return NULL;
  422.         }
  423.     /* else initString is not blank, pass two ... */
  424.     /* allocate the device structure */
  425.     pDrvCtrl = (END_DEVICE *)calloc (sizeof (END_DEVICE), 1);
  426.     if (pDrvCtrl == NULL)
  427. goto errorExit;
  428.     /* parse the init string, filling in the device structure */
  429.     if (templateParse (pDrvCtrl, initString) == ERROR)
  430. goto errorExit;
  431.     /* Ask the BSP for the ethernet address. */
  432.     SYS_ENET_ADDR_GET(pDrvCtrl);
  433.     /* initialize the END and MIB2 parts of the structure */
  434.     /*
  435.      * The M2 element must come from m2Lib.h
  436.      * This template is set up for a DIX type ethernet device.
  437.      */
  438.     if (END_OBJ_INIT (&pDrvCtrl->end, NULL, "template",
  439.                       pDrvCtrl->unit, &templateFuncTable,
  440.                       "END Template Driver.") == ERROR
  441.      || END_MIB_INIT (&pDrvCtrl->end, M2_ifType_ethernet_csmacd,
  442.                       &pDrvCtrl->enetAddr[0], 6, END_BUFSIZ,
  443.                       END_SPEED)
  444.     == ERROR)
  445. goto errorExit;
  446.     /* Perform memory allocation/distribution */
  447.     if (templateMemInit (pDrvCtrl) == ERROR)
  448. goto errorExit;
  449.     /* reset and reconfigure the device */
  450.     templateReset (pDrvCtrl);
  451.     templateConfig (pDrvCtrl);
  452.     /* set the flags to indicate readiness */
  453.     END_OBJ_READY (&pDrvCtrl->end,
  454.     IFF_NOTRAILERS | IFF_BROADCAST | IFF_MULTICAST);
  455.     DRV_LOG (DRV_DEBUG_LOAD, "Done loading Template...", 1, 2, 3, 4, 5, 6);
  456.     return (&pDrvCtrl->end);
  457. errorExit:
  458.     if (pDrvCtrl != NULL)
  459. free ((char *)pDrvCtrl);
  460.     return NULL;
  461.     }
  462. /*******************************************************************************
  463. *
  464. * templateParse - parse the init string
  465. *
  466. * Parse the input string.  Fill in values in the driver control structure.
  467. *
  468. * The muxLib.o module automatically prepends the unit number to the user's
  469. * initialization string from the BSP (configNet.h).
  470. *
  471. * .IP <unit>
  472. * Device unit number, a small integer.
  473. * .IP <vecNum>
  474. * Interrupt vector number
  475. * .IP <intLvl>
  476. * Interrupt level
  477. * .LP
  478. *
  479. * RETURNS: OK or ERROR for invalid arguments.
  480. */
  481. LOCAL STATUS templateParse
  482.     (
  483.     END_DEVICE * pDrvCtrl, /* device pointer */
  484.     char * initString /* information string */
  485.     )
  486.     {
  487.     char* tok;
  488.     char* pHolder = NULL;
  489.     /* Parse the initString */
  490.     /* Unit number. (from muxLib.o) */
  491.     tok = strtok_r (initString, ":", &pHolder);
  492.     if (tok == NULL)
  493. return ERROR;
  494.     pDrvCtrl->unit = atoi (tok);
  495.     /* Interrupt vector. */
  496.     tok = strtok_r (NULL, ":", &pHolder);
  497.     if (tok == NULL)
  498. return ERROR;
  499.     pDrvCtrl->ivec = atoi (tok);
  500.     /* Interrupt level. */
  501.     tok = strtok_r (NULL, ":", &pHolder);
  502.     if (tok == NULL)
  503. return ERROR;
  504.     pDrvCtrl->ilevel = atoi (tok);
  505.     DRV_LOG (DRV_DEBUG_LOAD, "Processed all arugmentsn", 1, 2, 3, 4, 5, 6);
  506.     return OK;
  507.     }
  508. /*******************************************************************************
  509. *
  510. * templateMemInit - initialize memory for the chip
  511. *
  512. * This routine is highly specific to the device.
  513. *
  514. * Design choices available:
  515. *
  516. * Use default system buffers, or create device specific buffer pools.
  517. *
  518. * Use contiguous buffers for device frame descriptors and the data, or
  519. * use descriptor buffers separate from the data buffers.
  520. *
  521. * Use the same buffering scheme for Rx and Tx, or each side uses it's
  522. * own buffering scheme.
  523. *
  524. * RETURNS: OK or ERROR.
  525. */
  526. LOCAL STATUS templateMemInit
  527.     (
  528.     END_DEVICE * pDrvCtrl /* device to be initialized */
  529.     )
  530.     {
  531.     int count = 0;
  532.     /* TODO - allocate and initialize any shared memory areas */
  533.     /*
  534.      * This is how we would set up an END netPool using netBufLib(1).
  535.      * This code is pretty generic.
  536.      */
  537.     if ((pDrvCtrl->end.pNetPool = malloc (sizeof(NET_POOL))) == NULL)
  538.         return (ERROR);
  539.     /*
  540.      * Note, Separating the descriptor from the data buffer can be
  541.      * advantageous for architectures that need cached data buffers but
  542.      * don't have snooping units to make the caches fully coherent.
  543.      * It is a disadvantage for architectures that do have snooping, becuase
  544.      * they need to do twice the number of netBufLib operations for each
  545.      * data frame.  This template driver assumes the descriptor and data
  546.      * buffer are contiguous.
  547.      */
  548.     /* number of driver Descriptor/data buffers */
  549.     templateClDescTbl[0].clNum = 16;
  550.     /* Setup mbuf/cluster block pool with more mbufs than clBlks */
  551.     templateMclBlkConfig.clBlkNum = templateClDescTbl[0].clNum;
  552.     templateMclBlkConfig.mBlkNum = templateMclBlkConfig.clBlkNum * 4;
  553.     /* Calculate the total memory for all the M-Blks and CL-Blks. */
  554.     templateMclBlkConfig.memSize = (templateMclBlkConfig.mBlkNum *
  555.     (MSIZE + sizeof (long))) +
  556.       (templateMclBlkConfig.clBlkNum *
  557.     (CL_BLK_SZ + sizeof(long)));
  558.     /* allocate mbuf/Cluster blocks from normal memory */
  559.     if ((templateMclBlkConfig.memArea = (char *) memalign (sizeof(long),
  560.                                                   templateMclBlkConfig.memSize))
  561.         == NULL)
  562.         return (ERROR);
  563.     /* Round cluster size up to a multiple of a cache line */
  564.     templateClDescTbl[0].clSize =
  565. ROUND_UP(templateClDescTbl[0].clSize,_CACHE_ALIGN_SIZE);
  566.     /* Calculate the memory size of all the clusters. */
  567.     templateClDescTbl[0].memSize = (templateClDescTbl[0].clNum
  568.     * templateClDescTbl[0].clSize);
  569.     /* Allocate the memory for the clusters from cache safe memory. */
  570.     templateClDescTbl[0].memArea =
  571.         (char *) cacheDmaMalloc (templateClDescTbl[0].memSize);
  572.     /* cacheDmaMalloc memory is assumed to be cache line aligned ! */
  573.     /* use cacheDmaFuncs for cacheDmaMalloc memory */
  574.     pDrvCtrl->pCacheFuncs = &cacheDmaFuncs;
  575.     if (templateClDescTbl[0].memArea == NULL)
  576.         {
  577.         DRV_LOG (DRV_DEBUG_LOAD, "system memory unavailablen",
  578. 1, 2, 3, 4, 5, 6);
  579.         return (ERROR);
  580.         }
  581.     /* Initialize the memory pool. */
  582.     if (netPoolInit(pDrvCtrl->end.pNetPool, &templateMclBlkConfig,
  583.                     &templateClDescTbl[0], templateClDescTblNumEnt,
  584.     NULL) == ERROR)
  585.         {
  586.         DRV_LOG (DRV_DEBUG_LOAD, "Could not init bufferingn",
  587. 1, 2, 3, 4, 5, 6);
  588.         return (ERROR);
  589.         }
  590.     /*
  591.      * If you need clusters to store received packets into then get them
  592.      * here ahead of time.  This template driver only uses the cluster pool
  593.      * for receiving.  Here it takes all the clusters out of the pool and
  594.      * attaches them to the device.  The device will fill them with incoming
  595.      * packets and trigger an interrupt.  This will schedule the
  596.      * templateHandleRcvInt routine.  It will unlink the cluster and send
  597.      * it to the stack.  When the stack is done with the data, the cluster
  598.      * is freed and returned to the cluster pool to be used by the device
  599.      * again.
  600.      */
  601.     if ((pDrvCtrl->pClPoolId =
  602. netClPoolIdGet (pDrvCtrl->end.pNetPool, sizeof (RFD), FALSE))
  603.         == NULL)
  604.         return (ERROR);
  605.     while (count < templateClDescTbl[0].clNum)
  606.         {
  607. char * pTempBuf;
  608.         if ((pTempBuf = (char *)netClusterGet(pDrvCtrl->end.pNetPool,
  609.                                               pDrvCtrl->pClPoolId))
  610.             == NULL)
  611.             {
  612.             DRV_LOG (DRV_DEBUG_LOAD, "Could not get a buffern",
  613.                      1, 2, 3, 4, 5, 6);
  614.             return (ERROR);
  615.             }
  616.         /* TODO - Store the pointer in some appropriate structure. */
  617.         }
  618.     DRV_LOG (DRV_DEBUG_LOAD, "Memory setup completen", 1, 2, 3, 4, 5, 6);
  619.     return OK;
  620.     }
  621. /*******************************************************************************
  622. *
  623. * templateStart - start the device
  624. *
  625. * This function calls BSP functions to connect interrupts and start the
  626. * device running in interrupt mode.
  627. *
  628. * RETURNS: OK or ERROR
  629. *
  630. */
  631. LOCAL STATUS templateStart
  632.     (
  633.     END_DEVICE * pDrvCtrl /* device ID */
  634.     )
  635.     {
  636.     STATUS result;
  637.     SYS_INT_CONNECT (pDrvCtrl, templateInt, (int)pDrvCtrl, &result);
  638.     if (result == ERROR)
  639. return ERROR;
  640.     DRV_LOG (DRV_DEBUG_LOAD, "Interrupt connected.n", 1, 2, 3, 4, 5, 6);
  641.     SYS_INT_ENABLE (pDrvCtrl);
  642.     DRV_LOG (DRV_DEBUG_LOAD, "interrupt enabled.n", 1, 2, 3, 4, 5, 6);
  643.     END_FLAGS_SET (&pDrvCtrl->end, IFF_UP | IFF_RUNNING);
  644.     /* TODO  - start the device, enabling interrupts */
  645.     return (OK);
  646.     }
  647. /*******************************************************************************
  648. *
  649. * templateInt - handle controller interrupt
  650. *
  651. * This routine is called at interrupt level in response to an interrupt from
  652. * the controller.
  653. *
  654. * RETURNS: N/A.
  655. */
  656. LOCAL void templateInt
  657.     (
  658.     END_DEVICE  *pDrvCtrl /* interrupting device */
  659.     )
  660.     {
  661.     UCHAR stat;
  662.     DRV_LOG (DRV_DEBUG_INT, "Got an interrupt!n", 1, 2, 3, 4, 5, 6);
  663.     /* Read the device status register */
  664.     stat = templateStatusRead (pDrvCtrl);
  665.     /* If false interrupt, return. */
  666.     if (!(stat & TEMPLATE_VALID_INT)) /* test for valid interrupt */
  667. {
  668.         return; /* return immediately, no error message */
  669. }
  670.     /*
  671.      * enable interrupts, clear receive and/or transmit interrupts, and clear
  672.      * any errors that may be set.
  673.      */
  674.     /* TODO - Check for errors */
  675.     /* Have netTask handle any input packets */
  676.     if ((stat & TEMPLATE_RINT) && (stat & TEMPLATE_RXON))
  677.         {
  678.         if (!(pDrvCtrl->rxHandling))
  679.             {
  680.             pDrvCtrl->rxHandling = TRUE;
  681.             netJobAdd ((FUNCPTR)templateHandleRcvInt, (int)pDrvCtrl,
  682.                        0,0,0,0);
  683.             }
  684.         }
  685.     /* TODO - handle transmit interrupts */
  686.     }
  687. /*******************************************************************************
  688. *
  689. * templatePacketGet - get next received message
  690. *
  691. * Get next received message.  Returns NULL if none are
  692. * ready.
  693. *
  694. * RETURNS: ptr to next packet, or NULL if none ready.
  695. */
  696. LOCAL PKT* templatePacketGet
  697.     (
  698.     END_DEVICE  *pDrvCtrl /* device structure */
  699.     )
  700.     {
  701.     /*
  702.      * TODO - get next received packet. Packet address must be a valid
  703.      * virtual address, not a physical address.
  704.      */
  705.     return (PKT *)NULL;
  706.     }
  707. /*******************************************************************************
  708. *
  709. * templateRecv - process the next incoming packet
  710. *
  711. * Handle one incoming packet.  The packet is checked for errors.
  712. *
  713. * RETURNS: N/A.
  714. */
  715. LOCAL STATUS templateRecv
  716.     (
  717.     END_DEVICE *pDrvCtrl, /* device structure */
  718.     PKT* pPkt /* packet to process */
  719.     )
  720.     {
  721.     int         len = 0;
  722.     M_BLK_ID  pMblk;
  723.     char*       pCluster = NULL;
  724.     char*       pNewCluster;
  725.     CL_BLK_ID pClBlk;
  726.     /* Add one to our unicast data. */
  727.     END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1);
  728.     /*
  729.      * We implicitly are loaning here, if copying is necessary this
  730.      * step may be skipped, but the data must be copied before being
  731.      * passed up to the protocols.
  732.      */
  733.     pNewCluster = netClusterGet (pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId);
  734.     if (pNewCluster == NULL)
  735.         {
  736. DRV_LOG (DRV_DEBUG_RX, "Cannot loan!n", 1, 2, 3, 4, 5, 6);
  737. END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1);
  738. goto cleanRXD;
  739.         }
  740.     /* Grab a cluster block to marry to the cluster we received. */
  741.     if ((pClBlk = netClBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT)) == NULL)
  742.         {
  743.         netClFree (pDrvCtrl->end.pNetPool, (UCHAR *)pNewCluster);
  744. DRV_LOG (DRV_DEBUG_RX, "Out of Cluster Blocks!n", 1, 2, 3, 4, 5, 6);
  745. END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1);
  746. goto cleanRXD;
  747.         }
  748.     if ((pMblk = mBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT, MT_DATA)) == NULL)
  749.         {
  750.         netClBlkFree (pDrvCtrl->end.pNetPool, pClBlk);
  751.         netClFree (pDrvCtrl->end.pNetPool, (UCHAR *)pNewCluster);
  752. DRV_LOG (DRV_DEBUG_RX, "Out of M Blocks!n", 1, 2, 3, 4, 5, 6);
  753. END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1);
  754. goto cleanRXD;
  755.         }
  756.     /* Join the cluster to the MBlock */
  757.     netClBlkJoin (pClBlk, pCluster, len, NULL, 0, 0, 0);
  758.     netMblkClJoin (pMblk, pClBlk);
  759.     /* TODO - Invalidate any RFD dma buffers */
  760.     /* TODO - Packet must be checked for errors. */
  761.     END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1);
  762.     len = TEMPLATE_PKT_LEN_GET (pPkt);
  763.     pCluster = TEMPLATE_PKT_VIRT_GET (pPkt);
  764.     pMblk->mBlkHdr.mLen = len;
  765.     pMblk->mBlkHdr.mFlags |= M_PKTHDR;
  766.     pMblk->mBlkPktHdr.len = len;
  767.     /* make the packet data coherent */
  768.     END_CACHE_INVALIDATE (pMblk->mBlkHdr.mData, len);
  769.     DRV_LOG (DRV_DEBUG_RX, "Calling upper layer!n", 1, 2, 3, 4, 5, 6);
  770.     /* TODO - Done with processing, clean up and pass it up. */
  771.     /* Call the upper layer's receive routine. */
  772.     END_RCV_RTN_CALL(&pDrvCtrl->end, pMblk);
  773. cleanRXD:
  774.     return (OK);
  775.     }
  776. /*******************************************************************************
  777. *
  778. * templateHandleRcvInt - task level interrupt service for input packets
  779. *
  780. * This routine is called at task level indirectly by the interrupt
  781. * service routine to do any message received processing.
  782. *
  783. * The double loop is to protect against a race condition where the interrupt
  784. * code see rxHandling as TRUE, but it is then turned off by task code.
  785. * This race is not fatal, but does cause occassional delays until a second
  786. * packet is received and then triggers the netTask to call this routine again.
  787. *
  788. * RETURNS: N/A.
  789. */
  790. LOCAL void templateHandleRcvInt
  791.     (
  792.     END_DEVICE *pDrvCtrl /* interrupting device */
  793.     )
  794.     {
  795.     PKT* pPkt;
  796.     do
  797.         {
  798.         pDrvCtrl->rxHandling = TRUE;
  799.         while ((pPkt = templatePacketGet (pDrvCtrl)) != NULL)
  800.             templateRecv (pDrvCtrl, pPkt);
  801.         pDrvCtrl->rxHandling = FALSE;
  802.         }
  803.     while (templatePacketGet (pDrvCtrl) != NULL);
  804.     }
  805. /*******************************************************************************
  806. *
  807. * templateSend - the driver send routine
  808. *
  809. * This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
  810. * The buffer must already have the addressing information properly installed
  811. * in it.  This is done by a higher layer.  The last arguments are a free
  812. * routine to be called when the device is done with the buffer and a pointer
  813. * to the argument to pass to the free routine.
  814. *
  815. * RETURNS: OK, ERROR, or END_ERR_BLOCK.
  816. */
  817. LOCAL STATUS templateSend
  818.     (
  819.     END_DEVICE * pDrvCtrl, /* device ptr */
  820.     M_BLK_ID     pMblk /* data to send */
  821.     )
  822.     {
  823.     int         oldLevel = 0;
  824.     BOOL        freeNow = TRUE;
  825.     /*
  826.      * Obtain exclusive access to transmitter.  This is necessary because
  827.      * we might have more than one stack transmitting at once.
  828.      */
  829.     if (!(pDrvCtrl->flags & TEMPLATE_POLLING))
  830. END_TX_SEM_TAKE (&pDrvCtrl->end, WAIT_FOREVER);
  831.     /* TODO - Flush the data buffer(s), if it might be cached */
  832.     /* TODO - If necessary, get a Tx Frame Descriptor (TFD) */
  833.     /*
  834.      * TODO - If resources are not available,
  835.      * release the semaphore and return END_ERR_BLOCK.
  836.      * Do not free packet
  837.      */
  838.     /* TODO - Translate buffer virtual address to a remove bus physical addr */
  839.     /* place a transmit request */
  840.     if (!(pDrvCtrl->flags & TEMPLATE_POLLING))
  841.         oldLevel = intLock (); /* protect templateInt */
  842.     /* TODO - initiate device transmit, FLUSH TFD */
  843.     /* Advance our management index(es) */
  844.     if (!(pDrvCtrl->flags & TEMPLATE_POLLING))
  845. END_TX_SEM_GIVE (&pDrvCtrl->end);
  846.     if (!(pDrvCtrl->flags & TEMPLATE_POLLING))
  847.         intUnlock (oldLevel);
  848.     /* Bump the statistics counters. */
  849.     END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1);
  850.     /*
  851.      * Cleanup.  If the driver copied the data from the mblks to a different
  852.      * buffer, then free the mblks now.  Otherwise, free the mblk chain
  853.      * after the device is finished with the TFD.
  854.      */
  855.     if (freeNow)
  856.         netMblkClChainFree (pMblk);
  857.     return (OK);
  858.     }
  859. /*******************************************************************************
  860. *
  861. * templateIoctl - the driver I/O control routine
  862. *
  863. * Process an ioctl request.
  864. *
  865. * RETURNS: A command specific response, usually OK or ERROR.
  866. */
  867. LOCAL int templateIoctl
  868.     (
  869.     END_DEVICE * pDrvCtrl, /* device receiving command */
  870.     int cmd, /* ioctl command code */
  871.     caddr_t data /* command argument */
  872.     )
  873.     {
  874.     int error = 0;
  875.     long value;
  876.     switch ((unsigned)cmd)
  877.         {
  878.         case EIOCSADDR: /* set MAC address */
  879.     if (data == NULL)
  880. return (EINVAL);
  881.             bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->end),
  882.    END_HADDR_LEN(&pDrvCtrl->end));
  883.             break;
  884.         case EIOCGADDR: /* get MAC address */
  885.     if (data == NULL)
  886. return (EINVAL);
  887.             bcopy ((char *)END_HADDR(&pDrvCtrl->end), (char *)data,
  888.     END_HADDR_LEN(&pDrvCtrl->end));
  889.             break;
  890.         case EIOCSFLAGS: /* set (or clear) flags */
  891.     value = (long)data;
  892.     if (value < 0)
  893. {
  894. value = -value;
  895. value--;
  896. END_FLAGS_CLR (&pDrvCtrl->end, value);
  897. }
  898.     else
  899. {
  900. END_FLAGS_SET (&pDrvCtrl->end, value);
  901. }
  902.     templateConfig (pDrvCtrl);
  903.             break;
  904.         case EIOCGFLAGS: /* get flags */
  905.     *(int *)data = END_FLAGS_GET(&pDrvCtrl->end);
  906.             break;
  907. case EIOCPOLLSTART: /* Begin polled operation */
  908.     templatePollStart (pDrvCtrl);
  909.     break;
  910. case EIOCPOLLSTOP: /* End polled operation */
  911.     templatePollStop (pDrvCtrl);
  912.     break;
  913.         case EIOCGMIB2233:
  914.         case EIOCGMIB2: /* return MIB information */
  915.             if (data == NULL)
  916.                 return (EINVAL);
  917.             bcopy((char *)&pDrvCtrl->end.mib2Tbl, (char *)data,
  918.                   sizeof(pDrvCtrl->end.mib2Tbl));
  919.             break;
  920.         case EIOCGFBUF: /* return minimum First Buffer for chaining */
  921.             if (data == NULL)
  922.                 return (EINVAL);
  923.             *(int *)data = TEMPLATE_MIN_FBUF;
  924.             break;
  925.         case EIOCGHDRLEN:
  926.             if (data == NULL)
  927.                 return (EINVAL);
  928.             *(int *)data = EH_SIZE;
  929.             break;
  930.         default: /* unknown request */
  931.             error = EINVAL;
  932.         }
  933.     return (error);
  934.     }
  935. /******************************************************************************
  936. *
  937. * templateConfig - reconfigure the interface under us.
  938. *
  939. * Reconfigure the interface setting promiscuous mode, and changing the
  940. * multicast interface list.
  941. *
  942. * RETURNS: N/A.
  943. */
  944. LOCAL void templateConfig
  945.     (
  946.     END_DEVICE *pDrvCtrl /* device to be re-configured */
  947.     )
  948.     {
  949.     /* Set promiscuous mode if it's asked for. */
  950.     if (END_FLAGS_GET(&pDrvCtrl->end) & IFF_PROMISC)
  951. {
  952. DRV_LOG (DRV_DEBUG_IOCTL, "Setting promiscuous mode on!n",
  953. 1, 2, 3, 4, 5, 6);
  954. }
  955.     else
  956. {
  957. DRV_LOG (DRV_DEBUG_IOCTL, "Setting promiscuous mode off!n",
  958. 1, 2, 3, 4, 5, 6);
  959. }
  960.     /* Set up address filter for multicasting. */
  961.     if (END_MULTI_LST_CNT(&pDrvCtrl->end) > 0)
  962. {
  963. templateAddrFilterSet (pDrvCtrl);
  964. }
  965.     /* TODO - shutdown device completely */
  966.     /* TODO - reset all device counters/pointers, etc. */
  967.     /* TODO - initialise the hardware according to flags */
  968.     return;
  969.     }
  970. /******************************************************************************
  971. *
  972. * templateAddrFilterSet - set the address filter for multicast addresses
  973. *
  974. * This routine goes through all of the multicast addresses on the list
  975. * of addresses (added with the endAddrAdd() routine) and sets the
  976. * device's filter correctly.
  977. *
  978. * RETURNS: N/A.
  979. */
  980. LOCAL void templateAddrFilterSet
  981.     (
  982.     END_DEVICE *pDrvCtrl /* device to be updated */
  983.     )
  984.     {
  985.     ETHER_MULTI* pCurr;
  986.     pCurr = END_MULTI_LST_FIRST (&pDrvCtrl->end);
  987.     while (pCurr != NULL)
  988. {
  989.         /* TODO - set up the multicast list */
  990. pCurr = END_MULTI_LST_NEXT(pCurr);
  991. }
  992.     /* TODO - update the device filter list */
  993.     }
  994. /*******************************************************************************
  995. *
  996. * templatePollRcv - routine to receive a packet in polled mode.
  997. *
  998. * Polled mode operation takes place without any kernel or other OS
  999. * services available.  Use extreme care to insure that this code does not
  1000. * call any kernel services.  Polled mode is only for WDB system mode use.
  1001. * Kernel services, semaphores, tasks, etc, are not available during WDB
  1002. * system mode.
  1003. *
  1004. * The WDB agent polls the device constantly looking for new data.  Typically
  1005. * the device has a ring of RFDs to receive incoming packets.  This routine
  1006. * examines the ring for any new data and copies it to the provided mblk.
  1007. * The concern here is to keep the device supplied with empty buffers at all
  1008. * time.
  1009. *
  1010. * RETURNS: OK upon success.  EAGAIN is returned when no packet is available.
  1011. * A return of ERROR indicates a hardware fault or no support for polled mode
  1012. * at all.
  1013. */
  1014. LOCAL STATUS templatePollRcv
  1015.     (
  1016.     END_DEVICE * pDrvCtrl, /* device to be polled */
  1017.     M_BLK_ID      pMblk /* ptr to buffer */
  1018.     )
  1019.     {
  1020.     u_short stat;
  1021.     char* pPacket;
  1022.     int len = 0;
  1023.     /* TODO - If no packet is available return immediately */
  1024.     stat = templateStatusRead (pDrvCtrl);
  1025.     if (!(stat & TEMPLATE_RINT))
  1026. {
  1027.         return (EAGAIN);
  1028. }
  1029.     /* Upper layer must provide a valid buffer. */
  1030.     if ((pMblk->mBlkHdr.mLen < len) || (!(pMblk->mBlkHdr.mFlags & M_EXT)))
  1031. {
  1032. return (EAGAIN);
  1033. }
  1034.     /* TODO - Invalidate any inbound RFD DMA buffers */
  1035.     /* TODO - clear any status bits that may be set. */
  1036.     /* TODO - Check packet and device for errors */
  1037.     /* Get packet and  length from device buffer/descriptor */
  1038.     pPacket = NULL; /* DUMMY CODE */
  1039.     len = 64; /* DUMMY CODE */
  1040.     /* TODO - Invalidate any inbound data DMA buffers */
  1041.     /* TODO - Process device packet into net buffer */
  1042.     bcopy (pPacket, pMblk->m_data, len);
  1043.     pMblk->mBlkHdr.mFlags |= M_PKTHDR; /* set the packet header */
  1044.     pMblk->mBlkHdr.mLen = len; /* set the data len */
  1045.     pMblk->mBlkPktHdr.len = len; /* set the total len */
  1046.     /*
  1047.      * TODO - Done with this packet, clean up device. If needed
  1048.      * setup a new RFD/buffer for incoming packets
  1049.      */
  1050.     return (OK);
  1051.     }
  1052. /*******************************************************************************
  1053. *
  1054. * templatePollSend - routine to send a packet in polled mode.
  1055. *
  1056. * Polled mode operation takes place without any kernel or other OS
  1057. * services available.  Use extreme care to insure that this code does not
  1058. * call any kernel services.  Polled mode is only for WDB system mode use.
  1059. * Kernel services, semaphores, tasks, etc, are not available during WDB
  1060. * system mode.
  1061. *
  1062. * A typical implementation is to set aside a fixed buffer for polled send
  1063. * operation.  Copy the mblk data to the buffer and pass the fixed buffer
  1064. * to the device.  Performance is not a consideration for polled operations.
  1065. *
  1066. * An alternate implementation is a synchronous one.  The routine accepts
  1067. * user data but does not return until the data has actually been sent.  If an
  1068. * error occurs, the routine returns EAGAIN and the user will retry the request.
  1069. *
  1070. * If the device returns OK, then the data has been sent and the user may free
  1071. * the associated mblk.  The driver never frees the mblk in polled mode.
  1072. * The calling routine will free the mblk upon success.
  1073. *
  1074. * RETURNS: OK upon success.  EAGAIN if device is busy or no resources.
  1075. * A return of ERROR indicates a hardware fault or no support for polled mode
  1076. * at all.
  1077. */
  1078. LOCAL STATUS templatePollSend
  1079.     (
  1080.     END_DEVICE*  pDrvCtrl, /* device to be polled */
  1081.     M_BLK_ID    pMblk /* packet to send */
  1082.     )
  1083.     {
  1084.     int         len;
  1085.     u_short stat;
  1086.     static char txBuff [END_BUFSIZ];
  1087.     /* TODO - test to see if tx is busy */
  1088.     stat = templateStatusRead (pDrvCtrl); /* dummy code */
  1089.     if ((stat & TEMPLATE_TINT) == 0)
  1090. return ((STATUS) EAGAIN);
  1091.     /* TODO - Copy data from mblk */
  1092.     len = netMblkToBufCopy (pMblk, &txBuff[0], NULL);
  1093.     len = max (ETHERSMALL, len);
  1094.     /* TODO - If necessary get a TFD */
  1095.     /* TODO - Setup the TFD, with bus physical addresses, Flush it */
  1096.     /* TODO - Handoff TFD/data to device */
  1097.     return (OK);
  1098.     }
  1099. /*****************************************************************************
  1100. *
  1101. * templateMCastAdd - add a multicast address for the device
  1102. *
  1103. * This routine adds a multicast address to whatever the driver
  1104. * is already listening for.  It then resets the address filter.
  1105. *
  1106. * RETURNS: OK or ERROR.
  1107. */
  1108. LOCAL STATUS templateMCastAdd
  1109.     (
  1110.     END_DEVICE *pDrvCtrl, /* device pointer */
  1111.     char* pAddress /* new address to add */
  1112.     )
  1113.     {
  1114.     int error;
  1115.     if ((error = etherMultiAdd (&pDrvCtrl->end.multiList,
  1116. pAddress)) == ENETRESET)
  1117. templateConfig (pDrvCtrl);
  1118.     return (OK);
  1119.     }
  1120. /*****************************************************************************
  1121. *
  1122. * templateMCastDel - delete a multicast address for the device
  1123. *
  1124. * This routine removes a multicast address from whatever the driver
  1125. * is listening for.  It then resets the address filter.
  1126. *
  1127. * RETURNS: OK or ERROR.
  1128. */
  1129. LOCAL STATUS templateMCastDel
  1130.     (
  1131.     END_DEVICE *pDrvCtrl, /* device pointer */
  1132.     char* pAddress /* address to be deleted */
  1133.     )
  1134.     {
  1135.     int error;
  1136.     if ((error = etherMultiDel (&pDrvCtrl->end.multiList,
  1137.      (char *)pAddress)) == ENETRESET)
  1138. templateConfig (pDrvCtrl);
  1139.     return (OK);
  1140.     }
  1141. /*****************************************************************************
  1142. *
  1143. * templateMCastGet - get the multicast address list for the device
  1144. *
  1145. * This routine gets the multicast list of whatever the driver
  1146. * is already listening for.
  1147. *
  1148. * RETURNS: OK or ERROR.
  1149. */
  1150. LOCAL STATUS templateMCastGet
  1151.     (
  1152.     END_DEVICE *pDrvCtrl, /* device pointer */
  1153.     MULTI_TABLE* pTable /* address table to be filled in */
  1154.     )
  1155.     {
  1156.     return (etherMultiGet (&pDrvCtrl->end.multiList, pTable));
  1157.     }
  1158. /*******************************************************************************
  1159. *
  1160. * templateStop - stop the device
  1161. *
  1162. * This function calls BSP functions to disconnect interrupts and stop
  1163. * the device from operating in interrupt mode.
  1164. *
  1165. * RETURNS: OK or ERROR.
  1166. */
  1167. LOCAL STATUS templateStop
  1168.     (
  1169.     END_DEVICE *pDrvCtrl /* device to be stopped */
  1170.     )
  1171.     {
  1172.     STATUS result = OK;
  1173.     END_FLAGS_CLR (&pDrvCtrl->end, IFF_UP | IFF_RUNNING);
  1174.     /* TODO - stop/disable the device. */
  1175.     SYS_INT_DISCONNECT (pDrvCtrl, (FUNCPTR)templateInt, (int)pDrvCtrl, &result);
  1176.     if (result == ERROR)
  1177. {
  1178. DRV_LOG (DRV_DEBUG_LOAD, "Could not disconnect interrupt!n",
  1179. 1, 2, 3, 4, 5, 6);
  1180. }
  1181.     return (result);
  1182.     }
  1183. /******************************************************************************
  1184. *
  1185. * templateUnload - unload a driver from the system
  1186. *
  1187. * This function first brings down the device, and then frees any
  1188. * stuff that was allocated by the driver in the load function.
  1189. *
  1190. * RETURNS: OK or ERROR.
  1191. */
  1192. LOCAL STATUS templateUnload
  1193.     (
  1194.     END_DEVICE* pDrvCtrl /* device to be unloaded */
  1195.     )
  1196.     {
  1197.     END_OBJECT_UNLOAD (&pDrvCtrl->end);
  1198.     /* TODO - Free any special allocated memory */
  1199.     /* New: free the END_OBJ structure allocated during templateLoad() */
  1200.     cfree ((char *)pDrvCtrl);
  1201.     return (OK);
  1202.     }
  1203. /*******************************************************************************
  1204. *
  1205. * templatePollStart - start polled mode operations
  1206. *
  1207. * RETURNS: OK or ERROR.
  1208. */
  1209. LOCAL STATUS templatePollStart
  1210.     (
  1211.     END_DEVICE * pDrvCtrl /* device to be polled */
  1212.     )
  1213.     {
  1214.     int         oldLevel;
  1215.     oldLevel = intLock ();          /* disable ints during update */
  1216.     /* TODO - turn off interrupts */
  1217.     pDrvCtrl->flags |= TEMPLATE_POLLING;
  1218.     intUnlock (oldLevel);   /* now templateInt won't get confused */
  1219.     DRV_LOG (DRV_DEBUG_POLL, "STARTEDn", 1, 2, 3, 4, 5, 6);
  1220.     templateConfig (pDrvCtrl); /* reconfigure device */
  1221.     return (OK);
  1222.     }
  1223. /*******************************************************************************
  1224. *
  1225. * templatePollStop - stop polled mode operations
  1226. *
  1227. * This function terminates polled mode operation.  The device returns to
  1228. * interrupt mode.
  1229. *
  1230. * The device interrupts are enabled, the current mode flag is switched
  1231. * to indicate interrupt mode and the device is then reconfigured for
  1232. * interrupt operation.
  1233. *
  1234. * RETURNS: OK or ERROR.
  1235. */
  1236. LOCAL STATUS templatePollStop
  1237.     (
  1238.     END_DEVICE * pDrvCtrl /* device to be polled */
  1239.     )
  1240.     {
  1241.     int         oldLevel;
  1242.     oldLevel = intLock (); /* disable ints during register updates */
  1243.     /* TODO - re-enable interrupts */
  1244.     pDrvCtrl->flags &= ~TEMPLATE_POLLING;
  1245.     intUnlock (oldLevel);
  1246.     templateConfig (pDrvCtrl);
  1247.     DRV_LOG (DRV_DEBUG_POLL, "STOPPEDn", 1, 2, 3, 4, 5, 6);
  1248.     return (OK);
  1249.     }
  1250. /*******************************************************************************
  1251. *
  1252. * templateReset - reset device
  1253. *
  1254. * RETURNS: N/A.
  1255. */
  1256. LOCAL void templateReset
  1257.     (
  1258.     END_DEVICE *pDrvCtrl
  1259.     )
  1260.     {
  1261.     /* TODO - reset the controller */
  1262.     }
  1263. /*******************************************************************************
  1264. *
  1265. * templateStatusRead - get current device state/status
  1266. *
  1267. * RETURNS: status bits.
  1268. */
  1269. LOCAL UINT templateStatusRead
  1270.     (
  1271.     END_DEVICE *pDrvCtrl
  1272.     )
  1273.     {
  1274.     /* TODO - read and return status bits/register */
  1275.     return (0);
  1276.     }