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

VxWorks

开发平台:

C/C++

  1. /* if_cs.c - Crystal Semiconductor CS8900 network interface driver */
  2. /*
  3.  * Copyright 1996 Crystal Semiconductor Corp.
  4.  * Copyright 1984-1997 Wind River Systems, Inc.
  5.  */
  6. #include "copyright_wrs.h"
  7. /*
  8. modification history
  9. --------------------
  10. 01c,23feb98,vin  converted to BSD44 driver, merge from SENS
  11. 01b,13jun97,map  doc updates [SPR# 8138]
  12. 01a,16dec96,hdn  adapted.
  13. */
  14. /*
  15. DESCRIPTION
  16. This module implements a driver for a Crystal Semiconductor CS8900 Ethernet
  17. controller chip.
  18. The CS8900 is a single chip Ethernet controller with a direct ISA bus
  19. interface which can operate in either memory space or I/O space. It also
  20. supports a direct interface to a host DMA controller to transfer receive
  21. frames to host memory.  The device has a 4K RAM which is used for transmit,
  22. and receive buffers; a serial EEPROM interface; and both 10BASE-T/AUI port
  23. support.
  24. This driver is capable of supporting both memory mode and I/O mode operations
  25. of the chip. When configured for memory mode, the intenal RAM of the chip is
  26. mapped to a contiguous 4K address block, providing the CPU direct access to
  27. the internal registers and frame buffers. When configured for I/O mode, the
  28. internal registers are accessible through eight contiguous, 16-bit I/O ports.
  29. The driver also supports an interface to an EEPROM containing device
  30. configuration.
  31. While the DMA slave mode is supported by the device for receive frame
  32. transfers, this driver does not enable DMA.
  33. This network interface driver does not support output hook routines,
  34. because to do so requires that an image of the transmit packet be built in
  35. memory before the image is copied to the CS8900 chip.  It is much more
  36. efficient to copy the image directly from the mbuf chain to the CS8900 chip.
  37. However, this network interface driver does support input hook routines.
  38. CONFIGURATION
  39. The defined I/O address and IRQ in config.h must match the one stored
  40. in EEPROM by the vendor's DOS utility program.
  41. The I/O Address parameter is the only required csAttach() parameter.  If the
  42. CS8900 chip has a EEPROM attached, then the I/O Address parameter, passed to
  43. the csAttach() routine, must match the I/O address programmed into the EEPROM.
  44. If the CS8900 chip does not have a EEPROM attached, then the I/O Address
  45. parameter must be 0x300.
  46. The Interrupt Level parameter must have one of the following values:
  47.    0  - Get interrupt level from EEPROM
  48.    5  - IRQ 5
  49.    10 - IRQ 10
  50.    11 - IRQ 11
  51.    12 - IRQ 12
  52. If the Interrupt Vector parameter is zero, then the network interface driver
  53. derives the interrupt vector from the interrupt level if possible.  It is
  54. possible to derive the interrupt vector in an IBM PC compatible system.  This
  55. parameter is present for systems which are not IBM PC compatible.
  56. The Memory Address parameter specifies the base address of the CS8900 chip's
  57. memory buffer (PacketPage).  If the Memory Address parameter is not zero, then
  58. the CS8900 chip operates in memory mode at the specified address.  If the
  59. Memory Address parameter is zero, then the CS8900 chip operates in the mode
  60. specified by the EEPROM or the Configuration Flags parameter.
  61. The Media Type parameter must have one of the following values:
  62. .CS
  63.  0 - Get media type from EEPROM
  64.  1 - AUI  (Thick Cable)
  65.  2 - BNC  10Base2 (Thin Cable)
  66.  3 - RJ45 10BaseT (Twisted Pair)
  67. .CE
  68. The Configuration Flags parameter is usually passed to the csAttach() routine
  69. as zero and the Configuration Flags information is retrieved from the EEPROM.
  70. The bits in the Configuration Flags parameter are usually specified by a
  71. hardware engineer and not by the end user.  However, if the CS8900 chip does
  72. not have a EEPROM attached, then this information must be passed as a parameter
  73. to the csAttach() routine.  The Configuration Flags are:
  74. .CS
  75.  0x8000 - CS_CFGFLG_NOT_EEPROM    Don't get Config. Flags from the EEPROM
  76.  0x0001 - CS_CFGFLG_MEM_MODE      Use memory mode to access the chip
  77.  0x0002 - CS_CFGFLG_USE_SA        Use system addr to qualify MEMCS16 signal
  78.  0x0004 - CS_CFGFLG_IOCHRDY       Use IO Channel Ready signal to slow access
  79.  0x0008 - CS_CFGFLG_DCDC_POL      The DC/DC conv. enable pin is active high
  80.  0x0010 - CS_CFGFLG_FDX           10BaseT is full duplex
  81. .CE
  82. If configuration flag information is passed to the csAttach() routine, then the
  83. CS_CFGFLG_NOT_EEPROM flag should be set.  This ensures that the Configuration
  84. Flags parameter is not zero, even if all specified flags are zero.
  85. If the Memory Address parameter is not zero and the Configuration Flags
  86. parameter is zero, then the CS8900 network interface driver implicitly sets
  87. the CS_CFGFLG_MEM_MODE flag and the CS8900 chip operates in memory mode.
  88. However, if the Configuration Flags parameter is not zero, then the CS8900
  89. chip operates in memory mode only if the CS_CFGFLG_MEM_MODE flag is explicitly
  90. set.  If the Configuration Flags parameter in not zero and the
  91. CS_CFGFLG_MEM_MODE flag is not set, then the CS8900 chip operates in I/O mode.
  92. The Ethernet Address parameter is usually passed to the csAttach() routine as
  93. zero and the Ethernet address is retrieved from the EEPROM.  The Ethernet
  94. address (also called hardware address and individual address) is usually
  95. supplied by the adapter manufacturer and is stored in the EEPROM.  However, if
  96. the CS8900 chip does not have a EEPROM attached, then the Ethernet address must
  97. be passed as a parameter to the csAttach() routine.
  98. The Ethernet Address parameter, passed to the csAttach() routine, contains the
  99. address of a NULL terminated string.  The string consists of 6 hexadecimal
  100. numbers separated by colon characters.  Each hexadecimal number is in the range
  101. 00 - FF.  An example of this string is:
  102. .CS
  103.    "00:24:20:10:FF:2A"
  104. .CE
  105. BOARD LAYOUT
  106. This device is soft-configured.  No jumpering diagram is required.
  107. EXTERNAL INTERFACE
  108. The only user-callable routines are csAttach():
  109. .iP csAttach() 14
  110. publishes the `cs' interface and initializes the driver and device.
  111. .LP
  112. The network interface driver includes a show routine, called csShow(), which
  113. displays driver configuration and statistics information.  To invoke the show
  114. routine, type at the shell prompt:
  115. .CS
  116.         -> csShow
  117. .CE
  118. To reset the statistics to zero, type at the shell prompt:
  119. .CS
  120.         -> csShow 0, 1
  121. .CE
  122. Another routine that you may find useful is:
  123. .CS
  124.         -> ifShow "cs0"
  125. .CE
  126. EXTERNAL ROUTINES
  127. For debugging purposes, this driver calls logMsg() to print error and debugging
  128. information.  This will cause the logLib library to be linked with any image
  129. containing this driver.
  130. This driver needs the following macros defined for proper execution.  Each
  131. has a default definition that assumes a PC386/PC486 system and BSP.
  132. The macro CS_IN_BYTE(reg,pAddr) reads one byte from the I/O address 'reg',
  133. placing the result at address 'pAddr'.  There is no status result from this
  134. operation, we assume the operation completes normally, or a bus exception
  135. will occur.  By default, this macro assumes there is a BSP routine sysInByte()
  136. to perform the I/O operation.
  137. The macro CS_IN_WORD(reg,pAddr) read a short word (2 bytes) from the I/O
  138. address 'reg', storing the result at address 'pAddr'.  We assume this
  139. completes normally, or causes a bus exception.  The default declaration
  140. assumes a BSP routine sysInWord() to perform the operation.
  141. The macro CS_OUT_WORD(reg,data) writes a short word value 'data' at the
  142. I/O address 'reg'.  The default declaration assumes a BSP routine sysOutWord().
  143. The macro CS_INT_ENABLE(level, pResult) is used to enable the interrupt
  144. level passed as an argument to csAttach.  The default definition call the
  145. BSP routine sysIntEnablePIC(level).  The STATUS return value from the 
  146. actual routine is stored at 'pResult' for the driver to examine.
  147. The macro CS_INT_CONNECT(ivec,rtn,arg,pResult) macro is used to connect
  148. the driver interrupt routine to the vector provided as an argument to 
  149. csAttach (after translaction by INUM_TO_IVEC).  The default definition
  150. calls the cpu architecture routine intConnect().
  151. The macro CS_IRQ0_VECTOR(pAddr) is used to fetch the base vector for the
  152. interrupt level mechanism.  If the int vector argument to csAttach is zero,
  153. then the driver will compute a vector number by adding the interrupt level
  154. to the value returned by this macro.  If the user supplies a non-zero
  155. interrupt vector number, then this macro is not used.  The default definition
  156. of this macro fetches the base vector number from a global value
  157. called 'sysVectorIRQ0'.
  158. The macro CS_MSEC_DELAY(msec) is used to delay execution for a specified
  159. number of milliseconds.  The default definition uses taskDelay to suspend
  160. task for some number of clock ticks.  The resolution of the system clock
  161. is usually around 16 milliseconds (msecs), which is fairly coarse.
  162. */
  163. #include "vxWorks.h"
  164. #include "sysLib.h"
  165. #include "intLib.h"
  166. #include "logLib.h"
  167. #include "netLib.h"
  168. #include "etherLib.h"
  169. #include "stdio.h"
  170. #include "iv.h"
  171. #include "ioctl.h"
  172. #include "taskLib.h"
  173. #include "net/if_subr.h"
  174. #include "drv/netif/if_cs.h"
  175. /* defines */
  176. #define MAXUNITS    2 /* Maximum number of CS8900 chips */
  177. #ifndef CS_IN_BYTE /* read one byte from I/O space */
  178. #define CS_IN_BYTE(reg,pAddr) 
  179. (*(pAddr) = sysInByte(reg))
  180. #endif /*CS_IN_BYTE*/
  181. #ifndef CS_IN_WORD /* read a short (16bits) from I/O */
  182. #define CS_IN_WORD(reg,pAddr) 
  183. (*(pAddr) = sysInWord(reg))
  184. #endif /*CS_IN_WORD*/
  185. #ifndef CS_OUT_WORD /* write a short to I/O space */
  186. #define CS_OUT_WORD(reg,data) 
  187. (sysOutWord((reg),(data)))
  188. #endif /*CS_OUT_WORD*/
  189. #ifndef CS_INT_ENABLE /* enable interrupt level */
  190. #define CS_INT_ENABLE(level,pResult) 
  191. (*pResult = sysIntEnablePIC(level))
  192. #endif /*CS_INT_ENABLE*/
  193. #ifndef CS_INT_CONNECT /* connect routine to intr. vector */
  194. #define CS_INT_CONNECT(ivec,rtn,arg,pResult) 
  195. (*pResult = intConnect(ivec,rtn,arg))
  196. #endif /*CS_INT_CONNECT*/
  197. #ifndef CS_IRQ0_VECTOR /* get vector for intr. level 0 */
  198. #define CS_IRQ0_VECTOR(pAddr) 
  199. IMPORT UINT sysVectorIRQ0; 
  200. *pAddr = sysVectorIRQ0; 
  201. }
  202. #endif /*CS_IRQ0_VECTOR*/
  203. #ifndef CS_MSEC_DELAY /* delay for (x) milliseconds */
  204. #define CS_MSEC_DELAY(msec) 
  205. taskDelay ((((msec) * sysClkRateGet()) + sysClkRateGet() - 1)/ 1000);
  206. #endif /*CS_MSEC_DELAY*/
  207. /* typedefs */
  208. typedef struct ether_header ETH_HDR; 
  209. /* globals */
  210. /* locals */
  211. LOCAL CS_SOFTC cs_softc[MAXUNITS]; /* Instance global variables */
  212. /* prototypes */
  213. #if defined(__STDC__) || defined(__cplusplus)
  214.       STATUS csAttach (int unit, int ioAddr, int intVector,
  215.  int intLevel, int memAddr, int mediaType,
  216.  int configFlags, char *pEnetAddr);
  217.       void csShow (int unit, BOOL zap);
  218. LOCAL STATUS csInit (int unit);
  219. LOCAL void csReset (int unit);
  220. LOCAL void csIntr (int unit);
  221. LOCAL int csIoctl (struct ifnet *pIf, int command, char *pData);
  222. #ifdef BSD43_DRIVER
  223. LOCAL void csStartOutput (int unit);
  224. LOCAL int csOutput (struct ifnet *pIf, struct mbuf *pMbufChain,
  225.  SOCKADDR *pDst);
  226. #else
  227. LOCAL void csStartOutput (CS_SOFTC *pCs);
  228. #endif
  229. LOCAL STATUS csChipVerify (CS_SOFTC *pCs);
  230. LOCAL STATUS csChipReset (CS_SOFTC *pCs);
  231. LOCAL void csChipInit (CS_SOFTC *pCs);
  232. LOCAL void csIntrBuffer (CS_SOFTC *pCs, USHORT buffEvent);
  233. LOCAL void csIntrTx (CS_SOFTC *pCs, USHORT txEvent);
  234. LOCAL void csIntrRx (CS_SOFTC *pCs, USHORT rxEvent);
  235. LOCAL void csTxFrameCopy (CS_SOFTC *pCs, struct mbuf *pMbufChain);
  236. LOCAL void csRxFrameCopy (CS_SOFTC *pCs, CS_RXBUF *pRxBuff);
  237. LOCAL void csRxProcess (CS_SOFTC *pCs, CS_RXBUF *pRxBuff);
  238. LOCAL STATUS csRxBuffInit (CS_SOFTC *pCs);
  239. LOCAL CS_RXBUF *csRxBuffAlloc (CS_SOFTC *pCs);
  240. LOCAL void csRxBuffFree (CS_SOFTC *pCs, CS_RXBUF *pRxBuff);
  241. LOCAL USHORT csPacketPageR (CS_SOFTC *pCs, USHORT offset);
  242. LOCAL void csPacketPageW (CS_SOFTC *pCs, USHORT offset, USHORT value);
  243. LOCAL void csError (CS_SOFTC *pCs, char *pString);
  244. LOCAL STATUS csParmsGet (CS_SOFTC *pCs);
  245. LOCAL STATUS csParmsValidate (CS_SOFTC *pCs);
  246. LOCAL STATUS csEnetAddrGet (CS_SOFTC *pCs, char *pEnetAddr);
  247. LOCAL STATUS csEepromRead (CS_SOFTC *pCs, USHORT offset, USHORT *pValue);
  248. LOCAL char *csHexWord (char *pChar, USHORT *pWord);
  249. LOCAL char *csHexByte (char *pChar, UCHAR *pByte);
  250. #else  /* Not ANSI C or C++ */
  251.       STATUS csAttach ();
  252.       void csShow ();
  253. LOCAL STATUS csInit ();
  254. LOCAL void csReset ();
  255. LOCAL void csStartOutput ();
  256. LOCAL void csIntr ();
  257. LOCAL int csIoctl ();
  258. LOCAL int csOutput ();
  259. LOCAL STATUS csChipVerify ();
  260. LOCAL STATUS csChipReset ();
  261. LOCAL void csChipInit ();
  262. LOCAL void csIntrBuffer ();
  263. LOCAL void csIntrTx ();
  264. LOCAL void csIntrRx ();
  265. LOCAL void csTxFrameCopy ();
  266. LOCAL void csRxFrameCopy ();
  267. LOCAL void csRxProcess ();
  268. LOCAL STATUS csRxBuffInit ();
  269. LOCAL CS_RXBUF *csRxBuffAlloc ();
  270. LOCAL void csRxBuffFree ();
  271. LOCAL USHORT csPacketPageR ();
  272. LOCAL void csPacketPageW ();
  273. LOCAL void csError ();
  274. LOCAL STATUS csParmsGet ();
  275. LOCAL STATUS csParmsValidate ();
  276. LOCAL STATUS csEnetAddrGet ();
  277. LOCAL STATUS csEepromRead ();
  278. LOCAL char *csHexWord ();
  279. LOCAL char *csHexByte ();
  280. #endif  /* defined(__STDC__) || defined(__cplusplus) */
  281. /*******************************************************************************
  282. *
  283. * csAttach - publish the `cs' network interface and initialize the driver.
  284. *
  285. * This routine is a major entry point to this network interface driver and is
  286. * called only once per operating system reboot by the operating system startup
  287. * code.  This routine is called before the csInit() routine.
  288. *
  289. * This routine takes passed-in configuration parameters and parameters from
  290. * the EEPROM and fills in the instance global variables in the cs_softc
  291. * structure.  These variables are later used by the csChipInit() routine.
  292. *
  293. * This routine connects the interrupt handler, csIntr(), to the specified
  294. * interrupt vector, initializes the 8259 PIC and resets the CS8900 chip.
  295. *
  296. * Finally, this routine calls the ether_attach() routine, to fill in the ifnet
  297. * structure and attach this network interface driver to the system.  The
  298. * driver's main entry points (csInit(), csIoctl(), csOutput(), csReset()) are
  299. * made visable to the protocol stack.
  300. *
  301. * Refer to "man if_cs" for detailed description of the configuration flags.
  302. *
  303. * RETURNS: OK or ERROR.
  304. */
  305. STATUS csAttach
  306.     (
  307.     int unit, /* unit number */
  308.     int ioAddr, /* base IO address */
  309.     int intVector, /* interrupt vector, or zero */
  310.     int intLevel, /* interrupt level */
  311.     int memAddr, /* base memory address */
  312.     int mediaType, /* 0: Autodetect  1: AUI  2: BNC  3: RJ45 */
  313.     int configFlags, /* configuration flag */
  314.     char *pEnetAddr /* ethernet address */
  315.     )
  316.     {
  317.     FAST CS_SOFTC *pCs = &cs_softc[unit];
  318.     STATUS result;
  319.     if (unit >= MAXUNITS)
  320. {
  321. printf ("ncs%d - Invalid unit number (%d)n", unit, unit);
  322. return (ERROR);
  323. }
  324.     /* Save the passed-in parameters */
  325.     pCs->ioAddr      = ioAddr;
  326.     pCs->intLevel    = intLevel;
  327.     pCs->intVector   = intVector;
  328.     pCs->pPacketPage = (USHORT *)memAddr;
  329.     pCs->mediaType   = mediaType;
  330.     pCs->configFlags = configFlags;
  331.     /* Start out in IO mode */
  332.     pCs->inMemoryMode = FALSE;
  333.     /* Set counters to zero */
  334.     pCs->rxDepth    = 0;
  335.     pCs->maxRxDepth = 0;
  336.     pCs->maxTxDepth = 0;
  337.     pCs->loanCount  = 0;
  338.     /* Allocate the receive frame buffers */
  339.     if (csRxBuffInit (pCs) == ERROR)
  340. {
  341. printf ("ncs%d - Can not allocate receive buffersn", unit);
  342. return (ERROR);
  343. }
  344.     /* Verify that it is the correct chip */
  345.     if (csChipVerify (pCs) == ERROR)
  346. return (ERROR);
  347.     /* Get parameters, which were not specified, from the EEPROM */
  348.     if (csParmsGet (pCs) == ERROR)
  349. return (ERROR);
  350.     /* Verify that parameters are valid */
  351.     if (csParmsValidate (pCs) == ERROR)
  352. return (ERROR);
  353.     /* Get and store the Ethernet address */
  354.     if (csEnetAddrGet (pCs,pEnetAddr) == ERROR)
  355. return (ERROR);
  356.     /* If memory address was specified but configuration flags were not */
  357.     if (memAddr!=0 && configFlags==0)
  358. pCs->configFlags |= CS_CFGFLG_MEM_MODE;  /* Implictly set memory mode */
  359.     /* If the interrupt vector was not specified then derive it */
  360.     if (intVector == 0)
  361. {
  362. CS_IRQ0_VECTOR(&intVector);
  363. pCs->intVector = intVector + pCs->intLevel;
  364. }
  365.     /* Setup the interrupt handler and the IDT table entry */
  366.     CS_INT_CONNECT (INUM_TO_IVEC (pCs->intVector), csIntr, unit, &result);
  367.     if (result == ERROR)
  368. {
  369. printf ("ncs%d - Can not connect interruptn", unit);
  370. return (ERROR);
  371. }
  372.     /* Enable interrupt at the 8259 PIC */
  373.     CS_INT_ENABLE(pCs->intLevel, &result);
  374.     if (result == ERROR)
  375. {
  376. printf ("ncs%d - Can not enable interruptn", unit);
  377. return (ERROR);
  378. }
  379.     /* Reset the chip */
  380.     if (csChipReset (pCs) == ERROR)
  381. {
  382. printf ("ncs%d - Can not reset the chipn", unit);
  383. return (ERROR);
  384. }
  385.     /* Attach this network interface driver to the system */
  386. #ifdef BSD43_DRIVER
  387.     ether_attach (&pCs->arpCom.ac_if, unit, "cs", csInit, csIoctl, csOutput,
  388.   (FUNCPTR)csReset);
  389. #else
  390.     ether_attach    (
  391.                     &pCs->arpCom.ac_if,
  392.                     unit,
  393.                     "cs",
  394.                     (FUNCPTR) csInit,
  395.                     (FUNCPTR) csIoctl,
  396.                     (FUNCPTR) ether_output, /* generic ether_output */
  397.                     (FUNCPTR) csReset
  398.                     );
  399.     pCs->arpCom.ac_if.if_start = (FUNCPTR) csStartOutput; 
  400. #endif
  401.     return (OK);
  402.     }
  403. /*******************************************************************************
  404. *
  405. * csChipVerify - verifies that the chip is present and correct
  406. *
  407. * This routine verifies that the Ethernet chip is present and correct.
  408. *
  409. * RETURNS: OK or ERROR
  410. */
  411. LOCAL STATUS csChipVerify 
  412.     (
  413.     CS_SOFTC *pCs
  414.     )
  415.     {
  416.     USHORT eisaNumber = csPacketPageR (pCs, CS_PKTPG_EISA_NUM);
  417.     /* Verify that we can read from the chip */
  418.     if (eisaNumber == 0xFFFF)
  419. {
  420. printf ("ncs0 - Can't read from chip (I/O address correct?)n");
  421. return (ERROR);
  422. }
  423.     
  424.     /* Verify that the chip is a Crystal Semiconductor chip */
  425.     if (eisaNumber != CS_EISA_NUM_CRYSTAL)
  426. {
  427. printf ("ncs0 - Chip is not a Crystal Semiconductor chipn");
  428. return (ERROR);
  429. }
  430.     /* Verify that the chip is a CS8900 */
  431.     if ((csPacketPageR (pCs, CS_PKTPG_PRODUCT_ID) & CS_PROD_ID_MASK) !=
  432. CS_PROD_ID_CS8900)
  433. {
  434. printf ("ncs0 - Chip is not a CS8900n");
  435. return (ERROR);
  436. }
  437.     return (OK);
  438.     }
  439. /*******************************************************************************
  440. *
  441. * csParmsGet - gets parameters that were not specifed to csAttach()
  442. *
  443. * This routine gets parameters, that were not specifed to csAttach(),
  444. * from the EEPROM and puts them in the cs_softc structure.  If all the
  445. * parameters were specified to csAttach(), then this routine does
  446. * not attempt to read the EEPROM.
  447. *
  448. * RETURNS: N/A
  449. */
  450. LOCAL STATUS csParmsGet
  451.     (
  452.     CS_SOFTC *pCs
  453.     )
  454.     {
  455.     USHORT selfStatus;
  456.     USHORT isaConfig;
  457.     USHORT memBase;
  458.     USHORT adapterConfig;
  459.     USHORT xmitCtl;
  460.     /* If all of these parameters were specified */
  461.     if ((pCs->configFlags != 0) &&
  462. (pCs->pPacketPage != NULL) &&
  463. (pCs->intLevel != 0) &&
  464. (pCs->mediaType != 0))
  465. return (OK);  /* Don't need to get anything from the EEPROM */
  466.     /* Verify that the EEPROM is present and OK */
  467.     selfStatus = csPacketPageR (pCs, CS_PKTPG_SELF_ST);
  468.     if (!((selfStatus & CS_SELF_ST_EEP_PRES) &&
  469. (selfStatus & CS_SELF_ST_EEP_OK)))
  470. {
  471. printf ("ncs0 - EEPROM is missing or badn");
  472. return (ERROR);
  473. }
  474.     /* Get ISA configuration from the EEPROM */
  475.     if (csEepromRead (pCs, CS_EEPROM_ISA_CFG, &isaConfig) == ERROR)
  476. return (ERROR);
  477.     /* Get adapter configuration from the EEPROM */
  478.     if (csEepromRead (pCs, CS_EEPROM_ADPTR_CFG, &adapterConfig) == ERROR)
  479. return (ERROR);
  480.     /* Get transmission control from the EEPROM */
  481.     if (csEepromRead (pCs, CS_EEPROM_XMIT_CTL, &xmitCtl) == ERROR)
  482. return (ERROR);
  483.     /* If the configuration flags were not specified */
  484.     if (pCs->configFlags == 0)
  485. {
  486. /* Copy the memory mode flag */
  487. if (isaConfig & CS_ISA_CFG_MEM_MODE)
  488.     pCs->configFlags |= CS_CFGFLG_MEM_MODE;
  489. /* Copy the USE_SA flag */
  490. if (isaConfig & CS_ISA_CFG_USE_SA)
  491.     pCs->configFlags |= CS_CFGFLG_USE_SA;
  492. /* Copy the IO Channel Ready flag */
  493. if (isaConfig & CS_ISA_CFG_IOCHRDY)
  494.     pCs->configFlags |= CS_CFGFLG_IOCHRDY;
  495. /* Copy the DC/DC Polarity flag */
  496. if (adapterConfig & CS_ADPTR_CFG_DCDC_POL)
  497.     pCs->configFlags |= CS_CFGFLG_DCDC_POL;
  498. /* Copy the Full Duplex flag */
  499. if (xmitCtl & CS_XMIT_CTL_FDX)
  500.     pCs->configFlags |= CS_CFGFLG_FDX;
  501. }
  502.      /* If the PacketPage pointer was not specified */
  503.      if (pCs->pPacketPage == NULL)
  504.  {
  505.  /* If memory mode is enabled
  506.   *   Get the memory base address from EEPROM
  507.   *   Setup the PacketPage pointer
  508.   */
  509.  if (pCs->configFlags & CS_CFGFLG_MEM_MODE)
  510.      {
  511.      if (csEepromRead (pCs, CS_EEPROM_MEM_BASE, &memBase) == ERROR)
  512.  return (ERROR);
  513.       memBase &= CS_MEM_BASE_MASK;  /* Clear unused bits */
  514.       pCs->pPacketPage = (USHORT *)(((ULONG)memBase) << 8);
  515.       }
  516.  }
  517.     /* If the interrupt level was not specified
  518.      *   Get the interrupt level from the IsaConfig
  519.      */
  520.     if (pCs->intLevel == 0)
  521. {
  522. pCs->intLevel = isaConfig & CS_ISA_CFG_IRQ_MASK;
  523. if (pCs->intLevel == 3)
  524.     pCs->intLevel = 5;
  525. else
  526.     pCs->intLevel += 10;
  527. }
  528.     /* If the media type was not specified
  529.      *   Get the media type from the adapterConfig
  530.      */
  531.     if (pCs->mediaType == 0)
  532. {
  533. switch (adapterConfig & CS_ADPTR_CFG_MEDIA)
  534.     {
  535.     case CS_ADPTR_CFG_AUI:
  536. pCs->mediaType = CS_MEDIA_AUI;
  537. break;
  538.     case CS_ADPTR_CFG_10BASE2:
  539. pCs->mediaType = CS_MEDIA_10BASE2;
  540. break;
  541.     case CS_ADPTR_CFG_10BASET:
  542.     default:
  543. pCs->mediaType = CS_MEDIA_10BASET;
  544. break;
  545.     }
  546. }
  547.     return (OK);
  548.     }
  549. /*******************************************************************************
  550. *
  551. * csParmsValidate - validate the memory address, interrupt level and media type
  552. *
  553. * This routine verifies that the memory address, interrupt level and media
  554. * type are valid.  If any of these parameters are invalid, then and error
  555. * message is printed and ERROR is returned.
  556. *
  557. * RETURNS: OK or ERROR
  558. */
  559. LOCAL STATUS csParmsValidate
  560.     (
  561.     CS_SOFTC *pCs
  562.     )
  563.     {
  564.     int memAddr = (int)(pCs->pPacketPage);
  565.     if ((memAddr & 0x000FFF) != 0)
  566. {
  567. printf ("ncs0 - Memory address (0x%X) must start on a 4K boundryn",
  568.         memAddr);
  569. return (ERROR);
  570. }
  571.     if (memAddr > 0xFFF000)
  572. {
  573. printf ("ncs0 - Memory address (0x%X) is too largen", memAddr);
  574. return (ERROR);
  575. }
  576.     if (!(pCs->intLevel==5 || pCs->intLevel==10 || pCs->intLevel==11 ||
  577.   pCs->intLevel==12))
  578. {
  579. printf ("ncs0 - Interrupt level (%d) is invalidn", pCs->intLevel);
  580. return (ERROR);
  581. }
  582.     if (!(pCs->mediaType==CS_MEDIA_AUI || pCs->mediaType==CS_MEDIA_10BASE2 ||
  583.   pCs->mediaType==CS_MEDIA_10BASET))
  584. {
  585. printf ("ncs0 - Media type (%d) is invalidn", pCs->mediaType);
  586. return (ERROR);
  587. }
  588.     return (OK);
  589.     }
  590. /*******************************************************************************
  591. *
  592. * csEnetAddrGet - get the ethernet address from arguments or EEPROM
  593. *
  594. * If a pointer to an Ethernet address string was passed-in to the csAttach()
  595. * routine, then this routine coverts the address string to an Ethernet address
  596. * and saves it in the arpcom structure.  If an Ethernet address string was
  597. * not passed-in, then the Ethernet address is read from the EEPROM and saved
  598. * in the arpcom structure.
  599. *
  600. * RETURNS: OK or ERROR
  601. */
  602. LOCAL STATUS csEnetAddrGet
  603.     (
  604.     CS_SOFTC *pCs,
  605.     char *pEthernetAddr
  606.     )
  607.     {
  608.     USHORT selfStatus;
  609.     CS_IA *pIA = (CS_IA *)pCs->arpCom.ac_enaddr;
  610.     /* If the Ethernet address was not specified */
  611.     if (pEthernetAddr == NULL)
  612. {
  613. /* Verify that the EEPROM is present and OK */
  614. selfStatus = csPacketPageR (pCs, CS_PKTPG_SELF_ST);
  615. if (!((selfStatus & CS_SELF_ST_EEP_PRES) && 
  616.     (selfStatus & CS_SELF_ST_EEP_OK)))
  617.     {
  618.     printf ("ncs0 - EEPROM is missing or badn");
  619.     return (ERROR);
  620.     }
  621.        /* Get Ethernet address from the EEPROM */
  622.        if (csEepromRead (pCs, CS_EEPROM_IND_ADDR_H, &pIA->word[0]) == ERROR)
  623.    return (ERROR);
  624.        if (csEepromRead (pCs, CS_EEPROM_IND_ADDR_M, &pIA->word[1]) == ERROR)
  625.    return (ERROR);
  626.        if (csEepromRead (pCs, CS_EEPROM_IND_ADDR_L, &pIA->word[2]) == ERROR)
  627.    return (ERROR);
  628.        }
  629.     else  /* The Ethernet address was specified */
  630.        {
  631.        /* Convert and save the Ethernet address string */
  632.        pEthernetAddr = csHexWord (pEthernetAddr, &pIA->word[0]);
  633.        if (pEthernetAddr == NULL)
  634.    return (ERROR);
  635.        pEthernetAddr = csHexWord (pEthernetAddr, &pIA->word[1]);
  636.        if (pEthernetAddr == NULL)
  637.    return (ERROR);
  638.        pEthernetAddr = csHexWord (pEthernetAddr, &pIA->word[2]);
  639.        if (pEthernetAddr == NULL)
  640.    return (ERROR);
  641.        }
  642.     return (OK);
  643.     }
  644. /*******************************************************************************
  645. *
  646. * csHexWord - converts a sequence of hex characters to the 16-bit value
  647. *
  648. * This routine converts a sequence of hex characters to the 16-bit value
  649. * that they represent.  The address of the first hex character is passed
  650. * in the pChar parameter and the address just beyond the last hex
  651. * character is returned.  The 16-bit variable pointed to by the pWord
  652. * parameter is updated with the converted 16-bit value.  If an error
  653. * occurred then NULL is returned.
  654. *
  655. * RETURNS: address of next character
  656. */
  657. LOCAL char *csHexWord
  658.     (
  659.     char *pChar,
  660.     USHORT *pWord
  661.     )
  662.     {
  663.     union
  664. {
  665. USHORT word;
  666. UCHAR  byte[2];
  667. } value;
  668.     /* Get the value of the first hex byte */
  669.     pChar = csHexByte (pChar, &value.byte[0]);
  670.     if ((pChar != NULL) && (*pChar == 0))
  671. printf ("ncs0 - Ethernet address string too shortn");
  672.     if ((pChar == NULL) || (*pChar == 0))
  673. return (NULL);
  674.     /* Get the value of the second hex byte */
  675.     pChar = csHexByte (pChar, &value.byte[1]);
  676.     if (pChar == NULL)
  677. return (NULL);
  678.     /* Save value of the hex word */
  679.     *pWord = value.word;
  680.  
  681.     return (pChar);
  682.     }
  683. /*******************************************************************************
  684. *
  685. * csHexByte - converts a sequence of hex characters to the 8-bit value
  686. *
  687. * This routine converts a sequence of hex characters to the 8-bit value
  688. * that they represent.  There may be zero, one or two hex characters and
  689. * they may be optionally terminated with a colon or a zero byte.
  690. * The address of the first hex character is passed in the pChar parameter
  691. * and the address just beyond the last hex character is returned.
  692. * The 8-bit variable pointed to by the pByte parameter is updated with
  693. * the converted 8-bit value.  If an error occurred then NULL is returned.
  694. *
  695. * RETURNS: address of next character
  696. */
  697. LOCAL char *csHexByte
  698.     (
  699.     char *pChar,
  700.     UCHAR *pByte
  701.     )
  702.     {
  703.     int ix;
  704.     /* Inititalize the byte value to zero */
  705.     *pByte = 0;
  706.     /* Process two hex characters */
  707.     for (ix=0; ix<2; ix++, pChar++)
  708. {
  709. /* Stop early if find a colon or end of string */
  710. if ((*pChar == ':') || (*pChar == 0))
  711.     break;
  712. /* Convert the hex character to a value */
  713. if ((*pChar >= '0') && (*pChar <= '9'))
  714.     *pByte = (*pByte * 16) + *pChar - '0';
  715. else if ((*pChar >= 'a') && (*pChar <= 'f'))
  716.     *pByte = (*pByte * 16) + *pChar - 'a' + 10;
  717. else if ((*pChar >= 'A') && (*pChar <= 'F'))
  718.     *pByte = (*pByte * 16) + *pChar - 'A' + 10;
  719. else
  720.     {
  721.     printf ("ncs0 - Illegal character '%c' in Enet address stringn",
  722.             *pChar);
  723.     return (NULL);  /* Illegal character */
  724.     }
  725. }
  726.     /* Skip past terminating colon */
  727.     if (*pChar == ':')
  728. pChar++;
  729.     return (pChar);
  730.     }
  731. /*******************************************************************************
  732. *
  733. * csEepromRead - reads a word from the EEPROM
  734. *
  735. * This routine reads a word from the EEPROM at the specified offset.
  736. *
  737. * RETURNS: OK or ERROR
  738. */
  739. LOCAL STATUS csEepromRead
  740.     (
  741.     CS_SOFTC *pCs,
  742.     USHORT offset,
  743.     USHORT *pValue
  744.     )
  745.     {
  746.     int ix;
  747.     /* Ensure that the EEPROM is not busy */
  748.     for (ix=0; ix<CS_MAXLOOP; ix++)
  749. if (!(csPacketPageR (pCs, CS_PKTPG_SELF_ST) & CS_SELF_ST_SI_BUSY))
  750.     break;
  751.     if (ix == CS_MAXLOOP)
  752.        {
  753.        printf ("ncs0 - Can not read from EEPROMn");
  754.        return (ERROR);
  755.        }
  756.     /* Issue the command to read the offset within the EEPROM */
  757.     csPacketPageW (pCs, CS_PKTPG_EEPROM_CMD, offset | CS_EEPROM_CMD_READ);
  758.     /* Wait until the command is completed */
  759.     for (ix=0; ix<CS_MAXLOOP; ix++)
  760. if (!(csPacketPageR (pCs, CS_PKTPG_SELF_ST) & CS_SELF_ST_SI_BUSY))
  761.     break;
  762.     if (ix == CS_MAXLOOP)
  763. {
  764. printf ("ncs0 - Can not read from EEPROMn");
  765. return (ERROR);
  766. }
  767.     /* Get the EEPROM data from the EEPROM data register */
  768.     *pValue = csPacketPageR (pCs, CS_PKTPG_EEPROM_DATA);
  769.  
  770.     return (OK);
  771.     }
  772. /*******************************************************************************
  773. *
  774. * csInit - resets and then initializes the CS8900 chip
  775. *
  776. * This routine is a major entry point and is called to initialize this network
  777. * interface driver.  This routine may be called several times for each
  778. * operating system reboot to dynamically bring the network interface driver
  779. * to an up and running state.  This routine is called by the protocol stack,
  780. * the set_if_addr() routine, and the csIoctl() routine.
  781. *
  782. * RETURNS: OK or ERROR
  783. */
  784. LOCAL STATUS csInit
  785.     (
  786.     int unit
  787.     )
  788.     {
  789.     FAST CS_SOFTC *pCs = &cs_softc[unit];
  790.     if (unit >= MAXUNITS)
  791. return (ERROR);
  792.     /* Mark the interface as down */
  793.     pCs->arpCom.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
  794.     /* Enable debugging */
  795.     /* pCs->arpCom.ac_if.if_flags |= IFF_DEBUG; */
  796.     csError (pCs, "Initializing interface");
  797.     /* Reset the chip */
  798.     if (csChipReset (pCs) == ERROR)
  799. {
  800. csError (pCs, "Can not reset the chip");
  801. return (ERROR);
  802. }
  803.     /* Initialize the chip */
  804.     csChipInit (pCs);
  805.     /* Mark the interface as up and running */
  806.     pCs->arpCom.ac_if.if_flags |= (IFF_UP | IFF_RUNNING);
  807.     return (OK);
  808.     }
  809. /*******************************************************************************
  810. *
  811. * csReset - resets the CS8900 chip.
  812. *
  813. * This routine is a major entry point and is called by the protocol stack to
  814. * shut down this network interface driver.  This routine may be called several
  815. * times for each operating system reboot to dynamically bring the network
  816. * interface driver to a non-running state.
  817. *
  818. * RETURNS: N/A
  819. */
  820. LOCAL void csReset
  821.     (
  822.     int unit
  823.     )
  824.     {
  825.     FAST CS_SOFTC *pCs = &cs_softc[unit];
  826.     if (unit >= MAXUNITS)
  827. return;
  828.     csError (pCs, "Resetting interface");
  829.     /* Mark the interface as down */
  830.     pCs->arpCom.ac_if.if_flags &= ~IFF_RUNNING;
  831.     /* Reset the chip */
  832.     csChipReset (pCs);
  833.     }
  834. /*******************************************************************************
  835. *
  836. * csIoctl - ioctl for interface
  837. *
  838. * This routine is a major entry point and is called by the protocol stack to
  839. * modify characteristics of this network interface driver.  There are many
  840. * network interface ioctl commands, but this driver only supports two of them:
  841. * Set Interface Address and Set Interface Flags.
  842. *
  843. * RETURNS: OK if successful, otherwise errno.
  844. */
  845. LOCAL int csIoctl
  846.     (
  847.     struct ifnet *pIf,
  848.     int command,
  849.     char *pData
  850.     )
  851.     {
  852.     FAST CS_SOFTC *pCs = &cs_softc[pIf->if_unit];
  853.     int result         = OK;  /* Assume everything will go OK */
  854.     int state          = splnet();
  855.     switch (command)
  856. {
  857. case SIOCSIFADDR:  /* Set interface address (IP address) */
  858.     csError (pCs, "Ioctl: Set interface address");
  859.     result = set_if_addr (pIf, pData, (UCHAR *)pCs->arpCom.ac_enaddr);
  860.     /* Note: set_if_addr () calls csInit() */
  861.     break;
  862. case SIOCSIFFLAGS:  /* Set interface flags */
  863.     csError (pCs, "Ioctl: Set interface flags");
  864.     if (pIf->if_flags & IFF_UP)
  865. {
  866. /* Mark the interface as up and running */
  867. pCs->arpCom.ac_if.if_flags |= (IFF_UP | IFF_RUNNING);
  868. /* Initialize the interface */
  869. csInit (pIf->if_unit);
  870. }
  871.     else  /* The interface is down */
  872. {
  873. /* Mark the interface as down */
  874. pCs->arpCom.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
  875. /* Reset the chip */
  876. csChipReset (pCs);
  877. }
  878.     break;
  879. default:
  880.     result = EINVAL;  /* Invalid argument */
  881.     break;
  882. }
  883.     splx (state);
  884.     return (result);
  885.     }
  886. /*******************************************************************************
  887. *
  888. * csChipReset - resets the CS8900 chip
  889. *
  890. * This routine resets the CS8900 chip.
  891. *
  892. * RETURNS: OK or ERROR
  893. */
  894. LOCAL STATUS csChipReset 
  895.     (
  896.     CS_SOFTC *pCs
  897.     )
  898.     {
  899.     int intState;
  900.     int ix;
  901.     UCHAR temp;
  902.     /* Disable interrupts at the CPU so reset command is atomic */
  903.     intState = intLock (); /* INT LOCK */
  904.     /* We are now resetting the chip
  905.      * A spurious interrupt is generated by the chip when it is reset.
  906.      * This variable informs the interrupt handler to ignore this interrupt.
  907.      */
  908.     pCs->resetting = TRUE;
  909.     /* Issue a reset command to the chip */
  910.     csPacketPageW (pCs, CS_PKTPG_SELF_CTL, CS_SELF_CTL_RESET);
  911.     /* Re-enable interrupts at the CPU */
  912.     intUnlock (intState); /* INT UNLOCK */
  913.     /* The chip is always in IO mode after a reset */
  914.     pCs->inMemoryMode = FALSE;
  915.     /* If transmission was in progress, it is not now */
  916.     pCs->txInProgress = FALSE;
  917.     /* Delay for 125 micro-seconds (one eighth of a second) */
  918.     CS_MSEC_DELAY(125);
  919.     /* Transition SBHE to switch chip from 8-bit to 16-bit */
  920.     CS_IN_BYTE (pCs->ioAddr + CS_PORT_PKTPG_PTR, &temp);
  921.     CS_IN_BYTE (pCs->ioAddr + CS_PORT_PKTPG_PTR + 1, &temp);
  922.     CS_IN_BYTE (pCs->ioAddr + CS_PORT_PKTPG_PTR, &temp);
  923.     CS_IN_BYTE (pCs->ioAddr + CS_PORT_PKTPG_PTR + 1, &temp);
  924.     /* Wait until the EEPROM is not busy */
  925.     for (ix=0; ix<CS_MAXLOOP; ix++)
  926. if (!(csPacketPageR (pCs, CS_PKTPG_SELF_ST) & CS_SELF_ST_SI_BUSY))
  927.     break;
  928.     if (ix == CS_MAXLOOP)
  929. return (ERROR);
  930.     /* Wait until initialization is done */
  931.     for (ix=0; ix<CS_MAXLOOP; ix++)
  932. if (csPacketPageR (pCs, CS_PKTPG_SELF_ST) & CS_SELF_ST_INIT_DONE)
  933.     break;
  934.     if (ix == CS_MAXLOOP)
  935. return (ERROR);
  936.     /* Reset is no longer in progress */
  937.     pCs->resetting = FALSE;
  938.     return (OK);
  939.     }
  940. /*******************************************************************************
  941. *
  942. * csChipInit - initializes the CS8900 chip
  943. *
  944. * This routine uses the instance global variables in the cs_softc structure to
  945. * initialize the CS8900 chip.
  946. *
  947. * RETURNS: N/A
  948. */
  949. LOCAL void csChipInit
  950.     (
  951.     CS_SOFTC *pCs
  952.     )
  953.     {
  954.     USHORT busCtl;
  955.     USHORT selfCtl;
  956.     CS_IA  *pIA;
  957.     /* If memory mode is enabled */
  958.     if (pCs->configFlags & CS_CFGFLG_MEM_MODE)
  959. {
  960. /* If external logic is present for address decoding */
  961. if (csPacketPageR (pCs, CS_PKTPG_SELF_ST) & CS_SELF_ST_EL_PRES)
  962.     {
  963.     /* Program the external logic to decode address bits SA20-SA23 */
  964.     csPacketPageW (pCs, CS_PKTPG_EEPROM_CMD,
  965.        ((UINT)(pCs->pPacketPage)>>20) | CS_EEPROM_CMD_ELSEL);
  966.     }
  967. /* Setup chip for memory mode */
  968. csPacketPageW (pCs, CS_PKTPG_MEM_BASE, (UINT)(pCs->pPacketPage)&0xFFFF);
  969. csPacketPageW (pCs, CS_PKTPG_MEM_BASE+2, (UINT)(pCs->pPacketPage)>>16);
  970. busCtl = CS_BUS_CTL_MEM_MODE;
  971. if (pCs->configFlags & CS_CFGFLG_USE_SA)
  972.     busCtl |= CS_BUS_CTL_USE_SA;
  973. csPacketPageW (pCs, CS_PKTPG_BUS_CTL, busCtl);
  974. /* We are in memory mode now! */
  975. pCs->inMemoryMode = TRUE;
  976. }
  977.     /* If IOCHRDY is enabled then clear the bit in the busCtl register */
  978.     busCtl = csPacketPageR (pCs, CS_PKTPG_BUS_CTL);
  979.     if (pCs->configFlags & CS_CFGFLG_IOCHRDY)
  980. csPacketPageW (pCs, CS_PKTPG_BUS_CTL, busCtl & ~CS_BUS_CTL_IOCHRDY);
  981.     else
  982. csPacketPageW (pCs, CS_PKTPG_BUS_CTL, busCtl | CS_BUS_CTL_IOCHRDY);
  983.     /* Set the Line Control register to match the media type */
  984.     if (pCs->mediaType == CS_MEDIA_10BASET)
  985. csPacketPageW (pCs, CS_PKTPG_LINE_CTL, CS_LINE_CTL_10BASET);
  986.     else
  987. csPacketPageW (pCs, CS_PKTPG_LINE_CTL, CS_LINE_CTL_AUI_ONLY);
  988.     /* Set the BSTATUS/HC1 pin to be used as HC1 */
  989.     /* HC1 is used to enable the DC/DC converter */
  990.     selfCtl = CS_SELF_CTL_HC1E;
  991.     /* If the media type is 10Base2 */
  992.     if (pCs->mediaType == CS_MEDIA_10BASE2)
  993. {
  994. /* Enable the DC/DC converter
  995.  * If the DC/DC converter has a low enable
  996.  *   Set the HCB1 bit, which causes the HC1 pin to go low
  997.  */
  998. if ((pCs->configFlags & CS_CFGFLG_DCDC_POL) == 0)
  999.     selfCtl |= CS_SELF_CTL_HCB1;
  1000. }
  1001.     else  /* Media type is 10BaseT or AUI */
  1002. {
  1003. /* Disable the DC/DC converter
  1004.  * If the DC/DC converter has a high enable
  1005.  *   Set the HCB1 bit, which causes the HC1 pin to go low
  1006.  */
  1007. if ((pCs->configFlags & CS_CFGFLG_DCDC_POL) != 0)
  1008.     selfCtl |= CS_SELF_CTL_HCB1;
  1009. }
  1010.     csPacketPageW (pCs, CS_PKTPG_SELF_CTL, selfCtl);
  1011.     /* If media type is 10BaseT */
  1012.     if (pCs->mediaType == CS_MEDIA_10BASET)
  1013. {
  1014. /* If full duplex mode then set the FDX bit in TestCtl register */
  1015. if (pCs->configFlags & CS_CFGFLG_FDX)
  1016.     csPacketPageW (pCs, CS_PKTPG_TEST_CTL, CS_TEST_CTL_FDX);
  1017. }
  1018.     /* Initialize the config and control registers */
  1019.     csPacketPageW (pCs, CS_PKTPG_RX_CFG, CS_RX_CFG_ALL_IE);
  1020.     csPacketPageW (pCs, CS_PKTPG_RX_CTL,
  1021.    CS_RX_CTL_RX_OK_A | CS_RX_CTL_IND_A | CS_RX_CTL_BCAST_A);
  1022.     csPacketPageW (pCs, CS_PKTPG_TX_CFG, CS_TX_CFG_ALL_IE);
  1023.     csPacketPageW (pCs, CS_PKTPG_BUF_CFG, CS_BUF_CFG_RX_MISS_IE);
  1024.     /* Put Ethernet address into the Individual Address register */
  1025.     pIA = (CS_IA *)pCs->arpCom.ac_enaddr;
  1026.     csPacketPageW (pCs, CS_PKTPG_IND_ADDR,   pIA->word[0]);
  1027.     csPacketPageW (pCs, CS_PKTPG_IND_ADDR+2, pIA->word[1]);
  1028.     csPacketPageW (pCs, CS_PKTPG_IND_ADDR+4, pIA->word[2]);
  1029.     /* Set the interrupt level in the chip */
  1030.     if (pCs->intLevel == 5)
  1031. csPacketPageW (pCs, CS_PKTPG_INT_NUM, 3);
  1032.     else
  1033. csPacketPageW (pCs, CS_PKTPG_INT_NUM, (pCs->intLevel) - 10);
  1034.     /* Enable reception and transmission of frames */
  1035.     csPacketPageW (pCs, CS_PKTPG_LINE_CTL,
  1036.     csPacketPageR (pCs, CS_PKTPG_LINE_CTL) |
  1037.    CS_LINE_CTL_RX_ON | CS_LINE_CTL_TX_ON);
  1038.     /* Enable interrupt at the chip */
  1039.     csPacketPageW (pCs, CS_PKTPG_BUS_CTL,
  1040.     csPacketPageR (pCs, CS_PKTPG_BUS_CTL) |
  1041.    CS_BUS_CTL_INT_ENBL);
  1042.     }
  1043. #ifdef BSD43_DRIVER
  1044. /*******************************************************************************
  1045. *
  1046. * csOutput - ethernet output routine
  1047. *
  1048. * This routine is a major entry point and is called by the protocol stack to
  1049. * transmit a packet across the LAN.  The packet data is passed to this routine
  1050. * in a chain of mbuf structures.
  1051. *
  1052. * This routine calls the ether_output() routine, which in turn calls the
  1053. * csStartOutput() routine.  The ether_output() routine resolves the destination
  1054. * IP address to it's Ethernet address, builds an Ethernet header and prepends
  1055. * the Ethernet header to the mbuf chain.  The mbuf chain is added to the end
  1056. * of the network interface driver's transmit queue.  If the network interface
  1057. * NOTRAILERS flag is clear (trailers enabled), then the ether_output() routine
  1058. * converts the packet data to the trailers format.  Finally, the ether_output()
  1059. * routine calls the csStartOutput() routine begin transmission of the packet.
  1060. *
  1061. * RETURNS: OK if successful, otherwise errno.
  1062. */
  1063. LOCAL int csOutput
  1064.     (
  1065.     struct ifnet *pIf,
  1066.     struct mbuf *pMbufChain,
  1067.     SOCKADDR *pDst
  1068.     )
  1069.     {
  1070.     FAST CS_SOFTC *pCs = &cs_softc[pIf->if_unit];
  1071.     return (ether_output (pIf, pMbufChain, pDst, (FUNCPTR)csStartOutput,
  1072.   &pCs->arpCom));
  1073.     }
  1074. /*******************************************************************************
  1075. *
  1076. * csStartOutput - copy a packet to the interface
  1077. *
  1078. * This routine is called to start the transmission of the packet at the head
  1079. * of the transmit queue.  This routine is called by the ether_output() routine
  1080. * when a new packet is added to the transmit queue and this routine is called
  1081. * by csIntrTx() via netTask() when a previous packet transmission is
  1082. * completed.  This routine is always executed at task time (never at interrupt
  1083. * time).
  1084. *
  1085. * Note: This network interface driver does not support output hook routines,
  1086. * because to do so requires that an image of the transmit packet be built in
  1087. * memory before the image is copied to the CS8900 chip.  It is much more
  1088. * efficient to copy the image directly from the mbuf chain to the CS8900 chip.
  1089. * However, this network interface driver does support input hook routines.
  1090. *
  1091. * RETURNS: N/A
  1092. */
  1093. LOCAL void csStartOutput
  1094.     (
  1095.     int unit
  1096.     )
  1097.     {
  1098.     FAST CS_SOFTC *pCs = &cs_softc[unit];
  1099. #else /* BSD43_DRIVER */
  1100. LOCAL void csStartOutput
  1101.     (
  1102.     CS_SOFTC * pCs /* pointer to control structure */
  1103.     )
  1104.     {
  1105. #endif /* BSD43_DRIVER */
  1106.     FAST struct mbuf *pMbuf;
  1107.     struct mbuf *pMbufChain;
  1108.     struct ifqueue *pTxQueue;
  1109.     USHORT busStatus;
  1110.     USHORT length;
  1111.     int intState;
  1112. #ifdef BSD43_DRIVER
  1113.     if (unit >= MAXUNITS)
  1114. return;
  1115. #endif /* BSD43_DRIVER */
  1116.     pTxQueue = &pCs->arpCom.ac_if.if_snd;
  1117.     /* Note the maximum depth of the transmit queue */
  1118.     if (pTxQueue->ifq_len > pCs->maxTxDepth)
  1119. pCs->maxTxDepth = pTxQueue->ifq_len;
  1120.     /* Don't interrupt a transmission in progress */
  1121.     if (pCs->txInProgress)
  1122. return;
  1123.     /* Disable interrupts at the CPU so disabling chip interrupt is atomic */
  1124.     intState = intLock (); /* INT LOCK */
  1125.     /* Disable interrupt at the chip so transmit sequence is not disturbed */
  1126.     csPacketPageW (pCs, CS_PKTPG_BUS_CTL,
  1127.     csPacketPageR (pCs, CS_PKTPG_BUS_CTL) &
  1128.    ~CS_BUS_CTL_INT_ENBL);
  1129.     /* Re-enable interrupts at the CPU */
  1130.     intUnlock (intState); /* INT UNLOCK */
  1131.     /* While there is still more to transmit */
  1132.     while (pTxQueue->ifq_head != NULL)
  1133. {
  1134. /* Dequeue an mbuf chain from the transmit queue */
  1135. IF_DEQUEUE (pTxQueue, pMbufChain);
  1136. /* Find the total length of the data to transmit */
  1137. length = 0;
  1138. for (pMbuf=pMbufChain; pMbuf!=NULL; pMbuf=pMbuf->m_next)
  1139.     length += pMbuf->m_len;
  1140. /* etherOutputHookRtn is not supported */
  1141.  
  1142. /* Request that the transmit be started after
  1143.  * all data has been copied
  1144.  */
  1145. if (pCs->inMemoryMode)
  1146.     {
  1147.     csPacketPageW (pCs, CS_PKTPG_TX_CMD, CS_TX_CMD_START_ALL);
  1148.     csPacketPageW (pCs, CS_PKTPG_TX_LENGTH, length);
  1149.     }
  1150. else  /* In IO mode */
  1151.     {
  1152.     CS_OUT_WORD (pCs->ioAddr + CS_PORT_TX_CMD, CS_TX_CMD_START_ALL);
  1153.     CS_OUT_WORD (pCs->ioAddr + CS_PORT_TX_LENGTH, length);
  1154.     }
  1155. /* Read the busStatus register which indicates success of the request */
  1156. busStatus = csPacketPageR (pCs, CS_PKTPG_BUS_ST);
  1157. /* If there was an error in the transmit bid */
  1158. if (busStatus & CS_BUS_ST_TX_BID_ERR)
  1159.     {
  1160.     csError (pCs, "Transmit bid error (too big)");
  1161.     /* Discard the bad mbuf chain */
  1162.     m_freem (pMbufChain);
  1163.     pCs->arpCom.ac_if.if_oerrors++;
  1164.     /* Loop up to transmit the next chain */
  1165.     }
  1166. else if (busStatus & CS_BUS_ST_RDY4TXNOW)
  1167.     {
  1168.     /* The chip is ready for transmission now */
  1169.     /* Copy the frame to the chip to start transmission */
  1170.     csTxFrameCopy (pCs, pMbufChain);
  1171.     /* Free the mbuf chain */
  1172.     m_freem (pMbufChain);
  1173.     /* Transmission is now in progress */
  1174.     pCs->txInProgress = TRUE;
  1175.     break;  /* Exit this routine */
  1176.     }
  1177. else
  1178.        csError (pCs, "Not ready for transmission now");
  1179. }
  1180.     /* Re-enable interrupt at the chip */
  1181.     csPacketPageW (pCs, CS_PKTPG_BUS_CTL, 
  1182.    csPacketPageR (pCs, CS_PKTPG_BUS_CTL) | CS_BUS_CTL_INT_ENBL);
  1183.     }
  1184. /*******************************************************************************
  1185. *
  1186. * csTxFrameCopy - copies the packet from a mbuf chain to the chip
  1187. *
  1188. * This routine copies the packet from a chain of mbufs to the chip.  When all
  1189. * the data has been copied, then the chip automatically begins transmitting
  1190. * the data.
  1191. *
  1192. * The reason why this "simple" copy routine is so long and complicated is
  1193. * because all reads and writes to the chip must be done as 16-bit words.
  1194. * If an mbuf has an odd number of bytes, then the last byte must be saved
  1195. * and combined with the first byte of the next mbuf.
  1196. *
  1197. * RETURNS: N/A
  1198. */
  1199. LOCAL void csTxFrameCopy
  1200.     (
  1201.     CS_SOFTC *pCs,
  1202.     struct mbuf *pMbufChain
  1203.     )
  1204.     {
  1205.     struct mbuf *pMbuf;
  1206.     FAST USHORT *pFrame;
  1207.     FAST USHORT *pBuff;
  1208.     FAST USHORT *pBuffLimit;
  1209.     FAST int txDataPort;
  1210.     UCHAR  *pStart;
  1211.     USHORT  length;
  1212.     BOOL haveExtraByte;
  1213.     union
  1214. {
  1215. UCHAR  byte[2];
  1216. USHORT word;
  1217. } straddle;
  1218.     /* Initialize frame pointer and data port address */
  1219.     pFrame = pCs->pPacketPage + (CS_PKTPG_TX_FRAME/2);
  1220.     txDataPort = pCs->ioAddr + CS_PORT_RXTX_DATA;
  1221.     haveExtraByte = FALSE;  /* Start out with no extra byte */
  1222.     /* Process the chain of mbufs */
  1223.     for (pMbuf=pMbufChain; pMbuf!=NULL; pMbuf=pMbuf->m_next)
  1224. {
  1225. /* Setup starting pointer and length */
  1226. pStart = mtod (pMbuf, UCHAR *);
  1227. length = pMbuf->m_len;
  1228. /* If there is an extra byte left over from the previous mbuf */
  1229. if (haveExtraByte)
  1230.     {
  1231.     /* Add the first byte from this mbuf to make a word */
  1232.     straddle.byte[1] = *pStart;
  1233.     /* Write the word which straddles the mbufs to the chip */
  1234.     if (pCs->inMemoryMode)
  1235. *pFrame++ = straddle.word;
  1236.     else
  1237. {
  1238. CS_OUT_WORD (txDataPort, straddle.word);
  1239. }
  1240.     /* Adjust starting pointer and length */
  1241.     pStart++;
  1242.     length--;
  1243.     }
  1244. /* Point pBuff to the correct starting point */
  1245. pBuff = (USHORT *)pStart;
  1246.  
  1247. /* If there are odd bytes remaining in the mbuf */
  1248. if (length & 1)
  1249.     {
  1250.     haveExtraByte = TRUE;
  1251.     /* Point pBuffLimit to the extra byte */
  1252.     pBuffLimit = (USHORT *)(pStart+length-1);
  1253.     }
  1254. else  /* There is an even number of bytes remaining */
  1255.     {
  1256.     haveExtraByte = FALSE;
  1257.     /* Point pBuffLimit to just beyond the last word */
  1258.     pBuffLimit = (USHORT *)(pStart+length);
  1259.     }
  1260. /* Copy the words in the mbuf to the chip */
  1261. if (pCs->inMemoryMode)
  1262.     while (pBuff < pBuffLimit)
  1263. *pFrame++ = *pBuff++;
  1264. else
  1265.     while (pBuff < pBuffLimit)
  1266. {
  1267. CS_OUT_WORD (txDataPort, *pBuff++);
  1268. }
  1269.         /* If there is an extra byte left over in this mbuf
  1270.  *   Save the extra byte for later
  1271.  */
  1272.         if (haveExtraByte)
  1273.     straddle.byte[0] = *(UCHAR *)pBuff;
  1274. }
  1275.     /* If there is an extra byte left over from the last mbuf */
  1276.     if (haveExtraByte)
  1277. {
  1278. /* Add a zero byte to make a word */
  1279. straddle.byte[1] = 0;
  1280. /* Write the last word to the chip */
  1281. if (pCs->inMemoryMode)
  1282.     *pFrame = straddle.word;
  1283. else
  1284.     {
  1285.     CS_OUT_WORD (txDataPort, straddle.word);
  1286.     }
  1287. }
  1288.     }
  1289.  
  1290. /*******************************************************************************
  1291. *
  1292. * csIntr - Ethernet interface interrupt
  1293. *
  1294. * This routine in the interrupt service routine.  This routine is called by
  1295. * assembly language wrapper code whenever the CS8900 chip generates and
  1296. * interrupt.  The wrapper code issues an EOI command intr. controller.
  1297. *
  1298. * This routine processes the events on the Interrupt Status Queue.  The events
  1299. * are read one at a time from the ISQ and the appropriate event handlers are
  1300. * called.  The ISQ is read until it is empty.  If the chip's interrupt request
  1301. * line is active, then reading a zero from the ISQ will deactivate the
  1302. * interrupt request line.
  1303. *
  1304. * RETURNS: N/A
  1305. */
  1306. LOCAL void csIntr
  1307.     (
  1308.     int unit
  1309.     )
  1310.     {
  1311.     FAST CS_SOFTC *pCs = &cs_softc[unit];
  1312.     USHORT event;
  1313.     if (unit >= MAXUNITS)
  1314. return;
  1315.     /* Ignore any interrupts that happen while the chip is being reset */
  1316.     if (pCs->resetting)
  1317. return;
  1318.     /* Read an event from the Interrupt Status Queue */
  1319.     if (pCs->inMemoryMode)
  1320. event = csPacketPageR (pCs, CS_PKTPG_ISQ);
  1321.     else
  1322. {
  1323. CS_IN_WORD (pCs->ioAddr + CS_PORT_ISQ, &event);
  1324. }
  1325.     /* Process all the events in the Interrupt Status Queue */
  1326.     while (event != 0)
  1327. {
  1328. /* Dispatch to an event handler based on the register number */
  1329. switch (event & CS_REG_NUM_MASK)
  1330.     {
  1331.     case CS_REG_NUM_RX_EVENT:
  1332. csIntrRx (pCs, event);
  1333. break;
  1334.     case CS_REG_NUM_TX_EVENT:
  1335. csIntrTx (pCs, event);
  1336. break;
  1337.     case CS_REG_NUM_BUF_EVENT:
  1338. csIntrBuffer (pCs, event);
  1339. break;
  1340.     default:
  1341. csError (pCs, "Unknown interrupt event");
  1342. break;
  1343.     }
  1344. /* Read another event from the Interrupt Status Queue */
  1345. if (pCs->inMemoryMode)
  1346.     event = csPacketPageR (pCs, CS_PKTPG_ISQ);
  1347. else
  1348.     {
  1349.     CS_IN_WORD (pCs->ioAddr + CS_PORT_ISQ, &event);
  1350.     }
  1351. }
  1352.     }
  1353. /*******************************************************************************
  1354. *
  1355. * csIntrBuffer - interrupt handler for the receive miss event
  1356. *
  1357. * The routine is called whenever an event occurs regarding the transmit and
  1358. * receive buffers within the CS8900 chip.  The only buffer event that could
  1359. * happen with this network interface driver is the receive miss event.  When
  1360. * there are no receive buffers available within the chip and a packet arrives
  1361. * from the LAN, then this interrupt is generated.  This routine simply
  1362. * increments the input error counter.
  1363. *
  1364. * RETURNS: N/A
  1365. */
  1366. LOCAL void csIntrBuffer 
  1367.     (
  1368.     CS_SOFTC *pCs,
  1369.     USHORT bufEvent
  1370.     )
  1371.     {
  1372.     struct ifnet *pIf = &pCs->arpCom.ac_if;
  1373.     if (bufEvent & CS_BUF_EVENT_RX_MISS)
  1374. {
  1375. /* Increment the input error count */
  1376. pIf->if_ierrors++;
  1377. csError (pCs, "Receive miss");
  1378. }
  1379.     if (bufEvent & CS_BUF_EVENT_SW_INT)
  1380. {
  1381. csError (pCs, "Software initiated interrupt");
  1382. }
  1383.     }
  1384. /*******************************************************************************
  1385. *
  1386. * csIntrTx - interrupt handler for the transmission
  1387. *
  1388. * This routine is called whenever the transmission of a packet has completed
  1389. * successfully or unsuccessfully.  If the transmission was not successful,
  1390. * then the output error count is incremented.  If collisions occured while
  1391. * sending the packet, then the number of collisions is added to the collision
  1392. * counter.  If there are more packets on the transmit queue, then the next
  1393. * packet is started at task time by calling csStartOutput() via netTask().
  1394. *
  1395. * RETURNS: N/A
  1396. */
  1397. LOCAL void csIntrTx
  1398.     (
  1399.     CS_SOFTC *pCs,
  1400.     USHORT txEvent
  1401.     )
  1402.     {
  1403.     struct ifnet *pIf = &pCs->arpCom.ac_if;
  1404.     /* If there were any errors transmitting this frame */
  1405.     if (txEvent & (CS_TX_EVENT_LOSS_CRS | CS_TX_EVENT_SQE_ERR 
  1406. | CS_TX_EVENT_OUT_WIN | CS_TX_EVENT_JABBER
  1407. | CS_TX_EVENT_16_COLL))
  1408. {
  1409. /* Increment the output error count */
  1410. pIf->if_oerrors++;
  1411. /* If debugging is enabled then log error messages */
  1412. if (pIf->if_flags & IFF_DEBUG)
  1413.     {
  1414.     if (txEvent & CS_TX_EVENT_LOSS_CRS)
  1415. csError (pCs, "Loss of carrier");
  1416.     if (txEvent & CS_TX_EVENT_SQE_ERR)
  1417. csError (pCs, "SQE error");
  1418.     if (txEvent & CS_TX_EVENT_OUT_WIN)
  1419. csError (pCs, "Out-of-window collision");
  1420.     if (txEvent & CS_TX_EVENT_JABBER)
  1421. csError (pCs, "Jabber");
  1422.     if (txEvent & CS_TX_EVENT_16_COLL)
  1423. csError (pCs, "16 collisions");
  1424.     }
  1425. }
  1426.     /* Add the number of collisions for this frame */
  1427.     if (txEvent & CS_TX_EVENT_16_COLL)
  1428. pIf->if_collisions += 16;
  1429.     else
  1430. pIf->if_collisions += ((txEvent & CS_TX_EVENT_COLL_MASK) >> 11);
  1431.     /* Transmission is no longer in progress */
  1432.     pCs->txInProgress = FALSE;
  1433.     /* If there is more to transmit
  1434.      *   Start the next transmission at task time
  1435.      */
  1436.     if (pIf->if_snd.ifq_head != NULL)
  1437. {
  1438. #ifdef BSD43_DRIVER
  1439. netJobAdd ((FUNCPTR)csStartOutput, pIf->if_unit, 0, 0, 0, 0);
  1440. #else /* BSD43_DRIVER */
  1441. netJobAdd ((FUNCPTR)csStartOutput, (int)pCs, 0, 0, 0, 0);
  1442. #endif /* BSD43_DRIVER */
  1443. }
  1444.     }
  1445. /*******************************************************************************
  1446. *
  1447. * csIntrRx - interrupt handler for the reception
  1448. *
  1449. * This routine is called whenever a packet is received at the chip.  If the
  1450. * packet is received with errors, then the input error count is incremented.
  1451. * If the packet is received OK, then the data is copied to an internal receive
  1452. * buffer and the csRxProcess() routine is called via netTask() to
  1453. * process the received packet at task time.
  1454. *
  1455. * RETURNS: N/A
  1456. */
  1457. LOCAL void csIntrRx
  1458.     (
  1459.     CS_SOFTC *pCs,
  1460.     USHORT rxEvent
  1461.     )
  1462.     {
  1463.     struct ifnet *pIf = &pCs->arpCom.ac_if;
  1464.     CS_RXBUF *pRxBuff;
  1465.     /* If the frame was not received OK */
  1466.     if (!(rxEvent & CS_RX_EVENT_RX_OK))
  1467.         {
  1468.         /* Increment the input error count */
  1469.         pIf->if_ierrors++;
  1470.         /* If debugging is enabled then log error messages */
  1471.         if (pIf->if_flags & IFF_DEBUG)
  1472.     {
  1473.     /* If an error bit is set */
  1474.     if (rxEvent != CS_REG_NUM_RX_EVENT)
  1475.         {
  1476.         if (rxEvent & CS_RX_EVENT_RUNT)
  1477.     csError (pCs, "Runt");
  1478.         if (rxEvent & CS_RX_EVENT_X_DATA)
  1479.     csError (pCs, "Extra data");
  1480.         if (rxEvent & CS_RX_EVENT_CRC_ERR)
  1481.     {
  1482.     if (rxEvent & CS_RX_EVENT_DRIBBLE)
  1483.         csError (pCs, "Alignment error");
  1484.     else
  1485.         csError (pCs, "CRC Error");
  1486.     }
  1487.         else if (rxEvent & CS_RX_EVENT_DRIBBLE)
  1488.     csError (pCs, "Dribble bits");
  1489.         /* Must read the length of all received frames */
  1490.         csPacketPageR (pCs, CS_PKTPG_RX_LENGTH);
  1491.         /* Skip the received frame */
  1492.         csPacketPageW (pCs, CS_PKTPG_RX_CFG,
  1493.        csPacketPageR (pCs,CS_PKTPG_RX_CFG)
  1494.     | CS_RX_CFG_SKIP);
  1495.         }
  1496.     else 
  1497.         csError (pCs, "Implied skip");
  1498.     }
  1499. return;
  1500. }
  1501.     /* Get a receive frame buffer */
  1502.     pRxBuff = csRxBuffAlloc (pCs);
  1503.     if (pRxBuff == NULL)  /* If no buffer available */
  1504. {
  1505. /* Increment the input error count */
  1506. pIf->if_ierrors++;
  1507. csError (pCs, "No receive buffer available");
  1508. /* Must read the length of all received frames */
  1509. csPacketPageR (pCs, CS_PKTPG_RX_LENGTH);
  1510. /* Skip the received frame */
  1511. csPacketPageW (pCs, CS_PKTPG_RX_CFG,
  1512.        csPacketPageR (pCs, CS_PKTPG_RX_CFG) | CS_RX_CFG_SKIP);
  1513. return;
  1514. }
  1515.     /* Copy the received frame from the chip to the buffer */
  1516.     csRxFrameCopy (pCs, pRxBuff);
  1517.     /* Process the received frame at task time */
  1518.     netJobAdd ((FUNCPTR)csRxProcess, (int)pCs, (int)pRxBuff, 0, 0, 0);
  1519.     }
  1520. /*******************************************************************************
  1521. *
  1522. * csRxFrameCopy - copies a received frame from the chip to a receive buffer
  1523. *
  1524. * This routine copies a received frame from the chip to a receive buffer.
  1525. *
  1526. * RETURNS: N/A
  1527. */
  1528. LOCAL void csRxFrameCopy
  1529.     (
  1530.     CS_SOFTC *pCs,
  1531.     CS_RXBUF *pRxBuff
  1532.     )
  1533.     {
  1534.     FAST USHORT *pFrame = pCs->pPacketPage + (CS_PKTPG_RX_LENGTH/2);
  1535.     FAST int rxDataPort = pCs->ioAddr + CS_PORT_RXTX_DATA;
  1536.     FAST USHORT *pBuff;
  1537.     FAST USHORT *pBuffLimit;
  1538.     USHORT temp;
  1539.     /* Get the length of the received frame */
  1540.     if (pCs->inMemoryMode)
  1541. {
  1542. pRxBuff->length = *pFrame++;
  1543. }
  1544.     else  /* In IO mode */
  1545. {
  1546. CS_IN_WORD (rxDataPort, &temp);  /* Discard RxStatus */
  1547. CS_IN_WORD (rxDataPort, &pRxBuff->length);
  1548. }
  1549.     /* Setup pointers to the buffer for copying */
  1550.     pBuff = (USHORT *)pRxBuff->data;
  1551.     pBuffLimit = pBuff + ((pRxBuff->length + 1)/2);
  1552.     /* Copy the frame from the chip to the buffer */
  1553.     if (pCs->inMemoryMode)
  1554. while (pBuff < pBuffLimit)
  1555.     *pBuff++ = *pFrame++;
  1556.     else
  1557. while (pBuff < pBuffLimit)
  1558.     {
  1559.     CS_IN_WORD (rxDataPort, pBuff);
  1560.     pBuff++;
  1561.     }
  1562.     }
  1563. /*******************************************************************************
  1564. *
  1565. * csRxProcess - processes a received packet in task level
  1566. *
  1567. * This routine processes a received packet.  The received packet was copied to
  1568. * a receive buffer at interrupt time and this routine processses the receive
  1569. * buffer at task time via netTask().
  1570. *  
  1571. * If a recieve hook routine is specified, then the packet is given to the
  1572. * hook routine for processing.  If the received packet does not use trailers
  1573. * and the packet is large, then a cluster mbuf is built that points to the
  1574. * receive buffer directly.  If a cluster mbuf is not used, then the packet
  1575. * is copied to an mbuf chain.  The cluster mbuf or mbuf chain is then passed
  1576. * up to the protocol stack.
  1577. *
  1578. * RETURNS: N/A
  1579. */
  1580. LOCAL void csRxProcess
  1581.     (
  1582.     CS_SOFTC *pCs,
  1583.     CS_RXBUF *pRxBuff
  1584.     )
  1585.     {
  1586.     struct ifnet *pIf = &pCs->arpCom.ac_if;
  1587.     struct mbuf *pMbufChain;
  1588.     ETH_HDR *pEtherHeader;
  1589.     UCHAR *pData;
  1590.     int dataLength;
  1591. #ifdef BSD43_DRIVER
  1592.     int trailerOffset;
  1593.     USHORT type;
  1594. #endif /* BSD43_DRIVER */
  1595.     /* If a hook routine is specified */
  1596.     if (etherInputHookRtn != NULL)
  1597. {
  1598. /* Call the hook routine */
  1599. if ((*etherInputHookRtn) (pIf, pRxBuff->data, pRxBuff->length) != 0)
  1600.     {
  1601.     /* The hook routine has handled the received frame */
  1602.     csRxBuffFree (pCs, pRxBuff);
  1603.     return;
  1604.     }
  1605. }
  1606.     /* Setup working variables */
  1607.     pEtherHeader = (ETH_HDR *)pRxBuff->data;
  1608.     pData = &pRxBuff->data[SIZEOF_ETHERHEADER];
  1609.     dataLength = pRxBuff->length - SIZEOF_ETHERHEADER;
  1610. #ifdef BSD43_DRIVER
  1611.     /* Check if the received frame uses trailers */
  1612.     check_trailer (pEtherHeader, pData, &dataLength, &trailerOffset, pIf);
  1613.     /* Save the type because build_cluster() will overwrite it */
  1614.     type = pEtherHeader->ether_type;
  1615.     /* If trailers are not used and there is enough data for clustering */
  1616.     if ((trailerOffset == 0) && USE_CLUSTER (dataLength))
  1617. #else /* BSD43_DRIVER */
  1618.     /* If trailers are not used and there is enough data for clustering */
  1619.     if (USE_CLUSTER (dataLength))
  1620. #endif /* BSD43_DRIVER */
  1621. {
  1622. /* Build a cluster mbuf that points to my receive buffer */
  1623. pMbufChain = build_cluster (pData, dataLength, pIf, CS_MC_LOANED,
  1624.  &pRxBuff->refCount, (FUNCPTR)csRxBuffFree , (int)pCs, (int)pRxBuff, 0);
  1625. if (pMbufChain != NULL)
  1626.     {
  1627.     pRxBuff->status = CS_RXBUF_LOANED;
  1628.     pCs->loanCount++;
  1629.     }
  1630. else
  1631.     csRxBuffFree (pCs, pRxBuff);
  1632. }
  1633.     else  /* Can not do clustering */
  1634. {
  1635. /* Copy the received data to a chain of mbufs */
  1636. #ifdef BSD43_DRIVER
  1637. pMbufChain = copy_to_mbufs (pData, dataLength, trailerOffset, pIf);
  1638. #else /* BSD43_DRIVER */
  1639. pMbufChain = copy_to_mbufs (pData, dataLength, 0, pIf);
  1640. #endif /* BSD43_DRIVER */
  1641. csRxBuffFree (pCs, pRxBuff);
  1642. }
  1643.     /* If could not get an mbuf */
  1644.     if (pMbufChain == NULL)
  1645. {
  1646. pIf->if_ierrors++;
  1647. csError (pCs, "No receive mbuf available");
  1648. return;
  1649. }
  1650.     /* Pass the mbuf chain up to the protocol stack */
  1651. #ifdef BSD43_DRIVER
  1652.     do_protocol_with_type (type, pMbufChain, &pCs->arpCom, dataLength);
  1653. #else /* BSD43_DRIVER */
  1654.     do_protocol (pEtherHeader, pMbufChain, &pCs->arpCom, dataLength);
  1655. #endif /* BSD43_DRIVER */
  1656.     /* Another packet successfully received! */
  1657.     pIf->if_ipackets++;
  1658.     }
  1659. /*******************************************************************************
  1660. *
  1661. * csRxBuffInit - initializes the receive buffers
  1662. *
  1663. * This routine initializes the network interface driver's collection of
  1664. * receive buffers.  The receive buffers are allocated from system memory
  1665. * and linked together in a linked list of free receive buffers.
  1666. *
  1667. * RETURNS: OK or ERROR
  1668. */
  1669. LOCAL STATUS csRxBuffInit
  1670.     (
  1671.     CS_SOFTC *pCs
  1672.     )
  1673.     {
  1674.     CS_RXBUF *pRxBuff;
  1675.     CS_RXBUF *pRxLast;
  1676.     /* Allocate the receive frame buffers */
  1677.     pCs->pFreeRxBuff = (CS_RXBUF *)malloc (sizeof(CS_RXBUF) * CS_RXBUFCOUNT);
  1678.     if (pCs->pFreeRxBuff == NULL)
  1679. return (ERROR);
  1680.     /* Link all the receive frame buffers together on the free list */
  1681.     pRxLast = pCs->pFreeRxBuff + CS_RXBUFCOUNT - 1;
  1682.     for (pRxBuff=pCs->pFreeRxBuff; pRxBuff<pRxLast; pRxBuff++)
  1683. {
  1684. pRxBuff->pNext  = pRxBuff + 1;
  1685. pRxBuff->status = CS_RXBUF_FREE;
  1686. }
  1687.     pRxLast->pNext  = NULL;
  1688.     pRxLast->status = CS_RXBUF_FREE;
  1689.     return (OK);
  1690.     }
  1691. /*******************************************************************************
  1692. *
  1693. * csRxBuffAlloc - removes a receive buffer from the free receive buffer list
  1694. *
  1695. * This routine removes a receive buffer from the free receive buffer list.
  1696. *
  1697. * RETURNS: pointer of the buffer
  1698. */
  1699. LOCAL CS_RXBUF *csRxBuffAlloc
  1700.     (
  1701.     CS_SOFTC *pCs
  1702.     )
  1703.     {
  1704.     CS_RXBUF *pRxBuff;
  1705.     if (pCs->pFreeRxBuff == NULL)
  1706. return (NULL);
  1707.     /* Remove a buffer from the free list */
  1708.     pRxBuff = pCs->pFreeRxBuff;
  1709.     pCs->pFreeRxBuff = pRxBuff->pNext;
  1710.     pRxBuff->pNext = NULL;
  1711.     /* Init the reference count to zero */
  1712.     pRxBuff->refCount = 0;
  1713.     /* The buffer is now allocated */
  1714.     pRxBuff->status = CS_RXBUF_ALLOCATED;
  1715.     /* Increment number of receive buffers currently in use */
  1716.     pCs->rxDepth++;
  1717.     if (pCs->rxDepth > pCs->maxRxDepth)
  1718. pCs->maxRxDepth = pCs->rxDepth;
  1719.     return (pRxBuff);
  1720.     }
  1721. /*******************************************************************************
  1722. *
  1723. * csRxBuffFree - returns an allocated receive buffer back to the free list
  1724. *
  1725. * This routine returns an allocated receive buffer back to the free list.
  1726. *
  1727. * RETURNS: N/A
  1728. */
  1729. LOCAL void csRxBuffFree
  1730.     (
  1731.     CS_SOFTC *pCs,
  1732.     CS_RXBUF *pRxBuff
  1733.     )
  1734.     {
  1735.     int intState = intLock(); /* INT LOCK (csRxBuffAlloc() won't interrupt) */
  1736.     /* Put the buffer at the head of the free list */
  1737.     pRxBuff->pNext = pCs->pFreeRxBuff;
  1738.     pCs->pFreeRxBuff = pRxBuff;
  1739.     /* The buffer is now free */
  1740.     pRxBuff->status = CS_RXBUF_FREE;
  1741.     /* Decrement the outstanding receive depth */
  1742.     pCs->rxDepth--;
  1743.     /* Re-enable interrupts at the CPU */
  1744.     intUnlock (intState); /* INT UNLOCK */
  1745.     }
  1746. /*******************************************************************************
  1747. *
  1748. * csPacketPageR - reads a word from the PacketPage
  1749. *
  1750. * This routine reads a word from the PacketPage at the specified offset.
  1751. *
  1752. * RETURNS: a word in the offset
  1753. */
  1754. LOCAL USHORT csPacketPageR
  1755.     (
  1756.     CS_SOFTC *pCs,
  1757.     USHORT offset
  1758.     )
  1759.     {
  1760.     if (pCs->inMemoryMode)
  1761. {
  1762. return (*((pCs->pPacketPage) + (offset/2)));
  1763. }
  1764.     else  /* In IO mode */
  1765. {
  1766. USHORT temp;
  1767. CS_OUT_WORD (pCs->ioAddr + CS_PORT_PKTPG_PTR, offset);
  1768. CS_IN_WORD (pCs->ioAddr + CS_PORT_PKTPG_DATA, &temp);
  1769. return (temp);
  1770. }
  1771.     }
  1772. /*******************************************************************************
  1773. *
  1774. * csPacketPageW - writes a value to the PacketPage
  1775. *
  1776. * This routine writes a value to the PacketPage at the specified offset.
  1777. *
  1778. * RETURNS: N/A
  1779. */
  1780. LOCAL void csPacketPageW
  1781.     (
  1782.     CS_SOFTC *pCs,
  1783.     USHORT offset,
  1784.     USHORT value
  1785.     )
  1786.     {
  1787.     if (pCs->inMemoryMode)
  1788. {
  1789. *((pCs->pPacketPage) + (offset/2)) = value;
  1790. }
  1791.     else  /* In IO mode */
  1792. {
  1793. CS_OUT_WORD (pCs->ioAddr + CS_PORT_PKTPG_PTR, offset);
  1794. CS_OUT_WORD (pCs->ioAddr + CS_PORT_PKTPG_DATA, value);
  1795. }
  1796.     }
  1797. /*******************************************************************************
  1798. *
  1799. * csError - logs a message to the logging task
  1800. *
  1801. * This routine logs a message to the logging task if debugging is enabled.
  1802. *
  1803. * RETURNS: N/A
  1804. */
  1805. LOCAL void csError
  1806.     (
  1807.     CS_SOFTC *pCs,
  1808.     char *pString
  1809.     )
  1810.     {
  1811.     /* If debugging is enabled */
  1812.     if (pCs->arpCom.ac_if.if_flags & IFF_DEBUG)
  1813. {
  1814. logMsg ("cs%d - %sn", pCs->arpCom.ac_if.if_unit, (int)pString, 
  1815. 0, 0, 0, 0);
  1816. }
  1817.     }
  1818. /*******************************************************************************
  1819. *
  1820. * csShow - shows statistics for the `cs' network interface
  1821. *
  1822. * This routine displays statistics about the `cs' Ethernet network interface.
  1823. * It has two parameters:
  1824. * .iP <unit>
  1825. * interface unit; should be 0.
  1826. * .iP <zap>
  1827. * if 1, all collected statistics are cleared to zero.
  1828. * .LP
  1829. *
  1830. * RETURNS: N/A
  1831. */
  1832. void csShow
  1833.     (
  1834.     int unit, /* interface unit */
  1835.     BOOL zap /* zero totals */
  1836.     )
  1837.     {
  1838.     FAST CS_SOFTC *pCs = &cs_softc[unit];
  1839.     struct ifnet *pIf  = &pCs->arpCom.ac_if;
  1840.     if (unit >= MAXUNITS)
  1841. {
  1842. printf ("cs%d - Invalid unit numbern", unit);
  1843. return;
  1844. }
  1845.     if (zap)
  1846. {
  1847. /* Reset all the statistics to zero */
  1848. pIf->if_ipackets   = 0;
  1849. pIf->if_opackets   = 0;
  1850. pIf->if_ierrors    = 0;
  1851. pIf->if_oerrors    = 0;
  1852. pIf->if_collisions = 0;
  1853. /* Reset counters to zero */
  1854. pCs->rxDepth    = 0;
  1855. pCs->maxRxDepth = 0;
  1856. pCs->maxTxDepth = 0;
  1857. pCs->loanCount  = 0;
  1858. }
  1859.     printf ("n");
  1860.     printf ("Show cs%d: ", unit);
  1861.     printf ("Crystal Semiconductor CS8900 Network Interface Drivern");
  1862.     printf ("I/O Address      : 0x%Xn", pCs->ioAddr);
  1863.     printf ("Interrupt Level  : %dn",   pCs->intLevel);
  1864.     printf ("Interrupt Vector : %dn",   pCs->intVector);
  1865.     printf ("Access Mode      : ");
  1866.     if (pCs->inMemoryMode)
  1867. {
  1868. printf ("Memory Moden");
  1869. printf ("Memory Address   : 0x%Xn", (int)pCs->pPacketPage);
  1870. }
  1871.     else 
  1872. printf ("I/O Moden");
  1873.     printf ("Media Type       : ");
  1874.     switch (pCs->mediaType)
  1875. {
  1876. case CS_MEDIA_AUI:
  1877.     printf ("AUIn");
  1878.     break;
  1879. case CS_MEDIA_10BASE2:
  1880.     printf ("10Base2n");
  1881.     break;
  1882. case CS_MEDIA_10BASET:
  1883.     if (pCs->configFlags & CS_CFGFLG_FDX)
  1884. printf ("10BaseT, FDXn");
  1885.     else
  1886. printf ("10BaseTn");
  1887.     break;
  1888. default:
  1889.     printf ("Unknownn");
  1890.     break;
  1891. }
  1892.     printf ("Interface Flags  : ");
  1893.     if (pIf->if_flags & IFF_UP)
  1894. printf ("UP");
  1895.     else 
  1896. printf ("DOWN");
  1897.     if (pIf->if_flags & IFF_RUNNING)
  1898. printf (", RUNNING");
  1899.     if (pIf->if_flags & IFF_BROADCAST)
  1900. printf (", BROADCAST");
  1901.     if (pIf->if_flags & IFF_DEBUG)
  1902. printf (", DEBUG");
  1903.     if (pIf->if_flags & IFF_LOOPBACK)
  1904. printf (", LOOPBACK");
  1905.     if (pIf->if_flags & IFF_POINTOPOINT)
  1906. printf (", POINTOPOINT");
  1907.     if (pIf->if_flags & IFF_NOTRAILERS)
  1908. printf (", NOTRAILERS");
  1909.     if (pIf->if_flags & IFF_NOARP)
  1910. printf (", NOARP");
  1911.     if (pIf->if_flags & IFF_PROMISC)
  1912. printf (", PROMISC");
  1913.     if (pIf->if_flags & IFF_ALLMULTI)
  1914. printf (", ALLMULTI");
  1915.     printf ("n");
  1916.     printf ("Input Packets    : %dn", pIf->if_ipackets);
  1917.     printf ("Output Packets   : %dn", pIf->if_opackets);
  1918.     printf ("Input Errors     : %dn", pIf->if_ierrors );
  1919.     printf ("Output Errors    : %dn", pIf->if_oerrors );
  1920.     printf ("Collisions       : %dn", pIf->if_collisions);
  1921.     printf ("Current Tx Depth : %dn", pIf->if_snd.ifq_len);
  1922.     printf ("Current Rx Depth : %dn", pCs->rxDepth);
  1923.     printf ("Maximum Tx Depth : %dn", pCs->maxTxDepth);
  1924.     printf ("Maximum Rx Depth : %dn", pCs->maxRxDepth);
  1925.     printf ("Loan Count       : %dn", pCs->loanCount);
  1926.     printf ("n");
  1927.     }