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

VxWorks

开发平台:

C/C++

  1. /* elt3c509End.c - END  network interface driver  for 3COM 3C509*/
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01j,17jun02,dmh  increased delay loop in elt3c509EepromRead SPR# 78830
  8. 01i,28aug00,stv  corrected the handling of EIOCSFLAGS ioctl (SPR# 29423).
  9. 01h,02aug00,jkf  Added statistics definitions to this file, SPR#26952.
  10. 01g,11jun00,ham  removed reference to etherLib.
  11. 01f,27jan00,dat  fixed use of NULL, removed warnings
  12. 01e,01dec99,stv  freed mBlk chain before returning ERROR (SPR #28492).
  13. 01d,29mar99,dat  SPR 26119, documentation, usage of .bS/.bE
  14. 01c,10mar99,sbs  added checking for non-zero value of nRxFrames.
  15. 01b,06dec98,ms_  remove comment about "assumptions stated below", which we
  16.                  think
  17. is leftover from the template lance driver.
  18. 01a,28sep98,snk  written by mBedded Innovations Inc.
  19. */
  20. /*
  21. DESCRIPTION
  22. This module implements the 3COM 3C509 EtherLink III Ethernet network 
  23. interface driver.
  24. This driver is designed to be moderately generic.  Thus, it operates 
  25. unmodified across the range of architectures and targets supported by 
  26. VxWorks.  To achieve this, the driver load routine requires an input 
  27. string consisting of several target-specific values.  The driver also 
  28. requires some external support routines.  These target-specific values 
  29. and the external support routines are described below.  
  30. BOARD LAYOUT
  31. This device is on-board.  No jumpering diagram is necessary.
  32. EXTERNAL INTERFACE
  33. The only external interface is the elt3c509Load() routine, which expects
  34. the <initString> parameter as input.  This parameter passes in a 
  35. colon-delimited string of the format:
  36. <unit>:<port>:<intVector>:<intLevel>:<attachementType>:<nRxFrames>
  37. The elt3c509Load() function uses strtok() to parse the string.
  38. TARGET-SPECIFIC PARAMETERS
  39. .IP <unit>
  40. A convenient holdover from the former model.  This parameter is used only
  41. in the string name for the driver.
  42. .IP <intVector>
  43. Configures the ELT device to generate hardware interrupts
  44. for various events within the device. Thus, it contains
  45. an interrupt handler routine.  The driver calls intConnect() to connect
  46. its interrupt handler to the interrupt vector generated as a result of
  47. the ELT interrupt.
  48. .IP <intLevel>
  49. This parameter is passed to an external support routine, sysEltIntEnable(),
  50. which is described below in "External Support Requirements." This routine 
  51. is called during as part of driver's initialization.  It handles any 
  52. board-specific operations required to allow the servicing of a ELT 
  53. interrupt on targets that use additional interrupt controller devices to 
  54. help organize and service the various interrupt sources.  This parameter 
  55. makes it possible for this driver to avoid all board-specific knowledge of 
  56. such devices.  
  57. .IP <attachmentType>
  58. This parameter is used to select the transceiver hardware attachment. 
  59. This is then used by the elt3c509BoardInit() routine to activate the 
  60. selected attachment. elt3c509BoardInit() is called as a part of the driver's
  61. initialization.
  62. .IP <nRxFrames>
  63. This parameter is used as number of receive frames by the driver.
  64. EXTERNAL SUPPORT REQUIREMENTS
  65. This driver requires several external support functions, defined as macros:
  66. .CS
  67.     SYS_INT_CONNECT(pDrvCtrl, routine, arg)
  68.     SYS_INT_DISCONNECT (pDrvCtrl, routine, arg)
  69.     SYS_INT_ENABLE(pDrvCtrl)
  70.     SYS_INT_DISABLE(pDrvCtrl)
  71.     SYS_OUT_BYTE(pDrvCtrl, reg, data)
  72.     SYS_IN_BYTE(pDrvCtrl, reg, data)
  73.     SYS_OUT_WORD(pDrvCtrl, reg, data)
  74.     SYS_IN_WORD(pDrvCtrl, reg, data)
  75.     SYS_OUT_WORD_STRING(pDrvCtrl, reg, pData, len)
  76.     SYS_IN_WORD_STRING(pDrvCtrl, reg, pData, len)
  77.     
  78.     sysEltIntEnable(pDrvCtrl->intLevel) 
  79.     sysEltIntDisable(pDrvCtrl->intLevel) 
  80. .CE
  81. There are default values in the source code for these macros.  They presume
  82. IO-mapped accesses to the device registers and the normal intConnect(),
  83. and intEnable() BSP functions.  The first argument to each is the device
  84. controller structure. Thus, each has access back to all the device-specific
  85. information.  Having the pointer in the macro facilitates the addition 
  86. of new features to this driver.
  87. The macros SYS_INT_CONNECT, SYS_INT_DISCONNECT, and SYS_INT_ENABLE allow
  88. the driver to be customized for BSPs that use special versions of these
  89. routines.
  90. The macro SYS_INT_CONNECT is used to connect the interrupt handler to
  91. the appropriate vector.  By default it is the routine intConnect().
  92. The macro SYS_INT_DISCONNECT is used to disconnect the interrupt handler prior
  93. to unloading the module.  By default this is a dummy routine that
  94. returns OK.
  95. The macro SYS_INT_ENABLE is used to enable the interrupt level for the
  96. end device.  It is called once during initialization.  It calls an
  97. external board level routine sysEltIntEnable(). 
  98. The macro SYS_INT_DISABLE is used to disable the interrupt level for the
  99. end device.  It is called during stop.  It calls an
  100. external board level routine sysEltIntDisable(). 
  101. SYSTEM RESOURCE USAGE
  102. When implemented, this driver requires the following system resources:
  103.     - one interrupt vector
  104.     - 9720 bytes of text
  105.     - 88 bytes in the initialized data section (data)
  106.     - 0 bytes of bss
  107. The driver requires 1520 bytes of preallocation for Transmit Buffer and 
  108. 1520*nRxFrames of receive buffers. The default value of nRxFrames is 64
  109. therefore total pre-allocation is (64 + 1)*1520.
  110. TUNING HINTS
  111. nRxFrames parameter can be used for tuning no of receive frames to be used
  112. for handling packet receive. More no. of these could help receiving more 
  113. loaning in case of massive reception.
  114. INTERNAL
  115. This driver is END compliant. It supports Multicasting and Poll mode Send and
  116. Receive capabilities. The initialization calls elt3c509BoardInit(), which 
  117. initializes the ELT3C509 chip, and elt3c509MemInit() routine which initializes
  118. memory allocation for Tx and Rx functionality. One mblk chain is allocated for 
  119. storing Tx frame and nRxFrame(64) mblk chainss are allocated for Rx frames.
  120. When a receive interrupt is received, netJobAdd() is called to schedule
  121. elt3c509HandlePktsRcv() routine for handling reception of the packets. This 
  122. routine empties the FIFO in a mblk chain and loops for more packets.
  123. The cluster is then passed up to the Receive routine of the upper layer.
  124. To transmit a packet, contents of mblk are copied into the TxFrame which is
  125. used to fill the FIFO of the chip. Transmit complete interrupt is used to 
  126. check for status of the transmission.
  127. When Polling mode is enabled, both for Tx and Rx together, elt3c509PollRcv()
  128. routine gets the packet out of the FIFO, copies into the mblk. For Tx in 
  129. Poll mode, elt3c509PollSend(0 routine is called by the upper layer, the data
  130. is copied into the TxFrame from the mblk and sent out. The interrupt is 
  131. disabled for transmit complete.
  132. Multicast addresses are handled by setting/resetting the RX_F_MULTICAST bit
  133. in the chip. When an address is added, the bit is set. When an address is 
  134. removed and the address list is empty, the bit is reset.
  135. INCLUDES:
  136. end.h endLib.h etherMultiLib.h elt3c509End.h
  137. SEE ALSO: muxLib, endLib
  138. .I "Writing an Enhanced Network Driver"
  139. */
  140. /* includes */
  141. #include "vxWorks.h"
  142. #include "wdLib.h"
  143. #include "stdlib.h"
  144. #include "taskLib.h"
  145. #include "logLib.h"
  146. #include "intLib.h"
  147. #include "netLib.h"
  148. #include "stdio.h"
  149. #include "stdlib.h"
  150. #include "sysLib.h"
  151. #include "iv.h"
  152. #include "memLib.h"
  153. #include "semLib.h"
  154. #include "cacheLib.h"
  155. #include "sys/ioctl.h"
  156. #include "etherMultiLib.h" /* multicast stuff. */
  157. #include "end.h" /* Common END structures. */
  158. #include "endLib.h"
  159. #include "lstLib.h" /* Needed to maintain protocol list. */
  160. #include "netBufLib.h"
  161. #include "muxLib.h"
  162. #include "m2Lib.h"
  163. #include "drv/end/elt3c509End.h"
  164. /* statistic macro's */
  165. #define collisions      elt3c509Stats[0]
  166. #define crcs            elt3c509Stats[1]
  167. #define aligns          elt3c509Stats[2]
  168. #define rxnobuffers     elt3c509Stats[3]
  169. #define rxoverruns      elt3c509Stats[4]
  170. #define disabled        elt3c509Stats[5]
  171. #define deferring       elt3c509Stats[6]
  172. #define txunderruns     elt3c509Stats[7]
  173. #define aborts          elt3c509Stats[8]
  174. #define outofwindow     elt3c509Stats[9]
  175. #define heartbeats      elt3c509Stats[10]
  176. #define badPacket       elt3c509Stats[11]
  177. #define shortPacket     elt3c509Stats[12]
  178. #define txnoerror       elt3c509Stats[13]
  179. #define rxnoerror       elt3c509Stats[14]
  180. #define txerror         elt3c509Stats[15]
  181. #define rxerror         elt3c509Stats[16]
  182. #define overwrite       elt3c509Stats[17]
  183. #define wrapped         elt3c509Stats[18]
  184. #define interrupts      elt3c509Stats[19]
  185. #define elt3c509_reset  elt3c509Stats[20]
  186. #define strayint        elt3c509Stats[21]
  187. #define multcollisions  elt3c509Stats[22]
  188. #define latecollisions  elt3c509Stats[23]
  189. #define nocarriers      elt3c509Stats[24]
  190. #define jabbers         elt3c509Stats[25]
  191. #define txoverruns      elt3c509Stats[26]
  192. #define rxunderruns     elt3c509Stats[27]
  193. #define rxearly         elt3c509Stats[28]
  194. #ifdef ELT_TIMING       
  195. #define timerUpdates    elt3c509Stats[29]
  196. #define timerOverflow   elt3c509Stats[30]
  197. #define timerInvalid    elt3c509Stats[31]
  198. #define maxRxLatency    elt3c509Stats[32]
  199. #define minRxLatency    elt3c509Stats[33]
  200. #define maxIntLatency   elt3c509Stats[34]
  201. #define taskQRxOuts     elt3c509Stats[35]
  202. #define maxRxTaskQ      elt3c509Stats[36]  
  203. #define taskQTxOuts     elt3c509Stats[37]  
  204. #define maxTxTaskQ      elt3c509Stats[38]  
  205. #endif /* ELT_TIMING */ 
  206. /* Cache macros */
  207. #define ELT3C509_CACHE_INVALIDATE(address, len) 
  208.         CACHE_DRV_INVALIDATE (&pDrvCtrl->cacheFuncs, (address), (len))
  209. #define ELT3C509_CACHE_PHYS_TO_VIRT(address) 
  210.         CACHE_DRV_PHYS_TO_VIRT (&pDrvCtrl->cacheFuncs, (address))
  211. #define ELT3C509_CACHE_VIRT_TO_PHYS(address) 
  212.         CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, (address))
  213. /*
  214.  * Default macro definitions for BSP interface.
  215.  * These macros can be redefined in a wrapper file, to generate
  216.  * a new module with an optimized interface.
  217.  */
  218. /* Macro to connect interrupt handler to vector */
  219. #ifndef SYS_INT_CONNECT
  220. #   define SYS_INT_CONNECT(pDrvCtrl,rtn,arg,pResult) 
  221. *pResult = intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (pDrvCtrl->ivec), 
  222.      rtn, (int)arg); 
  223. }
  224. #endif
  225. /* Macro to disconnect interrupt handler from vector */
  226. #ifndef SYS_INT_DISCONNECT
  227. #   define SYS_INT_DISCONNECT(pDrvCtrl,rtn,arg,pResult) 
  228. *pResult = OK;  
  229. }
  230. #endif
  231. /* Macro to enable the appropriate interrupt level */
  232. #ifndef SYS_INT_ENABLE
  233. #   define SYS_INT_ENABLE(pDrvCtrl) 
  234. IMPORT void sysEltIntEnable(); 
  235. sysEltIntEnable (pDrvCtrl->intLevel); 
  236. }
  237. #endif
  238. /* Macro to disable the appropriate interrupt level */
  239. #ifndef SYS_INT_DISABLE
  240. #   define SYS_INT_DISABLE(pDrvCtrl) 
  241. IMPORT void sysEltIntDisable (); 
  242. sysEltIntDisable (pDrvCtrl->intLevel); 
  243. }
  244. #endif
  245. /*
  246.  * Macros to do a byte access to the chip. Uses
  247.  * sysOutByte() and sysInByte().
  248.  */
  249. #ifndef SYS_OUT_BYTE
  250. #   define SYS_OUT_BYTE(pDrvCtrl,addr,value) 
  251.         sysOutByte((addr), (value)); 
  252. }
  253. #endif
  254. #ifndef SYS_IN_BYTE
  255. #   define SYS_IN_BYTE(pDrvCtrl,addr,data) 
  256.         { 
  257.         (data) = sysInByte((addr)); 
  258.         }
  259. #endif 
  260. /*
  261.  * Macros to do a word access to the chip. Uses
  262.  * sysOutWord() and sysInWord().
  263.  */
  264. #ifndef SYS_OUT_WORD
  265. #   define SYS_OUT_WORD(pDrvCtrl,addr,value) 
  266.         sysOutWord((addr), (value)); 
  267. }
  268. #endif
  269. #ifndef SYS_IN_WORD
  270. #   define SYS_IN_WORD(pDrvCtrl,addr,data) 
  271.         { 
  272.         (data) = sysInWord((addr)); 
  273.         }
  274. #endif 
  275. #ifndef SYS_IN_WORD_STRING
  276. #define SYS_IN_WORD_STRING(pDrvCtrl, reg, pData, len) 
  277.         sysInWordString ((reg), (pData),(len)); 
  278. }
  279. #endif
  280. #ifndef SYS_OUT_WORD_STRING
  281. #define SYS_OUT_WORD_STRING(pDrvCtrl, reg, pData, len) 
  282.         sysOutWordString ((reg),(pData), (len)); 
  283. }
  284. #endif
  285. /* A shortcut for getting the hardware address from the MIB II stuff. */
  286. #define END_HADDR(pEnd)
  287. ((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
  288. #define END_HADDR_LEN(pEnd) 
  289. ((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
  290. #define VOID_TO_DRVCTRL(pVoid,pDrvCtrl) ((pDrvCtrl)=(ELT3C509_DEVICE *)(pVoid))
  291. /* externs */
  292. IMPORT int endMultiLstCnt (END_OBJ *);
  293. M_CL_CONFIG elt3c509MclConfig =  /* network mbuf configuration table */
  294.     {
  295.     /* 
  296.     no. mBlks no. clBlks memArea memSize
  297.     ----------- ---------- ------- -------
  298.     */
  299.     0,  0,  NULL,  0
  300.     };
  301. CL_DESC elt3c509ClDescTbl [] =  /* network cluster pool configuration table */
  302.     {
  303.     /* 
  304.     clusterSize num memArea memSize
  305.     ----------- ---- ------- -------
  306.     */
  307.     {ELT3C509_BUFSIZ, 0, NULL, 0}
  308.     }; 
  309. int elt3c509ClDescTblNumEnt = (NELEMENTS(elt3c509ClDescTbl));
  310. /* DEBUG MACROS */
  311. #undef DRV_DEBUG
  312. #ifdef DRV_DEBUG
  313. int  elt3c509Debug = 0x0f;  /* Turn it off initially. */
  314. NET_POOL * pEltPool;
  315. #define ENDLOGMSG(x) 
  316. if (elt3c509Debug) 
  317.     { 
  318.     logMsg x; 
  319.     }
  320. #else
  321. #define ENDLOGMSG(x)
  322. #endif /* DRV_DEBUG */
  323. /* forward static functions */
  324.       STATUS elt3c509Parse (ELT3C509_DEVICE *, char *);
  325. LOCAL STATUS elt3c509Start (void * pEnd);
  326. LOCAL STATUS elt3c509Stop (void * pEnd);
  327. LOCAL STATUS elt3c509Unload (void * pEnd);
  328. LOCAL int elt3c509Ioctl (void * pEnd, int cmd, caddr_t data);
  329. LOCAL STATUS elt3c509Send (void * pEnd, M_BLK_ID pBuf);
  330. LOCAL STATUS elt3c509MCastAdd (void * pEnd, char * pAddress);
  331. LOCAL STATUS elt3c509MCastDel (void * pEnd, char * pAddress);
  332. LOCAL STATUS elt3c509MCastGet (void * pEnd, MULTI_TABLE * pTable);
  333. LOCAL STATUS elt3c509PollSend (void * pEnd, M_BLK_ID pBuf);
  334. LOCAL STATUS elt3c509PollRcv (void * pEnd, M_BLK_ID pBuf);
  335. LOCAL void elt3c509Reset (ELT3C509_DEVICE * pDrvCtrl);
  336. LOCAL void elt3c509Int (ELT3C509_DEVICE * pDrvCtrl);
  337. LOCAL void elt3c509HandlePktsRcv (ELT3C509_DEVICE * pDrvCtrl);
  338. LOCAL STATUS    elt3c509BoardInit (ELT3C509_DEVICE * pDrvCtrl);
  339. LOCAL void elt3c509Config (ELT3C509_DEVICE * pDrvCtrl);
  340. LOCAL STATUS elt3c509PollStart (ELT3C509_DEVICE * pDrvCtrl);
  341. LOCAL STATUS elt3c509PollStop (ELT3C509_DEVICE * pDrvCtrl);
  342. LOCAL STATUS elt3c509MemInit (ELT3C509_DEVICE * pDrvCtrl);
  343. LOCAL void elt3c509IntDisable (ELT3C509_DEVICE * pDrvCtrl);
  344. LOCAL void elt3c509IntEnable (ELT3C509_DEVICE * pDrvCtrl);
  345. LOCAL void elt3c509RxStart (ELT3C509_DEVICE * pDrvCtrl);
  346. LOCAL void elt3c509TxStart (ELT3C509_DEVICE * pDrvCtrl);
  347. LOCAL STATUS elt3c509Activate (ELT3C509_DEVICE * pDrvCtrl);
  348. LOCAL void elt3c509IdCommand (int idPort);
  349. LOCAL UINT16 elt3c509IdEepromRead (int address);
  350. LOCAL int elt3c509EepromRead (int port, int offset);
  351. LOCAL void  elt3c509IntMaskSet (ELT3C509_DEVICE * pDrvCtrl, int maskBits);
  352. LOCAL void  elt3c509StatFlush (ELT3C509_DEVICE * pDrvCtrl);
  353. /* LOCALS */
  354. /*
  355.  * Declare our function table.  This is static across all driver
  356.  * instances.
  357.  */
  358. LOCAL NET_FUNCS elt3c509FuncTable =
  359.     {
  360.     (FUNCPTR)elt3c509Start,     /* Function to start the device. */
  361.     (FUNCPTR)elt3c509Stop, /* Function to stop the device. */
  362.     (FUNCPTR)elt3c509Unload, /* Unloading function for the driver. */
  363.     (FUNCPTR)elt3c509Ioctl, /* Ioctl function for the driver. */
  364.     (FUNCPTR)elt3c509Send, /* Send function for the driver. */
  365.     (FUNCPTR)elt3c509MCastAdd, /* Multicast address add function for the */
  366. /* driver. */
  367.     (FUNCPTR)elt3c509MCastDel, /* Multicast address delete function for */
  368. /* the driver. */
  369.     (FUNCPTR)elt3c509MCastGet, /* Multicast table retrieve function for */
  370. /* the driver. */
  371.     (FUNCPTR)elt3c509PollSend, /* Polling send function for the driver. */
  372.     (FUNCPTR)elt3c509PollRcv, /* Polling receive function for the driver. */
  373.     endEtherAddressForm,        /* Put address info into a packet.  */
  374.     endEtherPacketDataGet,      /* Get a pointer to packet data. */
  375.     endEtherPacketAddrGet       /* Get packet addresses. */
  376.     };
  377. /*******************************************************************************
  378. *
  379. * elt3c509Load - initialize the driver and device
  380. *
  381. * This routine initializes the driver and the device to the operational state.
  382. * All of the device-specific parameters are passed in <initString>, which
  383. * expects a string of the following format:
  384. *
  385. * <unit>:<port>:<intVector>:<intLevel>:<attachementType>:<noRxFrames>
  386. *
  387. * This routine can be called in two modes. If it is called with an empty but
  388. * allocated string, it places the name of this device (that is, "elt") into 
  389. * the <initString> and returns 0.
  390. *
  391. * If the string is allocated and not empty, the routine attempts to load
  392. * the driver using the values specified in the string.
  393. *
  394. * RETURNS: An END object pointer, or NULL on error, or 0 and the name of the
  395. * device if the <initString> was NULL.
  396. */
  397. END_OBJ * elt3c509Load
  398.     (
  399.     char * initString /* String to be parsed by the driver. */
  400.     )
  401.     {
  402.     ELT3C509_DEVICE *  pDrvCtrl;
  403.     int    productID;
  404.     short *  pAddr;
  405.     ENDLOGMSG (("Loading elt3c...n", 1, 2, 3, 4, 5, 6));
  406.     if (initString == NULL)
  407.         return (NULL);
  408.     
  409.     if (initString [0] == 0)
  410.         {
  411.         bcopy ((char *)ELT3C509_DEV_NAME, initString, ELT3C509_DEV_NAME_LEN);
  412.         return (0);
  413.         }
  414.     /* allocate the device structure */
  415.     pDrvCtrl = (ELT3C509_DEVICE *)calloc (sizeof (ELT3C509_DEVICE), 1);
  416.     if (pDrvCtrl == NULL)
  417. goto errorExit;
  418.     /* parse the init string, filling in the device structure */
  419.     if (elt3c509Parse (pDrvCtrl, initString) == ERROR)
  420. goto errorExit;
  421.     /* initialize the END and MIB2 parts of the structure */
  422.     /*
  423.      * The M2 element must come from m2Lib.h 
  424.      * 
  425.      */
  426.     
  427.     if (END_OBJ_INIT (&pDrvCtrl->endObj, (DEV_OBJ *)pDrvCtrl,
  428.                       ELT3C509_DEV_NAME,
  429.                       pDrvCtrl->unit, &elt3c509FuncTable,
  430.                       "3COM 3c509 EtherLink III Endhanced Network Driver.")
  431.         == ERROR)
  432.         goto errorExit;
  433.     productID = elt3c509EepromRead (pDrvCtrl->port, EE_A_PRODUCT_ID);
  434.     if (productID == ELT_PRODUCTID_3C589)
  435. {
  436.         pAddr = (short *)pDrvCtrl->enetAddr;
  437. *pAddr++ = htons (elt3c509EepromRead
  438.                           (pDrvCtrl->port, EE_A_OEM_NODE_0));
  439. *pAddr++ = htons (elt3c509EepromRead
  440.                           (pDrvCtrl->port, EE_A_OEM_NODE_1));
  441. *pAddr++ = htons (elt3c509EepromRead
  442.                       (pDrvCtrl->port, EE_A_OEM_NODE_2));
  443. SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  444.                     SELECT_WINDOW | WIN_CONFIG);
  445. SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ADDRESS_CONFIG,
  446.                     elt3c509EepromRead (pDrvCtrl->port, EE_A_ADDRESS));
  447. SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + RESOURCE_CONFIG,
  448.                     elt3c509EepromRead (pDrvCtrl->port,EE_A_RESOURCE));
  449. }
  450.     else
  451.         {
  452.         if (elt3c509Activate (pDrvCtrl) != OK)
  453.             return (NULL);
  454.         }
  455.     if (END_MIB_INIT (&pDrvCtrl->endObj, M2_ifType_ethernet_csmacd,
  456.                       &pDrvCtrl->enetAddr[0], 6, ETHERMTU, ELT3C509_SPEED)
  457.          == ERROR)
  458. goto errorExit;
  459.      
  460.     /* Initialize the Board here */
  461.     
  462.     if (elt3c509BoardInit (pDrvCtrl) == ERROR)
  463. goto errorExit;
  464.     /* Perform memory allocation/distribution */
  465.     if (elt3c509MemInit (pDrvCtrl) == ERROR)
  466. goto errorExit;
  467.     
  468.     /* set the flags to indicate readiness */
  469.     END_OBJ_READY (&pDrvCtrl->endObj, IFF_NOTRAILERS | IFF_BROADCAST
  470.                    | IFF_MULTICAST | IFF_UP | IFF_RUNNING);
  471.     
  472.     pDrvCtrl->rxFilter = RX_F_NORMAL;
  473.     /* configure the device */
  474.     elt3c509Config (pDrvCtrl);
  475.     ENDLOGMSG (("Done loading end...", 1, 2, 3, 4, 5, 6));
  476.     return (&pDrvCtrl->endObj);
  477. errorExit:
  478.     if (pDrvCtrl != NULL)
  479. free ((char *)pDrvCtrl);
  480.     return NULL;
  481.     }
  482. /*******************************************************************************
  483. *
  484. * elt3c509Parse - parse the init string
  485. *
  486. * Parse the input string.  Fill in values in the driver control structure.
  487. *
  488. * The initialization string format is:
  489. * .CS
  490. *     <unit>:<port>:<intVector>:<intLevel>:<attachementType>:<noRxFrames>
  491. * .CE
  492. * .IP <unit>
  493. * Device unit number, a small integer.
  494. * .IP <port>
  495. * base I/O address
  496. * .IP <intVector>
  497. * Interrupt vector number (used with sysIntConnect)
  498. * .IP <intLevel>
  499. * Interrupt level
  500. * .IP <attachmentType>
  501. * type of Ethernet connector
  502. * .IP <nRxFrames>
  503. * no. of Rx Frames in integer format
  504. * .LP
  505. *
  506. * RETURNS: OK or ERROR for invalid arguments.
  507. */
  508. STATUS elt3c509Parse
  509.     (
  510.     ELT3C509_DEVICE *  pDrvCtrl, /* device pointer */
  511.     char *  initString /* initialization info string */
  512.     )
  513.     {
  514.     char * tok;
  515.     char * holder = NULL;
  516.     
  517.     /* unit number. */
  518.     tok = strtok_r (initString, ":", &holder);
  519.     if (tok == NULL)
  520. return ERROR;
  521.     pDrvCtrl->unit = atoi (tok);
  522.     /* port number */
  523.     tok = strtok_r (NULL, ":", &holder);
  524.     if (tok == NULL)
  525. return ERROR;
  526.     pDrvCtrl->port = strtoul (tok, NULL, 16);
  527.     
  528.     /* interrupt vector. */
  529.     tok = strtok_r (NULL, ":", &holder);
  530.     if (tok == NULL)
  531. return ERROR;
  532.     pDrvCtrl->ivec = strtoul (tok, NULL, 16);
  533.     /* interrupt level. */
  534.     tok = strtok_r (NULL, ":", &holder);
  535.     if (tok == NULL)
  536. return ERROR;
  537.     pDrvCtrl->intLevel = strtoul (tok, NULL, 16);
  538.     /* attachment Type */
  539.     tok = strtok_r (NULL, ":", &holder);
  540.     if (tok == NULL)
  541. return ERROR;
  542.     pDrvCtrl->attachment = atoi (tok);
  543.     /* no. of Rx Frames */
  544.     tok = strtok_r (NULL, ":", &holder);
  545.     if (tok == NULL)
  546.         return ERROR;
  547.     pDrvCtrl->nRxFrames = atoi (tok);
  548.     
  549.     ENDLOGMSG (("Processed all arugmentsn", 1, 2, 3, 4, 5, 6));
  550.     return OK;
  551.     }
  552. /*******************************************************************************
  553. *
  554. * elt3c509BoardInit - Initialise the device
  555. *
  556. * This function prepares the board for operation
  557. *
  558. * RETURNS: OK or ERROR
  559. *
  560. */
  561. LOCAL STATUS elt3c509BoardInit
  562.     (
  563.     ELT3C509_DEVICE * pDrvCtrl /* device to be initialized */
  564.     )
  565.     {
  566.     int  port;
  567.     int  index;
  568.     UINT16  transceiver;
  569.     UINT16  mediaStatus;
  570.     port = pDrvCtrl->port;
  571.     END_FLAGS_CLR (&pDrvCtrl->endObj, IFF_UP | IFF_RUNNING);
  572.     elt3c509IntDisable (pDrvCtrl);   /* make it OK to change register window */
  573.     SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND,
  574.                   (SELECT_WINDOW | WIN_ADDRESS));
  575.     for (index = 0; index < EA_SIZE; index++)
  576.         SYS_OUT_BYTE (pDrvCtrl, port + index, pDrvCtrl->enetAddr [index]);
  577.     /* Select the transceiver hardware (attachment) then do whatever is
  578.      * necessary to activate the selected attachment.
  579.      * A truly complete implementation would probably check to see
  580.      * if the selected attachment were present.
  581.      */
  582.     SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND,
  583.                   (SELECT_WINDOW | WIN_CONFIG));
  584.     SYS_IN_WORD (pDrvCtrl, port + ADDRESS_CONFIG, transceiver);
  585.     if (pDrvCtrl->attachment == ATTACHMENT_DEFAULT)
  586.         {
  587.         switch (transceiver & AC_XCVR_MASK)
  588.             {
  589.             case AC_XCVR_TPE:
  590.                 pDrvCtrl->attachment = ATTACHMENT_RJ45;
  591.                 break;
  592.             case AC_XCVR_BNC:
  593.                 pDrvCtrl->attachment = ATTACHMENT_BNC;
  594.                 break;
  595.             case AC_XCVR_AUI:
  596.                 pDrvCtrl->attachment = ATTACHMENT_AUI;
  597.                 break;
  598.             default:    /* there's only one other value; it's "reserved" */
  599.                 pDrvCtrl->attachment = ATTACHMENT_AUI;  /* good enough */
  600.                 break;
  601.             }
  602.         }
  603.     /* Now set the selected attachment type, even if it was already selected */
  604.     transceiver &= ~AC_XCVR_MASK;
  605.     switch (pDrvCtrl->attachment)
  606.         {
  607.         case ATTACHMENT_RJ45:
  608.             SYS_OUT_WORD (pDrvCtrl, port + ADDRESS_CONFIG,
  609.                           (transceiver | AC_XCVR_TPE));
  610.             SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND,
  611.                           (SELECT_WINDOW | WIN_DIAGNOSTIC));
  612.             SYS_IN_BYTE (pDrvCtrl, port + MEDIA_STATUS, mediaStatus);
  613.             SYS_OUT_BYTE (pDrvCtrl, port + MEDIA_STATUS,
  614.                           mediaStatus |
  615.                           MT_S_JABBER_ENABLE |
  616.                           MT_S_LINK_BEAT_ENABLE);
  617.             break;
  618.         case ATTACHMENT_BNC:
  619.             SYS_OUT_WORD (pDrvCtrl, port + ADDRESS_CONFIG,
  620.                           transceiver | AC_XCVR_BNC);
  621.             SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, START_COAX);
  622.             break;
  623.             
  624.         case ATTACHMENT_AUI:
  625.         default:
  626.             SYS_OUT_WORD (pDrvCtrl, port + ADDRESS_CONFIG,
  627.                           transceiver | AC_XCVR_AUI);
  628.             break;
  629.         }
  630.     /*
  631.      * Define the set of status bits that could cause interrupts.
  632.      * There is no interrupt cause indicator separate from the board status.
  633.      * To keep the ISR from seeing status conditions we didn't want to be
  634.      * interrrupted for, we must mask the STATUS off, not the interrupt.
  635.      * This prevents the condition from interrupting and also prevents
  636.      * the ISR from seeing the condition even if it is true.
  637.      * The interrupt mask is set only once to the set of all conditions
  638.      * we might want to be interrupted by; the status mask is set and
  639.      * cleared according to which conditions we want at any particular
  640.      * time.  The intMask field in the control structure
  641.      * is named for its effect; it is really used in the status mask
  642.      * command (3Com calls it the read zero mask).
  643.      */
  644.     /* enable the status bits we currently want to cause interrupts */
  645.     elt3c509IntMaskSet (pDrvCtrl, ADAPTER_FAILURE | TX_COMPLETE |
  646.                         RX_COMPLETE | RX_EARLY | UPDATE_STATS);
  647.     /* enable the collection of statistics */
  648.     SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, STATS_ENABLE);
  649.     /* enable the hardware to generate interrupt requests */
  650.     SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND,
  651.                   SELECT_WINDOW | WIN_CONFIG);
  652.     SYS_OUT_WORD (pDrvCtrl, port + CONFIG_CONTROL, CC_ENABLE);
  653.     SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND,
  654.                   SELECT_WINDOW | WIN_OPERATING);
  655.     elt3c509IntEnable (pDrvCtrl);
  656.     elt3c509RxStart (pDrvCtrl);
  657.     elt3c509TxStart (pDrvCtrl);
  658.     return (OK);
  659.     }
  660. /*******************************************************************************
  661. *
  662. * elt3c509MemInit - initialize memory for the chip
  663. *
  664. * This routine is highly specific to the device.  
  665. *
  666. * RETURNS: OK or ERROR.
  667. */
  668. LOCAL STATUS elt3c509MemInit
  669.     (
  670.     ELT3C509_DEVICE *  pDrvCtrl /* device to be initialized */
  671.     )
  672.     {
  673.     if ((pDrvCtrl->endObj.pNetPool = malloc (sizeof(NET_POOL))) == NULL)
  674.         return (ERROR);
  675. #ifdef DRV_DEBUG    
  676.     pEltPool = pDrvCtrl->endObj.pNetPool;
  677. #endif    
  678.     /* check if the value of nRxFrames is valid */
  679.     pDrvCtrl->nRxFrames = pDrvCtrl->nRxFrames ? 
  680.                           pDrvCtrl->nRxFrames : DEF_NUM_RX_FRAMES; 
  681.     /* assign static cluster config/desc structures to unit specific structures
  682.      * This is done to enable multiple units to operate.
  683.      */
  684.     pDrvCtrl->endClDesc = elt3c509ClDescTbl [0];
  685.     pDrvCtrl->endClConfig = elt3c509MclConfig;
  686.     
  687.     pDrvCtrl->endClDesc.clNum = pDrvCtrl->nRxFrames  + 1;
  688.     pDrvCtrl->endClConfig.mBlkNum  = (2 * pDrvCtrl->endClDesc.clNum);
  689.     pDrvCtrl->endClConfig.clBlkNum = pDrvCtrl->endClDesc.clNum;
  690.     /* Calculate the total memory for all the M-Blks and CL-Blks. */
  691.     pDrvCtrl->endClConfig.memSize = (pDrvCtrl->endClConfig.mBlkNum *
  692.                                      (MSIZE + sizeof (long))) +
  693.                              (pDrvCtrl->endClConfig.clBlkNum *
  694.                                      (CL_BLK_SZ + sizeof(long)));
  695.     if ((pDrvCtrl->endClConfig.memArea =
  696.          (char *) memalign (sizeof(long), pDrvCtrl->endClConfig.memSize))
  697.         == NULL)
  698.         {
  699.         return (ERROR);
  700.         }
  701.     
  702.     /* Calculate the memory size of all the clusters. */
  703.     pDrvCtrl->endClDesc.memSize = ((pDrvCtrl->endClDesc.clNum *
  704.                                     (ELT3C509_BUFSIZ + 8)) +
  705.                                    sizeof(int));
  706.     /* Allocate the memory for the clusters from cache safe memory. */
  707.     pDrvCtrl->endClDesc.memArea =
  708.         (char *) memalign (sizeof(long), pDrvCtrl->endClDesc.memSize);
  709.     if (pDrvCtrl->endClDesc.memArea == NULL)
  710.         {
  711.         ENDLOGMSG(("system memory unavailablen", 1,2,3,4,5,6));
  712.         return (ERROR);
  713.         }
  714.     pDrvCtrl->cacheFuncs = cacheNullFuncs;
  715.     /* Initialize the memory pool. */
  716.     if (netPoolInit (pDrvCtrl->endObj.pNetPool, &pDrvCtrl->endClConfig,
  717.                      &pDrvCtrl->endClDesc, elt3c509ClDescTblNumEnt, NULL)
  718.         == ERROR)
  719.         {
  720.         ENDLOGMSG (("Could not init bufferingn",1,2,3,4,5,6));
  721.         return (ERROR);
  722.         }
  723.     /* Get Cluster POOL ID here */
  724.     pDrvCtrl->pClPoolId = clPoolIdGet (pDrvCtrl->endObj.pNetPool,
  725.                                        ELT3C509_BUFSIZ, FALSE);
  726.     /* allocate one cluster for the transmit frame */
  727.     pDrvCtrl->pTxCluster = (char *)netClusterGet (pDrvCtrl->endObj.pNetPool,
  728.                                                   pDrvCtrl->pClPoolId);
  729.     ENDLOGMSG (("Memory setup completen",1,2,3,4,5,6));
  730.     return OK;
  731.     }
  732. /*******************************************************************************
  733. *
  734. * elt3c509Start - start the device
  735. *
  736. * This function calls BSP functions to connect interrupts and start the
  737. * device running in interrupt mode.
  738. *
  739. * RETURNS: OK or ERROR
  740. *
  741. */
  742. LOCAL STATUS elt3c509Start
  743.     (
  744.     void * pEnd /* device to be started */
  745.     )
  746.     {
  747.     STATUS  result;
  748.     ELT3C509_DEVICE *  pDrvCtrl;
  749.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  750.     
  751.     SYS_INT_CONNECT (pDrvCtrl, elt3c509Int, (int)pDrvCtrl, &result);
  752.     if (result == ERROR)
  753. return ERROR;
  754.     ENDLOGMSG (("Interrupt connected.n", 1, 2, 3, 4, 5, 6));
  755.     SYS_INT_ENABLE (pDrvCtrl);
  756.     ENDLOGMSG (("interrupt enabled.n", 1, 2, 3, 4, 5, 6));
  757.     return (OK);
  758.     }
  759. /*******************************************************************************
  760. *
  761. * elt3c509Stop - stop the device
  762. *
  763. * This function calls BSP functions to disconnect interrupts and stop
  764. * the device from operating in interrupt mode.
  765. *
  766. * RETURNS: OK or ERROR.
  767. */
  768. LOCAL STATUS elt3c509Stop
  769.     (
  770.     void * pEnd /* device to be stopped */
  771.     )
  772.     {
  773.     STATUS  result = OK;
  774.     ELT3C509_DEVICE *  pDrvCtrl;
  775.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  776.     elt3c509Reset(pDrvCtrl);
  777.     SYS_INT_DISCONNECT (pDrvCtrl, elt3c509Int, (int)pDrvCtrl, &result);
  778.     if (result == ERROR)
  779. {
  780. ENDLOGMSG (("Could not diconnect interrupt!n", 1, 2, 3, 4, 5, 6));
  781. }
  782.     SYS_INT_DISABLE (pDrvCtrl);
  783.     END_FLAGS_CLR (&pDrvCtrl->endObj, IFF_UP | IFF_RUNNING);
  784.     return (result);
  785.     }
  786. /******************************************************************************
  787. *
  788. * elt3c509Unload - unload a driver from the system
  789. *
  790. * This function first brings down the device, and then frees any
  791. * stuff that was allocated by the driver in the load function.
  792. *
  793. * RETURNS: OK or ERROR.
  794. */
  795. LOCAL STATUS elt3c509Unload
  796.     (
  797.     void * pEnd /* device to be unloaded */
  798.     )
  799.     {
  800.     ELT3C509_DEVICE * pDrvCtrl;
  801.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  802.     
  803.     END_OBJECT_UNLOAD (&pDrvCtrl->endObj);
  804.     if (pDrvCtrl->endClDesc.memArea != NULL)
  805.         free (pDrvCtrl->endClDesc.memArea);
  806.     if (pDrvCtrl->endClConfig.memArea != NULL)
  807.         free ( pDrvCtrl->endClConfig.memArea);
  808.     
  809.     if (pDrvCtrl->endObj.pNetPool != NULL)
  810.         free (pDrvCtrl->endObj.pNetPool);
  811.     
  812.     return (OK);
  813.     }
  814. /*******************************************************************************
  815. *
  816. * elt3c509Ioctl - the driver I/O control routine
  817. *
  818. * Process an ioctl request.
  819. *
  820. * RETURNS: A command specific response, OK or ERROR or EINVAL.
  821. */
  822. LOCAL int elt3c509Ioctl
  823.     (
  824.     void *  pEnd,           /* device  ptr*/
  825.     int  cmd, /* ioctl command code */
  826.     caddr_t  data /* command argument */
  827.     )
  828.     {
  829.     int  error = 0;
  830.     long  value;
  831.     ELT3C509_DEVICE *  pDrvCtrl;
  832.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  833.     switch (cmd)
  834.         {
  835.         case EIOCSADDR:
  836.     if (data == NULL)
  837. return (EINVAL);
  838.             bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->endObj),
  839.    END_HADDR_LEN(&pDrvCtrl->endObj));
  840.             break;
  841.         case EIOCGADDR:
  842.     if (data == NULL)
  843. return (EINVAL);
  844.             bcopy ((char *)END_HADDR(&pDrvCtrl->endObj), (char *)data,
  845.     END_HADDR_LEN(&pDrvCtrl->endObj));
  846.             break;
  847.         case EIOCSFLAGS:
  848.     value = (long)data;
  849.     if (value < 0)
  850. {
  851. value = -value;
  852. value--;
  853. END_FLAGS_CLR (&pDrvCtrl->endObj, value);
  854. }
  855.     else
  856. {
  857. END_FLAGS_SET (&pDrvCtrl->endObj, value);
  858. }
  859.     elt3c509Config (pDrvCtrl);
  860.             break;
  861.         case EIOCGFLAGS:
  862.     *(int *)data = END_FLAGS_GET(&pDrvCtrl->endObj);
  863.             break;
  864. case EIOCPOLLSTART:
  865.     error = elt3c509PollStart(pDrvCtrl);
  866.     break;
  867.  
  868. case EIOCPOLLSTOP:
  869.     error = elt3c509PollStop(pDrvCtrl);
  870.       break;
  871.         case EIOCGMIB2:
  872.             if (data == NULL)
  873.                 return (EINVAL);
  874.             bcopy((char *)&pDrvCtrl->endObj.mib2Tbl, (char *)data,
  875.                   sizeof(pDrvCtrl->endObj.mib2Tbl));
  876.             break;
  877.         case EIOCGFBUF:
  878.             return (EINVAL); /* no scatter gather supported for the chip */
  879.             break;
  880.         case EIOCGMWIDTH:
  881.             if (data == NULL)
  882.                 return (EINVAL);
  883.             break;
  884.         case EIOCGHDRLEN:
  885.             if (data == NULL)
  886.                 return (EINVAL);
  887.             *(int *)data = EH_SIZE;
  888.             break;
  889.         default:
  890.             error = EINVAL;
  891.         }
  892.     return (error);
  893.     }
  894. /*******************************************************************************
  895. *
  896. * elt3c509Send - the driver send routine
  897. *
  898. * This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
  899. * The buffer must already have the addressing information properly installed
  900. * in it.  This is done by a higher layer.
  901. *
  902. * RETURNS: OK or END_ERR_BLOCK or ERROR.
  903. */
  904. LOCAL STATUS elt3c509Send
  905.     (
  906.     void  *  pEnd, /* device ptr */
  907.     M_BLK_ID  pMblk /* data to send */
  908.     )
  909.     {
  910.     int len;
  911.     int * pLenMask;
  912.     char * pBuf;
  913.     int intLevel;
  914.     ELT3C509_DEVICE *  pDrvCtrl;
  915.     UINT16 tempData;
  916.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  917.     /* change this drv flag set */
  918.     if (pDrvCtrl->flags & ELT3C_POLLING)
  919.         { 
  920.         netMblkClChainFree (pMblk); /* free the given mBlk chain */
  921.         errno = EINVAL;
  922.         return (ERROR);
  923.         }
  924.         
  925.     /* check if transmitter ready */
  926.     SYS_IN_WORD (pDrvCtrl, pDrvCtrl->port + TX_FREE_BYTES, tempData);
  927.     if (tempData >= TX_IDLE_COUNT)
  928.         {
  929.         pBuf = pDrvCtrl->pTxCluster;  /* pointer to the transmit cluster */
  930.         pLenMask = (UINT32 *)pBuf;
  931.         
  932.         /* allow space for the preamble the trasmit buffer is 1520 */
  933.         pBuf += sizeof(UINT32);
  934.         len = netMblkToBufCopy (pMblk, pBuf, NULL);
  935.         /* free the mblk chain */
  936.         
  937.         netMblkClChainFree (pMblk);
  938.         len = max(len, ETHERSMALL); /* set the packet size */
  939.         *pLenMask = len | TX_F_INTERRUPT; /* set the preamble */
  940.         len = (len + TX_F_PREAMBLE_SIZE + 3) & TX_F_DWORD_MASK;
  941.         /* place a transmit request */
  942.         SYS_OUT_WORD_STRING (pDrvCtrl, pDrvCtrl->port + DATA_REGISTER, 
  943.                              (short *)pLenMask, len / 2);
  944.         }
  945.     else
  946.         {
  947.         intLevel = intLock();
  948. pDrvCtrl->txBlocked = TRUE;
  949.         intUnlock (intLevel);
  950.         ENDLOGMSG(("Error in Send, not enough TxFreeBytesn",1,2,3,4,5,6));
  951.         return (END_ERR_BLOCK);
  952.         }
  953.     
  954.     /* Bump the statistic counter. */
  955.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);
  956.     ENDLOGMSG (("Send completen",1,2,3,4,5,6));
  957.     return (OK);
  958.     }
  959. /*****************************************************************************
  960. *
  961. * elt3c509MCastAdd - add a multicast address for the device
  962. *
  963. * This routine adds a multicast address to whatever the driver
  964. * is already listening for.  It then resets the address filter.
  965. *
  966. * RETURNS: OK or ERROR.
  967. */
  968. LOCAL STATUS elt3c509MCastAdd
  969.     (
  970.     void  *  pEnd,         /* device pointer */
  971.     char *  pAddress /* new address to add */
  972.     )
  973.     {
  974.     int  error;
  975.     ELT3C509_DEVICE *  pDrvCtrl;
  976.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  977.     if ((error = etherMultiAdd (&pDrvCtrl->endObj.multiList,
  978. pAddress)) == ENETRESET)
  979. elt3c509Config (pDrvCtrl);
  980.     return (OK);
  981.     }
  982. /*****************************************************************************
  983. *
  984. * elt3c509MCastDel - delete a multicast address for the device
  985. *
  986. * This routine removes a multicast address from whatever the driver
  987. * is listening for.  It then resets the address filter.
  988. *
  989. * RETURNS: OK or ERROR.
  990. */
  991. LOCAL STATUS elt3c509MCastDel
  992.     (
  993.     void  *  pEnd,         /* device pointer */
  994.     char *  pAddress /* address to be deleted */
  995.     )
  996.     {
  997.     int  error;
  998.     ELT3C509_DEVICE *  pDrvCtrl;
  999.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  1000.     if ((error = etherMultiDel (&pDrvCtrl->endObj.multiList,
  1001.      (char *)pAddress)) == ENETRESET)
  1002. elt3c509Config (pDrvCtrl);
  1003.     return (OK);
  1004.     }
  1005. /*****************************************************************************
  1006. *
  1007. * elt3c509MCastGet - get the multicast address list for the device
  1008. *
  1009. * This routine gets the multicast list of whatever the driver
  1010. * is already listening for.
  1011. *
  1012. * RETURNS: OK or ERROR.
  1013. */
  1014. LOCAL STATUS elt3c509MCastGet
  1015.     (
  1016.     void  *  pEnd,         /* device pointer */
  1017.     MULTI_TABLE *  pTable /* address table to be filled in */
  1018.     )
  1019.     {
  1020.     ELT3C509_DEVICE * pDrvCtrl;
  1021.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  1022.     return (etherMultiGet (&pDrvCtrl->endObj.multiList, pTable));
  1023.     }
  1024. /*******************************************************************************
  1025. *
  1026. * elt3c509Int - handle controller interrupt
  1027. *
  1028. * This routine is called at interrupt level in response to an interrupt from
  1029. * the controller.
  1030. *
  1031. * RETURNS: N/A.
  1032. */
  1033. LOCAL void elt3c509Int
  1034.     (
  1035.     ELT3C509_DEVICE * pDrvCtrl /* interrupting device */
  1036.     )
  1037.     {
  1038.     UINT16  status;
  1039.     UINT16  statusDiag;
  1040.     UINT8   statusTx;
  1041.     int     port;
  1042.     BOOL    needTxStart = FALSE;
  1043.     port = pDrvCtrl->port;
  1044.     ENDLOGMSG (("Got an interrupt!n", 1, 2, 3, 4, 5, 6));
  1045. #ifdef ELT_TIMING
  1046.     {
  1047.     int time;
  1048.     SYS_IN_BYTE (pDrvCtrl, pDrvCtrl->port + TIMER, time);
  1049.     if (time> pDrvCtrl->elt3c509Stat.maxIntLatency)
  1050.         pDrvCtrl->elt3c509Stat.maxIntLatency = time; 
  1051.     if (pDrvCtrl->interruptTime == -1)
  1052.         pDrvCtrl->interruptTime = time;
  1053.     else if (pDrvCtrl->interruptTime >= 0)
  1054.         pDrvCtrl->interruptTime = -1;
  1055.     }
  1056. #endif /* ELT_TIMING */
  1057.     SYS_IN_BYTE (pDrvCtrl, pDrvCtrl->port + ELT3C509_STATUS, status);
  1058.     status &= 0x00ff;
  1059.     if ((status & INTERRUPT_LATCH) == 0)
  1060.         {
  1061.         ++pDrvCtrl->elt3c509Stat.strayint;
  1062.         return;
  1063.         }
  1064.     else
  1065.         ++pDrvCtrl->elt3c509Stat.interrupts;
  1066.     /* Handle adapter failure first in case other conditions mask it */
  1067.     if ((status & ADAPTER_FAILURE) != 0)
  1068.         {
  1069.         SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND,
  1070.                       SELECT_WINDOW | WIN_DIAGNOSTIC);
  1071.         SYS_IN_WORD (pDrvCtrl, port + FIFO_DIAGNOSTIC, statusDiag);
  1072.         SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND,
  1073.                       SELECT_WINDOW | WIN_OPERATING);
  1074.         if ((statusDiag & FD_TX_OVERRUN) != 0)
  1075.             {
  1076.             ++pDrvCtrl->elt3c509Stat.txoverruns;
  1077.             SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, TX_RESET);
  1078.             elt3c509TxStart (pDrvCtrl);
  1079.             }
  1080.         if ((status & FD_RX_UNDERRUN) != 0)
  1081.             {
  1082.             ++pDrvCtrl->elt3c509Stat.rxunderruns;
  1083.             SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, RX_RESET);
  1084.             elt3c509RxStart (pDrvCtrl);
  1085.             }
  1086.         }
  1087.     if (status & (RX_COMPLETE | RX_EARLY))
  1088.         {
  1089.         if ((status & RX_EARLY) != 0)
  1090.             ++pDrvCtrl->elt3c509Stat.rxearly;
  1091.         if (netJobAdd ((FUNCPTR)elt3c509HandlePktsRcv, (int) pDrvCtrl,
  1092.                        0, 0, 0, 0) == OK)
  1093.             {
  1094.             pDrvCtrl->intMask &= ~(RX_COMPLETE | RX_EARLY);
  1095.                 
  1096. #ifdef ELT_TIMING
  1097.             if((int)++pDrvCtrl->elt3c509Stat.taskQRxOuts >
  1098.                (int)pDrvCtrl->elt3c509Stat.maxRxTaskQ)
  1099.                 {
  1100.                 pDrvCtrl->elt3c509Stat.maxRxTaskQ =
  1101.                     pDrvCtrl->elt3c509Stat.taskQRxOuts;
  1102.                 }
  1103. #endif /* ELT_TIMING */
  1104.             }
  1105.         else
  1106.             logMsg ("elt: netJobAdd (elt3c509HandlePktsRcv) failedn",
  1107.                     0, 0, 0, 0, 0, 0);
  1108.         }
  1109.     
  1110.     /* Handle transmitter interrupts */
  1111.     if ((status & TX_COMPLETE) != 0)
  1112.         {
  1113.         SYS_IN_BYTE (pDrvCtrl, port+TX_STATUS, statusTx);
  1114.         if ((statusTx & TX_S_COMPLETE) != 0)
  1115.             {
  1116.             SYS_OUT_BYTE (pDrvCtrl,port + TX_STATUS, 0); /* clear old status */
  1117.             /*
  1118.              * other errors are tabulated by reading the statistics registers
  1119.              */
  1120.             if ((statusTx & TX_S_MAX_COLL) != 0)
  1121.                 END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +16);
  1122.             if ((statusTx & TX_S_JABBER) != 0)
  1123.                 END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
  1124.             if ((statusTx & (TX_S_JABBER | TX_S_MAX_COLL | TX_S_UNDERRUN))
  1125.                 != 0)
  1126.                 {
  1127.                 needTxStart = TRUE;                 /* restart transmitter */
  1128.                 /* packet not sent */
  1129.                 END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
  1130.                 END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, -1);
  1131.                 }
  1132.             if ((statusTx & (TX_S_JABBER | TX_S_UNDERRUN)) != 0)
  1133.                 {
  1134.                 /* Must reset transmitter; this clears the tx FIFO */
  1135.                 SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, TX_RESET);
  1136.                 }
  1137.             }
  1138.         if (needTxStart)                            /* check flag */
  1139.             elt3c509TxStart (pDrvCtrl);
  1140.         if (pDrvCtrl->txBlocked)
  1141.             {
  1142.             pDrvCtrl->txBlocked = FALSE;
  1143.             /* restart the transmit flow */
  1144.             netJobAdd ((FUNCPTR) muxTxRestart, (int) &pDrvCtrl->endObj, 0, 0,
  1145.                        0, 0);
  1146. #ifdef ELT_TIMING
  1147.             if ((int)++pDrvCtrl->elt3c509Stat.taskQTxOuts >
  1148.                  (int)pDrvCtrl->elt3c509Stat.maxTxTaskQ)
  1149.                 pDrvCtrl->elt3c509Stat.maxTxTaskQ =
  1150.                     pDrvCtrl->elt3c509Stat.taskQTxOuts;
  1151. #endif /* ELT_TIMING */
  1152.             }
  1153.         }
  1154.     /* Handle update statistics interrupt */
  1155.     if ((status & UPDATE_STATS) != 0)
  1156.         elt3c509StatFlush (pDrvCtrl);
  1157.     /* mask and ack the events we've just handled or queued handlers for */
  1158.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  1159.                   MASK_STATUS | pDrvCtrl->intMask);
  1160.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  1161.                   ACK_INTERRUPT | status);
  1162.     sysBusIntAck (pDrvCtrl->intLevel);
  1163.     }
  1164. /*******************************************************************************
  1165. *
  1166. * elt3c509HandlePktsRcv - task level interrupt service for input packets
  1167. *
  1168. * This routine is called at task level indirectly by the interrupt
  1169. * service routine to do any message received processing.
  1170. *
  1171. * RETURNS: N/A.
  1172. */
  1173. LOCAL void elt3c509HandlePktsRcv
  1174.     (
  1175.     ELT3C509_DEVICE * pDrvCtrl /* interrupting device */
  1176.     )
  1177.     {
  1178.     M_BLK_ID  pMblk; /* pointer to the mBlk */
  1179.     CL_BLK_ID pClBlk; /* pointer to the clBlk */
  1180.     char * pCluster; /* pointer to the cluster */
  1181.     int     port; /* IO port to read */
  1182.     STATUS       result = OK;    /* Tracks result of Cluster Alloc */
  1183.     port = pDrvCtrl->port;
  1184.     
  1185.     /* loop for more frames */
  1186.     while (TRUE)
  1187.         {
  1188.         /* get a cluster */
  1189.         pCluster = netClusterGet (pDrvCtrl->endObj.pNetPool,
  1190.                                   pDrvCtrl->pClPoolId);
  1191.         if (pCluster == NULL)
  1192.             {
  1193.             ENDLOGMSG (("Cannot loan!n", 1, 2, 3, 4, 5, 6));
  1194.             ++pDrvCtrl->elt3c509Stat.rxnobuffers;
  1195.             END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1196.     result = ERROR;
  1197.             break;
  1198.             }
  1199.         /* get a cluster block */
  1200.         if ((pClBlk = netClBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT)) ==
  1201.             NULL)
  1202.             {
  1203.             netClFree (pDrvCtrl->endObj.pNetPool, pCluster);
  1204.             ENDLOGMSG (("Out of Cluster Blocks!n", 1, 2, 3, 4, 5, 6));
  1205.             END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1206.     result = ERROR;
  1207.             break;
  1208.             }
  1209.     
  1210.         /* get an mBlk */
  1211.         if ((pMblk = mBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT, MT_DATA))
  1212.             == NULL)
  1213.             {
  1214.             netClBlkFree (pDrvCtrl->endObj.pNetPool, pClBlk); 
  1215.             netClFree (pDrvCtrl->endObj.pNetPool, pCluster);
  1216.             ENDLOGMSG (("Out of M Blocks!n", 1, 2, 3, 4, 5, 6));
  1217.             END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1218.     result = ERROR;
  1219.             break;
  1220.             }
  1221.         /* Join the cluster to the MBlock */
  1222.         netClBlkJoin (pClBlk, pCluster, ELT3C509_BUFSIZ, NULL, 0, 0, 0);
  1223.         netMblkClJoin (pMblk, pClBlk);
  1224.         
  1225.         if (elt3c509PollRcv ((void *)pDrvCtrl, pMblk) == OK)
  1226.             {
  1227.             END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
  1228.             ENDLOGMSG (("Calling upper layer's recv rtnn", 1, 2, 3, 4, 5, 6));
  1229.             /* Call the upper layer's receive routine. */
  1230.             END_RCV_RTN_CALL (&pDrvCtrl->endObj, pMblk);
  1231.             }
  1232.         else
  1233.             {
  1234.             ENDLOGMSG (("EAGAINn", 1, 2, 3, 4, 5, 6));
  1235.             netMblkClFree (pMblk);
  1236.     result = ERROR;
  1237.             break;
  1238.             }
  1239.         }
  1240.     
  1241.     /* Discard the packet in the FIFO here of there was an error */
  1242.     if (result == ERROR)
  1243. {
  1244. /* discard packet */
  1245.         SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, RX_DISCARD);
  1246. }
  1247.      /* enable the recv interrupt */
  1248.     elt3c509IntMaskSet (pDrvCtrl, (RX_COMPLETE | RX_EARLY));
  1249.     }
  1250. /*******************************************************************************
  1251. *
  1252. * elt3c509PollRcv - routine to receive a packet in polled mode.
  1253. *
  1254. * This routine is called by a user to try and get a packet from the
  1255. * device.
  1256. *
  1257. * RETURNS: EGAIN or OK
  1258. */
  1259. LOCAL STATUS elt3c509PollRcv
  1260.     (
  1261.     void  *  pEnd, /* device pointer */
  1262.     M_BLK_ID  pMblk /* pointer to the mBlk chain */
  1263.     )
  1264.     {
  1265.     UINT16  statusRx;
  1266.     UINT16  statusRxNew;
  1267.     UINT16  length;
  1268.     int     port;
  1269.     int ix = 0;
  1270.     int       status = OK;
  1271.     ELT3C509_DEVICE *  pDrvCtrl;
  1272.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  1273.     port = pDrvCtrl->port;
  1274.     
  1275.     SYS_IN_WORD (pDrvCtrl, port + RX_STATUS, statusRx);
  1276.     
  1277.     if (statusRx & RX_S_INCOMPLETE) /* incomplete */
  1278.         {
  1279.         if (statusRx == RX_S_INCOMPLETE) /* no bytes available */
  1280.             {
  1281.             ENDLOGMSG (("no more packetsn", 1, 2, 3, 4, 5, 6));
  1282.             return (EAGAIN);
  1283.             }
  1284.         while (ix < 10000)
  1285.             {
  1286.             SYS_IN_WORD (pDrvCtrl, port + RX_STATUS, statusRxNew);
  1287.             if (statusRx == statusRxNew)
  1288.                 {
  1289.                 break;
  1290.                 }
  1291.             else
  1292.                 {
  1293.                 statusRx = statusRxNew;
  1294.                 ix++;
  1295.                 }
  1296.             }
  1297.         
  1298.         if (statusRx & RX_S_INCOMPLETE)
  1299.             {
  1300.             END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1301.             ENDLOGMSG (("status quon", 1, 2, 3, 4, 5, 6));
  1302.             status = EAGAIN;
  1303.             goto PollRcvErrHandle;
  1304.             }
  1305.         }
  1306.     /* Check for errors in completed packet */
  1307.     if (statusRx & RX_S_ERROR)
  1308.         {
  1309.         switch (statusRx & RX_S_CODE_MASK)
  1310.             {
  1311.             case RX_S_OVERRUN: /* handled by statistics registers */
  1312.                 break;
  1313.             case RX_S_RUNT:
  1314.                 ++pDrvCtrl->elt3c509Stat.shortPacket;
  1315.                 break;
  1316.             case RX_S_ALIGN:
  1317.                 ++pDrvCtrl->elt3c509Stat.aligns;
  1318.                 break;
  1319.             case RX_S_CRC:
  1320.                 ++pDrvCtrl->elt3c509Stat.crcs;
  1321.                 break;
  1322.             case RX_S_OVERSIZE:
  1323.                 ++pDrvCtrl->elt3c509Stat.badPacket;
  1324.                 break;
  1325.             default: /* no other codes are defined */
  1326.                 break;
  1327.             }
  1328.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1329.         ENDLOGMSG (("recv errorn", 1, 2, 3, 4, 5, 6));
  1330.         status = EAGAIN;
  1331.         goto PollRcvErrHandle;
  1332.         }
  1333.     /* length of the buffer in the FIFO */
  1334.     length = statusRx & RX_S_CNT_MASK;
  1335.     /* discard packet if received frame is bigger than MAX_FRAME_SIZE */
  1336.     if (length > MAX_FRAME_SIZE)
  1337.         {
  1338.         ENDLOGMSG (("pktlen>MAX_FRAME_SIZEn", 1, 2, 3, 4, 5, 6));
  1339.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1340.         status = EAGAIN;
  1341.         goto PollRcvErrHandle;
  1342.         }
  1343.     /* if given mBlk does not have enough space */
  1344.     if ((!(pMblk->mBlkHdr.mFlags & M_EXT)) || (pMblk->pClBlk->clSize < length))
  1345. {
  1346.         ENDLOGMSG (("PRX bad mblk len:%d flags:%dn", pMblk->mBlkHdr.mLen,
  1347.                    pMblk->mBlkHdr.mFlags, 3, 4, 5, 6));
  1348.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1349.         status = EAGAIN;
  1350.         goto PollRcvErrHandle;
  1351. }
  1352.     /* read the packet from the FIFO into the cluster */
  1353.     
  1354.     SYS_IN_WORD_STRING (pDrvCtrl, port + DATA_REGISTER, 
  1355. (short *) pMblk->mBlkHdr.mData, (length + 1) / 2);
  1356.     /* update the mBlk fields */
  1357.     pMblk->mBlkHdr.mLen   = length;
  1358.     pMblk->mBlkHdr.mFlags |= M_PKTHDR;
  1359.     pMblk->mBlkPktHdr.len = length;
  1360.     status = OK;
  1361.     
  1362.     PollRcvErrHandle:
  1363.      {
  1364. /* discard packet */
  1365.         SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, RX_DISCARD);
  1366.         /* wait for command to finish */
  1367.         statusRxNew = ERROR;
  1368.         while ((statusRxNew & COMMAND_IN_PROGRESS) != 0)
  1369.             {
  1370.             SYS_IN_WORD (pDrvCtrl, port + ELT3C509_STATUS, statusRxNew);
  1371.             }
  1372.         }
  1373.     return (status);
  1374.     }
  1375. /******************************************************************************
  1376. *
  1377. * elt3c509Config - reconfigure the interface under us.
  1378. *
  1379. * Reconfigure the interface setting promiscuous mode, and changing the
  1380. * multicast interface list.
  1381. *
  1382. * RETURNS: N/A.
  1383. */
  1384. LOCAL void elt3c509Config
  1385.     (
  1386.     ELT3C509_DEVICE * pDrvCtrl /* device to be re-configured */
  1387.     )
  1388.     {
  1389.     /* Set promiscuous mode if it's asked for. */
  1390.     if (END_FLAGS_GET (&pDrvCtrl->endObj) & IFF_PROMISC)
  1391. {
  1392. ENDLOGMSG (("Setting promiscuous mode on!n", 1, 2, 3, 4, 5, 6));
  1393.         pDrvCtrl->rxFilter |= RX_F_PROMISCUOUS;
  1394.         SYS_OUT_WORD(pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  1395.                      SET_RX_FILTER | pDrvCtrl->rxFilter);
  1396. }
  1397.     else
  1398. {
  1399. ENDLOGMSG (("Setting promiscuous mode off!n", 1, 2, 3, 4, 5, 6));
  1400.         pDrvCtrl->rxFilter &= ~RX_F_PROMISCUOUS;
  1401.         SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  1402.                       SET_RX_FILTER | pDrvCtrl->rxFilter);
  1403. }
  1404.     /* Set up address filter for multicasting. 
  1405.      * Multicast bit is set if the address list has one or more entries
  1406.      * Multicasting is disabled if the address list is empty
  1407.      */
  1408.     if (END_MULTI_LST_CNT (&pDrvCtrl->endObj) > 0 ||
  1409.              (END_FLAGS_GET (&pDrvCtrl->endObj) & IFF_MULTICAST))
  1410. {
  1411. ENDLOGMSG (("Setting multicast mode on!n", 1, 2, 3, 4, 5, 6));
  1412.         pDrvCtrl->rxFilter |= RX_F_MULTICAST;
  1413.         SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  1414.                       SET_RX_FILTER | pDrvCtrl->rxFilter);
  1415. }
  1416.     else
  1417. {
  1418. ENDLOGMSG (("Setting multcast mode off!n", 1, 2, 3, 4, 5, 6));
  1419.         pDrvCtrl->rxFilter &= ~RX_F_MULTICAST;
  1420.         SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  1421.                       SET_RX_FILTER | pDrvCtrl->rxFilter);
  1422. }
  1423.     return;
  1424.     }
  1425. /*******************************************************************************
  1426. *
  1427. * elt3c509PollSend - routine to send a packet in polled mode.
  1428. *
  1429. * This routine is called by a user to try and send a packet on the
  1430. * device.
  1431. *
  1432. * RETURNS: OK upon success.  EAGAIN if device is busy.
  1433. */
  1434. LOCAL STATUS elt3c509PollSend
  1435.     (
  1436.     void  *  pEnd,         /* device pointer */
  1437.     M_BLK_ID  pMblk /* packet to send */
  1438.     )
  1439.     {
  1440.     int len;
  1441.     int * pLenMask;
  1442.     char * pBuf;
  1443.     ELT3C509_DEVICE *  pDrvCtrl;
  1444.     UINT16 txStatus;
  1445.     VOID_TO_DRVCTRL (pEnd, pDrvCtrl);
  1446.     SYS_IN_WORD (pDrvCtrl, pDrvCtrl->port + TX_FREE_BYTES, txStatus);
  1447.     if (txStatus >= TX_IDLE_COUNT)
  1448.         {
  1449.         pBuf = pDrvCtrl->pTxCluster;  /* pointer to the transmit cluster */
  1450.         pLenMask = (UINT32 *)pBuf;
  1451.         
  1452.         /* allow space for the preamble the trasmit buffer is 1520 */
  1453.         pBuf += sizeof(UINT32);
  1454.         len = netMblkToBufCopy(pMblk, pBuf, NULL);
  1455.         len = max(len, ETHERSMALL); /* set the packet size */
  1456.         *pLenMask = len | TX_F_INTERRUPT; /* set the preamble */
  1457.         len = (len + TX_F_PREAMBLE_SIZE + 3) & TX_F_DWORD_MASK;
  1458.         /* place a transmit request */
  1459.         SYS_OUT_WORD_STRING (pDrvCtrl, pDrvCtrl->port + DATA_REGISTER, 
  1460. (short *)pLenMask, len / 2);
  1461.         /* read the tranmsit status */
  1462.         SYS_IN_BYTE (pDrvCtrl, pDrvCtrl->port + TX_STATUS, txStatus);
  1463.         /* wait until tramit is complete */
  1464.         while (!(txStatus & TX_S_COMPLETE))
  1465.             {
  1466.             SYS_IN_BYTE (pDrvCtrl, pDrvCtrl->port + TX_STATUS, txStatus);
  1467.             }
  1468. /* clear old status */
  1469.         SYS_OUT_BYTE (pDrvCtrl, pDrvCtrl->port + TX_STATUS, 0);
  1470.         }
  1471.     else
  1472.         {
  1473.         ENDLOGMSG(("Error in Send, not enough TxFreeBytesn",1,2,3,4,5,6));
  1474.         return (EAGAIN);
  1475.         }
  1476.     
  1477.     /* Bump the statistic counter. */
  1478.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);
  1479.     ENDLOGMSG (("Poll Send completen",1,2,3,4,5,6));
  1480.     return (OK);
  1481.     }
  1482. /*******************************************************************************
  1483. *
  1484. * elt3c509PollStart - start polled mode operations
  1485. *
  1486. * This function starts polled mode operation.
  1487. *
  1488. * The device interrupts are disabled, the current mode flag is switched
  1489. * to indicate Polled mode and the device is reconfigured.
  1490. *
  1491. * RETURNS: OK or ERROR.
  1492. */
  1493. LOCAL STATUS elt3c509PollStart
  1494.     (
  1495.     ELT3C509_DEVICE * pDrvCtrl /* device to be polled */
  1496.     )
  1497.     {
  1498.     int         oldLevel;
  1499.     
  1500.     oldLevel = intLock ();          /* disable ints during update */
  1501.     pDrvCtrl->flags |= ELT3C_POLLING;
  1502.     intUnlock (oldLevel);   /* now elt3c509Int won't get confused */
  1503.     elt3c509IntDisable (pDrvCtrl);
  1504.     ENDLOGMSG (("STARTEDn", 1, 2, 3, 4, 5, 6));
  1505.     elt3c509Config (pDrvCtrl); /* reconfigure device */
  1506.     return (OK);
  1507.     }
  1508. /*******************************************************************************
  1509. *
  1510. * elt3c509PollStop - stop polled mode operations
  1511. *
  1512. * This function terminates polled mode operation.  The device returns to
  1513. * interrupt mode.
  1514. *
  1515. * The device interrupts are enabled, the current mode flag is switched
  1516. * to indicate interrupt mode and the device is then reconfigured for
  1517. * interrupt operation.
  1518. *
  1519. * RETURNS: OK or ERROR.
  1520. */
  1521. LOCAL STATUS elt3c509PollStop
  1522.     (
  1523.     ELT3C509_DEVICE * pDrvCtrl /* device structure */
  1524.     )
  1525.     {
  1526.     int         oldLevel;
  1527.     oldLevel = intLock (); /* disable ints during register updates */
  1528.     pDrvCtrl->flags &= ~ELT3C_POLLING;
  1529.     intUnlock (oldLevel);
  1530.     elt3c509IntEnable (pDrvCtrl);
  1531.     elt3c509Config (pDrvCtrl);
  1532.     ENDLOGMSG (("STOPPEDn", 1, 2, 3, 4, 5, 6));
  1533.     return (OK);
  1534.     }
  1535. /*******************************************************************************
  1536. *
  1537. * elt3c509IntEnable - enable board to cause interrupts
  1538. *
  1539. * Because the board has maskable status, this routine can simply set the
  1540. * mask to all ones.  We set all the bits symbolically; the effect is the
  1541. * same.  Note that the interrupt latch is not maskable; if none of the other
  1542. * mask bits are set, no interrupts will occur at all.  Only those interrupts
  1543. * whose status bits are enabled will actually occur.  Note that the "intMask"
  1544. * field in the device control structure is really the status mask.
  1545. *
  1546. * RETURNS: N/A.
  1547. */
  1548. LOCAL void elt3c509IntEnable
  1549.     (
  1550.     ELT3C509_DEVICE * pDrvCtrl /* device structure */
  1551.     )
  1552.     {
  1553.     UINT16  status;
  1554.     SYS_IN_BYTE (pDrvCtrl, pDrvCtrl->port + ELT3C509_STATUS, status);
  1555.     status &= 0x00ff;
  1556.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  1557.                   ACK_INTERRUPT | status);
  1558.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, MASK_INTERRUPT |
  1559.                   ADAPTER_FAILURE | TX_COMPLETE | TX_AVAILABLE | RX_COMPLETE |
  1560.                   RX_EARLY | INTERRUPT_REQ | UPDATE_STATS);
  1561.     }
  1562. /*******************************************************************************
  1563. *
  1564. * elt3c509IntDisable - prevent board from causing interrupts
  1565. *
  1566. * This routine simply sets all the interrupt mask bits to zero.
  1567. * It is intended for guarding board-critical sections.
  1568. *
  1569. * RETURNS: N/A.
  1570. */
  1571. LOCAL void elt3c509IntDisable
  1572.     (
  1573.     ELT3C509_DEVICE * pDrvCtrl /* device structure */
  1574.     )
  1575.     {
  1576.     UINT16  status;
  1577.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  1578.                   MASK_INTERRUPT | 0);
  1579.     SYS_IN_BYTE (pDrvCtrl, pDrvCtrl->port + ELT3C509_STATUS, status);
  1580.     status &= 0x00ff;
  1581.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  1582.                   ACK_INTERRUPT | status);
  1583.     }
  1584. /*******************************************************************************
  1585. *
  1586. * elt3c509TxStart - turn on board's transmit function
  1587. *
  1588. * RETURNS: N/A.
  1589. */
  1590. LOCAL void elt3c509TxStart
  1591.     (
  1592.     ELT3C509_DEVICE *  pDrvCtrl /* device structure */
  1593.     )
  1594.     {
  1595.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, TX_ENABLE);
  1596.     }
  1597. /*******************************************************************************
  1598. *
  1599. * elt3c509RxStart - enable board to start receiving
  1600. *
  1601. * RETURNS: N/A.
  1602. */
  1603. LOCAL void elt3c509RxStart
  1604.     (
  1605.     ELT3C509_DEVICE *  pDrvCtrl /* device structure */
  1606.     )
  1607.     {
  1608.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  1609.                   SET_RX_FILTER | pDrvCtrl->rxFilter);
  1610.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, RX_ENABLE);
  1611.     }
  1612. /*******************************************************************************
  1613. *
  1614. * elt3c509Reset - reset the elt3c509 interface
  1615. *
  1616. * Mark interface as inactive and reset the adapter.
  1617. *
  1618. * RETURNS: N/A.
  1619. */
  1620. LOCAL void elt3c509Reset
  1621.     (
  1622.     ELT3C509_DEVICE * pDrvCtrl /* device structure */
  1623.     )
  1624.     {
  1625.     elt3c509IntDisable (pDrvCtrl); /* prevent device from interrupting */
  1626.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, RX_RESET);
  1627.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND, TX_RESET);
  1628.     }
  1629. /*******************************************************************************
  1630. *
  1631. * elt3c509StatFlush - flush the board's statistics registers to statistics
  1632. * block Called when the board reports that its statistics registers are getting
  1633. * full, or when someone wants to see the current statistics (to fully update
  1634. * the statistics block).
  1635. *
  1636. * Note that reading a statistics register zeroes it in the hardware.
  1637. * Note also that zeroing all the registers is necessary and sufficient
  1638. * to clear the interrupt condition.
  1639. *
  1640. * Must be called with board or system interrupts disabled.
  1641. *
  1642. * RETURNS: N/A.
  1643. */
  1644. LOCAL void elt3c509StatFlush
  1645.     (
  1646.     ELT3C509_DEVICE * pDrvCtrl /* device structure */
  1647.     )
  1648.     {
  1649.     int         port;
  1650.     UINT16 tempCounter;
  1651.     port = pDrvCtrl->port;
  1652.     SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND,
  1653.                   SELECT_WINDOW | WIN_STATISTICS);
  1654.     SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, STATS_DISABLE);
  1655.     SYS_IN_BYTE (pDrvCtrl, port+CARRIER_LOSTS, tempCounter);
  1656.     pDrvCtrl->elt3c509Stat.nocarriers += tempCounter & 0x0f;
  1657.     SYS_IN_BYTE (pDrvCtrl, port+SQE_FAILURES, tempCounter);
  1658.     pDrvCtrl->elt3c509Stat.heartbeats += tempCounter & 0x0f;
  1659.     SYS_IN_BYTE (pDrvCtrl, port+MULT_COLLISIONS, tempCounter);
  1660.     pDrvCtrl->elt3c509Stat.multcollisions += tempCounter & 0x3f;
  1661.     SYS_IN_BYTE (pDrvCtrl, port+ONE_COLLISIONS, tempCounter);
  1662.     pDrvCtrl->elt3c509Stat.collisions +=  tempCounter & 0x3f;
  1663.     SYS_IN_BYTE (pDrvCtrl, port+LATE_COLLISIONS, tempCounter);
  1664.     pDrvCtrl->elt3c509Stat.latecollisions += tempCounter;
  1665.     SYS_IN_BYTE (pDrvCtrl, port+RECV_OVERRUNS, tempCounter);
  1666.     pDrvCtrl->elt3c509Stat.rxoverruns += tempCounter;
  1667.     SYS_IN_BYTE (pDrvCtrl, port+GOOD_TRANSMITS, tempCounter);
  1668.     pDrvCtrl->elt3c509Stat.txnoerror += tempCounter;
  1669.     SYS_IN_BYTE (pDrvCtrl, port+GOOD_RECEIVES, tempCounter);
  1670.     pDrvCtrl->elt3c509Stat.rxnoerror += tempCounter;
  1671.     SYS_IN_BYTE (pDrvCtrl, port+TX_DEFERRALS, tempCounter);
  1672.     pDrvCtrl->elt3c509Stat.deferring += tempCounter;
  1673.     /* Must read all the registers to be sure to clear the interrupt */
  1674.     SYS_IN_WORD (pDrvCtrl, port + BYTES_RECEIVED, tempCounter);
  1675.     SYS_IN_WORD (pDrvCtrl, port + BYTES_TRANSMITTED, tempCounter);
  1676.     SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND, STATS_ENABLE);
  1677.     SYS_OUT_WORD (pDrvCtrl, port + ELT3C509_COMMAND,
  1678.                   SELECT_WINDOW | WIN_OPERATING);
  1679.     }
  1680. /*******************************************************************************
  1681. *
  1682. * elt3c509IntMaskSet - enable specific status conditions to cause interrupts
  1683. *
  1684. * Sets bit(s) in the intMask field of the device control structure and in
  1685. * the board's "read zero mask" where a one bit enables the corresponding
  1686. * status condition to be read and to cause an interrupt.
  1687. *
  1688. * RETURNS: N/A.
  1689. */
  1690. LOCAL void elt3c509IntMaskSet
  1691.     (
  1692.     ELT3C509_DEVICE *  pDrvCtrl, /* device structure */
  1693.     int  maskBits /* mask bits */
  1694.     )
  1695.     {
  1696.     elt3c509IntDisable (pDrvCtrl);
  1697.     pDrvCtrl->intMask |= maskBits;
  1698.     SYS_OUT_WORD (pDrvCtrl, pDrvCtrl->port + ELT3C509_COMMAND,
  1699.                   MASK_STATUS | pDrvCtrl->intMask);
  1700.     elt3c509IntEnable (pDrvCtrl);
  1701.     }
  1702. /*******************************************************************************
  1703. *
  1704. * elt3c509Activate - attempt to activate the adapter with given address
  1705. *
  1706. * The 3Com 3C509 ISA adapter does not enable itself at power-on.  This is
  1707. * left to the driver, which presumably knows which board it wants.  This
  1708. * we do know, from the port field in the driver control structure.
  1709. *
  1710. * As a helpful side effect, this routine stores the OEM Ethernet address
  1711. * of the selected adapter into the driver control structure.
  1712. *
  1713. * Note that this procedure will activate only one board of the given I/O
  1714. * address; this is presumably designed in by 3Com as a helpful feature.
  1715. *
  1716. * RETURNS: OK or ERROR.
  1717. */
  1718. LOCAL STATUS elt3c509Activate
  1719.     (
  1720.     ELT3C509_DEVICE * pDrvCtrl
  1721.     )
  1722.     {
  1723.     int  adapterPort;    /* I/O address of adapter we're to look for */
  1724.     int  selectedPort;   /* I/O address of adapter we've found */
  1725.     int  addressConfig;  /* adapter's address configuration register */
  1726.     int  resourceConfig; /* adapter's resource configuration register */
  1727.     char  nodeAddress [EA_SIZE];
  1728.     STATUS  status = OK;  /* presume OK, change if there's a problem */
  1729.     adapterPort = pDrvCtrl->port;
  1730.     elt3c509IdCommand (ID_PORT);             /* wake up all adapters */
  1731.     SYS_OUT_BYTE (pDrvCtrl, ID_PORT, ID_SET_TAG);   /* clear all tags */
  1732.     /* first see if there's a 3Com 3C5xx board out there at all */
  1733.     if (elt3c509IdEepromRead (EE_A_MANUFACTURER) != MANUFACTURER_ID)
  1734.         return (ERROR);
  1735.     /* Identify adapters one by one until we find the right one;
  1736.      * as we eliminate adapters, we tag them so they don't participate
  1737.      * in the next round of contention eliminations.  Along the way,
  1738.      * as part of the adapter contention process, we read out the
  1739.      * station address and resource configuration.
  1740.      */
  1741.     do
  1742.         {
  1743.         elt3c509IdCommand (ID_PORT);         /* prepare for contention */
  1744.         /* Now read all untagged adapters' addresses from EEPROM
  1745.          * a bit at a time.  Tagged adapters ignore the reads therefore
  1746.          * won't be found; we find the next untagged adapter.
  1747.          */
  1748.         * (UINT16 *) &nodeAddress [0] = elt3c509IdEepromRead (EE_A_OEM_NODE_0);
  1749.         * (UINT16 *) &nodeAddress [2] = elt3c509IdEepromRead (EE_A_OEM_NODE_1);
  1750.         * (UINT16 *) &nodeAddress [4] = elt3c509IdEepromRead (EE_A_OEM_NODE_2);
  1751.         resourceConfig = elt3c509IdEepromRead (EE_A_RESOURCE);
  1752.         addressConfig = elt3c509IdEepromRead (EE_A_ADDRESS);
  1753.         if ((addressConfig & AC_IO_BASE_MASK) == AC_IO_BASE_EISA)
  1754.             {
  1755.             /* the EISA base address is the last possible one; if we hit
  1756.              * this value without finding the adapter we want, we're done.
  1757.              */
  1758.             status = ERROR;
  1759.             break;
  1760.             }
  1761.         selectedPort = (addressConfig & AC_IO_BASE_MASK) * AC_IO_BASE_FACTOR +
  1762.                        AC_IO_BASE_ZERO;
  1763.         ENDLOGMSG (("elt: activate: adapter at 0x%04xn", selectedPort, 2, 3,
  1764.                     4, 5, 6));
  1765.         /* tag this adapter so if we don't want it it won't contend again */
  1766.         SYS_OUT_BYTE (pDrvCtrl, ID_PORT, ID_SET_TAG + 1);
  1767.         }
  1768.     while (selectedPort != adapterPort);
  1769.     if (status != ERROR)
  1770.         {
  1771.         SYS_OUT_BYTE (pDrvCtrl, ID_PORT, ID_ACTIVATE);
  1772.         uswab (nodeAddress, (char *)pDrvCtrl->enetAddr, EA_SIZE);
  1773.         }
  1774.     return (status);
  1775.     }
  1776. /*******************************************************************************
  1777. *
  1778. * elt3c509IdCommand - put all adapters into ID command state
  1779. *
  1780. * This procedure synchronizes the ID state machines of all installed 3Com
  1781. * adapters in preparation for contending among them.
  1782. *
  1783. * RETURNS: N/A.
  1784. */
  1785. LOCAL void elt3c509IdCommand
  1786.     (
  1787.     int idPort          /* I/O address to use as ID port (1x0 hex) */
  1788.     )
  1789.     {
  1790.     int  idValue;        /* data read or written to ID port */
  1791.     int  count;
  1792.     /* We should guard this routine since the ID procedure touches
  1793.      * all unactivated adapters.  In fact the first three writes should
  1794.      * be guarded against any possible intervening write to any port
  1795.      * 0x100, 0x110, 0x120, ... , 0x1f0.
  1796.      */
  1797.     SYS_OUT_BYTE (pDrvCtrl, idPort, ID_RESET); /* select the ID port */
  1798.     
  1799.     /* put adapters in ID-WAIT state */
  1800.     
  1801.     SYS_OUT_BYTE (pDrvCtrl, idPort, ID_RESET);
  1802.     idValue = ID_SEQUENCE_INITIAL;
  1803.     for (count = ID_SEQUENCE_LENGTH; count > 0; count--)
  1804.         {
  1805.         SYS_OUT_BYTE (pDrvCtrl, idPort, idValue);
  1806.         idValue <<= 1;
  1807.         if ((idValue & ID_CARRY_BIT) != 0)
  1808.             idValue ^= ID_POLYNOMIAL;
  1809.         }
  1810.     }
  1811. /*******************************************************************************
  1812. *
  1813. * elt3c509EepromRead - read one 16-bit adapter EEPROM register.
  1814. *
  1815. * RETURNS: Value from an offset of the EEPROM.
  1816. */
  1817. LOCAL int elt3c509EepromRead
  1818.     (
  1819.     int  port,
  1820.     int  offset
  1821.     )
  1822.     {
  1823.     int  ix;
  1824.     UINT16 epromStatus;
  1825.     SYS_OUT_WORD (NULL, port + EEPROM_CONTROL, 0x80 + offset);
  1826.     /* wait 162 us minimum */
  1827.     for (ix = 0; ix < 400; ix++)
  1828. sysDelay ();
  1829.     
  1830.     SYS_IN_WORD (NULL, port + EEPROM_DATA, epromStatus);
  1831.     return (epromStatus);
  1832.     }
  1833. /*******************************************************************************
  1834. *
  1835. * elt3c509IdEepromRead - read one 16-bit adapter EEPROM register
  1836. *
  1837. * Read an EEPROM register bitwise by way of the ID port.  Used for adapter
  1838. * contention process and to find out what's in the EEPROM.  Addresses are
  1839. * masked to a valid size; invalid addresses are simply truncated.
  1840. *
  1841. * RETURNS: Value from an offset of Eeprom.
  1842. */
  1843. LOCAL UINT16 elt3c509IdEepromRead
  1844.     (
  1845.     int address                         /* EEPROM register address */
  1846.     )
  1847.     {
  1848.     int  bitCount;
  1849.     UINT16  value;
  1850.     UINT16 tempVal;
  1851.     SYS_OUT_BYTE (NULL, ID_PORT, ID_EEPROM_READ | (address & ID_EEPROM_MASK));
  1852.     taskDelay (2);                      /* must wait for 162 uS read cycle */
  1853.     value = 0;
  1854.     for (bitCount = ID_REGISTER_SIZE; bitCount > 0; bitCount--)
  1855.         {
  1856.         value <<= 1;
  1857.         SYS_IN_BYTE (NULL, ID_PORT, tempVal);
  1858. value |= (tempVal & 1);
  1859.         }
  1860.     return (value);
  1861.     }
  1862. #ifdef DRV_DEBUG
  1863. /*******************************************************************************
  1864. *
  1865. * elt3c509Show - display statistics for the 3C509 `elt' network interface
  1866. *
  1867. * This routine displays statistics about the `elt' Ethernet network interface.
  1868. * It has two parameters: 
  1869. * .iP <unit>
  1870. * interface unit; should be 0.
  1871. * .iP <zap>
  1872. * if 1, all collected statistics are cleared to zero.
  1873. * .LP
  1874. *
  1875. * NOMANUAL
  1876. *
  1877. * RETURNS: N/A
  1878. */
  1879. void elt3c509Show 
  1880.     (
  1881.     ELT3C509_DEVICE *  pDrvCtrl, /* device structure */
  1882.     BOOL  zap     /* 1 = zero totals */
  1883.     )
  1884.     {
  1885.     FAST int ix;
  1886.     LOCAL char *e_message [] = {
  1887.         "collisions",
  1888.         "crcs",
  1889.         "aligns",
  1890.         "rx no buffers",
  1891.         "rx over-runs",
  1892.         "disabled",
  1893.         "deferring",
  1894.         "tx under-run",
  1895.         "aborts",
  1896.         "out-of-window",
  1897.         "heart-beats",
  1898.         "bad-packet",
  1899.         "short-packet",
  1900.         "tx-no-error",
  1901.         "rx-no-error",
  1902.         "tx-error",
  1903.         "rx-error",
  1904.         "over-write",
  1905.         "wrapped",
  1906.         "interrupts",
  1907.         "reset",
  1908.         "stray-int",
  1909.         "multiple-collisions",
  1910.         "late-collisions",
  1911.         "no-carriers",
  1912.         "jabbers",
  1913.         "tx over-run",
  1914.         "rx under-run",
  1915. #ifdef ELT_TIMING
  1916.         "rx early",
  1917.         "timer updates",
  1918.         "timer overflows",
  1919.         "timer invalids",
  1920.         "max rx latency",
  1921.         "min rx latency",
  1922.         "max int latency",
  1923.         "current outstanding net rx tasks",
  1924.         "max outstanding rx net tasks",
  1925.         "current outstanding net tx tasks",
  1926.         "max outstanding tx net tasks"
  1927. #else
  1928.         "rx early"
  1929. #endif /* ELT_TIMING */
  1930. };
  1931.     /* Disable board interrupts because elt3c509StatFlush()
  1932.      * changes reg. window
  1933.      */
  1934.     elt3c509IntDisable (pDrvCtrl);
  1935.     elt3c509StatFlush (pDrvCtrl);            /* get the latest statistics */
  1936.     elt3c509IntEnable (pDrvCtrl);
  1937.     for (ix = 0; ix < NELEMENTS(e_message); ix++)
  1938.         {
  1939.         printf ("    %-30.30s  %4dn", e_message [ix],
  1940.                 pDrvCtrl->elt3c509Stat.stat [ix]);
  1941.         if (zap)
  1942.             pDrvCtrl->elt3c509Stat.stat [ix] = 0;
  1943.         }
  1944.     }
  1945. #endif /* DRV_DEBUG */