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

VxWorks

开发平台:

C/C++

  1. /* iOlicomEnd.c - END style Intel Olicom PCMCIA network interface driver */
  2. /* Copyright 1997-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01q,14jan02,dat  Removing warnings from Diab compiler
  8. 01p,20sep01,dat  Removing ANSI errors, for diab compiler
  9. 01o,28aug00,stv  corrected the handling of EIOCSFLAGS ioctl (SPR# 29423).
  10. 01n,11jun00,ham  removed reference to etherLib.
  11. 01m,16nov99,jpd  fixed warnings caused by new definition of NULL.
  12. 01l,01dec99,stv  freed mBlk chain before returning ERROR (SPR #28492).
  13. 01k,11nov99,cn   removed unnecessary freeing of pDrvCtrl in iOlicomUnload
  14.  (SPR# 28772).
  15. 01j,16nov98,jpd  claim buffers using malloc() not cacheDmaMalloc(). Fix bug
  16.  parsing CIS. Improved efficiency. Tidied. Fix problem after
  17.  (hard) PID7T reset.
  18. 01i,29mar99,dat  SPR 26119, documentation, usage of .bS/.bE
  19. 01h,30sep98,dbt  Adding missing code in poll receive routine.
  20. 01g,22sep98,dat  SPR 22325, System mode transition.
  21. 01f,14may98,jgn  disable RX stop interrupts, tidy comments (SPR #21202)
  22. 01e,13may98,jgn  fixed driver lock up on PID (SPR #21202)
  23. 01d,11may98,jpd  fixed incorrect parameters in strtok_r calls (SPR #21192).
  24. 01c,09apr98,jpd  made conditionally-compilable version for Brutus or PID.
  25.  fixed fault in iOlicomRxIntHandle().
  26. 01b,24mar98,jpd  modified to work on Brutus, but not yet on both Brutus and PID.
  27. 01a,16dec97,rlp  modified if_oli.c to END style
  28. */
  29. /*
  30. This module implements the Olicom (Intel 82595TX) network interface
  31. driver.  The physical device is a PCMCIA card.  This driver also houses
  32. code to manage a Vadem PCMCIA Interface controller on the ARM PID
  33. board, which is strictly a subsystem in it's own right.
  34. This network interface driver does not include support for trailer protocols
  35. or data chaining.  However, buffer loaning has been implemented in an effort to
  36. boost performance.
  37. BOARD LAYOUT
  38. The device resides on a PCMCIA card and is soft configured.
  39. No jumpering diagram is necessary.
  40. EXTERNAL INTERFACE
  41. This driver provides the END external interface with the following
  42. exceptions.  The only external interface is the iOlicomEndLoad() routine.
  43. All of the paramters are passed as strings in a colon (:) separated list
  44. to the load function as an initString.  The iOlicomEndLoad() function uses
  45. strtok() to parse the string.
  46. The string contains the target specific parameters like this:
  47.  "<io_baseA>:<attr_baseA>:<mem_baseA>:<io_baseB>:<attr_baseB>:<mem_baseB>: 
  48.   <ctrl_base>:<intVectA>:<intLevelA>:<intVectB>:<intLevelB>: 
  49.   <txBdNum>:<rxBdNum>:<pShMem>:<shMemSize>"
  50. TARGET-SPECIFIC PARAMETERS
  51. .iP "I/O base address A"
  52. This is the first parameter passed to the driver init string. This
  53. parameter indicates the base address of the PCMCIA I/O space for socket
  54. A.
  55. .iP "Attribute base address A"
  56. This is the second parameter passed to the driver init string. This
  57. parameter indicates the base address of the PCMCIA attribute space for
  58. socket A. On the PID board, this should be the offset of the beginning
  59. of the attribute space from the beginning of the memory space.
  60. .iP "Memory base address A"
  61. This is the third parameter passed to the driver init string. This
  62. parameter indicates the base address of the PCMCIA memory space for
  63. socket A.
  64. .iP "I/O base address B"
  65. This is the fourth parameter passed to the driver init string. This
  66. parameter indicates the base address of the PCMCIA I/O space for socket
  67. B.
  68. .iP "Attribute base address B"
  69. This is the fifth parameter passed to the driver init string. This
  70. parameter indicates the base address of the PCMCIA attribute space for
  71. socket B. On the PID board, this should be the offset of the beginning
  72. of the attribute space from the beginning of the memory space.
  73. .iP "Memory base address B"
  74. This is the sixth parameter passed to the driver init string. This
  75. parameter indicates the base address of the PCMCIA memory space for
  76. socket B.
  77. .iP "PCMCIA controller base address"
  78. This is the seventh parameter passed to the driver init string. This
  79. parameter indicates the base address of the Vadem PCMCIA controller.
  80. .iP "interrupt vectors and levels"
  81. These are the eighth, ninth, tenth and eleventh parameters passed to the
  82. driver init string.
  83. The mapping of IRQs generated at the Card/PCMCIA level to interrupt
  84. levels and vectors is system dependent. Furthermore the slot holding
  85. the PCMCIA card is not initially known. The interrupt levels and
  86. vectors for both socket A and socket B must be passed to
  87. iOlicomEndLoad(), allowing the driver to select the required parameters
  88. later.
  89. .iP "number of transmit and receive buffer descriptors"
  90. These are the twelfth and thirteenth parameters passed to the driver
  91. init string.
  92. The number of transmit and receive buffer descriptors (BDs) used is
  93. configurable by the user upon attaching the driver. There must be a
  94. minimum of two transmit and two receive BDs, and there is a maximum of
  95. twenty transmit and twenty receive BDs.  If this parameter is "NULL" a
  96. default value of 16 BDs will be used.
  97. .iP "offset"
  98. This is the fourteenth parameter passed to the driver in the init string.
  99. This parameter defines the offset which is used to solve alignment problem.
  100. .iP "base address of buffer pool"
  101. This is the fifteenth parameter passed to the driver in the init string.
  102. This parameter is used to notify the driver that space for the transmit
  103. and receive buffers need not be allocated, but should be taken from a
  104. private memory space provided by the user at the given address.  The
  105. user should be aware that memory used for buffers must be 4-byte
  106. aligned but need not be non-cacheable. If this parameter is "NONE",
  107. space for buffers will be obtained by calling malloc() in
  108. iOlicomEndLoad().
  109. .iP "mem size of buffer pool"
  110. This is the sixteenth parameter passed to the driver in the init string.
  111. The memory size parameter specifies the size of the pre-allocated memory
  112. region. If memory base is specified as NONE (-1), the driver ignores this
  113. parameter.
  114. .iP "Ethernet address"
  115. This parameter is obtained from the Card Information Structure on the
  116. Olicom PCMCIA card.
  117. .LP
  118. EXTERNAL SUPPORT REQUIREMENTS
  119. This driver requires three external support function:
  120. .iP "void sysLanIntEnable (int level)" "" 9 -1
  121. This routine provides a target-specific interface for enabling Ethernet
  122. device interrupts at a specified interrupt level.  This routine is
  123. called each time that the iOlicomStart() routine is called.
  124. .iP "void sysLanIntDisable (int level)" "" 9 -1
  125. This routine provides a target-specific interface for disabling
  126. Ethernet device interrupts.  The driver calls this routine from the
  127. iOlicomStop() routine each time a unit is disabled.
  128. .iP "void sysBusIntAck(void)" "" 9 -1
  129. This routine acknowledge the interrupt if it's necessary.
  130. .LP
  131. SEE ALSO: muxLib, endLib
  132. .I "Intel 82595TX ISA/PCMCIA High Integration Ethernet Controller User Manual,"
  133. .I "Vadem VG-468 PC Card Socket Controller Data Manual."
  134. */
  135. /* includes */
  136. #include "vxWorks.h"
  137. #include "iv.h"
  138. #include "taskLib.h"
  139. #include "memLib.h"
  140. #include "errno.h"
  141. #include "errnoLib.h"
  142. #include "intLib.h"
  143. #include "cacheLib.h"
  144. #include "netLib.h"
  145. #include "stdio.h"
  146. #include "stdlib.h"
  147. #include "logLib.h"
  148. #include "sysLib.h"
  149. #include "net/if.h"
  150. #include "netinet/if_ether.h"
  151. #include "drv/end/iOlicomEnd.h" /* Common defines. */
  152. #include "etherMultiLib.h" /* multicast stuff. */
  153. #include "end.h" /* Common END structures. */
  154. #include "endLib.h"
  155. #include "lstLib.h" /* Needed to maintain protocol list. */
  156. /* defines */
  157. #define RX_BD_SIZ sizeof(RX_BD)
  158. #define TX_BD_SIZ sizeof(TX_BD)
  159. #define LOG_MSG(X0, X1, X2, X3, X4, X5, X6)
  160. {
  161.     if (_func_logMsg != NULL)
  162. _func_logMsg(X0, X1, X2, X3, X4, X5, X6);
  163. }
  164. #undef DEBUG
  165. #ifdef  DEBUG
  166. #define LOCAL
  167. #define END_DEBUG_OFF           0x0000
  168. #define END_DEBUG_RX            0x0001
  169. #define END_DEBUG_TX            0x0002
  170. #define END_DEBUG_INT           0x0004
  171. #define END_DEBUG_POLL          (END_DEBUG_POLL_RX | END_DEBUG_POLL_TX)
  172. #define END_DEBUG_POLL_RX       0x0008
  173. #define END_DEBUG_POLL_TX       0x0010
  174. #define END_DEBUG_LOAD          0x0020
  175. #define END_DEBUG_IOCTL         0x0040
  176. #define END_DEBUG_ADDR 0x0080
  177. #define END_DEBUG_ALL_FUNCS     0x0100
  178. #define END_DEBUG_LOAD_FAIL 0x0200
  179. #define END_DEBUG_POLL_REDIR    0x10000
  180. #define END_DEBUG_LOG_NVRAM     0x20000
  181. #define END_DEBUG_TUPLES 0x40000
  182. int     oliDebug = END_DEBUG_LOAD_FAIL;
  183. #define END_LOG_MSG(FLG, X0, X1, X2, X3, X4, X5, X6)    
  184.         if (oliDebug & FLG)                             
  185.             LOG_MSG(X0, X1, X2, X3, X4, X5, X6);
  186. #else /* DEBUG */
  187. #define END_LOG_MSG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
  188. #endif /* DEBUG */
  189. /*
  190.  * Default macro definitions for BSP interface.
  191.  * These macros can be redefined in a wrapper file, to generate
  192.  * a new module with an optimized interface.
  193.  */
  194. #ifndef SYS_INT_CONNECT
  195. #define SYS_INT_CONNECT(pDrvCtrl,rtn,arg,pResult) 
  196.     { 
  197.     IMPORT STATUS intConnect(); 
  198.     *pResult = intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (pDrvCtrl->ivec), 
  199.      rtn, (int)arg); 
  200.     }
  201. #endif /*SYS_INT_CONNECT*/
  202. #ifndef SYS_INT_DISCONNECT
  203. #define SYS_INT_DISCONNECT(pDrvCtrl,rtn,arg,pResult) 
  204.     { 
  205.     *pResult = OK; /* HELP: need a real routine */ 
  206.     }
  207. #endif /*SYS_INT_DISCONNECT*/
  208. #ifndef SYS_INT_ENABLE
  209. #define SYS_INT_ENABLE(pDrvCtrl) 
  210.     { 
  211.     IMPORT STATUS sysLanIntEnable(); 
  212.     sysLanIntEnable (pDrvCtrl->ilevel); 
  213.     }
  214. #endif /*SYS_INT_ENABLE*/
  215. #ifndef SYS_INT_DISABLE
  216. #define SYS_INT_DISABLE(pDrvCtrl) 
  217.     { 
  218.     IMPORT STATUS sysLanIntDisable(); 
  219.     sysLanIntDisable (pDrvCtrl->ilevel); 
  220.     }
  221. #endif /*SYS_INT_DISABLE*/
  222. #ifndef SYS_BUS_INT_ACK
  223. #define SYS_BUS_INT_ACK(pDrvCtrl) 
  224.     { 
  225.     IMPORT int sysBusIntAck(); 
  226.     sysBusIntAck (pDrvCtrl->ilevel); 
  227.     }
  228. #endif /*SYS_BUS_INT_ACK*/
  229. /* A shortcut for getting the hardware address from the MIB II stuff. */
  230. #define END_HADDR(pEnd)
  231. ((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
  232. #define END_HADDR_LEN(pEnd) 
  233. ((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
  234. #ifndef PCMCIA_NO_VADEM
  235. /* Vadem access macros */
  236. #ifndef OLI_VADEM_READ
  237. #define OLI_VADEM_READ(index) 
  238. iOlicomVademRead(pDrvCtrl->pcmcia.ctrlBase, index)
  239. #endif /* OLI_VADEM_READ */
  240. #ifndef OLI_VADEM_WRITE
  241. #define OLI_VADEM_WRITE(index,val) 
  242. iOlicomVademWrite(pDrvCtrl->pcmcia.ctrlBase, index, val)
  243. #endif /* OLI_VADEM_WRITE */
  244. #ifndef OLI_VADEM_UNLOCK
  245. #define OLI_VADEM_UNLOCK() 
  246. iOlicomVademUnlock(pDrvCtrl->pcmcia.ctrlBase)
  247. #endif /* OLI_VADEM_UNLOCK */
  248. #endif /* !PCMCIA_NO_VADEM */
  249. /* END_DEVICE flags access macros */
  250. #define DRV_FLAGS_SET(setBits)
  251.         (pDrvCtrl->flags |= (setBits))
  252. #define DRV_FLAGS_ISSET(setBits)
  253.         (pDrvCtrl->flags & (setBits))
  254. #define DRV_FLAGS_CLR(clrBits)
  255.         (pDrvCtrl->flags &= ~(clrBits))
  256. #define DRV_FLAGS_GET()
  257.         (pDrvCtrl->flags)
  258. #define NET_BUF_ALLOC()
  259.     netClusterGet (pDrvCtrl->endObj.pNetPool, pDrvCtrl->clPoolId)
  260. #define NET_BUF_FREE(pBuf)
  261.     netClFree (pDrvCtrl->endObj.pNetPool, (UINT8 *)pBuf)
  262. #define NET_MBLK_ALLOC()
  263.     mBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT, MT_DATA)
  264. #define NET_MBLK_FREE(pMblk)
  265.     netMblkFree (pDrvCtrl->endObj.pNetPool, (M_BLK_ID)pMblk)
  266. #define NET_CL_BLK_ALLOC()
  267.     clBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT)
  268. #define NET_CL_BLK_FREE(pClblk)
  269.     clBlkFree (pDrvCtrl->endObj.pNetPool, (CL_BLK_ID)pClBlk)
  270. #define NET_MBLK_BUF_FREE(pMblk)
  271.     netMblkClFree ((M_BLK_ID)pMblk)
  272. #define NET_MBLK_CHAIN_FREE(pMblk)
  273.     {
  274.     M_BLK *pNext;
  275.     pNext=pMblk;
  276.     while (pNext)
  277.         pNext=NET_MBLK_BUF_FREE (pNext);
  278.     }
  279. #define NET_MBLK_CL_JOIN(pMblk, pClBlk)
  280.     netMblkClJoin ((pMblk), (pClBlk))
  281. #define NET_CL_BLK_JOIN(pClBlk, pBuf, len)
  282.     netClBlkJoin ((pClBlk), (pBuf), (len), NULL, 0, 0, 0)
  283. /* globals */
  284. #ifdef DEBUG
  285.     END_DEVICE * pDbgDrvCtrl;
  286. #endif
  287. /* local */
  288. /* forward static functions */
  289. LOCAL void iOlicomReset (END_DEVICE * pDrvCtrl);
  290. LOCAL void iOlicomInt (END_DEVICE * pDrvCtrl);
  291. LOCAL void iOlicomRxIntHandle (END_DEVICE * pDrvCtrl);
  292. LOCAL STATUS iOlicomRecv (END_DEVICE * pDrvCtrl, RX_BD * pData);
  293. LOCAL void iOlicomConfig (END_DEVICE * pDrvCtrl);
  294. LOCAL STATUS iOlicomAddrFilterSet (END_DEVICE * pDrvCtrl);
  295. LOCAL STATUS iOlicomInit (END_DEVICE * pDrvCtrl);
  296. LOCAL void iOlicomTxBdQueueClean (END_DEVICE * pDrvCtrl);
  297. LOCAL void iOlicomTxStart (END_DEVICE * pDrvCtrl);
  298. LOCAL void iOlicomTxRestart (END_DEVICE * pDrvCtrl);
  299. LOCAL RX_BD * iOlicomPacketGet (END_DEVICE * pDrvCtrl);
  300. LOCAL TX_BD * iOlicomTxBdGet (END_DEVICE * pDrvCtrl);
  301. LOCAL STATUS iOlicomPcmciaSetup (END_DEVICE * pDrvCtrl);
  302. LOCAL void iOlicomInitialiseSlot (END_DEVICE * pDrvCtrl, UINT socket);
  303. LOCAL void iOlicomShutdownSlot (END_DEVICE * pDrvCtrl, UINT socket);
  304. LOCAL UINT iOlicomPcmciaReadTuple (END_DEVICE * pDrvCtrl, UINT offset,
  305. UCHAR * buffer, UINT buflen);
  306. LOCAL UCHAR * iOlicomPcmciaFindTuple (END_DEVICE * pDrvCtrl, UINT tuple,
  307. UINT * offset, UCHAR * buffer, UINT buflen);
  308. LOCAL STATUS iOlicomReadCardAttributes (END_DEVICE * pDrvCtrl);
  309. LOCAL STATUS iOlicomCardInsertion (END_DEVICE * pDrvCtrl, UINT socket);
  310. LOCAL STATUS iOlicomInitialiseCard (END_DEVICE * pDrvCtrl);
  311. LOCAL STATUS iOlicomMapIOSpace (END_DEVICE * pDrvCtrl, UINT base, UINT range,
  312. int mapirq);
  313. #ifndef PCMCIA_NO_VADEM
  314. LOCAL void iOlicomMapMemory (END_DEVICE * pDrvCtrl, UINT socket,
  315. UINT window, UINT base, UINT range, UINT offset,
  316. MEMTYPE type);
  317. LOCAL UINT iOlicomVademRead (char * ctrlBase, UINT index);
  318. LOCAL void iOlicomVademWrite (char * ctrlBase, UINT index, UINT  value);
  319. LOCAL void iOlicomVademUnlock (char * ctrlBase);
  320. #endif /* !PCMCIA_NO_VADEM */
  321. /* END Specific interfaces. */
  322. /* These are the only externally visible interfaces. */
  323. END_OBJ *  iOlicomEndLoad (char * initString);
  324. void iOlicomIntHandle (END_DEVICE * pDrvCtrl);
  325. LOCAL STATUS iOlicomStart (END_DEVICE * pDrvCtrl);
  326. LOCAL STATUS iOlicomStop (END_DEVICE * pDrvCtrl);
  327. LOCAL STATUS iOlicomUnload ();
  328. LOCAL int iOlicomIoctl (END_DEVICE * pDrvCtrl, int cmd, char * data);
  329. LOCAL STATUS iOlicomSend (END_DEVICE * pDrvCtrl, M_BLK * pMblk);
  330. LOCAL STATUS iOlicomMCastAddrAdd (END_DEVICE * pDrvCtrl, char * pAddress);
  331. LOCAL STATUS iOlicomMCastAddrDel (END_DEVICE * pDrvCtrl, char * pAddress);
  332. LOCAL STATUS iOlicomMCastAddrGet (END_DEVICE * pDrvCtrl,
  333.     MULTI_TABLE * pTable);
  334. LOCAL STATUS iOlicomPollSend (END_DEVICE * pDrvCtrl, M_BLK * pMblk);
  335. LOCAL STATUS iOlicomPollReceive (END_DEVICE * pDrvCtrl, M_BLK * pMblk);
  336. LOCAL STATUS iOlicomPollStart (END_DEVICE * pDrvCtrl);
  337. LOCAL STATUS iOlicomPollStop (END_DEVICE * pDrvCtrl);
  338. LOCAL STATUS iOlicomInitParse ();
  339. LOCAL STATUS iOlicomInitMem ();
  340. /*
  341.  * Declare our function table.  This is static across all driver
  342.  * instances.
  343.  */
  344. LOCAL NET_FUNCS iOlicomFuncTable =
  345.     {
  346.     (FUNCPTR) iOlicomStart, /* Function to start the device. */
  347.     (FUNCPTR) iOlicomStop, /* Function to stop the device. */
  348.     (FUNCPTR) iOlicomUnload, /* Unloading function for the driver. */
  349.     (FUNCPTR) iOlicomIoctl, /* Ioctl function for the driver. */
  350.     (FUNCPTR) iOlicomSend, /* Send function for the driver. */
  351.     (FUNCPTR) iOlicomMCastAddrAdd, /* Multicast address add fn for driver */
  352.     (FUNCPTR) iOlicomMCastAddrDel, /* Multicast address delete fn for driver. */
  353.     (FUNCPTR) iOlicomMCastAddrGet, /* Multicast table retrieve fn for driver. */
  354.     (FUNCPTR) iOlicomPollSend,    /* Polling send function for driver. */
  355.     (FUNCPTR) iOlicomPollReceive,  /* Polling receive function for driver. */
  356.     endEtherAddressForm,/* put address info into a NET_BUFFER */
  357.     endEtherPacketDataGet, /* get pointer to data in NET_BUFFER */
  358.     endEtherPacketAddrGet  /* Get packet addresses. */
  359.     };
  360. /*******************************************************************************
  361. *
  362. * iOlicomEndLoad - initialize the driver and device
  363. *
  364. * This routine initializes the driver and the device to the operational state.
  365. * All of the device specific parameters are passed in the initString.
  366. *
  367. * This routine can be called in two modes. If it is called with an empty, but
  368. * allocated string then it places the name of this device (i.e. oli) into the
  369. * initString and returns 0.
  370. *
  371. * If the string is allocated then the routine attempts to perform its load
  372. * functionality.
  373. *
  374. * RETURNS: An END object pointer or NULL on error or 0 and the name of the
  375. * device if the initString was NULL.
  376. */
  377. END_OBJ * iOlicomEndLoad
  378.     (
  379.     char * initString /* String to be parsed by the driver. */
  380.     )
  381.     {
  382.     END_DEVICE * pDrvCtrl;
  383.     END_LOG_MSG (END_DEBUG_LOAD, "Loading oli...n", 0, 0, 0, 0, 0, 0);
  384.     if (initString == NULL)
  385. {
  386. END_LOG_MSG (END_DEBUG_LOAD_FAIL, "initString was nulln",
  387.      0, 0, 0, 0, 0, 0);
  388.         return (NULL);
  389. }
  390.     if (initString[0] == EOS)
  391.         {
  392.         memcpy(initString, (char *)DRV_NAME, DRV_NAME_LEN);
  393. END_LOG_MSG (END_DEBUG_LOAD_FAIL, "initString[0] was nulln",
  394.      0, 0, 0, 0, 0, 0);
  395.         return (0);
  396.         }
  397.     /* allocate the device structure */
  398.     pDrvCtrl = (END_DEVICE *)calloc (sizeof (END_DEVICE), 1);
  399.     if (pDrvCtrl == NULL)
  400. {
  401.         END_LOG_MSG (END_DEBUG_LOAD_FAIL,
  402. "%s%d - Failed to allocate control structuren",
  403.                         DRV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  404. return (NULL);
  405. }
  406. #ifdef DEBUG
  407.     pDbgDrvCtrl = pDrvCtrl;
  408. #endif
  409.     /* parse the init string, filling in the device structure */
  410.     if (iOlicomInitParse (pDrvCtrl, initString) == ERROR)
  411. {
  412.         END_LOG_MSG (END_DEBUG_LOAD_FAIL,
  413.                 "%s%d - Failed to parse initialization parametersn",
  414.                         DRV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  415. goto errorExit;
  416. }
  417.     /* Sanity check on the unit number */
  418.     if (pDrvCtrl->unit < 0)
  419. {
  420. END_LOG_MSG (END_DEBUG_LOAD_FAIL, "unit number < 0n",
  421.      0, 0, 0, 0, 0, 0);
  422.         goto errorExit;
  423. }
  424.     /* Check if we are already attached */
  425.     if (pDrvCtrl->endObj.attached == TRUE)
  426. {
  427.         END_LOG_MSG (END_DEBUG_LOAD_FAIL, "%s - Already attachedn",
  428.                         DRV_NAME, 0, 0, 0, 0, 0);
  429.         goto errorExit;
  430. }
  431.     /* endObject Initializations */
  432.     if (END_OBJ_INIT (&pDrvCtrl->endObj, (DEV_OBJ*)pDrvCtrl, DRV_NAME,
  433.                       pDrvCtrl->unit, &iOlicomFuncTable,
  434.                       "olicom Enhanced Network Driver") == ERROR)
  435.         {
  436.         END_LOG_MSG (END_DEBUG_LOAD_FAIL,
  437.                 "%s%d - Failed to initialize END objectn",
  438.                         DRV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  439.         goto errorExit;
  440.         }
  441.     /*
  442.      * Initialise the PCMCIA side of things. I'm assuming here we have
  443.      * complete control over the PCMCIA system, this shouldn't really
  444.      * be done here, rather the whole job should be handled by a
  445.      * separate PCMCIA sub-system module.
  446.      * If there is an Olicom card in one of the slots, this will
  447.      * return TRUE. If no card is found then I just return an error
  448.      * and this attach() call will fail. A better implementation might
  449.      * just mark the interface as down, bringing it up when a card
  450.      * insertion is detected. This will suffice for a first pass though.
  451.      */
  452.     if (iOlicomPcmciaSetup(pDrvCtrl) != OK)
  453. {
  454.         END_LOG_MSG (END_DEBUG_LOAD_FAIL,
  455.                 "%s%d - Failed to initialize the PCMCIA siden",
  456.                         DRV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  457.         goto errorExit;
  458. }
  459.     /* Initialize MIB-II entries */
  460.     if (END_MIB_INIT (&pDrvCtrl->endObj, M2_ifType_ethernet_csmacd,
  461.                       (UINT8*) pDrvCtrl->enetAddr, EADDR_LEN,
  462.                        ETHERMTU, OLI_SPEED) == ERROR)
  463.         {
  464.         END_LOG_MSG (END_DEBUG_LOAD_FAIL,
  465.                 "%s%d - MIB-II initializations failedn",
  466.                         DRV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  467.         goto errorExit;
  468.         }
  469.     /* Perform memory allocation/distribution */
  470.     if (iOlicomInitMem (pDrvCtrl) == ERROR)
  471. {
  472. END_LOG_MSG (END_DEBUG_LOAD_FAIL, "initMem() failedn",
  473.      0, 0, 0, 0, 0, 0);
  474. goto errorExit;
  475. }
  476.     /* set the flags to indicate readiness */
  477.     END_OBJ_READY (&pDrvCtrl->endObj,
  478. IFF_NOTRAILERS | IFF_MULTICAST | IFF_BROADCAST);
  479.     END_LOG_MSG (END_DEBUG_LOAD, "Done loading oli...", 0, 0, 0, 0, 0, 0);
  480.     /* Successful return */
  481.     return (&pDrvCtrl->endObj);
  482.     /***** Handle error cases *****/
  483. errorExit:
  484.         {
  485.         iOlicomUnload (pDrvCtrl);
  486. taskDelay(120);
  487.         return (NULL);
  488.         }
  489.     }
  490. /*******************************************************************************
  491. *
  492. * iOlicomInitParse - parse the init string
  493. *
  494. * Parse the input string.  Fill in values in the driver control structure.
  495. *
  496. * The initialization string format is:
  497. * .CS
  498. *  "<nisa_base>:<nisa_pcmcia>:<nisa_pcmem>:<intVectA>:<intLevelA>:      
  499. *   <intVectB>:<intLevelB>:<txBdNum>:<rxBdNum>:<offset>:<pShMem>:<shMemSize>"
  500. * .CE
  501. *
  502. * .IP <nisa_base>
  503. * Base of NISA space
  504. * .IP <ctrlBase>
  505. * Base address of Vadem chip
  506. * .IP <nisa_pcmem>
  507. * Base address of mapped memory space
  508. * .IP <intVectA>
  509. * Interrupt vector for slot A
  510. * .IP <intLevelA>
  511. * Interrupt level for slot A
  512. * .IP <intVectB>
  513. * Interrupt vector for card B
  514. * .IP <intLevelB>
  515. * Interrupt level for card B
  516. * .IP <txBdNum>
  517. * number of transmit buffer descriptors; NULL = default
  518. * .IP <rxBdNum>
  519. * number of receive buffer descriptors; NULL = default
  520. * .IP <offset>
  521. * Memory offset for alignment.
  522. * .IP <pShMem>
  523. * Address of memory pool; NONE = malloc it
  524. * .IP <shMemSize>
  525. * memory pool size
  526. * .LP
  527. *
  528. * RETURNS: OK or ERROR for invalid arguments.
  529. */
  530. LOCAL STATUS iOlicomInitParse
  531.     (
  532.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  533.     char * initString /* init string */
  534.     )
  535.     {
  536.     char * tok;
  537.     char * holder = NULL;
  538.     /* Parse the initString */
  539.     /* Unit number. */
  540.     tok = strtok_r (initString, ":", &holder);
  541.     if (tok == NULL)
  542. return ERROR;
  543.     pDrvCtrl->unit = atoi (tok);
  544.     /* Base address of I/O space for card A. */
  545.     tok = strtok_r (NULL, ":", &holder);
  546.     if (tok == NULL)
  547. return ERROR;
  548.     pDrvCtrl->pcmcia.ioBaseA = (char *) strtoul (tok, NULL, 16);
  549.     /* Base address of Attribute Memory space for card A. */
  550.     tok = strtok_r (NULL, ":", &holder);
  551.     if (tok == NULL)
  552. return ERROR;
  553.     pDrvCtrl->pcmcia.attrBaseA = (char *) strtoul (tok, NULL, 16);
  554.     /* Base address of Common memory space for card A. */
  555.     tok = strtok_r (NULL, ":", &holder);
  556.     if (tok == NULL)
  557. return ERROR;
  558.     pDrvCtrl->pcmcia.memBaseA = (char *) strtoul (tok, NULL, 16);
  559.     /* Base address of I/O space for card B. */
  560.     tok = strtok_r (NULL, ":", &holder);
  561.     if (tok == NULL)
  562. return ERROR;
  563.     pDrvCtrl->pcmcia.ioBaseB = (char *) strtoul (tok, NULL, 16);
  564.     /* Base address of Attribute Memory space for card B. */
  565.     tok = strtok_r (NULL, ":", &holder);
  566.     if (tok == NULL)
  567. return ERROR;
  568.     pDrvCtrl->pcmcia.attrBaseB = (char *) strtoul (tok, NULL, 16);
  569.     /* Base address of Common memory space for card B. */
  570.     tok = strtok_r (NULL, ":", &holder);
  571.     if (tok == NULL)
  572. return ERROR;
  573.     pDrvCtrl->pcmcia.memBaseB = (char *) strtoul (tok, NULL, 16);
  574.     /* Base of Vadem controller */
  575.     tok = strtok_r (NULL, ":", &holder);
  576.     if (tok == NULL)
  577. return ERROR;
  578.     pDrvCtrl->pcmcia.ctrlBase = (char *) strtoul (tok, NULL, 16);
  579.     /* Interrupt vector for slot A. */
  580.     tok = strtok_r (NULL, ":", &holder);
  581.     if (tok == NULL)
  582. return ERROR;
  583.     pDrvCtrl->pcmcia.intVectA = strtoul (tok, NULL, 16);
  584.     /* Interrupt level for slot A. */
  585.     tok = strtok_r (NULL, ":", &holder);
  586.     if (tok == NULL)
  587. return ERROR;
  588.     pDrvCtrl->pcmcia.intLevelA = strtoul (tok, NULL, 16);
  589.     /* Interrupt vector for slot B. */
  590.     tok = strtok_r (NULL, ":", &holder);
  591.     if (tok == NULL)
  592. return ERROR;
  593.     pDrvCtrl->pcmcia.intVectB = strtoul (tok, NULL, 16);
  594.     /* Interrupt level for slot B. */
  595.     tok = strtok_r (NULL, ":", &holder);
  596.     if (tok == NULL)
  597. return ERROR;
  598.     pDrvCtrl->pcmcia.intLevelB = strtoul (tok, NULL, 16);
  599.     /* number of transmit buf descriptors */
  600.     tok = strtok_r(NULL, ":", &holder);
  601.     if (tok == NULL)
  602.         return ERROR;
  603.     pDrvCtrl->txBdNum = strtoul (tok, NULL, 16);
  604.     /* number of receive buf descriptors */
  605.     tok = strtok_r(NULL, ":", &holder);
  606.     if (tok == NULL)
  607.         return ERROR;
  608.     pDrvCtrl->rxBdNum = strtoul (tok, NULL, 16);
  609.     /* Caller supplied alignment offset. */
  610.     tok = strtok_r (NULL, ":", &holder);
  611.     if (tok == NULL)
  612.         return ERROR;
  613.     pDrvCtrl->offset = atoi (tok);
  614.     /* Address of memory pool. */
  615.     tok = strtok_r (NULL, ":", &holder);
  616.     if (tok == NULL)
  617. return ERROR;
  618.     pDrvCtrl->pShMem = (char *) strtoul (tok, NULL, 16);
  619.     /* memory pool size. */
  620.     tok = strtok_r (NULL, ":", &holder);
  621.     if (tok == NULL)
  622. return ERROR;
  623.     pDrvCtrl->shMemSize = strtoul (tok, NULL, 16);
  624.     END_LOG_MSG (END_DEBUG_LOAD,
  625.             "EndLoad: unit=%d pShMem=0x%X shMemSize=0x%X ctrlBase=0x%Xn",
  626.     pDrvCtrl->unit, pDrvCtrl->pShMem, pDrvCtrl->shMemSize,
  627.     pDrvCtrl->pcmcia.ctrlBase, 0, 0);
  628.     END_LOG_MSG (END_DEBUG_LOAD,
  629.             "ioBaseA=0x%X attrBaseA=0x%X memBaseA=0x%Xn"
  630.             "ioBaseB=0x%X attrBaseB=0x%X memBaseB=0x%Xn",
  631.      (int)pDrvCtrl->pcmcia.ioBaseA, (int)pDrvCtrl->pcmcia.attrBaseA,
  632.      (int)pDrvCtrl->pcmcia.memBaseA, (int)pDrvCtrl->pcmcia.ioBaseB,
  633.      (int)pDrvCtrl->pcmcia.attrBaseB, (int)pDrvCtrl->pcmcia.memBaseB);
  634.     END_LOG_MSG (END_DEBUG_LOAD,
  635.              "intLevelA=%#x intLevelB %#x txBdNum %#x rxBdNum %#x offset=%#xn",
  636.       pDrvCtrl->pcmcia.intLevelA, pDrvCtrl->pcmcia.intLevelB,
  637.       pDrvCtrl->txBdNum, pDrvCtrl->rxBdNum, pDrvCtrl->offset, 0);
  638.     END_LOG_MSG (END_DEBUG_LOAD, "Processed all argumentsn", 0, 0, 0, 0, 0, 0);
  639.     return (OK);
  640.     }
  641. /*******************************************************************************
  642. *
  643. * iOlicomInitMem - initialize memory for the chip
  644. *
  645. * Using data in the control structure, setup and initialize the memory
  646. * areas needed.  If the memory address is not already specified, then allocate
  647. * memory.
  648. *
  649. * RETURNS: OK or ERROR.
  650. */
  651. LOCAL STATUS iOlicomInitMem
  652.     (
  653.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  654.     )
  655.     {
  656.     M_CL_CONFIG oliMclBlkConfig;
  657.     CL_DESC     clDesc;                      /* cluster description */
  658.     void *      pBuf;
  659.     void *      pMemBase;
  660.     int         ix;
  661.     ULONG size;
  662.     /* Use default number of buffer descriptors if user did not specify */
  663.     if (pDrvCtrl->txBdNum == 0)
  664.         pDrvCtrl->txBdNum = TX_BD_DEFAULT;
  665.     if (pDrvCtrl->rxBdNum == 0)
  666.         pDrvCtrl->rxBdNum = RX_BD_DEFAULT;
  667.     /* must be at least two transmit and receive buffer descriptors */
  668.     pDrvCtrl->txBdNum = max (TX_BD_MIN, pDrvCtrl->txBdNum);
  669.     pDrvCtrl->rxBdNum = max (RX_BD_MIN, pDrvCtrl->rxBdNum);
  670.     /* Establish a region of memory.
  671.      *
  672.      * OK. We now know how much shared memory we need.  If the caller
  673.      * provides a specific memory region, we check to see if the provided
  674.      * region is large enough for our needs.  If the caller did not
  675.      * provide a specific region, then we attempt to allocate the memory
  676.      * from the system.
  677.      */
  678.     if ((int) pDrvCtrl->pShMem != NONE)
  679. {
  680. /* caller provided memory */
  681. size = ((pDrvCtrl->rxBdNum * (OLI_BUFSIZ + RX_BD_SIZ + 8)) + 4 +
  682. (pDrvCtrl->txBdNum * (OLI_BUFSIZ + TX_BD_SIZ + 8)) + 4 +
  683. (NUM_LOAN * (OLI_BUFSIZ + 8)) + 4);
  684. if (pDrvCtrl->shMemSize < size ) /* not enough space */
  685.     {
  686.     END_LOG_MSG (END_DEBUG_LOAD, "%s%d - not enough memory providedn",
  687. DRV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  688.             return ( ERROR );
  689.             }
  690. pMemBase = pDrvCtrl->pShMem; /* set the beginning of pool */
  691.         /* copy null structure */
  692.         pDrvCtrl->cacheFuncs = cacheNullFuncs;
  693. }
  694.     else
  695.         {
  696. size = (((pDrvCtrl->rxBdNum + 1) * RX_BD_SIZ) +
  697. ((pDrvCtrl->txBdNum + 1) * TX_BD_SIZ));
  698.         /* We must allocate memory for buffer descriptors */
  699. pDrvCtrl->pShMem =
  700. pMemBase = (char *) malloc (size);
  701. if (pMemBase == NULL)
  702.     {
  703.             END_LOG_MSG (END_DEBUG_LOAD, "%s%d - system memory unavailablen",
  704.                         DRV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  705.     return (ERROR);
  706.     }
  707. pDrvCtrl->shMemSize = size;
  708.         /* copy the DMA structure */
  709.         pDrvCtrl->cacheFuncs = cacheNullFuncs;
  710. /* Trasmit and receive descriptors allocated by driver */
  711. DRV_FLAGS_SET(OLI_MEMOWN);
  712.         }
  713.     /* zero the shared memory */
  714.     memset (pMemBase, 0, (int) size);
  715.     /* carve Tx memory structure */
  716.     pDrvCtrl->txBdBase = (TX_BD *) pDrvCtrl->pShMem;
  717.     /* carve Rx memory structure */
  718.     pDrvCtrl->rxBdBase = (RX_BD *) (pDrvCtrl->txBdBase + pDrvCtrl->txBdNum);
  719.     /* Initialize net buffer pool for tx/rx buffers */
  720.     memset ((char *)&oliMclBlkConfig, 0, sizeof(oliMclBlkConfig));
  721.     memset ((char *)&clDesc, 0, sizeof(clDesc));
  722.     oliMclBlkConfig.mBlkNum  = pDrvCtrl->rxBdNum * 4;
  723.     clDesc.clNum            = pDrvCtrl->rxBdNum + pDrvCtrl->txBdNum + NUM_LOAN;
  724.     oliMclBlkConfig.clBlkNum = clDesc.clNum;
  725.     /*
  726.      * mBlk and cluster configuration memory size initialization
  727.      * memory size adjusted to hold the netPool pointer at the head.
  728.      */
  729.     oliMclBlkConfig.memSize = ((oliMclBlkConfig.mBlkNum *
  730.                                (MSIZE + sizeof (long))) +
  731.                               (oliMclBlkConfig.clBlkNum *
  732.                                (CL_BLK_SZ + sizeof (long))));
  733.     if ((oliMclBlkConfig.memArea = (char *)memalign(sizeof (long),
  734. oliMclBlkConfig.memSize)) == NULL)
  735.         return (ERROR);
  736.     clDesc.clSize       = OLI_BUFSIZ;
  737.     clDesc.memSize      = ((clDesc.clNum * (clDesc.clSize + 4)) + 4);
  738.     if (DRV_FLAGS_ISSET(OLI_MEMOWN))
  739.         {
  740.         clDesc.memArea = malloc (clDesc.memSize);
  741.         if (clDesc.memArea == NULL)
  742.             {
  743.             END_LOG_MSG (END_DEBUG_LOAD, "%s%d - system memory unavailablen",
  744.                         DRV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  745.             return (ERROR);
  746.             }
  747.         }
  748.     else
  749.         clDesc.memArea = (char *) (pDrvCtrl->rxBdBase + pDrvCtrl->rxBdNum);
  750.     if ((pDrvCtrl->endObj.pNetPool = malloc (sizeof(NET_POOL))) == NULL)
  751.         return (ERROR);
  752.     /* Initialize the net buffer pool with transmit buffers */
  753.     if (netPoolInit (pDrvCtrl->endObj.pNetPool, &oliMclBlkConfig,
  754.                      &clDesc, 1, NULL) == ERROR)
  755.         {
  756.         END_LOG_MSG (END_DEBUG_LOAD, "%s%d - netPoolInit failedn",
  757.          DRV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  758.         return (ERROR);
  759.         }
  760.     /* Save the cluster pool id */
  761.     pDrvCtrl->clPoolId = clPoolIdGet (pDrvCtrl->endObj.pNetPool,
  762.                                       OLI_BUFSIZ, FALSE);
  763.     /* Setup the receive ring */
  764.     for (ix = 0; ix < pDrvCtrl->rxBdNum; ix++)
  765.         {
  766.         pBuf = (char *) NET_BUF_ALLOC();
  767.         if (pBuf == NULL)
  768.             {
  769.             END_LOG_MSG (END_DEBUG_LOAD, "%s%d - netClusterGet failedn",
  770.              DRV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  771.             return (ERROR);
  772.             }
  773. pBuf = (char *) pBuf + pDrvCtrl->offset;
  774.         pDrvCtrl->rxBdBase[ix].dataPointer = pBuf;
  775.         }
  776.     END_LOG_MSG (END_DEBUG_LOAD, "Memory setup completen", 0, 0, 0, 0, 0, 0);
  777.     return (OK);
  778.     }
  779. /*******************************************************************************
  780. *
  781. * iOlicomStart - start the device
  782. *
  783. * This function initializes the device and calls BSP functions to connect
  784. * interrupts and start the device running in interrupt mode.
  785. *
  786. * The complement of this routine is iOlicomStop.  Once a unit is reset by
  787. * iOlicomStop, it may be re-initialized to a running state by this routine.
  788. *
  789. * RETURNS: OK if successful, otherwise ERROR
  790. */
  791. LOCAL STATUS iOlicomStart
  792.     (
  793.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  794.     )
  795.     {
  796.     STATUS result;
  797.     int ix;
  798.     ULONG addrC;
  799.     END_LOG_MSG (END_DEBUG_ALL_FUNCS, "iOlicomStart()n", 0, 0, 0, 0, 0, 0);
  800.     /* Select bank 0 of the Olicom register set */
  801.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 0);
  802.     /* reset the device */
  803.     iOlicomReset (pDrvCtrl);
  804.     /* initialize the device */
  805.     iOlicomInit (pDrvCtrl);
  806.     /* initialize flags */
  807.     DRV_FLAGS_CLR(OLI_POLLING | OLI_TX_CLEANING | OLI_TX_STOP);
  808.     /* initialize receive buffer descriptors */
  809.     for (ix = 0; ix < pDrvCtrl->rxBdNum; ix++)
  810.         pDrvCtrl->rxBdBase[ix].statusMode = RX_BD_EMPTY;
  811.     pDrvCtrl->rxBdNext = 0;
  812.     /* initialize transmit buffer descriptors */
  813.     for (ix = 0; ix < pDrvCtrl->txBdNum; ix++)
  814.         {
  815. pDrvCtrl->txBdBase[ix].dataPointer =
  816. (char *)(addrC = (RAM_TX_BASE + (ix * OLI_MAX_XMT)));
  817.         PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, addrC);
  818.         PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (addrC >> 8));
  819. WRITE_R14_R15 (TX_BD_READY);
  820.         }
  821.     pDrvCtrl->txBdNext = 0;
  822.     pDrvCtrl->txBdIndexC = 0;
  823.     /* configure promiscuous mode and multicast addresses list */
  824.     iOlicomConfig(pDrvCtrl);
  825.     /* connect interrupt */
  826.     SYS_INT_CONNECT (pDrvCtrl, iOlicomInt, (int)pDrvCtrl, &result);
  827.     if (result == ERROR)
  828. return ERROR;
  829.     END_LOG_MSG (END_DEBUG_LOAD, "Interrupt connected.n", 0, 0, 0, 0, 0, 0);
  830.     /* set running & up flags */
  831.     END_FLAGS_SET (&pDrvCtrl->endObj, (IFF_UP | IFF_RUNNING));
  832.     /* enable interrupt */
  833.     SYS_INT_ENABLE (pDrvCtrl);
  834.     END_LOG_MSG (END_DEBUG_LOAD, "Interrupt enabled.n", 0, 0, 0, 0, 0, 0);
  835.     return (OK);
  836.     }
  837. /*******************************************************************************
  838. *
  839. * iOlicomIntHandle - interrupt service for card interrupts
  840. *
  841. * This routine is called when an interrupt has been detected from the Olicom
  842. * card.
  843. *
  844. * RETURNS: N/A.
  845. */
  846. void iOlicomIntHandle
  847.     (
  848.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  849.     )
  850.     {
  851.     int cardStat;
  852.     int intStat;
  853.     /*
  854.      * Read the card configuration state to verify this is a card I/O
  855.      * interrupt.
  856.      */
  857.     cardStat = PCMCIA_ATTR_READ(pDrvCtrl->pcmcia.oliAttribMem + CARDCONFREG1);
  858.     END_LOG_MSG (END_DEBUG_INT, "cardStat (config Reg 1) = 0x%Xn",
  859.     cardStat, 0, 0, 0, 0, 0);
  860.     /* I/O Interrupt, examine card to find out what */
  861.     if (cardStat & CREG1_INT_IO)
  862. {
  863. END_LOG_MSG (END_DEBUG_INT, "I/O interruptn",
  864.      0, 0, 0, 0, 0, 0);
  865. /*
  866.  * Read the chip's interrupt status register to find out why
  867.  * an IRQ was raised.
  868.  */
  869. intStat = PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R1);
  870. END_LOG_MSG (END_DEBUG_INT, "intStat (595 Reg 1) = 0x%Xn",
  871. intStat, 0, 0, 0, 0, 0);
  872. /*
  873.  * Decode the interrupt down and take action accordingly. Note
  874.  * that there may be multiple IRQ sources pending.
  875.  */
  876. /* handle receive events */
  877. if (intStat & BNK0_RX_IT)
  878.     {
  879.     /* netTask handles any input packets */
  880.     if (! DRV_FLAGS_ISSET(OLI_RCV_HANDLING))
  881. {
  882. DRV_FLAGS_SET(OLI_RCV_HANDLING);
  883. (void)netJobAdd ((FUNCPTR)iOlicomRxIntHandle,
  884.     (int)pDrvCtrl, 0,0,0,0);
  885. }
  886.     /* Acknowledge receive interrupt */
  887.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R1, BNK0_RX_IT);
  888.     }
  889. /* handle transmitter events */
  890. if (intStat & BNK0_TX_IT)
  891.     {
  892.     /*
  893.      * clean the transmit buffer descriptor queue if we have
  894.      * received a transmit interrupt and if we are not already
  895.      * cleaning this transmit queue.
  896.      */
  897.     if (! DRV_FLAGS_ISSET(OLI_TX_CLEANING))
  898. {
  899. DRV_FLAGS_SET(OLI_TX_CLEANING);
  900. (void)netJobAdd ((FUNCPTR)iOlicomTxBdQueueClean,
  901.     (int)pDrvCtrl, 0,0,0,0);
  902. }
  903.     /* Acknowledge transmit interrupts */
  904.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R1, BNK0_TX_IT);
  905.     }
  906. /* Acknowledge all other interrupts - ignore events */
  907. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R1,
  908.      ~(BNK0_TX_IT | BNK0_RX_IT));
  909. if (DRV_FLAGS_ISSET(OLI_TX_STOP))     /* cause a restart */
  910.     {
  911.     DRV_FLAGS_CLR(OLI_TX_STOP);
  912.     netJobAdd ((FUNCPTR)muxTxRestart, (int)&pDrvCtrl->endObj,
  913.     0, 0, 0, 0);
  914.     }
  915. }
  916.     return;
  917.     }
  918. /*******************************************************************************
  919. *
  920. * iOlicomRxIntHandle - task level interrupt service for input packets
  921. *
  922. * This routine is called at task level indirectly by the interrupt
  923. * service routine to do any message received processing.
  924. *
  925. * RETURNS: N/A.
  926. */
  927. LOCAL void iOlicomRxIntHandle
  928.     (
  929.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  930.     )
  931.     {
  932.     RX_BD * pRxBd = iOlicomPacketGet (pDrvCtrl);
  933.     END_LOG_MSG (END_DEBUG_RX, ("iOlicomRxIntHandlen"), 0, 0, 0, 0, 0, 0);
  934.     do
  935.         {
  936.         DRV_FLAGS_SET (OLI_RCV_HANDLING);
  937. while (pRxBd != NULL)
  938.     {
  939.     iOlicomRecv (pDrvCtrl, pRxBd);
  940.     pRxBd = iOlicomPacketGet (pDrvCtrl);
  941.     }
  942.         DRV_FLAGS_CLR (OLI_RCV_HANDLING);
  943. /* check once more after resetting flags */
  944. pRxBd = iOlicomPacketGet (pDrvCtrl);
  945.         }
  946.     while (pRxBd != NULL);
  947.     }
  948. /*******************************************************************************
  949. *
  950. * iOlicomPacketGet - get next received message
  951. *
  952. * Get next received message.  Returns NULL if none are ready.
  953. *
  954. * RETURNS: ptr to next packet, or NULL if none ready.
  955. */
  956. LOCAL RX_BD * iOlicomPacketGet
  957.     (
  958.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  959.     )
  960.     {
  961.     int start;
  962.     int event;
  963.     int status;
  964.     int length;
  965.     int s;
  966.     int nextStop;
  967.     UINT8 * pData;
  968.     UINT8 * pDataEnd;
  969.     RX_BD * pRxBd = &pDrvCtrl->rxBdBase[pDrvCtrl->rxBdNext];
  970.     volatile UINT8 * pR14;
  971.     END_LOG_MSG (END_DEBUG_RX, "iOlicomPacketGet oliAddr=0x%Xn",
  972.      pDrvCtrl->pcmcia.oliAddr, 0, 0, 0, 0, 0);
  973.     /*
  974.      * The RCV STOP register points to the last pair of bytes
  975.      * BEFORE the start of the next packet so we must add two
  976.      * bytes to reach the correct address.
  977.      */
  978.     s = intLock();
  979.     start = PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R6);
  980.     start |= (PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R7) << 8);
  981.     start += 2;
  982.     /* Handle the roll over case */
  983.     if (start > RAM_RX_LIMIT)
  984. start -= RAM_RX_BASE;
  985.     END_LOG_MSG (END_DEBUG_RX, "start= 0x%Xn", start, 0, 0, 0, 0, 0);
  986.     /* Set up address from where we wish to start reading data */
  987.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, start);
  988.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (start >> 8));
  989.     /* The first word describes the state of reception. */
  990.     READ_R14_R15 (event);
  991.     /* The following bit will be set once the packet is complete in memory */
  992.     if (!(event & RCV_EOF))
  993. {
  994. intUnlock (s);
  995. return ((RX_BD *) NULL);
  996. }
  997.     /* Collect the status of the packet */
  998.     READ_R14_R15 (status);
  999.     /* get next packet pointer */
  1000.     READ_R14_R15 (nextStop);
  1001.     /* The next stop value is 2 bytes back in the circular buffer */
  1002.     nextStop -= 2;
  1003.     /* Handle the roll over case */
  1004.     if (nextStop < RAM_RX_BASE)
  1005. nextStop += RAM_RX_BASE;
  1006.     /* get packet length */
  1007.     READ_R14_R15 (length);
  1008.     END_LOG_MSG (END_DEBUG_RX, "length= 0x%Xn", length, 0, 0, 0, 0, 0);
  1009.     /* Check for errors */
  1010.     if (!(status & RCV_OK))
  1011.         {
  1012.         /* Bump input error packet counter */
  1013.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1014. /* Update the STOP register from the next packet pointer */
  1015. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R6, nextStop);
  1016. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R7, (nextStop >> 8));
  1017. intUnlock (s);
  1018.         return ((RX_BD *) NULL);
  1019.         }
  1020.     /* check if a receive buffer descriptor is available */
  1021.     if (!(pRxBd->statusMode & RX_BD_EMPTY))
  1022.         {
  1023.         /* Bump input error packet counter */
  1024.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1025. /* Update the STOP register from the next packet pointer */
  1026. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R6, nextStop);
  1027. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R7, (nextStop >> 8));
  1028. intUnlock (s);
  1029.         return ((RX_BD *) NULL);
  1030.         }
  1031.     /*
  1032.      * We always read an even number of bytes from the controller,
  1033.      * so adjust the length if necessary.
  1034.      */
  1035.     if ((length & ODD_MSK) != 0)
  1036.         ++length;
  1037.     pRxBd->dataLength = length;
  1038.     /*
  1039.      * Read the data from the Rx ring buffer.
  1040.      *
  1041.      * Set up the pointer just before the loop: provokes code generator
  1042.      * into producing much better code.
  1043.      */
  1044.     pR14 = (volatile UINT8 *) (pDrvCtrl->pcmcia.oliAddr + I595_R14);
  1045.     for (pData = (UINT8 *)pRxBd->dataPointer, pDataEnd = pData + length;
  1046.  pData != pDataEnd; )
  1047. READ_PTR_R14_R15 (pData, pR14);
  1048.     END_LOG_MSG (END_DEBUG_RX, "data = 0x%X 0x%Xn",
  1049.  (pRxBd->dataPointer)[0], (pRxBd->dataPointer)[1], 0, 0, 0, 0);
  1050.     /* Update the STOP register from the next packet pointer */
  1051.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R6, nextStop);
  1052.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R7, (nextStop >> 8));
  1053.     /* Update status buffer descriptor */
  1054.     pRxBd->statusMode = 0;
  1055.     /* incr buffer descriptor count */
  1056.     pDrvCtrl->rxBdNext = (pDrvCtrl->rxBdNext + 1) % pDrvCtrl->rxBdNum;
  1057.     intUnlock (s);
  1058.     return pRxBd;
  1059.     }
  1060. /*******************************************************************************
  1061. *
  1062. * iOlicomRecv - process the next incoming packet
  1063. *
  1064. * This routine processes an input frame, then passes it up to the higher
  1065. * level in a form it expects.
  1066. *
  1067. * RETURNS: OK, always.
  1068. */
  1069. LOCAL STATUS iOlicomRecv
  1070.     (
  1071.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  1072.     RX_BD * pRxBd
  1073.     )
  1074.     {
  1075.     END_OBJ *   pOliObj = &pDrvCtrl->endObj;
  1076.     M_BLK_ID    pMblk;      /* MBLK to send upstream */
  1077.     CL_BLK_ID   pClBlk;     /* pointer to clBlk */
  1078.     char *      pBuf;       /* A replacement buffer for the current RxD */
  1079.     char *      pData;      /* Data pointer for the current RxD */
  1080.     int         len;        /* Len of the current data */
  1081.     END_LOG_MSG (END_DEBUG_RX, "iOlicomRecvn", 0, 0, 0, 0, 0, 0);
  1082.     /* Allocate an MBLK, and a replacement buffer */
  1083.     pMblk = NET_MBLK_ALLOC();
  1084.     pBuf  = NET_BUF_ALLOC();
  1085.     pClBlk = NET_CL_BLK_ALLOC();
  1086.     if ((pMblk == NULL) || (pBuf == NULL) || (pClBlk == NULL))
  1087.         {
  1088.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1089.         if (pMblk)
  1090.             NET_MBLK_FREE (pMblk);
  1091.         if (pBuf)
  1092.             NET_BUF_FREE (pBuf);
  1093.         if (pClBlk)
  1094.             NET_CL_BLK_FREE (pClBlk);
  1095.         goto cleanRxBd;
  1096.         }
  1097.     /* Get the data pointer and len from the current RX_BD */
  1098.     len   = pRxBd->dataLength;
  1099.     pData = pRxBd->dataPointer;
  1100.     pData -= pDrvCtrl->offset;
  1101.     /* Associate the data pointer with the CL_BLK */
  1102.     NET_CL_BLK_JOIN (pClBlk, pData, OLI_BUFSIZ);
  1103.     /* Associate the CL_BLK with the MBLK */
  1104.     NET_MBLK_CL_JOIN (pMblk, pClBlk);
  1105.     pMblk->mBlkHdr.mData  += pDrvCtrl->offset;
  1106.     pMblk->mBlkHdr.mFlags |= M_PKTHDR; /* set the packet header */
  1107.     pMblk->mBlkHdr.mLen    = len; /* set the data len */
  1108.     pMblk->mBlkPktHdr.len  = len; /* set the total len */
  1109.     /* Deal with memory alignment. */
  1110.     pBuf += pDrvCtrl->offset;
  1111.     /* Install the new data buffer */
  1112.     pRxBd->dataPointer = pBuf;
  1113.     /* mark the descriptor ready to receive */
  1114.     pRxBd->statusMode |= RX_BD_EMPTY;
  1115.     /* Bump the statistic counter. */
  1116.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
  1117.     /* send up to protocol */
  1118.     END_LOG_MSG (END_DEBUG_RX, ("Calling upper layer! n"), 0, 0, 0, 0, 0, 0);
  1119.     END_RCV_RTN_CALL (pOliObj, pMblk);
  1120.     return OK;
  1121. cleanRxBd:
  1122.     /* mark the descriptor ready to receive */
  1123.     pRxBd->statusMode |= RX_BD_EMPTY;
  1124.     return OK;
  1125.     }
  1126. /*******************************************************************************
  1127. *
  1128. * iOlicomSend - the driver send routine
  1129. *
  1130. * This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
  1131. * The buffer must already have the addressing information properly installed
  1132. * in it.  This is done by a higher layer.
  1133. *
  1134. * RETURNS: OK or ERROR.
  1135. */
  1136. LOCAL STATUS iOlicomSend
  1137.     (
  1138.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  1139.     M_BLK * pMblk
  1140.     )
  1141.     {
  1142.     TX_BD * pTxBd;
  1143.     char * pBuf;
  1144.     UINT8 * pData;
  1145.     UINT8 * pDataEnd;
  1146.     ULONG addrC;
  1147.     int len;
  1148.     int s;
  1149.     volatile UINT8 * pR14;
  1150.     END_LOG_MSG (END_DEBUG_ALL_FUNCS, "iOlicomSend()n", 0, 0, 0, 0, 0, 0);
  1151.     END_LOG_MSG (END_DEBUG_TX, "iOlicomSend()n", 0, 0, 0, 0, 0, 0);
  1152.     if (DRV_FLAGS_ISSET (OLI_POLLING))
  1153.         { 
  1154.         NET_MBLK_CHAIN_FREE (pMblk); /* free the given mBlk chain */
  1155.         errno = EINVAL;
  1156.         return (ERROR);
  1157.         }
  1158.     /*
  1159.      * Obtain exclusive access to transmitter.  This is necessary because
  1160.      * we might have more than one stack transmitting at once.
  1161.      */
  1162.     END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);
  1163.     END_LOG_MSG (END_DEBUG_TX, "iOlicomSend() got semaphoren",
  1164.  0, 0, 0, 0, 0, 0);
  1165.     /* get a free transmit frame descriptor */
  1166.     pTxBd = iOlicomTxBdGet (pDrvCtrl);
  1167.     addrC = (ULONG) pTxBd->dataPointer;
  1168.     /* get a free buufer */
  1169.     pBuf = NET_BUF_ALLOC();
  1170.     if ((pTxBd == NULL) || (pBuf == NULL))
  1171.         {
  1172.         END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
  1173.         END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1174.         if (pBuf)
  1175.             NET_BUF_FREE (pBuf);
  1176.         if (! DRV_FLAGS_ISSET(OLI_TX_CLEANING | OLI_TX_STOP))
  1177.     iOlicomTxBdQueueClean (pDrvCtrl);
  1178. s = intLock();
  1179.         DRV_FLAGS_SET(OLI_TX_STOP);        /* transmitter not ready */
  1180. intUnlock (s);
  1181. /* just return without freeing mBlk chain */
  1182.         return (END_ERR_BLOCK);
  1183.         }
  1184.     /* Copy and free the MBLK */
  1185.     len = netMblkToBufCopy (pMblk, pBuf, NULL);
  1186.     NET_MBLK_CHAIN_FREE (pMblk);
  1187.     s = intLock();
  1188.     /* Write the transmit buffer base address. */
  1189.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, addrC);
  1190.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (addrC >> 8));
  1191.     /* Write the command opcode, and reserved field for the packet */
  1192.     WRITE_R14_R15 (CMD_TRANSMIT);
  1193.     /* Write 16 bit status field */
  1194.     WRITE_R14_R15 (0x00);
  1195.     /* Write the chain pointer */
  1196.     WRITE_R14_R15 (0x00);
  1197.     /* Write the byte count low and high bytes */
  1198.     WRITE_R14_R15 (len & ~XMT_CHAIN);
  1199.     /*
  1200.      * Copy data. Initialise pointer here to provoke the compiler into
  1201.      * generating better code
  1202.      */
  1203.     pR14 = (volatile UINT8 *) (pDrvCtrl->pcmcia.oliAddr + I595_R14);
  1204.     for (pData = (UINT8 *)pBuf, pDataEnd = pData + len; pData < pDataEnd ; )
  1205. WRITE_PTR_R14_R15 (pData, pR14);
  1206.     /*
  1207.      * The Ethernet chip can't receive a transmit command while a
  1208.      * TRANSMIT is already in progress. The following test checks if the
  1209.      * 82595TX chip is transmitting a packet before issuing another transmit
  1210.      * command.
  1211.      */
  1212.     if (pDrvCtrl->txBdIndexC == pDrvCtrl->txBdNext)
  1213. {
  1214. /* Write the XMT base address register */
  1215. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R10, addrC);
  1216. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R11, (addrC >> 8));
  1217. /* Issue a XMT command to the 82595TX */
  1218. RUNCMD((UINT)(pDrvCtrl->pcmcia.oliAddr), CMD_TRANSMIT);
  1219. }
  1220.     /* Save the buf info */
  1221.     pDrvCtrl->freeBuf[pDrvCtrl->txBdNext].pClBuf  = pBuf;
  1222.     /* incr BD count */
  1223.     pDrvCtrl->txBdNext = (pDrvCtrl->txBdNext + 1) % pDrvCtrl->txBdNum;
  1224.     intUnlock(s);
  1225.     /* release exclusive access */
  1226.     END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1227.     /* Bump the statistic counter. */
  1228.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);
  1229.     END_LOG_MSG (END_DEBUG_ALL_FUNCS, "iOlicomSend() exitn", 0, 0, 0, 0, 0, 0);
  1230.     return (OK);
  1231.     }
  1232. /*******************************************************************************
  1233. *
  1234. * iOlicomTxBdGet - get an available transmit descriptor
  1235. *
  1236. * Get next transmited message descriptor.  Returns NULL if none are
  1237. * ready.
  1238. *
  1239. * RETURNS: an available transmit descriptor, otherwise NULL.
  1240. */
  1241. LOCAL TX_BD * iOlicomTxBdGet
  1242.     (
  1243.     END_DEVICE * pDrvCtrl
  1244.     )
  1245.     {
  1246.     ULONG       addrC;
  1247.     int         status;
  1248.     TX_BD * pTxBd = &pDrvCtrl->txBdBase[pDrvCtrl->txBdNext];
  1249.     addrC = (ULONG) pTxBd->dataPointer;
  1250.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, addrC);
  1251.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (addrC >> 8));
  1252.     READ_R14_R15 (status);
  1253.     /* check if a transmit buffer descriptor is available */
  1254.     if (!(status & TX_BD_READY) ||
  1255.  ((pDrvCtrl->txBdNext + 1) % pDrvCtrl->txBdNum) == pDrvCtrl->txBdIndexC)
  1256.         return (NULL);
  1257.     return (pTxBd);
  1258.     }
  1259. /*******************************************************************************
  1260. *
  1261. * iOlicomIoctl - the driver I/O control routine
  1262. *
  1263. * Process an ioctl request.
  1264. *
  1265. * This routine implements the network interface control functions.
  1266. * It handles EIOCSADDR, EIOCGADDR, EIOCSFLAGS, EIOCGFLAGS,
  1267. * EIOCPOLLSTART, EIOCPOLLSTOP, EIOCGMIB2, EIOCGFBUF commands.
  1268. *
  1269. * RETURNS: OK if successful, otherwise EINVAL.
  1270. */
  1271. LOCAL int iOlicomIoctl
  1272.     (
  1273.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  1274.     int cmd, /* command to process */
  1275.     char * data /* pointer to data */
  1276.     )
  1277.     {
  1278.     int error = 0;
  1279.     long value;
  1280.     END_LOG_MSG (END_DEBUG_ALL_FUNCS, "iOlicomIoctl()n", 0, 0, 0, 0, 0, 0);
  1281.     switch ((UINT)cmd)
  1282.         {
  1283.         case EIOCSADDR:
  1284.     if (data == NULL)
  1285. return (EINVAL);
  1286.             memcpy ((char *)END_HADDR(&pDrvCtrl->endObj), (char *)data,
  1287.    END_HADDR_LEN(&pDrvCtrl->endObj));
  1288.             break;
  1289.         case EIOCGADDR:
  1290.     if (data == NULL)
  1291. return (EINVAL);
  1292.             memcpy ((char *)data, (char *)END_HADDR(&pDrvCtrl->endObj),
  1293.     END_HADDR_LEN(&pDrvCtrl->endObj));
  1294.             break;
  1295.         case EIOCSFLAGS:
  1296.     value = (long)data;
  1297.     if (value < 0)
  1298. {
  1299. value = -value;
  1300. value--;
  1301. END_FLAGS_CLR (&pDrvCtrl->endObj, value);
  1302. }
  1303.     else
  1304. {
  1305. END_FLAGS_SET (&pDrvCtrl->endObj, value);
  1306. }
  1307.     iOlicomConfig (pDrvCtrl);
  1308.     END_LOG_MSG (END_DEBUG_IOCTL, "endFlags %#xn",
  1309. END_FLAGS_GET(&pDrvCtrl->endObj), 0, 0, 0, 0 ,0);
  1310.             break;
  1311.         case EIOCGFLAGS:
  1312.     *(int *)data = END_FLAGS_GET(&pDrvCtrl->endObj);
  1313.             break;
  1314. case EIOCPOLLSTART:
  1315.     error = iOlicomPollStart (pDrvCtrl);
  1316.     break;
  1317. case EIOCPOLLSTOP:
  1318.     error = iOlicomPollStop (pDrvCtrl);
  1319.     break;
  1320.         case EIOCGMIB2:
  1321.             if (data == NULL)
  1322.                 return (EINVAL);
  1323.             memcpy((char *)data, (char *)&pDrvCtrl->endObj.mib2Tbl,
  1324.                   sizeof(pDrvCtrl->endObj.mib2Tbl));
  1325.             break;
  1326.         case EIOCGFBUF:
  1327.             if (data == NULL)
  1328.                 return (EINVAL);
  1329.             *(int *)data = OLI_MIN_FBUF;
  1330.             break;
  1331.         default:
  1332.             error = EINVAL;
  1333.         }
  1334.     return (error);
  1335.     }
  1336. /******************************************************************************
  1337. *
  1338. * iOlicomConfig - reconfigure the interface under us.
  1339. *
  1340. * Reconfigure the interface setting promiscuous mode, and changing the
  1341. * multicast interface list.
  1342. *
  1343. * RETURNS: N/A
  1344. */
  1345. LOCAL void iOlicomConfig
  1346.     (
  1347.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  1348.     )
  1349.     {
  1350.     /* Set promiscuous mode if it's asked for. */
  1351.     if (END_FLAGS_GET (&pDrvCtrl->endObj) & IFF_PROMISC)
  1352. {
  1353. END_LOG_MSG (END_DEBUG_IOCTL, "Setting promiscuous mode on!n",
  1354.  0, 0, 0, 0, 0, 0);
  1355.         SELECTBANK (pDrvCtrl->pcmcia.oliAddr, 2);
  1356.         PCMCIA_IO_WRITE (pDrvCtrl->pcmcia.oliAddr + I595_R2,
  1357. (PCMCIA_IO_READ (pDrvCtrl->pcmcia.oliAddr + I595_R2) |
  1358. BNK2_PCS_EN));
  1359. }
  1360.     else
  1361. {
  1362. END_LOG_MSG (END_DEBUG_IOCTL, "Setting promiscuous mode off!n",
  1363.  0, 0, 0, 0, 0, 0);
  1364. }
  1365.     /* setup ethernet address and filtering mode */
  1366.     iOlicomAddrFilterSet (pDrvCtrl);
  1367.     return;
  1368.     }
  1369. /******************************************************************************
  1370. *
  1371. * iOlicomAddrFilterSet - set the address filter for multicast addresses
  1372. *
  1373. * This routine goes through all of the multicast addresses on the list
  1374. * of addresses (added with the iOlicomAddrAdd() routine) and sets the
  1375. * device's filter correctly.
  1376. *
  1377. * RETURNS: OK on success, ERROR otherwise.
  1378. */
  1379. LOCAL STATUS iOlicomAddrFilterSet
  1380.     (
  1381.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  1382.     )
  1383.     {
  1384.     UINT8 *     pFltrFrm;
  1385.     UINT8 *     pData;
  1386.     ETHER_MULTI * pMCastNode;
  1387.     TX_BD * pTxBd;
  1388.     int         length;
  1389.     int         ix;
  1390.     int         s;
  1391.     int         index = 0;
  1392.     ULONG       addrC;
  1393.     END_LOG_MSG (END_DEBUG_ADDR, "iOlicomAddrFilterSet n", 0, 0, 0, 0, 0, 0);
  1394.     /* gain exclusive access to transmitter */
  1395.     END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);
  1396.     /* Select bank 0 of the Olicom register set */
  1397.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 0);
  1398.     /* get a free transmit frame descriptor */
  1399.     pTxBd = iOlicomTxBdGet (pDrvCtrl);
  1400.     if (pTxBd == NULL)
  1401.         {
  1402. END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1403.         return (ERROR);
  1404.         }
  1405.     addrC = (ULONG) pTxBd->dataPointer;
  1406.     /* get a buffer */
  1407.      pFltrFrm = (UINT8 *)NET_BUF_ALLOC();
  1408.      if (pFltrFrm == NULL)
  1409.          {
  1410.          END_LOG_MSG (END_DEBUG_LOAD, "netClusterGet failedn",
  1411. 0, 0, 0, 0, 0, 0);
  1412.          END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1413.          return (ERROR);
  1414.          }
  1415.     /* clear all entries */
  1416.     memset (pFltrFrm, 0, FLTR_FRM_SIZE);
  1417.     /* install multicast addresses */
  1418.     pData = pFltrFrm;
  1419.     for (pMCastNode = END_MULTI_LST_FIRST (&pDrvCtrl->endObj);
  1420.         pMCastNode != NULL;
  1421.         pMCastNode = END_MULTI_LST_NEXT (pMCastNode))
  1422.         {
  1423.         for (ix = 0; ix < EADDR_LEN; ix++)
  1424.             *(pData++) = pMCastNode->addr[ix];
  1425.         index++;
  1426.         }
  1427.     /* Set variables to copy the buffer in */
  1428.     length = index * EADDR_LEN;
  1429.     pData--;
  1430.     s = intLock ();    /* disable ints during update */
  1431.     /* Write the transmit buffer base address. */
  1432.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, addrC);
  1433.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (addrC >> 8));
  1434.     /* Write the command opcode, and reserved field for the packet */
  1435.     WRITE_R14_R15 (CMD_MC_SETUP);
  1436.     /* Write 16 bit status field */
  1437.     WRITE_R14_R15 (0x00);
  1438.     /* Write the chain pointer */
  1439.     WRITE_R14_R15 (0x00);
  1440.     /* Write the byte count low and high bytes */
  1441.     WRITE_R14_R15 (length & ~XMT_CHAIN);
  1442.     /* copy data */
  1443.     for (; length > 0 ; length -= 2)
  1444.         {
  1445.         PCMCIA_IO_WRITE((UINT)(pDrvCtrl->pcmcia.oliAddr + I595_R14),
  1446. *pData--);
  1447.         PCMCIA_IO_WRITE((UINT)(pDrvCtrl->pcmcia.oliAddr + I595_R15),
  1448. *pData--);
  1449.         }
  1450.     /* Write the XMT base address register */
  1451.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R10, addrC);
  1452.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R11, (addrC >> 8));
  1453.     /* Issue a MC_SETUP command to the 82595TX */
  1454.     RUNCMD((UINT)(pDrvCtrl->pcmcia.oliAddr), CMD_MC_SETUP);
  1455.     /* incr BD count */
  1456.     pDrvCtrl->txBdNext = (pDrvCtrl->txBdNext + 1) % pDrvCtrl->txBdNum;
  1457.     /* Spin until we've sent it. */
  1458.     while (!(PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R1) & BNK0_EXE_IT));
  1459.     /* clear execution interrupt */
  1460.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R1, BNK0_EXE_IT);
  1461.     /* clean the transmit queue */
  1462.     iOlicomTxBdQueueClean(pDrvCtrl);
  1463.     intUnlock (s);   /* now iOlicomInt won't get confused */
  1464.     /* free the buffer */
  1465.     NET_BUF_FREE (pFltrFrm);
  1466.     /* release exclusive access */
  1467.     END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1468.     END_LOG_MSG (END_DEBUG_ADDR, "iOlicomAddrFilterSet() exitn",
  1469.  0, 0, 0, 0, 0, 0);
  1470.     return (OK);
  1471.     }
  1472. /*******************************************************************************
  1473. *
  1474. * iOlicomPollReceive - routine to receive a packet in polled mode.
  1475. *
  1476. * This routine is called by a user to try and get a packet from the
  1477. * device. It returns EAGAIN if no packet is available. The caller must
  1478. * supply a M_BLK_ID with enough space to contain the receiving packet. If
  1479. * enough buffer is not available then EAGAIN is returned.
  1480. *
  1481. * These routine should not call any kernel functions.
  1482. *
  1483. * RETURNS: OK on success, EAGAIN on failure.
  1484. */
  1485. LOCAL STATUS iOlicomPollReceive
  1486.     (
  1487.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  1488.     M_BLK  * pMblk
  1489.     )
  1490.     {
  1491.     char * pPacket;
  1492.     int status;
  1493.     int length;
  1494.     int event;
  1495.     int start;
  1496.     int nextStop;
  1497.     BOOL gotOne=FALSE;
  1498.     volatile UINT8 * pR14;
  1499.     END_LOG_MSG (END_DEBUG_ALL_FUNCS, "iOlicomPollReceive()n",
  1500.  0, 0, 0, 0, 0, 0);
  1501.     if ((pMblk->mBlkHdr.mFlags & M_EXT) != M_EXT)
  1502.         return (EAGAIN);
  1503.     /* Read the device status register */
  1504.     status = PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R1);
  1505.     /* If no interrupt then return. */
  1506.     if (!(status & BNK0_RX_IT))
  1507. {
  1508. END_LOG_MSG (END_DEBUG_POLL_RX, "iOlicomPollReceive no rintn",
  1509.  0, 0, 0, 0, 0, 0);
  1510.         return (EAGAIN);
  1511. }
  1512.     /*
  1513.      * The RCV STOP register points to the last pair of bytes
  1514.      * BEFORE the start of the next packet so we must add two
  1515.      * bytes to reach the correct address.
  1516.      */
  1517.     start = PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R6);
  1518.     start |= (PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R7) << 8);
  1519.     start += 2;
  1520.     /* Handle the roll over case */
  1521.     if (start > RAM_RX_LIMIT)
  1522. start -= RAM_RX_BASE;
  1523.     /* Set up address from where we wish to start reading data */
  1524.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, start);
  1525.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (start >> 8));
  1526.     /* The first word describes the state of reception.  */
  1527.     READ_R14_R15 (event);
  1528.     /* The following bit will be set once the packet is complete in memory. */
  1529.     if (event & RCV_EOF)
  1530.         {
  1531.         /* Collect the status of the packet */
  1532. READ_R14_R15 (status);
  1533. /* get next packet pointer */
  1534. READ_R14_R15 (nextStop);
  1535. /* The next stop value is 2 bytes back in the circular buffer */
  1536. nextStop -= 2;
  1537. /* Handle the roll over case */
  1538. if (nextStop < RAM_RX_BASE)
  1539.     nextStop += RAM_RX_BASE;
  1540.         /* get packet length */
  1541. READ_R14_R15 (length);
  1542.         /* Check for errors */
  1543.         if (!(status & RCV_OK) || ((length - SIZEOF_ETHERHEADER) <= 0))
  1544.             {
  1545.             /* bump input error packet counter */
  1546.             END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1547.             }
  1548.         else
  1549.             {
  1550.             /*
  1551.              * We always read an even number of bytes from the controller,
  1552.              * so adjust the length if necessary.
  1553.              */
  1554.             if ((length & ODD_MSK) != 0)
  1555.                 ++length;
  1556.             /* Upper layer provides the buffer. */
  1557.             if (pMblk->mBlkHdr.mLen < length)
  1558.                 goto pollRecvExit;
  1559.     /* Deal with memory aligment */
  1560.     if (((int) pMblk->mBlkHdr.mData & 0x3) == 0)
  1561. pMblk->mBlkHdr.mData += pDrvCtrl->offset;
  1562.             pMblk->mBlkHdr.mFlags |= M_PKTHDR; /* set the packet header */
  1563.     pMblk->mBlkPktHdr.len  = length; /* set the total len */
  1564.     pMblk->mBlkHdr.mLen    = length; /* set the data len */
  1565.             /* Copy data.
  1566.      *
  1567.      * Set up the pointer just before the loop: provokes code
  1568.      * generator into producing much better code.
  1569.      */
  1570.     pR14 = (volatile UINT8 *) (pDrvCtrl->pcmcia.oliAddr + I595_R14);
  1571.             for (pPacket = pMblk->mBlkHdr.mData; length != 0; length -=2)
  1572. READ_PTR_R14_R15 (pPacket, pR14);
  1573.     gotOne = TRUE;
  1574.             /* bump input packet counter */
  1575.             END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
  1576.             }
  1577.         /* Update the STOP register from the next packet pointer */
  1578. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R6, nextStop);
  1579. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R7, (nextStop >> 8));
  1580. }
  1581. pollRecvExit:
  1582.     /* clear receive interrupts. */
  1583.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R1, BNK0_RX_IT);
  1584.     return (gotOne ? OK : EAGAIN);
  1585.     }
  1586. /*******************************************************************************
  1587. *
  1588. * iOlicomPollSend - routine to send a packet in polled mode.
  1589. *
  1590. * This routine is called by a user to try and send a packet on the
  1591. * device. It sends a packet directly on the network from the caller without
  1592. * going through the normal processes of queuing a pacet on an output queue
  1593. * and the waiting for the device to decide to transmit it.
  1594. *
  1595. * If it detects a transmission error, the restart command is issued.
  1596. *
  1597. * These routine should not call any kernel functions.
  1598. *
  1599. * RETURNS: OK on success, EAGAIN on failure
  1600. */
  1601. LOCAL STATUS iOlicomPollSend
  1602.     (
  1603.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  1604.     M_BLK * pMblk
  1605.     )
  1606.     {
  1607.     TX_BD * pTxBd;
  1608.     char * pBuf;
  1609.     char * pData;
  1610.     ULONG addrC;
  1611.     int len;
  1612.     int status;
  1613.     volatile UINT8 * pR14;
  1614.     END_LOG_MSG (END_DEBUG_ALL_FUNCS, "iOlicomPollSend()n",
  1615.  0, 0, 0, 0, 0, 0);
  1616.     if (DRV_FLAGS_ISSET(OLI_TX_STOP))
  1617.         return (EAGAIN);
  1618.     /* get a free transmit frame descriptor */
  1619.     pTxBd = iOlicomTxBdGet (pDrvCtrl);
  1620.     addrC = (ULONG) pTxBd->dataPointer;
  1621.     /* get a free buffer */
  1622.     pBuf = NET_BUF_ALLOC ();
  1623.     if ((pTxBd == NULL) || (pBuf == NULL))
  1624.         {
  1625.         iOlicomTxBdQueueClean (pDrvCtrl);
  1626.         if (pBuf)
  1627.             NET_BUF_FREE (pBuf);
  1628.         return (EAGAIN);
  1629.         }
  1630.    /* copy the MBLK */
  1631.     len = netMblkToBufCopy (pMblk, pBuf, NULL);
  1632.     /* Write the transmit buffer base address. */
  1633.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, addrC);
  1634.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (addrC >> 8));
  1635.     /* Write the command opcode, and reserved field for the packet */
  1636.     WRITE_R14_R15 (CMD_TRANSMIT);
  1637.     /* Write 16 bit status field */
  1638.     WRITE_R14_R15 (0x00);
  1639.     /* Write the chain pointer */
  1640.     WRITE_R14_R15 (0x00);
  1641.     /* Write the byte count low and high bytes */
  1642.     WRITE_R14_R15 (len & ~XMT_CHAIN);
  1643.     /*
  1644.      * Copy data. Initialise pointer here to provoke the compiler into
  1645.      * generating better code
  1646.      */
  1647.     pR14 = (volatile UINT8 *) (pDrvCtrl->pcmcia.oliAddr + I595_R14);
  1648.     for (pData = pBuf; len > 0; len -= 2)
  1649.         WRITE_PTR_R14_R15 (pData, pR14);
  1650.     /* Write the XMT base address register */
  1651.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R10, addrC);
  1652.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R11, (addrC >> 8));
  1653.     /* Issue a XMT command to the 82595TX */
  1654.     RUNCMD((UINT)(pDrvCtrl->pcmcia.oliAddr), CMD_TRANSMIT);
  1655.     /* incr BD count */
  1656.     pDrvCtrl->txBdNext = (pDrvCtrl->txBdNext + 1) % pDrvCtrl->txBdNum;
  1657.     /* Bump the statistic counter. */
  1658.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);
  1659.     /* Spin until we've sent it. */
  1660.     while (!(PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R1) & BNK0_TX_IT));
  1661.     /* clear transmit interrupt */
  1662.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R1, BNK0_TX_IT);
  1663.     /* Free the data immediately. */
  1664.     NET_BUF_FREE (pBuf);
  1665.     /* check for output errors */
  1666.     addrC = (ULONG) pTxBd->dataPointer + 2;
  1667.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, addrC);
  1668.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (addrC >> 8));
  1669.     READ_R14_R15 (status);
  1670.     if (!(status & XMT_OK))
  1671.         return (EAGAIN);
  1672.     /*
  1673.      * we are allowed to do this because transmit queue is empty when we
  1674.      * start polling mode.
  1675.      */
  1676.     pDrvCtrl->txBdIndexC = pDrvCtrl->txBdNext;
  1677.     return (OK);
  1678.     }
  1679. /******************************************************************************
  1680. *
  1681. * iOlicomMCastAddrAdd - add a multicast address for the device
  1682. *
  1683. * This routine adds a multicast address to whatever the driver
  1684. * is already listening for.  It then resets the address filter.
  1685. *
  1686. * RETURNS: OK on success, ERROR otherwise.
  1687. */
  1688. LOCAL STATUS iOlicomMCastAddrAdd
  1689.     (
  1690.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  1691.     char * pAddress /* address to add to the table */
  1692.     )
  1693.     {
  1694.     int error;
  1695.     END_LOG_MSG (END_DEBUG_ALL_FUNCS, "iOlicomMCastAddrAddn",
  1696.      0, 0, 0, 0, 0, 0);
  1697.     if ((error = etherMultiAdd (&pDrvCtrl->endObj.multiList,
  1698. pAddress)) == ENETRESET)
  1699.     iOlicomConfig (pDrvCtrl);
  1700.     return (OK);
  1701.     }
  1702. /*****************************************************************************
  1703. *
  1704. * iOlicomMCastAddrDel - delete a multicast address for the device
  1705. *
  1706. * This routine removes a multicast address from whatever the driver
  1707. * is listening for.  It then resets the address filter.
  1708. *
  1709. * RETURNS: OK on success, ERROR otherwise.
  1710. */
  1711. LOCAL STATUS iOlicomMCastAddrDel
  1712.     (
  1713.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  1714.     char * pAddress /* address to delete from the table */
  1715.     )
  1716.     {
  1717.     int error;
  1718.     END_LOG_MSG (END_DEBUG_ALL_FUNCS, "iOlicomMCastAddrDeln", 0, 0, 0, 0, 0,0);
  1719.     if ((error = etherMultiDel (&pDrvCtrl->endObj.multiList,
  1720.      (char *)pAddress)) == ENETRESET)
  1721.     iOlicomConfig (pDrvCtrl);
  1722.     return (OK);
  1723.     }
  1724. /*****************************************************************************
  1725. *
  1726. * iOlicomMCastAddrGet - get the multicast address list for the device
  1727. *
  1728. * This routine gets the multicast list of whatever the driver
  1729. * is already listening for.
  1730. *
  1731. * RETURNS: OK on success, ERROR otherwise.
  1732. */
  1733. LOCAL STATUS iOlicomMCastAddrGet
  1734.     (
  1735.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  1736.     MULTI_TABLE * pTable /* table to fill in with addresses */
  1737.     )
  1738.     {
  1739.     int error;
  1740.     END_LOG_MSG (END_DEBUG_ALL_FUNCS, "iOlicomMCastAddrGetn", 0, 0, 0, 0, 0,0);
  1741.     error = etherMultiGet (&pDrvCtrl->endObj.multiList, pTable);
  1742.     return (error);
  1743.     }
  1744. /*******************************************************************************
  1745. *
  1746. * iOlicomStop - stop the device
  1747. *
  1748. * This routine marks the interface as down and resets the device.  This
  1749. * includes stopping the transmitter and receiver.
  1750. *
  1751. * The complement of this routine is iOlicomStart.  Once a unit is
  1752. * stopped in this routine, it may be re-initialized to a running state by
  1753. * iOlicomStart.
  1754. *
  1755. * RETURNS: OK or ERROR
  1756. */
  1757. LOCAL STATUS iOlicomStop
  1758.     (
  1759.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  1760.     )
  1761.     {
  1762.     STATUS result = OK;
  1763.     END_LOG_MSG (END_DEBUG_ALL_FUNCS, "iOlicomStop()n", 0, 0, 0, 0, 0, 0);
  1764.     /* reset the controller */
  1765.     iOlicomReset (pDrvCtrl);
  1766.     /* mark the interface -- down */
  1767.     END_FLAGS_CLR (&pDrvCtrl->endObj, IFF_UP | IFF_RUNNING);
  1768.     /* disconnect interrupt */
  1769.     SYS_INT_DISCONNECT (pDrvCtrl, iOlicomInt, (int)pDrvCtrl, &result);
  1770.     if (result == ERROR)
  1771. END_LOG_MSG (END_DEBUG_IOCTL, "Could not disconnect interrupt!n",
  1772.  0, 0, 0, 0, 0, 0);
  1773.     /* Disable LAN interrupts */
  1774.     SYS_INT_DISABLE (pDrvCtrl);
  1775.     return (result);
  1776.     }
  1777. /******************************************************************************
  1778. *
  1779. * iOlicomUnload - unload a driver from the system
  1780. *
  1781. * This function first brings down the device, and then frees any
  1782. * stuff that was allocated by the driver in the load function.
  1783. *
  1784. * RETURNS: OK, always.
  1785. */
  1786. LOCAL STATUS iOlicomUnload
  1787.     (
  1788.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  1789.     )
  1790.     {
  1791.     END_LOG_MSG (END_DEBUG_ALL_FUNCS, "iOlicomUnload()n", 0, 0, 0, 0, 0, 0);
  1792.     /* Bring down the device */
  1793.     pDrvCtrl->endObj.flags &= ~(IFF_UP);
  1794.     /* deallocate lists */
  1795.     END_OBJECT_UNLOAD (&pDrvCtrl->endObj);
  1796.     /* Free the memory. */
  1797.     if (DRV_FLAGS_ISSET (OLI_MEMOWN))
  1798. free ((char *)pDrvCtrl->pShMem);
  1799.     return (OK);
  1800.     }
  1801. /*******************************************************************************
  1802. *
  1803. * iOlicomPollStart - start polled mode operations
  1804. *
  1805. * This routine starts polling mode by disabling ethernet interrupts and
  1806. * setting the polling flag in the END_DEVICE stucture.
  1807. *
  1808. * RETURNS: OK, always.
  1809. */
  1810. LOCAL STATUS iOlicomPollStart
  1811.     (
  1812.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  1813.     )
  1814.     {
  1815.     int s;
  1816.     int txBdIndex;
  1817.     TX_BD * pTxBd;
  1818.     ULONG addrC;
  1819.     int status;
  1820.     if (pDrvCtrl->flags & OLI_POLLING)
  1821. return (OK);
  1822.     s = intLock ();          /* disable ints during update */
  1823.     txBdIndex = pDrvCtrl->txBdIndexC;
  1824.     /* Select bank 0 of the Olicom register set */
  1825.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 0);
  1826.     while (txBdIndex != pDrvCtrl->txBdNext)
  1827.         {
  1828.         pTxBd = & pDrvCtrl->txBdBase[txBdIndex];
  1829. addrC = (ULONG) (pTxBd->dataPointer);
  1830.         /* Spin until frame buffer is sent */
  1831. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, addrC);
  1832. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (addrC >> 8));
  1833. READ_R14_R15 (status);
  1834.         while (!(status & TX_BD_READY))
  1835.     {
  1836.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, addrC);
  1837.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (addrC >> 8));
  1838.     READ_R14_R15 (status);
  1839.     }
  1840.         /* free the buffer */
  1841.         if (pDrvCtrl->freeBuf[txBdIndex].pClBuf != NULL)
  1842.             {
  1843.             NET_BUF_FREE(pDrvCtrl->freeBuf[txBdIndex].pClBuf);
  1844.             pDrvCtrl->freeBuf[txBdIndex].pClBuf = NULL;
  1845.             }
  1846.         /* increment txBdIndex */
  1847.         txBdIndex = (txBdIndex + 1) % pDrvCtrl->txBdNum;
  1848. /* Send a Transmit command if the transmit queue is not empty */
  1849. if (txBdIndex != pDrvCtrl->txBdNext)
  1850.     iOlicomTxStart(pDrvCtrl);
  1851.         }
  1852.     /*
  1853.      * Program featues: not promiscuous, not receive broadcast,
  1854.      * do not save CRC, Length Enable is on, Source Address insertion is
  1855.      * on, only one individual address, loopback off.
  1856.      */
  1857.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 2);
  1858.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R2, (BNK2_SAI_EN |
  1859.                         BNK2_RX_CRC | BNK2_BRO_DIS));
  1860.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R3,
  1861.         PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R3) & ~BNK2_TST_EN);
  1862.     /* Now, transmit queue is empty. We can enter polling mode. */
  1863.     /* mask off the receive and transmit interrupts */
  1864.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 0);
  1865.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R3,
  1866.         (PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R3) |
  1867. BNK0_ITS_MSK));
  1868.     /* Set the polling flag */
  1869.     DRV_FLAGS_SET(OLI_POLLING);
  1870.     intUnlock (s);   /* now iOlicomInt won't get confused */
  1871.     return OK;
  1872.     }
  1873. /*******************************************************************************
  1874. *
  1875. * iOlicomPollStop - stop polled mode operations
  1876. *
  1877. * This routine stops polling mode by enabling ethernet interrupts and
  1878. * resetting the polling flag in the END_DEVICE structure.
  1879. *
  1880. * RETURNS: OK, always.
  1881. */
  1882. LOCAL STATUS iOlicomPollStop
  1883.     (
  1884.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  1885.     )
  1886.     {
  1887.     int s;
  1888.     s = intLock ();          /* disable ints during update */
  1889.     /*
  1890.      * Program featues: not promiscuous, receive broadcast,
  1891.      * do not save CRC, Length Enable is on, Source Address insertion is
  1892.      * on, only one individual address, loopback off.
  1893.      */
  1894.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 2);
  1895.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R2, (BNK2_SAI_EN |
  1896.                                 BNK2_RX_CRC));
  1897.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R3,
  1898.         PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R3) & ~BNK2_TST_EN);
  1899.     /* Rewrite the register to turn on interrupts */
  1900.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 0);
  1901.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R3,
  1902.         PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R3) &
  1903. ~(BNK0_RX_MK | BNK0_TX_MK | BNK0_EXE_MK));
  1904.     /* Reset the polling flag */
  1905.     DRV_FLAGS_CLR(OLI_POLLING);
  1906.     intUnlock (s);   /* now iOlicomInt won't get confused */
  1907.     return (OK);
  1908.     }
  1909. /*******************************************************************************
  1910. *
  1911. * iOlicomReset - network interface reset routine
  1912. *
  1913. * This routine resets the 82595TX on the PCMCIA card.The PCMCIA setup
  1914. * must have been done already and an I/O window mapped into the target's
  1915. * address space.
  1916. *
  1917. * RETURNS: N/A
  1918. */
  1919. LOCAL void iOlicomReset
  1920.     (
  1921.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  1922.     )
  1923.     {
  1924.     END_LOG_MSG (END_DEBUG_LOAD, "iOlicomReset()n", 0, 0, 0, 0, 0, 0);
  1925.     pDrvCtrl->endObj.flags &= ~(IFF_RUNNING);
  1926.     PCMCIA_ATTR_WRITE (pDrvCtrl->pcmcia.oliAttribMem + CARDCONFREG0, 0x80);
  1927.     }
  1928. /*******************************************************************************
  1929. *
  1930. * iOlicomInit - network interface initialisation routine
  1931. *
  1932. * This routine marks the interface as down, configures and initialises the
  1933. * 82595 on the PCMCIA card.
  1934. * The PCMCIA setup must have been done already and an I/O window mapped into
  1935. * the PID's address space.
  1936. *
  1937. * RETURNS: OK if successful, otherwise ERROR.
  1938. */
  1939. LOCAL STATUS iOlicomInit
  1940.     (
  1941.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  1942.     )
  1943.     {
  1944.     UCHAR * cptr;
  1945.     pDrvCtrl->endObj.flags &= ~(IFF_UP | IFF_RUNNING);
  1946.     /*
  1947.      * Bring card out of reset. To be safe employ a
  1948.      * delay before enabling I/O.
  1949.      */
  1950.     END_LOG_MSG(END_DEBUG_LOAD,
  1951. "iOlicomInit(): oliAttribMem = 0x%X oliAddr = 0x%Xn",
  1952. pDrvCtrl->pcmcia.oliAttribMem, pDrvCtrl->pcmcia.oliAddr,
  1953. 0, 0, 0, 0);
  1954.     PCMCIA_ATTR_WRITE(pDrvCtrl->pcmcia.oliAttribMem + CARDCONFREG0, 0x40);
  1955.     taskDelay(sysClkRateGet()/100+1);
  1956.     PCMCIA_ATTR_WRITE(pDrvCtrl->pcmcia.oliAttribMem + CARDCONFREG0, 0x41);
  1957.     PCMCIA_ATTR_WRITE(pDrvCtrl->pcmcia.oliAttribMem + CARDCONFREG1, 0x20);
  1958.     /*
  1959.      * Check that the Exec interrupt is set, and that the
  1960.      * state is Init Done
  1961.      */
  1962.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 0);
  1963.     if ((PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R1) &
  1964.  BNK0_ITS_MSK) != BNK0_EXE_IT ||
  1965.         (PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R0) &
  1966.  OPCODE_MASK) != RESULT_INIT_DONE)
  1967.         {
  1968.         /*
  1969.          * I'm not too sure what to do here, basically the chip has failed to
  1970.          * initialise, it may be useful to try and start from scratch, but
  1971.          * for now I'm just going to exit. Perhaps it would be better to have
  1972.          * this code return an ERROR if things don't work, then at least we
  1973.          * can inform something higher up.
  1974.          */
  1975. END_LOG_MSG(END_DEBUG_LOAD, "iOlicomInit() problemn",
  1976. 0, 0, 0, 0, 0, 0);
  1977.         }
  1978.     /* Acknowledge the interrupt */
  1979.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R1, BNK0_EXE_IT);
  1980.     /* Program transmit and receive ring buffer parameters */
  1981.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R4,
  1982. (UCHAR) (RAM_RX_BASE + 2));
  1983.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R5,
  1984. (UCHAR) ( (RAM_RX_BASE + 2) >> 8));
  1985.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R6,
  1986. (UCHAR) RAM_RX_BASE);
  1987.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R7,
  1988. (UCHAR) (RAM_RX_BASE >> 8));
  1989.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R10,
  1990. (UCHAR) RAM_TX_BASE);
  1991.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R11,
  1992. (UCHAR) (RAM_TX_BASE >> 8));
  1993.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 1);
  1994.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R8,
  1995.                     (RAM_RX_BASE >> 8) & OCT_MSK);
  1996.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R9,
  1997.                     (RAM_RX_LIMIT >> 8) & OCT_MSK);
  1998.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R10,
  1999.                     (RAM_TX_BASE >> 8) & OCT_MSK);
  2000.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R11,
  2001.                     (RAM_TX_LIMIT >> 8) & OCT_MSK);
  2002.     /* Clear feature selection */
  2003.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R7, 0);
  2004.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 0);
  2005.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R8, 0);
  2006.     if (BNK0_EXE_STE(PCMCIA_IO_READ( pDrvCtrl->pcmcia.oliAddr + I595_R1)) !=
  2007. BNK0_EXE_IDL)
  2008.         {
  2009.         /*
  2010.          * Not too sure what to do here either, we've got the chip up it seems
  2011.          * but the state should now be in an idle state.
  2012.          */
  2013. END_LOG_MSG(END_DEBUG_LOAD, "iOlicomInit problem 2n",
  2014. 0, 0, 0, 0, 0, 0);
  2015.         }
  2016.     /*
  2017.      * Select bank two of the chips registers ready to program in the
  2018.      * hardware MAC address.
  2019.      */
  2020.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 2);
  2021.     cptr = (UCHAR *) pDrvCtrl->enetAddr;
  2022.     /* Copy in the MAC address */
  2023.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R4, *cptr);
  2024.     ++cptr;
  2025.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R5, *cptr);
  2026.     ++cptr;
  2027.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R6, *cptr);
  2028.     ++cptr;
  2029.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R7, *cptr);
  2030.     ++cptr;
  2031.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R8, *cptr);
  2032.     ++cptr;
  2033.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R9, *cptr);
  2034.     /* now wait for the IA-SETUP command to finish */
  2035.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 0);
  2036.     while (BNK0_EXE_STE(PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R1)) !=
  2037. BNK0_EXE_IDL)
  2038.         /* do nothing */
  2039.         ;
  2040.     /*
  2041.      * We do not use Transmit Concurrent Processing,
  2042.      * but we do discard bad frames.
  2043.      */
  2044.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 2);
  2045.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R1, BNK2_BAD_DSC);
  2046.     /*
  2047.      * Program featues: not promiscuous, receive broadcast,
  2048.      * do not save CRC, Length Enable is on, Source Address insertion is
  2049.      * on, individual address enable, loopback off.
  2050.      */
  2051.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R2, (BNK2_SAI_EN |
  2052.                                 BNK2_RX_CRC));
  2053.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R3,
  2054.         PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R3) &
  2055. ~BNK2_TST_EN);
  2056.     /* Enable interrupts */
  2057.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 1);
  2058.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R1, BNK1_TST_EN);
  2059.     SELECTBANK(pDrvCtrl->pcmcia.oliAddr, 0);
  2060.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R3,
  2061.         (PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R3) &
  2062.   ~(BNK0_RX_MK | BNK0_TX_MK | BNK0_EXE_MK)));
  2063.     RUNCMD(pDrvCtrl->pcmcia.oliAddr, CMD_RESET_TRISTATE);
  2064.     RUNCMD(pDrvCtrl->pcmcia.oliAddr, CMD_RCV_ENABLE);
  2065.     return OK;
  2066.     }
  2067. /*******************************************************************************
  2068. *
  2069. * iOlicomTxBdQueueClean - clean the transmit buffer descriptor queue
  2070. *
  2071. * This routine cleans the transmit buffer queue.
  2072. *
  2073. * RETURNS: N/A
  2074. *
  2075. */
  2076. LOCAL void iOlicomTxBdQueueClean
  2077.     (
  2078.     END_DEVICE * pDrvCtrl        /* pointer to END_DEVICE structure */
  2079.     )
  2080.     {
  2081.     TX_BD * pTxBd;
  2082.     ULONG addrC;
  2083.     int s;
  2084.     int status;
  2085.     END_LOG_MSG (END_DEBUG_TX, "iOlicomTxBdQueueClean ...n", 0, 0, 0, 0, 0, 0);
  2086.     s = intLock();
  2087.     while (pDrvCtrl->txBdIndexC != pDrvCtrl->txBdNext)
  2088.         {
  2089.         pTxBd = & pDrvCtrl->txBdBase[pDrvCtrl->txBdIndexC];
  2090. addrC = (ULONG) pTxBd->dataPointer;
  2091.         /* read the current Transmit Done flag */
  2092. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, addrC);
  2093. PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (addrC >> 8));
  2094. READ_R14_R15 (status);
  2095.         if (status & TX_BD_READY)
  2096.     {
  2097.     READ_R14_R15 (status);
  2098.             /* check for output errors */
  2099.             if (!(status & XMT_OK))
  2100.         {
  2101.         if ((status & XMT_COL_MAX) || (status & XMT_UND_RUN) ||
  2102.          (status & XMT_LST_CRS)) /* Restart a transmit command */
  2103.     {
  2104.     (void) netJobAdd ((FUNCPTR) iOlicomTxRestart,
  2105. (int) pDrvCtrl, 0,0,0,0);
  2106.     break;
  2107.     }
  2108.         }
  2109.     }
  2110. else
  2111.     {
  2112.     /* Send a Transmit command if the transmit queue is not empty */
  2113.     iOlicomTxStart(pDrvCtrl);
  2114.     break;
  2115.     }
  2116. /* free the buffer */
  2117.         if (pDrvCtrl->freeBuf[pDrvCtrl->txBdIndexC].pClBuf != NULL)
  2118.             {
  2119.     NET_BUF_FREE(pDrvCtrl->freeBuf[pDrvCtrl->txBdIndexC].pClBuf);
  2120.             pDrvCtrl->freeBuf[pDrvCtrl->txBdIndexC].pClBuf = NULL;
  2121.             }
  2122.         /* incr txBdIndexC */
  2123.         pDrvCtrl->txBdIndexC = (pDrvCtrl->txBdIndexC + 1) % pDrvCtrl->txBdNum;
  2124.         }
  2125.     DRV_FLAGS_CLR(OLI_TX_CLEANING);
  2126.     intUnlock(s);
  2127.     }
  2128. /*******************************************************************************
  2129. *
  2130. * iOlicomTxStart - issue a XMT command to the 82595TX
  2131. *
  2132. * This routine issues a XMT command to the 82595TX.
  2133. *
  2134. * RETURNS: N/A
  2135. */
  2136. LOCAL void iOlicomTxStart
  2137.     (
  2138.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  2139.     )
  2140.     {
  2141.     TX_BD * pTxBd;
  2142.     ULONG addrC;
  2143.     int s;
  2144.     END_LOG_MSG (END_DEBUG_TX, "iOlicomTxStart n", 0, 0, 0, 0, 0, 0);
  2145.     pTxBd = & pDrvCtrl->txBdBase[pDrvCtrl->txBdIndexC];
  2146.     addrC = (ULONG) pTxBd->dataPointer;
  2147.     /* lock interrupts */
  2148.     s = intLock ();
  2149.     /* Write the XMT base address register */
  2150.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R10, addrC);
  2151.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R11, (addrC >> 8));
  2152.     /* Issue a XMT command to the 82595TX */
  2153.     RUNCMD(pDrvCtrl->pcmcia.oliAddr, CMD_TRANSMIT);
  2154.     /* Unlock interrupts */
  2155.     intUnlock (s);
  2156.     }
  2157. /*******************************************************************************
  2158. *
  2159. * iOlicomTxRestart - issue an other XMT  command to the 82595TX
  2160. *
  2161. * This routine issues an other XMT command to the 82595Tx.  It is
  2162. * executed by netTask (iOlicomTxBdQueueClean() did a netJobAdd).
  2163. *
  2164. * RETURNS: N/A
  2165. */
  2166. LOCAL void iOlicomTxRestart
  2167.     (
  2168.     END_DEVICE *        pDrvCtrl        /* pointer to END_DEVICE structure */
  2169.     )
  2170.     {
  2171.     END_LOG_MSG (END_DEBUG_TX, "iOlicomTxRestart n", 0, 0, 0, 0, 0, 0);
  2172.     /* update error counter */
  2173.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
  2174.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, -1);
  2175.     /* restart a transmit */
  2176.     iOlicomTxStart(pDrvCtrl);
  2177.     }
  2178. /*******************************************************************************
  2179. *
  2180. * iOlicomPcmciaReadTuple - read a tuple from the given offset in attribute space
  2181. *
  2182. * RETURNS: offset to beginning of next tuple, otherwise 0
  2183. */
  2184. LOCAL UINT iOlicomPcmciaReadTuple
  2185.     (
  2186.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  2187.     UINT offset, /* offset into tuple space */
  2188.     UCHAR * buffer, /* pointer to the holding buffer */
  2189.     UINT buflen /* size of the buffer in bytes */
  2190.     )
  2191.     {
  2192.     PCMCIASOCKET * pcs = &pDrvCtrl->pcmcia.theSocket;
  2193.     UINT tuple_type;
  2194.     UINT tuple_length;
  2195.     UINT base = pcs->pcs_attrbase;
  2196.     UCHAR * cptr = buffer;
  2197.     END_LOG_MSG (END_DEBUG_TUPLES,
  2198.     "iOlicomPcmciaReadTuple() going to read from (base+offset) (0x%X + 0x%Xn",
  2199. base, offset, 0, 0, 0, 0);
  2200.     /* Load the tuple type, check for end of list markers  */
  2201.     tuple_type = PCMCIA_ATTR_READ (base + offset);
  2202.     END_LOG_MSG (END_DEBUG_TUPLES,
  2203.  "iOlicomPcmciaReadTuple(): tuple type = 0x%Xn",
  2204.  tuple_type, 0, 0, 0, 0, 0);
  2205.     if ((tuple_type == 0xFF) || (tuple_type == 0x14))
  2206. {
  2207. END_LOG_MSG (END_DEBUG_TUPLES,
  2208. "iOlicomPcmciaReadTuple(): end of tuple listn",                                0, 0, 0, 0, 0, 0);
  2209. return 0;
  2210. }
  2211.     /*
  2212.      * We are going to be returning at least a type and a link,
  2213.      * so get these into the buffer.
  2214.      */
  2215.     *(cptr++) = tuple_type;
  2216.     offset += 2;
  2217.     END_LOG_MSG (END_DEBUG_TUPLES,
  2218.     "iOlicomPcmciaReadTuple() going to read from (base+offset) (0x%X + 0x%Xn",
  2219. base, offset, 0, 0, 0, 0);
  2220.     tuple_length = PCMCIA_ATTR_READ(base + offset);
  2221.     *cptr = tuple_length;
  2222.     offset += 2;
  2223.     END_LOG_MSG (END_DEBUG_TUPLES,
  2224. "iOlicomPcmciaReadTuple(): tuple length = 0x%Xn",
  2225. tuple_length, 0, 0, 0, 0, 0);
  2226.     /* Check for tuple link marking the end of a list */
  2227.     if (tuple_length == 0xFF)
  2228.         /* End of the list marker */
  2229.         return 0;
  2230.     /*
  2231.      * Copy the tuple data from attribute space into our buffer
  2232.      * until we reach the end of the tuple or run out of buffer
  2233.      * space (unlikely).
  2234.      */
  2235.     buflen -= 2;
  2236.     if (buflen > tuple_length)
  2237.         buflen = tuple_length;
  2238.     while (buflen-- > 0)
  2239. {
  2240.         *++cptr = PCMCIA_ATTR_READ(base + offset);
  2241.         offset += 2;
  2242. }
  2243.     /* finished */
  2244.     END_LOG_MSG (END_DEBUG_TUPLES,
  2245. "iOlicomPcmciaReadTuple() returning 0x%Xn",
  2246. offset, 0, 0, 0, 0, 0);
  2247.     return offset;
  2248.     }
  2249. /*******************************************************************************
  2250. *
  2251. * iOlicomPcmciaFindTuple - search a card's attribute space for a given tuple.
  2252. *
  2253. * RETURNS: Pointer to a buffer holding the tuple data.
  2254. */
  2255. LOCAL UCHAR *iOlicomPcmciaFindTuple
  2256.     (
  2257.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  2258.     UINT tuple, /* tuple code to find */
  2259.     UINT * offset, /* offset in attr space */
  2260.     UCHAR * buffer, /* buffer to hold data */
  2261.     UINT buflen /* size of buffer */
  2262.     )
  2263.     {
  2264.     UINT loff = *offset;                /* local offset */
  2265.     END_LOG_MSG (END_DEBUG_TUPLES,"iOlicomPcmciaFindTuple(), find tuple 0x%Xn",
  2266. tuple, 0, 0, 0, 0, 0);
  2267.     /* guard against potential false positives */
  2268.     *buffer = ~tuple;
  2269.     /* keep going until the tuple is found, or proven not to exist  */
  2270.     do
  2271.     {
  2272.         loff = iOlicomPcmciaReadTuple(pDrvCtrl, loff, buffer, buflen);
  2273.     }
  2274.     while (loff != 0 && *buffer != tuple);
  2275.     *offset = loff;
  2276. #ifdef DEBUG
  2277.     if (*buffer != tuple)
  2278. END_LOG_MSG (END_DEBUG_LOAD_FAIL,
  2279.      "PcmciaFindTuple(): tuple 0x%X not foundn",
  2280.      tuple, 0, 0, 0, 0, 0);
  2281. #endif
  2282.     return (*buffer == tuple) ? buffer : NULL;
  2283.     }
  2284. /*******************************************************************************
  2285. *
  2286. * iOlicomReadCardAttributes - read a card's attributes
  2287. *
  2288. * This is really read card attributes and check it's an Olicom Ethernet card.
  2289. * If this call returns OK, the card in the slot is an Olicom and the base
  2290. * address of the Ethernet hardware will have been set up in the pDrvCtrl
  2291. * structure.
  2292. *
  2293. * RETURNS: OK if successful, otherwise ERROR.
  2294. */
  2295. LOCAL STATUS iOlicomReadCardAttributes
  2296.     (
  2297.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  2298.     )
  2299.     {
  2300.     UCHAR buffer[256];
  2301.     UCHAR * cptr;
  2302.     UINT        offset = 0;
  2303.     UINT        iobase;
  2304.     UCHAR * hwaddr = (UCHAR *) pDrvCtrl->enetAddr;
  2305.     /*
  2306.      * There are four tuples that we need to read from the card:
  2307.      *
  2308.      * CARD_FUNCID - Should identify the card as an Network Adaptor
  2309.      *
  2310.      * CARD_FUNCE - Function extension tuple detailing the Ethernet
  2311.      * hardware address
  2312.      *
  2313.      * CARD_CONFIG - Describes card configuration registers
  2314.      *
  2315.      * CARD_CFT_ENTRY - There are several different copies of this
  2316.      * one tuple, which describe the different I/O addresses accepted by
  2317.      * the Intel 82595 Controller.
  2318.      *
  2319.      * These tuples should be in the order listed, so we start searching
  2320.      * for the next tuple from where the previous one finished, but we
  2321.      * also try again from the beginning if the search failed.
  2322.      */
  2323.     /* Find FUNCID tuple first */
  2324.     if ((cptr = iOlicomPcmciaFindTuple(pDrvCtrl, CARD_FUNCID, &offset,
  2325.         buffer, sizeof(buffer))) == NULL)
  2326.         return ERROR;
  2327.     if (*(cptr + 2) != 0x06)
  2328.         return ERROR;
  2329.     /* Look for FUNCE tuple */
  2330.     if ((cptr = iOlicomPcmciaFindTuple(pDrvCtrl, CARD_FUNCE, &offset,
  2331.         buffer, sizeof(buffer))) == NULL)
  2332.         {
  2333.         /* try again, from the beginning */
  2334.         offset = 0;
  2335.         if ((cptr = iOlicomPcmciaFindTuple(pDrvCtrl, CARD_FUNCE, &offset,
  2336.             buffer, sizeof(buffer))) == NULL)
  2337.             return ERROR;
  2338.         }
  2339.     /*
  2340.      * this should be flagged as a node id tuple (byte 2 = 0x04), with
  2341.      * a length (byte 3) of 6 bytes
  2342.      */
  2343.     if (*(cptr + 2) != 0x04 || *(cptr + 3) != 0x06)
  2344.         return ERROR;
  2345.     /* OK, copy the hardware address */
  2346.     memcpy(hwaddr, cptr + 4, 6);
  2347.     /* Find CONFIG tuple */
  2348.     if ((cptr = iOlicomPcmciaFindTuple(pDrvCtrl, CARD_CONFIG, &offset,
  2349.         buffer, sizeof(buffer))) == NULL)
  2350.         {
  2351.         /* try again, from the beginning */
  2352.         offset = 0;
  2353.         if ((cptr = iOlicomPcmciaFindTuple(pDrvCtrl, CARD_CONFIG, &offset,
  2354.             buffer, sizeof(buffer))) == NULL)
  2355.             return ERROR;
  2356.         }
  2357.     END_LOG_MSG (END_DEBUG_TUPLES,
  2358. "iOlicomReadCardAttributes() CONFIG Regs at 0x%X%Xn",
  2359. *(cptr + 5), *(cptr + 4), 0, 0, 0, 0);
  2360.     /*
  2361.      * OK, bytes 4 and 5 of the tuple contain the address (in attribute
  2362.      * memory) of the card configuration registers (lsb first), byte 6
  2363.      * contains the bitmap of which registers are present
  2364.      */
  2365.     if (*(cptr + 6) != 0x03)
  2366.         return ERROR;
  2367.     /*
  2368.      * tuple 4 - CARD_CFT_ENTRY
  2369.      *
  2370.      * I must confess to a certain level of ignorance here: using the
  2371.      * version of the PCMCIA Metaformat Specification that we have here
  2372.      * (November 1995) I cannot fully decode the default Configuration
  2373.      * Table Entry supplied by the Olicom Ethernet Card.  However, I
  2374.      * *can* understand the I/O Space Descriptions, of which the Olicom
  2375.      * card supplies several (because it does not fully decode the I/O
  2376.      * address); fortuitously, for all non-default CFTABLE_ENTRY tuples,
  2377.      * these I/O Space Descriptions are the first descriptions within
  2378.      * the tuple, and therefore easy to find.
  2379.      */
  2380.     if ((cptr = iOlicomPcmciaFindTuple(pDrvCtrl, CARD_CFT_ENTRY, &offset,
  2381.         buffer, sizeof(buffer))) == NULL)
  2382.         {
  2383.         /* try again, from the beginning */
  2384.         offset = 0;
  2385.         if ((cptr = iOlicomPcmciaFindTuple(pDrvCtrl, CARD_CFT_ENTRY, &offset,
  2386.             buffer, sizeof(buffer))) == NULL)
  2387.             return ERROR;
  2388.         }
  2389.     /* keep going until we get some I/O space mapped */
  2390.     for (;;)
  2391.         {
  2392.         /*
  2393.          * don't bother trying if this is the default configuration
  2394.          * tuple (identified by bit 6 of byte 2); can't cope with the
  2395.          * Interface Description field (flagged by bit 7, byte 2) being
  2396.          * present either.
  2397.          */
  2398.         if (((*(cptr + 2)) & 0xC0) == 0)
  2399.             {
  2400.             /*
  2401.              * Paranoia (i.e. limited implementation) checks:
  2402.              *
  2403.              * Bit 3 of byte 3 flags an I/O description structure;
  2404.              * this should be the lsb set in the byte.
  2405.              *
  2406.              * Byte 5 describes the I/O range - we can only
  2407.              * cope with a specific case (the general case
  2408.              * is neither hard, nor worth implementing).
  2409.              */
  2410.             if ((*(cptr + 3) & 0x0F) == 0x08 && *(cptr + 5) == 0x60)
  2411.                 {
  2412.                 /*
  2413.                  * OK, we can cope with this tuple: bytes 6 and 7
  2414.                  * give the I/O base address, and byte 8 gives the
  2415.                  * range (which should be 0x0F)
  2416.                  */
  2417.                 if (*(cptr + 8) != 0x0F)
  2418.                     return ERROR;
  2419.                 /*
  2420.                  * pull out the base address, and try to get this
  2421.                  * mapped into the PCMCIA controller's I/O space;
  2422.                  * note that we also ask for Interrupts to be "enabled"
  2423.                  * by the PCMCIA controller, but no interrupt sources
  2424.                  * on the card itself are enabled yet.
  2425.                  */
  2426.                 iobase = (*(cptr + 7) << 8) | *(cptr + 6);
  2427.                 if (iOlicomMapIOSpace(pDrvCtrl, iobase, 0x0F, 1) == OK)
  2428.                     {
  2429.                     /*
  2430.                      * calculate the actual base address of the
  2431.                      * chip in I/O space
  2432.                      */
  2433.     END_LOG_MSG (END_DEBUG_LOAD,
  2434.     "ReadCardAttributes(), iobase = 0x%Xn",
  2435.     iobase, 0, 0, 0, 0, 0);
  2436.     if (pDrvCtrl->pcmcia.socket == PC_SOCKET_A)
  2437. {
  2438. pDrvCtrl->pcmcia.oliAddr =
  2439. (char *) PCMCIA_CALC_ADDR(iobase)
  2440. + (UINT) pDrvCtrl->pcmcia.ioBaseA;
  2441. }
  2442.     else
  2443. {
  2444. pDrvCtrl->pcmcia.oliAddr =
  2445. (char *) (PCMCIA_CALC_ADDR(iobase)
  2446. + (UINT) pDrvCtrl->pcmcia.ioBaseB);
  2447. }
  2448.                     return OK;
  2449.                     }
  2450.                 }
  2451.             }
  2452.             if ((cptr = iOlicomPcmciaFindTuple(pDrvCtrl,
  2453.  CARD_CFT_ENTRY, &offset,
  2454.                 buffer, sizeof(buffer))) == NULL)
  2455.             return ERROR;
  2456.         }
  2457.     }
  2458. /*******************************************************************************
  2459. *
  2460. * iOlicomInitialiseCard - initialise the card
  2461. *
  2462. * Do any work necessary to bring a card to a consistent
  2463. * state, and implicitly check it is an Olicom ethernet card via the
  2464. * iOlicomReadCardAttributes() function.
  2465. *
  2466. * RETURNS: OK if successful, otherwise ERROR.
  2467. */
  2468. LOCAL STATUS iOlicomInitialiseCard
  2469.     (
  2470.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  2471.     )
  2472.     {
  2473.     UCHAR buffer[256];
  2474.     UCHAR * cptr;
  2475.     UINT        offset = 0;
  2476.     END_LOG_MSG (END_DEBUG_LOAD, "iOlicomInitialiseCard()n",
  2477. 0, 0, 0, 0, 0, 0);
  2478.     if ((cptr = iOlicomPcmciaFindTuple(pDrvCtrl, 0x15,
  2479.         &offset, buffer, sizeof(buffer))) != NULL)
  2480.         {
  2481.         /*
  2482.          * An Olicom Ethercom card has been found in the socket. Ascertain
  2483.          * the I/O space mapping from the tuple headers and then set up an
  2484.          * I/O window for this card.
  2485.          */
  2486.         if (iOlicomReadCardAttributes(pDrvCtrl) == OK)
  2487.     {
  2488.     END_LOG_MSG (END_DEBUG_LOAD,
  2489. "iOlicomCardInitialiseCard(): found Olicom cardn",
  2490. 0, 0, 0, 0, 0, 0);
  2491.             return OK;
  2492.     }
  2493. else
  2494.     END_LOG_MSG (END_DEBUG_LOAD_FAIL, "ReadCardAttributes() failedn",
  2495.  0, 0, 0, 0, 0, 0);
  2496.         }
  2497.     END_LOG_MSG (END_DEBUG_LOAD_FAIL, "card in slot is not Olicomn",
  2498.  0, 0, 0, 0, 0, 0);
  2499.     iOlicomShutdownSlot(pDrvCtrl, pDrvCtrl->pcmcia.socket);
  2500.     return ERROR;
  2501.     }
  2502. /*******************************************************************************
  2503. *
  2504. * iOlicomCardInsertion - cope with the insertion of a card
  2505. *
  2506. * Called when a card is detected in a slot, either by a real insertion
  2507. * or from detection during initialisation.
  2508. *
  2509. * RETURNS: OK if successful, otherwise ERROR.
  2510. */
  2511. LOCAL STATUS iOlicomCardInsertion
  2512.     (
  2513.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  2514.     UINT socket /* socket ID */
  2515.     )
  2516.     {
  2517.     END_LOG_MSG (END_DEBUG_LOAD, "iOlicomCardInsertion() socket = 0x%Xn",
  2518. socket, 0, 0, 0, 0, 0);
  2519.     /*
  2520.      * first set up the PCMCIA slot, then try
  2521.      * to set up the card itself
  2522.      */
  2523.     iOlicomInitialiseSlot(pDrvCtrl, socket);
  2524.     return iOlicomInitialiseCard(pDrvCtrl);
  2525.     }
  2526. #ifndef PCMCIA_NO_VADEM
  2527. /*******************************************************************************
  2528. *
  2529. * iOlicomInt - handle controller interrupt
  2530. *
  2531. * This interrupt service routine, reads device interrupt status, acknowledges
  2532. * the interrupting events, and schedules receive and transmit processing when
  2533. * required.
  2534. *
  2535. * RETURNS: N/A.
  2536. */
  2537. LOCAL void iOlicomInt
  2538.     (
  2539.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  2540.     )
  2541.     {
  2542.     int irqType;
  2543.     int cardStat;
  2544.     /* On some systems it may be necessary to acknowledge the interrupt. */
  2545.     SYS_BUS_INT_ACK(pDrvCtrl);
  2546.     /*
  2547.      * Handle low latency interrupt processing, such as device errors,
  2548.      * output complete, etc. Merely reading the interrupt state acknowledges
  2549.      * the request.
  2550.      *
  2551.      * First, check the PCMCIA status register. This should either be
  2552.      * generating a card detect change interrupt (due to card insertion or
  2553.      * removal) or a card I/O interrupt due to some event on the inserted
  2554.      * card.
  2555.      */
  2556.     irqType = OLI_VADEM_READ(PCCSTATCHNG + pDrvCtrl->pcmcia.socket);
  2557.     if (irqType & GSR_CDC) /* This is a card detect change */
  2558.         {
  2559.         /*
  2560.          * For card detect changes either a card has been plugged in or
  2561.          * a card has been removed. These are hooks for later extension and
  2562.          * neither event is handled here.
  2563.          */
  2564.         cardStat = (OLI_VADEM_READ(PCIFSTATUS + pDrvCtrl->pcmcia.socket))
  2565.  & GSR_CD;
  2566.         if (cardStat == GSR_CD)
  2567.             {
  2568.             /* This is a card insertion. */
  2569.             }
  2570.         else
  2571.             {
  2572.             /* Yikes! My card doesn't work. */
  2573.             }
  2574. END_LOG_MSG (END_DEBUG_INT, "False interrupt.n", 0, 0, 0, 0, 0, 0);
  2575.         return;
  2576.         }
  2577.     else /* A card state interrupt, examine the card for more */
  2578. iOlicomIntHandle(pDrvCtrl);
  2579.     return;
  2580.     }
  2581. /*******************************************************************************
  2582. *
  2583. * iOlicomPcmciaSetup - bring up the PCMCIA hardware
  2584. *
  2585. * This routine examines the two slots and attempts to initialise any
  2586. * Olicom card found.
  2587. *
  2588. * RETURNS: OK if successful, otherwise ERROR
  2589. */
  2590. LOCAL STATUS iOlicomPcmciaSetup
  2591.     (
  2592.     END_DEVICE * pDrvCtrl /* pointer to END_DEVICE structure */
  2593.     )
  2594.     {
  2595.     END_LOG_MSG (END_DEBUG_LOAD, "iOlicomPcmciaSetup() - %s%dn",
  2596.  DRV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  2597.     /*
  2598.      * VG-468 IRQs 4 & 3 are tied to AMBA interrupt lines
  2599.      * IRQ_CARDA and IRQ_CARDB respectively, set IRQ
  2600.      * steering as appropriate, and enable Card Detect
  2601.      * interrupts on both sockets
  2602.      */
  2603.     OLI_VADEM_WRITE(PCSTATCHNGINT + PC_SOCKET_A, (GSR_IRQ4 | GSR_CDE));
  2604.     OLI_VADEM_WRITE(PCSTATCHNGINT + PC_SOCKET_B, (GSR_IRQ3 | GSR_CDE));
  2605.     /* clear status registers */
  2606.     OLI_VADEM_READ(PCCSTATCHNG + PC_SOCKET_A);
  2607.     OLI_VADEM_READ(PCCSTATCHNG + PC_SOCKET_B);
  2608.     /*
  2609.      * Map the attribute memory of both sockets into ARM
  2610.      * address space. Then shutdown the sockets.
  2611.      */
  2612.     iOlicomMapMemory(pDrvCtrl, PC_SOCKET_A, 0, ATTRIB_MEMORY_A,
  2613.                 ATTRIBUTE_MEMORY_SLOT, 0, ATTRIBUTE);
  2614.     iOlicomShutdownSlot(pDrvCtrl, PC_SOCKET_A);
  2615.     iOlicomMapMemory(pDrvCtrl, PC_SOCKET_B, 0, ATTRIB_MEMORY_B,
  2616.                 ATTRIBUTE_MEMORY_SLOT, 0, ATTRIBUTE);
  2617.     iOlicomShutdownSlot(pDrvCtrl, PC_SOCKET_B);
  2618.     /*
  2619.      * Enable card detect debouncing, and Tri-state
  2620.      * unused pins. We need to unlock the VG-468
  2621.      * unique registers before this will work
  2622.      */
  2623.     OLI_VADEM_UNLOCK();
  2624.     OLI_VADEM_WRITE(PCCONTROL + PC_SOCKET_A, 0x00);
  2625.     OLI_VADEM_WRITE(PCCONTROL + PC_SOCKET_B, 0x00);
  2626.     END_LOG_MSG (END_DEBUG_LOAD, "Looking for cardsn", 0, 0, 0, 0, 0, 0);
  2627.     /*
  2628.      * initialise socket descriptor, first check socket A
  2629.      * and then socket B, looking for an Olicom Ethernet
  2630.      * card.
  2631.      */
  2632.     pDrvCtrl->pcmcia.cardPresent = FALSE;
  2633.     pDrvCtrl->pcmcia.socket = PC_SOCKET_A;
  2634.     pDrvCtrl->pcmcia.theSocket.pcs_attrbase = (UINT)pDrvCtrl->pcmcia.attrBaseA;
  2635.     pDrvCtrl->pcmcia.oliAttribMem = pDrvCtrl->pcmcia.attrBaseA;
  2636.     pDrvCtrl->pcmcia.theSocket.pcs_attrrange = ATTRIBUTE_MEMORY_SLOT;
  2637.     if (((OLI_VADEM_READ(PCIFSTATUS + PC_SOCKET_A) & GSR_CD) == GSR_CD) &&
  2638.         ( iOlicomCardInsertion(pDrvCtrl, PC_SOCKET_A) == OK ))
  2639.         {
  2640. END_LOG_MSG (END_DEBUG_LOAD, "Found card An", 0, 0, 0, 0, 0, 0);
  2641.         pDrvCtrl->ilevel = pDrvCtrl->pcmcia.intLevelA;
  2642.         pDrvCtrl->ivec = pDrvCtrl->pcmcia.intVectA;
  2643.         return OK;
  2644.         }
  2645.     pDrvCtrl->pcmcia.socket = PC_SOCKET_B;
  2646.     pDrvCtrl->pcmcia.theSocket.pcs_attrbase = (UINT)pDrvCtrl->pcmcia.attrBaseB;
  2647.     pDrvCtrl->pcmcia.oliAttribMem = pDrvCtrl->pcmcia.attrBaseB;
  2648.     if (((OLI_VADEM_READ(PCIFSTATUS + PC_SOCKET_B) & GSR_CD) == GSR_CD) &&
  2649.         ( iOlicomCardInsertion(pDrvCtrl, PC_SOCKET_B) == OK ))
  2650.         {
  2651. END_LOG_MSG (END_DEBUG_LOAD, "Found card Bn", 0, 0, 0, 0, 0, 0);
  2652.         pDrvCtrl->ilevel = pDrvCtrl->pcmcia.intLevelB;
  2653.         pDrvCtrl->ivec = pDrvCtrl->pcmcia.intVectB;
  2654.         return OK;
  2655.         }
  2656.     END_LOG_MSG (END_DEBUG_LOAD_FAIL, "Failed to find card in either slotn",
  2657.  0, 0, 0, 0, 0, 0);
  2658.     return ERROR;
  2659.     }
  2660. /*******************************************************************************
  2661. *
  2662. * iOlicomInitialiseSlot - initialise PCMCIA slot
  2663. *
  2664. * Called once a card has been detected in a PCMCIA slot, this function applies
  2665. * power to the slot and maps the attribute memory in.
  2666. *
  2667. * RETURNS: N/A
  2668. */
  2669. LOCAL void iOlicomInitialiseSlot
  2670.     (
  2671.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  2672.     UINT socket /* socket structure */
  2673.     )
  2674.     {
  2675.     END_LOG_MSG (END_DEBUG_LOAD, "iOlicomInitialiseSlot() socket = 0x%Xn",
  2676. socket, 0, 0, 0, 0, 0);
  2677.     /* socket now has a card present */
  2678.     pDrvCtrl->pcmcia.cardPresent = TRUE;
  2679.     /* Turn on power (use auto-select) */
  2680.     OLI_VADEM_WRITE(PCPWRRSTCTL + socket, (GSR_CPE | GSR_PSE));
  2681.     /* delay for at least 300 ms */
  2682.     taskDelay (((sysClkRateGet()*3)/10) + 1);
  2683.     /* then enable output. */
  2684.     OLI_VADEM_WRITE(PCPWRRSTCTL + socket, (GSR_CPE | GSR_PSE | GSR_OE));
  2685.     taskDelay (1);
  2686.     /*
  2687.      * reset the card by asserting the reset line, waiting a bit,
  2688.      * then taking reset off again
  2689.      */
  2690.     OLI_VADEM_WRITE(PCINTGCTL + socket, 0x00);
  2691.     /* assert reset for at least 10 ms */
  2692.     taskDelay ((sysClkRateGet()/100) + 1);
  2693.     /* deassert reset */
  2694.     OLI_VADEM_WRITE(PCINTGCTL + socket, GSR_DRT);
  2695.     /* delay for at least 20 ms */
  2696.     taskDelay (((sysClkRateGet()* 2)/100) + 1);
  2697.     /* Wait until card is ready */
  2698.     while ((OLI_VADEM_READ(PCIFSTATUS + socket) & GSR_RDY) == 0)
  2699.         /* do nothing */
  2700.         ;
  2701.     /* Enable window 0, which is the attribute memory window  */
  2702.     OLI_VADEM_WRITE(PCADDWINEN + socket, GSR_WD0);
  2703.     }
  2704. /*******************************************************************************
  2705. *
  2706. * iOlicomShutdownSlot - shutdown a PCMCIA slot
  2707. *
  2708. * This routine is the opposite of iOlicomInitialiseSlot(), it removes power to
  2709. * a PCMCIA slot and maps the card out of the processor's address space.
  2710. *
  2711. * RETURNS: N/A
  2712. */
  2713. LOCAL void iOlicomShutdownSlot
  2714.     (
  2715.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  2716.     UINT socket /* socket structure */
  2717.     )
  2718.     {
  2719.     /* Disable all I/O interrupts, and reset the card */
  2720.     OLI_VADEM_WRITE(PCINTGCTL + socket, 0x00);
  2721.     /* Disable all memory windows */
  2722.     OLI_VADEM_WRITE(PCADDWINEN + socket, 0x00);
  2723.     /* Remove the card's power */
  2724.     OLI_VADEM_WRITE(PCPWRRSTCTL + socket, GSR_PSE);
  2725.     }
  2726. /*******************************************************************************
  2727. *
  2728. * iOlicomMapMemory - map a section of memory into the processor's address space.
  2729. *
  2730. * RETURNS: N/A
  2731. */
  2732. LOCAL void iOlicomMapMemory
  2733.     (
  2734.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  2735.     UINT socket, /* Socket ID*/
  2736.     UINT window, /* window to use */
  2737.     UINT base, /* base address */
  2738.     UINT range, /* mapping range */
  2739.     UINT offset, /* offset in space */
  2740.     MEMTYPE type /* Memory type */
  2741.     )
  2742.     {
  2743.     UINT reg;
  2744.     UINT stop;
  2745.     UINT cardoff;
  2746.     /* registers for each window are 8 bytes apart */
  2747.     reg = socket + (window << 3);
  2748.     /* set start address, 16-bit data path, and no Zero Wait State */
  2749.     OLI_VADEM_WRITE(PCSYSA0MSTARTL + reg, (base >> 12) & OCT_MSK);
  2750.     OLI_VADEM_WRITE(PCSYSA0MSTARTH + reg, ((base >> 20) & 0x0F) | 0x80);
  2751.     /* set stop address, and 3 wait states for 16-bit access */
  2752.     stop = base + (range - 1);
  2753.     OLI_VADEM_WRITE(PCSYSA0MSTOPL + reg, (stop >> 12) & OCT_MSK);
  2754.     OLI_VADEM_WRITE(PCSYSA0MSTOPH + reg, ((stop >> 20) & 0x0F) | 0xC0);
  2755.     /* set card offset, no Write Protect, and attribute bit */
  2756.     cardoff = offset - base;
  2757.     OLI_VADEM_WRITE(PCCMEMA0OFFL + reg, (cardoff >> 12) & OCT_MSK);
  2758.     OLI_VADEM_WRITE(PCCMEMA0OFFH + reg, (((cardoff >> 20) & 0x3F) |
  2759.  ((type == ATTRIBUTE) ? 0x40 : 0x00)));
  2760.     }
  2761. /*******************************************************************************
  2762. *
  2763. * iOlicomMapIOSpace - map I/O space
  2764. *
  2765. * Attempt to map I/O space on the PCMCIA card into processor address space.
  2766. *
  2767. * RETURNS: OK if successful, otherwise ERROR
  2768. */
  2769. LOCAL STATUS iOlicomMapIOSpace
  2770.     (
  2771.     END_DEVICE * pDrvCtrl, /* pointer to END_DEVICE structure */
  2772.     UINT base, /* Base address of IO space */
  2773.     UINT range, /* Range of address to map */
  2774.     int mapirq /* Interrupt line to map */
  2775.     )
  2776.     {
  2777.     PCMCIASOCKET * pcs = &pDrvCtrl->pcmcia.theSocket;
  2778.     PCMCIASOCKET * altpcs;
  2779.     UINT socket = pDrvCtrl->pcmcia.socket;
  2780.     UINT irqline;
  2781.     /*
  2782.      * As with the Card Detect Interrupts in pcmciaSetup(), we
  2783.      * need to route IRQs from sockets A and B to IRQ4 and IRQ3
  2784.      * respectively
  2785.      */
  2786.     if (socket == PC_SOCKET_A)
  2787.         {
  2788.         irqline = 0x04;
  2789.         altpcs = pcs;
  2790.         }
  2791.     else
  2792.         {
  2793.         irqline = 0x03;
  2794.         altpcs = pcs;
  2795.         }
  2796.     /* check that I/O ranges do not overlap */
  2797.     if ((base >= altpcs->pcs_iobase &&
  2798.          base <= altpcs->pcs_iobase + altpcs->pcs_iorange) ||
  2799.         (base + range >= altpcs->pcs_iobase &&
  2800.          base + range <= altpcs->pcs_iobase + altpcs->pcs_iorange))
  2801.         /* Ranges overlap, not legal */
  2802.         return ERROR;
  2803.     /* OK - program I/O range for window 0 */
  2804.     OLI_VADEM_WRITE(PCIOA0STARTL + socket, base & OCT_MSK);
  2805.     OLI_VADEM_WRITE(PCIOA0STARTH + socket, (base >> 8) & OCT_MSK);
  2806.     OLI_VADEM_WRITE(PCIOA0STOPL + socket, (base + range) & OCT_MSK);
  2807.     OLI_VADEM_WRITE(PCIOA0STOPH + socket, ((base + range) >> 8) & OCT_MSK);
  2808.     /*
  2809.      * it is probably safe to assume that this socket contains
  2810.      * an I/O type card, so set the appropriate bit in the
  2811.      * control register
  2812.      */
  2813.     OLI_VADEM_WRITE(PCINTGCTL + socket, 0x60 | ((mapirq) ? irqline : 0));
  2814.     /*
  2815.      * This is by no means general, but at the moment I don't know how
  2816.      * to extract the relevant information, and I'm not sure how to
  2817.      * implement a general scheme for it anyway, so for the time being
  2818.      * it stays as a hard wired number.
  2819.      */
  2820.     OLI_VADEM_WRITE(PCIOCTL + socket, 0x00);
  2821.     /* enable I/O window 0 */
  2822.     OLI_VADEM_WRITE(PCADDWINEN + socket,
  2823.  (OLI_VADEM_READ(PCADDWINEN + socket) | 0x60));
  2824.     return OK;
  2825.     }
  2826. /*
  2827.  * Routines for accessing VG-468 controller.
  2828.  *
  2829.  * The Vadem chip will always shift data down to D[7:0] for reads,
  2830.  * but the data register is located at a byte-1 offset, so this shifting
  2831.  * of data conflicts with the ARM's behaviour during non-word aligned reads
  2832.  * (the ARM will try to shift byte-1 to D[7:0] itself).
  2833.  * PC_INDEX, PC_DATA_READ and PC_DATA_WRITE are macros defined in iOlicomEnd.h.
  2834.  * They depend on the base address of PCMCIA space, which is why this is
  2835.  * passed to all routines and seemingly not used.
  2836.  */
  2837. /******************************************************************************
  2838. *
  2839. * iOlicomVademRead - Read a register from the Vadem PCMCIA controller
  2840. *
  2841. * RETURNS: Value of requested register
  2842. */
  2843. LOCAL UINT iOlicomVademRead
  2844.     (
  2845.     char * ctrlBase, /* Base address of Vadem PCMCIA controller */
  2846.     UINT        index /* Index of register to read */
  2847.     )
  2848.     {
  2849.     *PC_INDEX = index;
  2850.     return ((*PC_DATA_READ >> 24) & OCT_MSK);
  2851.     }
  2852. /******************************************************************************
  2853. *
  2854. * iOlicomVademWrite - Write a register in the Vadem PCMCIA controller
  2855. *
  2856. * RETURNS: N/A
  2857. */
  2858. LOCAL void iOlicomVademWrite
  2859.     (
  2860.     char * ctrlBase, /* Base address of Vadem PCMCIA controller*/
  2861.     UINT        index, /* Index of register to write */
  2862.     UINT        value /* Value to be written */
  2863.     )
  2864.     {
  2865.     *PC_INDEX = index;
  2866.     *PC_DATA_WRITE = value;
  2867.     }
  2868. /*******************************************************************************
  2869. *
  2870. * iOlicomVademUnlock - Perform Vadem magic 'Unlock' sequence.
  2871. *
  2872. * To prevent erroneous configuration, the Vadem controller requires this
  2873. * magic unlock sequence to be issued before it will respond to any accesses
  2874. * made to the Vadem unique register set.
  2875. *
  2876. * RETURNS: N/A
  2877. */
  2878. LOCAL void iOlicomVademUnlock
  2879.     (
  2880.     char * ctrlBase /* Base address of Vadem PCMCIA controller*/
  2881.     )
  2882.     {
  2883.     *PC_INDEX = 0x0E; /* First 'magic' access */
  2884.     *PC_INDEX = 0x37; /* Second 'magic' access */
  2885.     }
  2886. #endif /* !PCMCIA_NO_VADEM */
  2887. #ifdef DEBUG
  2888. /* miscellaneous debug routines */
  2889. void drvFlagsIsset (int setBits)
  2890.     {
  2891.     END_DEVICE* pDrvCtrl = pDbgDrvCtrl;
  2892.     logMsg ("flag is %sn",
  2893. (DRV_FLAGS_ISSET(setBits) ? (int)"set" : (int)"clear"),
  2894. 0, 0, 0, 0, 0);
  2895.     }
  2896. void iOlicomRxState(void)
  2897.     {
  2898.     END_DEVICE* pDrvCtrl = pDbgDrvCtrl;
  2899.     logMsg ("reg 00 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R0),0,0,0,0,0);
  2900.     logMsg ("reg 01 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R1),0,0,0,0,0);
  2901.     logMsg ("reg 02 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R2),0,0,0,0,0);
  2902.     logMsg ("reg 03 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R3),0,0,0,0,0);
  2903.     logMsg ("reg 04 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R4),0,0,0,0,0);
  2904.     logMsg ("reg 05 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R5),0,0,0,0,0);
  2905.     logMsg ("reg 06 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R6),0,0,0,0,0);
  2906.     logMsg ("reg 07 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R7),0,0,0,0,0);
  2907.     logMsg ("reg 08 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R8),0,0,0,0,0);
  2908.     logMsg ("reg 09 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R9),0,0,0,0,0);
  2909.     logMsg ("reg 10 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R10),0,0,0,0,0);
  2910.     logMsg ("reg 11 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R11),0,0,0,0,0);
  2911.     logMsg ("reg 12 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R12),0,0,0,0,0);
  2912.     logMsg ("reg 13 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R13),0,0,0,0,0);
  2913.     logMsg ("reg 14 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R14),0,0,0,0,0);
  2914.     logMsg ("reg 15 = 0x%02xn", PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R15),0,0,0,0,0);
  2915.     }
  2916. void iOlicomDebugRcv(void)
  2917.     {
  2918.     END_DEVICE* pDrvCtrl = pDbgDrvCtrl;
  2919.     int s;
  2920.     int start;
  2921.     int status;
  2922.     int event;
  2923.     int length;
  2924.     s = intLock();
  2925.     start = PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R6);
  2926.     start |= (PCMCIA_IO_READ(pDrvCtrl->pcmcia.oliAddr + I595_R7) << 8);
  2927.     start += 2;
  2928.     logMsg ("start= 0x%04xn", start, 0, 0, 0, 0, 0);
  2929.     /* Set up address from where we wish to start reading data */
  2930.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R12, start);
  2931.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R13, (start >> 8));
  2932.     /* The first word describes the state of reception. */
  2933.     READ_R14_R15 (event);
  2934.     logMsg ("event= 0x%04xn", event, 0, 0, 0, 0, 0);
  2935.     /* Collect the status of the packet */
  2936.     READ_R14_R15 (status);
  2937.     logMsg ("status= 0x%04xn", status, 0, 0, 0, 0, 0);
  2938.     /* get next packet pointer */
  2939.     READ_R14_R15 (start);
  2940.     logMsg ("next= 0x%04xn", start, 0, 0, 0, 0, 0);
  2941.     /* get packet length */
  2942.     READ_R14_R15 (length);
  2943.     logMsg ("length= 0x%04xn", length, 0, 0, 0, 0, 0);
  2944.     intUnlock(s);
  2945.     }
  2946. void iOlicomAckInterrupt (int ackValue)
  2947.     {
  2948.     END_DEVICE* pDrvCtrl = pDbgDrvCtrl;
  2949.     PCMCIA_IO_WRITE(pDrvCtrl->pcmcia.oliAddr + I595_R1, ackValue);
  2950.     }
  2951. void iOlicomClusterNum(void)
  2952.     {
  2953.     CL_POOL_ID pClId = pDbgDrvCtrl->clPoolId;
  2954.     logMsg ("pDrvCtrl = %#x %d %dn", (int) pDbgDrvCtrl, pClId->clNum,
  2955.                                          pClId->clNumFree, 4, 5, 6);
  2956.     }
  2957. void iOlicomFlagsStatus(void)
  2958.     {
  2959.     logMsg ("txBdIndexC %#x txBdNext %#x Flags %3xn", pDbgDrvCtrl->txBdIndexC,
  2960.                 pDbgDrvCtrl->txBdNext, pDbgDrvCtrl->flags, 0, 0, 0);
  2961.     }
  2962. void iOlicomTxBdStatus(void)
  2963.     {
  2964.     TX_BD *     pTxBd;
  2965.     ULONG       addrC;
  2966.     int         status;
  2967.     int         ix;
  2968.     for (ix = 0; ix < pDbgDrvCtrl->txBdNum; ix++)
  2969.         {
  2970.         pTxBd = & pDbgDrvCtrl->txBdBase[ix];
  2971.         addrC = (ULONG) pTxBd->dataPointer;
  2972.         /* if the data buffer has not been transmitted, don't touch it */
  2973.         PCMCIA_IO_WRITE(pDbgDrvCtrl->pcmcia.oliAddr + I595_R12, addrC);
  2974.         PCMCIA_IO_WRITE(pDbgDrvCtrl->pcmcia.oliAddr + I595_R13, (addrC >> 8));
  2975.         status = PCMCIA_IO_READ(pDbgDrvCtrl->pcmcia.oliAddr + I595_R14);
  2976.         status |= (PCMCIA_IO_READ(pDbgDrvCtrl->pcmcia.oliAddr + I595_R15) << 8);
  2977.         LOG_MSG ("N %d Addr %#x Status %#xn", ix, addrC, status, 0, 0, 0);
  2978.         }
  2979.     }
  2980. #endif /* DEBUG */