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

VxWorks

开发平台:

C/C++

  1. /* sn83932End.c - Nat. Semi DP83932B SONIC Ethernet driver */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01t,20sep01,dat  Removing ANSI errors for diab compiler
  8. 01s,21jun01,rcs  Merge SPR# 63876 fix to Tornado-Comp-Drv
  9. 01r,16feb01,pai  fixed mutual exclusion in sn83932Send().
  10. 01q,16feb01,pai  removed int[Lock|Unlock] frame around <txBlocked> flag set.
  11. 01p,16feb01,pai  fixed handling of IFF_UP and IFF_RUNNING flags (SPR #63876).
  12. 01o,16feb01,pai  made strtok_r arguments consistent with SPR 62224 fix.
  13. 01n,16feb01,pai  allocated DRV_CTRL structure from heap (SPR #32774).
  14. 01m,16feb01,pai  removed reference to etherLib.
  15. 01l,16feb01,pai  fixed use of NULL
  16. 01k,16feb01,pai  corrected return error codes and freed mBlk chain (SPR #28492)
  17. 01j,22sep98,dat  lint warnings removed
  18. 01i,18aug98,fle  doc : made first line in one-line
  19. 01h,11dec97,kbw  making man page edits
  20. 01g,08dec97,gnn  END code review fixes.
  21. 01f,05dec97,pul  restored sonic driver after major rework
  22. 01e,20aug97,pul  modified buffering scheme to use MBLKs
  23. 01d,12aug97,gnn  changes necessitated by MUX/END update.
  24. 01c,02May97,sal  Man page fix - SPR8487
  25. 01b,29Apr97,sal  set LBR bit in snEndDcr by default
  26. 01a,04Feb97,sal  adapted from if_sn.c (01s,23apr96,wkm)
  27. */
  28. /*
  29. DESCRIPTION
  30. This module implements the National Semiconductor DP83932 SONIC Ethernet 
  31. network interface driver.
  32. This driver is designed to be moderately generic. Thus, it operates 
  33. unmodified across the range of architectures and targets supported by 
  34. VxWorks.  To achieve this, the driver load routine requires several 
  35. target-specific parameters.  The driver also depends on a few external 
  36. support routines.  These parameters and support routines are described 
  37. below.  If any of the assumptions stated below are not true for
  38. your particular hardware, this driver probably cannot function correctly
  39. with that hardware. This driver supports up to four individual units per CPU.
  40. BOARD LAYOUT
  41. This device is on-board.  No jumpering diagram is necessary.
  42. EXTERNAL INTERFACE
  43. This driver provides the END external interface. Thus, the 
  44. only normal external interface is the sn83932EndLoad() routine, 
  45. although snEndClkEnable() and snEndClkDisable() are provided for 
  46. the use (optional) of the internal clock.  All required parameters 
  47. are passed into the load function by means of a single colon-delimited 
  48. string.  The sn83932Load() function uses strtok() to parse the string,
  49. which it expects to be of the following format:
  50.     <unit_ID>:<devIO_addr>:<ivec>:<e_addr>
  51. The entry point for sn83932EndLoad() is defined within the 'endDevTbl' 
  52. in configNet.h.
  53. TARGET-SPECIFIC PARAMETERS
  54. .IP <unit_ID>
  55. A convenient holdover from the former model, this is only used in the
  56. string name for the driver.
  57. .IP <devIO_addr>
  58. Denotes the base address of the device's I/O register set. 
  59. .IP <ivec>
  60. Denotes the interrupt vector to be used by the driver to service an 
  61. interrupt from the SONIC device.  The driver connects the interrupt 
  62. handler to this vector by calling intConnect().
  63. .IP <e_addr>
  64. This parameter is obtained by calling sysEnetAddrGet(), an external 
  65. support routine. It specifies the unique six-byte address assigned to 
  66. the VxWorks target on the Ethernet.
  67. .LP
  68. EXTERNAL SUPPORT REQUIREMENTS
  69. This driver requires the following external support routines:
  70. .IP sysEnetInit()
  71. .CS
  72.     void sysEnetInit (int unit)
  73. .CE
  74. This routine performs any target-specific
  75. operations that must be executed before the SONIC device is initialized.
  76. The driver calls this routine, once per unit, during the unit start-up 
  77. phase.
  78. .IP sysEnetAddrGet()
  79. .CS
  80.     STATUS sysEnetAddrGet (int unit, char *pCopy)
  81. .CE
  82. This routine provides the six-byte Ethernet address used by <unit>.  It
  83. must copy the six-byte address to the space provided by <pCopy>.  This
  84. routine returns OK, or ERROR if it fails.  The driver calls this routine, 
  85. once per unit, during the unit start-up phase. 
  86. .IP sysEnetIntEnable()
  87. .CS
  88.     void sysEnetIntEnable (int unit), void sysEnetIntDisable (int unit)
  89. .CE
  90. These routines enable or disable the interrupt from
  91. the SONIC device for the specified <unit>.  Typically,
  92. this involves interrupt controller hardware,
  93. either internal or external to the CPU.  The driver calls these routines 
  94. only during initialization, during the unit start-up phase.
  95. .IP sysEnetIntAck()
  96. .CS
  97.     void sysEnetIntAck (int unit)
  98. .CE
  99. This routine performs any interrupt acknowledgment or
  100. clearing that may be required.  This typically
  101. involves an operation to some interrupt control hardware. 
  102. The driver calls this routine from the interrupt handler.
  103. .LP
  104. DEVICE CONFIGURATION
  105. Two global variables, 'snEndDcr' and 'snEndDcr2', are used to set the SONIC
  106. device configuration registers.  By default, the device is programmed in
  107. 32-bit mode with zero-wait states.  If these values are not suitable,
  108. the 'snEndDcr' and 'snEndDcr2' variables should be modified before 
  109. loading the driver.  See the SONIC manual for information on appropriate
  110. values for these parameters.
  111. SYSTEM RESOURCE USAGE
  112. When implemented, this driver requires the following system resources:
  113.     
  114.     - one interrupt vector
  115.     - 0 bytes in the initialized data section (data)
  116.     - 696 bytes in the uninitialized data section (BSS)
  117. The above data and BSS requirements are for the MC68020 architecture 
  118. and can vary for other architectures.  Code size (text) varies greatly 
  119. between architectures and is therefore not quoted here.
  120. This driver uses cacheDmaMalloc() to allocate the memory to be shared with 
  121. the SONIC device.  The size requested is 117,188 bytes.
  122. The SONIC device can only be operated if the shared memory region is
  123. write-coherent with the data cache.  The driver cannot maintain cache
  124. coherency for the device for data that is written by the driver
  125. because fields within the shared structures are asynchronously modified by
  126. the driver and the device, and these fields may share the same cache
  127. line.
  128. SEE ALSO: ifLib
  129. */
  130. /*
  131. INTERNAL
  132. This driver contains conditional compilation switch DEBUG.
  133. If defined, adds debug output routines.  Output is further
  134. selectable at run-time via the snDebug global variable.
  135. See also the NOTES section at the end of this file.
  136. Also contains LED DEBUG switch which enables the Led output.
  137. */
  138. #include "vxWorks.h"
  139. #include "sys/types.h"
  140. #include "taskLib.h"
  141. #include "iv.h"
  142. #include "memLib.h"
  143. #include "sys/ioctl.h"
  144. #include "etherMultiLib.h"
  145. #include "net/protosw.h"
  146. #include "errno.h"
  147. #include "cacheLib.h"
  148. #include "stdio.h"
  149. #include "intLib.h"
  150. #include "logLib.h"
  151. #include "netLib.h"
  152. #include "netBufLib.h"
  153. #include "muxLib.h"
  154. #include "netinet/if_ether.h"
  155. /* Include END specific headers */
  156. #include "endLib.h"
  157. /* Device Header File */
  158. #include "drv/end/sn83932End.h"
  159. /* CONDITIONAL SWITCHES */
  160. #undef DEBUG
  161. #undef LED_DEBUG
  162. #define SN_DEV_NAME "sn"
  163. #define SN_DEV_NAME_LEN 3
  164. #if defined(LED_DEBUG) 
  165. #include "../../../config/p4000/p4000.h"
  166. #endif
  167. /* STDOUT MACRO */
  168. #define SN_LOGMSG(s,x1,x2,x3,x4,x5,x6) logMsg (s,x1,x2,x3,x4,x5,x6) 
  169. /* LED */
  170. #if defined(LED_DEBUG) || defined(PULI_LED_DEBUG)
  171. #define PutLED(x,y)   *P4000_ALPHAN_CHAR(y) = x << 24;
  172. #define ClrLED
  173.     *P4000_ALPHAN_CLR_ = P4000_RESET_ONE;
  174.     *P4000_ALPHAN_CHAR(0) = ' ' << 24;
  175.     *P4000_ALPHAN_CHAR(1) = ' ' << 24;
  176.     *P4000_ALPHAN_CHAR(2) = ' ' << 24;
  177.     *P4000_ALPHAN_CHAR(3) = ' ' << 24
  178. #endif
  179.  
  180. /* LOCAL DEFINITIONS */
  181. /* Maximum number of Multicast addresses supported */
  182. #define MAX_MCASTS   15
  183. /* configurable cluster sizes of the two cluster pools */
  184. /* one, optimal cluster size */
  185. #define OPTIMAL_CLUSTER_SIZE 128
  186. /*second, MTU cluster size */
  187. #define MTU_CLUSTER_SIZE  (ETHERMTU + SIZEOF_ETHERHEADER + 6)
  188. /* 10 Mb */
  189. #define SN_SPEED    10000000
  190. /* Data Interrupt bits */
  191. #define SN_IMR_DATA (PRXEN | PTXEN | TXEREN)
  192. #define SN_IMR_INIT (SN_IMR_DATA | BREN)
  193. /* max number of units to support */
  194. #define MAX_UNITS   4                   
  195. /* Minimum buffer fragment */
  196. #define MIN_1STXMTBUF_SIZE 4
  197. /* size of one receive buffer */
  198. #define RX_BUF_SIZE (0x2000)            
  199. #define RX_BUF_EXTRA (0x200) /* Extra space needed to accomodate */
  200. /* Sonic buffer overrun in Rev. C */
  201. /* parts - found by Algorithmics  */
  202. /* Total Receive Buffer Area */
  203. #define RBA_SIZE    ((RX_BUF_SIZE + RX_BUF_EXTRA) * NUM_RRA_DESC)
  204. /*** END MACROS ***/ /* Should be in endlib.h in my opinion */
  205. #define END_M2_INUCAST(pEnd) (pEnd)->mib2Tbl.ifInUcastPkts++
  206. #define END_M2_INNUCAST(pEnd) (pEnd)->mib2Tbl.ifInNUcastPkts++
  207. #define END_M2_INERRORS(pEnd) (pEnd)->mib2Tbl.ifInErrors++
  208. #define END_M2_INDISCARDS(pEnd) (pEnd)->mib2Tbl.ifInDiscards++
  209. #define END_M2_INOCTETS(pEnd,bytes) (pEnd)->mib2Tbl.ifInOctets += bytes
  210. #define END_M2_OUTUCAST(pEnd) (pEnd)->mib2Tbl.ifOutUcastPkts++
  211. #define END_M2_OUTNUCAST(pEnd) (pEnd)->mib2Tbl.ifOutNUcastPkts++
  212. #define END_M2_OUTDISCARDS(pEnd) (pEnd)->mib2Tbl.ifOutDiscards++
  213. #define END_M2_OUTERRORS(pEnd) (pEnd)->mib2Tbl.ifOutErrors++
  214. #define END_M2_OUTOCTETS(pEnd,bytes) (pEnd)->mib2Tbl.ifOutOctets += bytes
  215. /* Struc to keep track of frag free routine: used in the driver struct below */
  216. typedef struct free_routine     
  217.     {
  218.     FUNCPTR pfreeRtn;                     /* Free routine for the */
  219.                            /* frag buffer */
  220.     void* pSpare1;                       /* Spare agurment */
  221.     void* pSpare2;                       /* Spare agurment */
  222.     }FREE_ROUTINE;            
  223. /* Driver control structure.  One per unit supported. */
  224. typedef struct drv_ctrl
  225.     {
  226.     END_OBJ endData;      /* Enhance network driver  */
  227.          /* structure */
  228.     SONIC* pDev;                             /* ptr to the device registers */
  229.     int   unit;      /* unit # of the device */
  230.     int   ivec;      /* interrupt vectore */
  231.     char* pMem;                              /* ptr to allocated chunk */
  232.     char* pShMem;                            /* ptr to area shared with  */
  233.                                              /* device */
  234.     unsigned long shMemSize;                 /* size of the shared area */
  235.     unsigned long RSA;                       /* Start of Resource Area */
  236.     unsigned long REA;                       /* End of Resource Area */
  237.     unsigned long RBA1;                      /* Start of Receive Buffer Area */
  238.     unsigned long RBA2;                      /* Start of Receive Buffer Area */
  239.     unsigned long RBA3;                      /* Start of Receive Buffer Area */
  240.     unsigned long RBA4;                      /* Start of Receive Buffer Area */
  241.     unsigned long RDA;                       /* Start of Receive Desc Area */
  242.     unsigned long CDA;                       /* Start of CAM Desc Area */
  243.     TX_DESC* pTDA;                           /* Start of Transmit Desc Area */
  244.     TX_DESC* pTXDFree;                       /* ptr to next free TXD */
  245.     TX_DESC* pTXDReclaim;                    /* ptr to next reclaimable TXD */
  246.     TX_DESC* pTXDLast;      /* ptr to last transmitted TXD */
  247.     BOOL     txBlocked;                      /* transmit flow control */
  248.     RX_DESC* pRXDNext;                       /* Next Receive descriptor */
  249.     RX_DESC* pRXDLast;                       /* Last one in link */
  250.     u_long* pCamEnableMask;      /* Pointer to CAM enable */
  251.                                              /* mask entry */
  252.     u_char  mcastTable[MAX_MCASTS * 6];      /* Our own mcast table */
  253.     FUNCPTR timerIntHandler;                 /* Interrupt timer handler */
  254.     int  ticks;                              /* number of interrupts */
  255.      /* generated per sec */
  256.     unsigned int imr;      /* Record of interrupt mask */
  257.     BOOL online;      /* Denotes device is */
  258.                                              /* online (started)*/
  259.     u_char flags;      /* Local Flags */
  260.     UCHAR enetAddr[6];      /* ethernet address */
  261.     FREE_ROUTINE freeBuf[NUM_TX_DESC];       /* per Tx descriptor */
  262.     CL_POOL_ID pClPoolId[NUM_CLUSTER_POOLS]; /* array of cluster pools each */
  263.              /* of different size */
  264.     } DRV_CTRL;
  265. /*network buffer configuration */
  266. M_CL_CONFIG SnMclConfig =              /*mBlk configuration table */
  267.     {
  268.     0, 0, NULL, 0
  269.     };
  270. /*network cluster pool configuration */
  271. CL_DESC SnClDescTbl []= 
  272.     {
  273.     /*
  274.     ClusterSize                num memArea memsize
  275.     -----------                ---      ------- -------
  276.     */
  277.     { OPTIMAL_CLUSTER_SIZE, 0, NULL,   0  },
  278.     { MTU_CLUSTER_SIZE,         0,      NULL,     0  }
  279.     };
  280. /*Number of cluster pools */
  281. int SnClDescTblNumEnt = (NELEMENTS(SnClDescTbl));
  282. /* Initialization Parameters within InitString */
  283. typedef struct 
  284.     {
  285.     int     unit;
  286.     int     ivec;
  287.     u_long  devaddr;
  288.     } INIT_PARM;
  289. /* GLOBALS */
  290. unsigned long snEndDcr = WAIT0 | DW_32 | LBR;
  291. unsigned long snEndDcr2 = 0;
  292. /* External function prototypes not defined in any header files.
  293.  * Some of these are the functions required of the BSP modules.
  294.  */
  295. IMPORT STATUS sysEnetAddrGet ();
  296. IMPORT STATUS sysEnetInit ();
  297. IMPORT STATUS sysEnetIntEnable ();
  298. IMPORT STATUS sysEnetIntDisable ();
  299. IMPORT STATUS sysEnetIntAck ();
  300. #if defined(LED_DEBUG) || defined(DEBUG)
  301. #undef  LOCAL
  302. #define LOCAL 
  303. #endif
  304. /* END EXTERNAL INTERFACE ROUTINES */
  305. END_OBJ*      sn83932EndLoad (char* initString);
  306. /* REQUIRED END ENTRY POINTS */
  307. LOCAL STATUS sn83932Start  (DRV_CTRL *);
  308. LOCAL STATUS sn83932Stop  (DRV_CTRL *);
  309. LOCAL STATUS sn83932Unload  (DRV_CTRL *);
  310. LOCAL int sn83932Ioctl  (DRV_CTRL *, int, caddr_t);
  311. LOCAL STATUS sn83932Send  (DRV_CTRL *, M_BLK_ID pBuf);
  312. LOCAL STATUS sn83932MCastAddrAdd  (DRV_CTRL *, char*);
  313. LOCAL STATUS sn83932MCastAddrDel  (DRV_CTRL *, char*);
  314. LOCAL STATUS sn83932MCastAddrGet  (DRV_CTRL *, MULTI_TABLE*);
  315. LOCAL STATUS sn83932PollSend  (DRV_CTRL *, M_BLK_ID pBuf);
  316. LOCAL STATUS sn83932PollRecv  (DRV_CTRL *, M_BLK_ID pBuf);
  317. /* Interrupt Handler */
  318. LOCAL void sn83932Int (DRV_CTRL *);
  319. /* INTERNAL ROUTINES */
  320. LOCAL STATUS snInitParse  (INIT_PARM *, char *);
  321. LOCAL STATUS snInitMem  (DRV_CTRL *);
  322. LOCAL void snChipReset (DRV_CTRL *);
  323. LOCAL void snChipInit (DRV_CTRL *);
  324. LOCAL void snChipStart (DRV_CTRL *);
  325. LOCAL void snCamMacLoad (DRV_CTRL *);
  326. LOCAL void snCamMcastLoad (DRV_CTRL *);
  327. LOCAL void snPollStart (DRV_CTRL *);
  328. LOCAL void snPollStop (DRV_CTRL *);
  329. LOCAL void snIfConfig (DRV_CTRL *, int);
  330. LOCAL void snTxReclaim (DRV_CTRL *, int);
  331. LOCAL int snProcessRxPkts (DRV_CTRL *, int, M_BLK_ID pBuf);
  332. LOCAL void snEventHandler (DRV_CTRL *);
  333. /* SONIC Clock TIMER ENTRY POINTS */
  334. void  snEndClkEnable (int, int, FUNCPTR);
  335. void  snEndClkDisable (int);
  336. /*
  337.  * Declare our function table.  This is static across all driver
  338.  * instances.
  339.  */
  340. LOCAL NET_FUNCS snFuncTable =
  341.     {
  342.     (FUNCPTR)sn83932Start, /* Function to start the device. */
  343.     (FUNCPTR)sn83932Stop, /* Function to stop the device. */
  344.     (FUNCPTR)sn83932Unload, /* Unloading function for the driver. */
  345.     (FUNCPTR)sn83932Ioctl, /* Ioctl function for the driver. */
  346.     (FUNCPTR)sn83932Send, /* Send function for the driver. */
  347.     (FUNCPTR)sn83932MCastAddrAdd,/* Multicast address add function */
  348.     (FUNCPTR)sn83932MCastAddrDel,/* Multicast address delete function. */
  349.     (FUNCPTR)sn83932MCastAddrGet,/* Multicast table retrieve function. */
  350.     (FUNCPTR)sn83932PollSend, /* Polling send function. */
  351.     (FUNCPTR)sn83932PollRecv, /* Polling receive function. */
  352.     endEtherAddressForm,        /* Put address info into a NET_BUFFER */
  353.     endEtherPacketDataGet,      /* Get pointer to data in NET_BUFFER. */
  354.     endEtherPacketAddrGet
  355.     };
  356. /* SECTION: Initialization and Start-Up Routines */
  357. /*******************************************************************************
  358. *
  359. * sn83932EndLoad - initialize the driver and device
  360. *
  361. * This routine initializes the driver and the device to the operational state.
  362. * All of the device specific parameters are passed in the <initString> 
  363. * parameter.  This string must be of the format:
  364. *
  365. *     <unit_number>:<device_reg_addr>:<ivec>
  366. *
  367. * These parameters are all individually described in the sn83932End man
  368. * page.
  369. *
  370. * RETURNS: An END object pointer or NULL on error.
  371. */
  372. END_OBJ * sn83932EndLoad
  373.     (
  374.     char * initString /* String to be parse by the driver. */
  375.     )
  376.     {
  377.     INIT_PARM initParm;
  378.     DRV_CTRL * pDrvCtrl;
  379. #ifdef DEBUG
  380.     SN_LOGMSG ("sn83932End Loading...n", 0,0,0,0,0,0);
  381. #endif 
  382.     /* Parse the initString Parameters */
  383.     if (initString == NULL)
  384.         return(NULL);
  385.     if (initString[0] == 0)
  386.         {
  387.         bcopy ((char *)SN_DEV_NAME, initString, SN_DEV_NAME_LEN);
  388.         return (0);
  389.         }
  390.     if (snInitParse (&initParm, initString) == ERROR)
  391. return NULL; 
  392.     /* Sanity check the unit number */
  393.     if (initParm.unit < 0 || initParm.unit >= MAX_UNITS)
  394.         return NULL;
  395.     /* allocate the device structure */
  396.     pDrvCtrl = (DRV_CTRL *)calloc (sizeof(DRV_CTRL), 1);
  397.     if (pDrvCtrl == NULL)
  398.         return (NULL);
  399.     if (pDrvCtrl->endData.attached == TRUE)
  400.         return (&pDrvCtrl->endData);
  401.     /* save the inputted parameters */
  402.     pDrvCtrl->unit = initParm.unit;
  403.     pDrvCtrl->ivec = initParm.ivec;
  404.     pDrvCtrl->pDev = (SONIC *) initParm.devaddr;
  405.     /* Initialize the default interrupt mask configuration in control block */
  406.     pDrvCtrl->imr = SN_IMR_INIT;
  407.     /* EndData Initialization */
  408.     if (END_OBJ_INIT (&pDrvCtrl->endData, (DEV_OBJ *)pDrvCtrl, "sn",
  409.                       pDrvCtrl->unit, &snFuncTable,
  410.                       "Sonic 83932 Enhanced Network Driver") == ERROR)
  411.       
  412.          return (NULL);
  413.     /* get an Ethernet addr from BSP and intialize the MIB2 */
  414.     if (sysEnetAddrGet (initParm.unit, pDrvCtrl->enetAddr) == ERROR)
  415.         return (NULL);
  416.     if (END_MIB_INIT (&pDrvCtrl->endData, M2_ifType_ethernet_csmacd,
  417.       (UCHAR *)pDrvCtrl->enetAddr,6,ETHERMTU, SN_SPEED) 
  418.       == ERROR)
  419. return (NULL);
  420.     /* Allocate, initialize and set up shared memory region */
  421.     if (snInitMem (pDrvCtrl) == ERROR)
  422. return (NULL);
  423.     /***** Perform device initialization *****/
  424.     snChipReset (pDrvCtrl);                 /* reset device */
  425.     sysEnetInit (pDrvCtrl->unit);           /* do any board specific set up */
  426.     sysEnetIntDisable (pDrvCtrl->unit);     /* board specific int disable */
  427.     snChipInit (pDrvCtrl);     /* init the device */
  428.     /* Set flags */
  429.     END_OBJ_READY (&pDrvCtrl->endData,
  430.    (IFF_NOTRAILERS | IFF_MULTICAST | IFF_BROADCAST));
  431.     return (&pDrvCtrl->endData);
  432.     }
  433. /*******************************************************************************
  434. *
  435. * snInitParse - parse parameter values from initString according to the
  436. * following format:
  437. *
  438. *    int    unit,       * unit number *
  439. *    char * pDevRegs,   * addr of device's regs *
  440. *    int    ivec        * vector number *
  441. *
  442. *
  443. * RETURNS: OK or ERROR
  444. */
  445. LOCAL STATUS snInitParse
  446.     (
  447.     INIT_PARM * pParms,      /* pointer contains the data in the initstring */
  448.     char *      pinitString
  449.     )
  450.     {
  451.     char * ptok; /* token for the initString */
  452.     char * pHolder=NULL;           /* temp string holder */
  453.     ptok = strtok_r(pinitString, ":", &pHolder);
  454.     if (ptok == NULL)
  455.         return ERROR;
  456.     pParms->unit = atoi(ptok);
  457.     ptok=strtok_r(NULL, ":", &pHolder);
  458.     if (ptok == NULL)
  459.         return ERROR; 
  460.     pParms->devaddr = strtoul (ptok, NULL, 16);
  461.     ptok=strtok_r(NULL, ":", &pHolder);
  462.     if (ptok == NULL)
  463.         return ERROR;
  464.     pParms->ivec = atoi (ptok);
  465.     
  466.     return OK;
  467.     }
  468. /*******************************************************************************
  469. *
  470. * sn83932Start - start the device
  471. *
  472. * This function connects interrupt, calls BSP to enable them,  and starts the
  473. * device running in interrupt mode.
  474. *
  475. * RETURNS: OK or ERROR
  476. * NOMANUAL
  477. */
  478. LOCAL STATUS sn83932Start
  479.     (
  480.     DRV_CTRL * pDrvCtrl
  481.     )
  482.     {
  483. #ifdef DEBUG
  484.     SN_LOGMSG ("sn83932Start...n",0,0,0,0,0,0);
  485. #endif
  486.     /* Sanity Check */
  487.     if (pDrvCtrl == NULL)
  488. return EINVAL;
  489.     if (pDrvCtrl->online)
  490. return OK;
  491.     /* Connect the interrupt vector */
  492.     if (intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC(pDrvCtrl->ivec),
  493.        sn83932Int, (int)pDrvCtrl) != OK)
  494. return ERROR;
  495.     /* Enable device interrupts at system level */
  496.     sysEnetIntEnable (pDrvCtrl->unit);
  497.     /* Initialize the physical address in the CAM */
  498.     snCamMacLoad (pDrvCtrl);
  499.     /* Bring up the device */
  500.     snChipStart (pDrvCtrl);
  501.     /* Denote it as online */
  502.     pDrvCtrl->online = TRUE;
  503.     /* mark the interface as up */
  504.     END_FLAGS_SET (&pDrvCtrl->endData, (IFF_UP | IFF_RUNNING));
  505. #ifdef DEBUG
  506.     SN_LOGMSG ("end of sn83932Start...n",0,0,0,0,0,0);
  507. #endif
  508.     return (OK);
  509.     } /* End of sn83932Start() */
  510. /*******************************************************************************
  511. *
  512. * sn83932Stop - Stop the device
  513. *
  514. * This routine disables interrupts and resets the device.
  515. *
  516. * RETURNS: OK or ERROR
  517. * NOMANUAL
  518. */
  519. LOCAL STATUS sn83932Stop
  520.     (
  521.     DRV_CTRL * pDrvCtrl
  522.     )
  523.     {
  524.     /* Sanity Check */
  525.     if (pDrvCtrl == NULL)
  526. return EINVAL;
  527.     sysEnetIntDisable (pDrvCtrl->unit);         /* board specific int */
  528. /* disable */
  529.     pDrvCtrl->pDev->imr = 0;                 /* Turn off interrupts */
  530.     pDrvCtrl->online = FALSE; /* denote unit as offline */
  531.     /* mark the interface as down */
  532.     END_FLAGS_CLR (&pDrvCtrl->endData, (IFF_UP | IFF_RUNNING));
  533.     return OK;
  534.     }
  535. /*******************************************************************************
  536. *
  537. * sn83932Unload - unload the device by freeing any allocated memory and
  538. *           releasing the EndData objects from the MUX.
  539. *
  540. *
  541. * RETURNS:  OK or ERROR
  542. * NOMANUAL
  543. *
  544. */
  545. LOCAL STATUS sn83932Unload
  546.     (
  547.     DRV_CTRL *pDrvCtrl
  548.     )
  549.     {
  550.     /* Sanity Check */
  551.     if (pDrvCtrl == NULL)
  552. return EINVAL;
  553.     if (pDrvCtrl->endData.attached == TRUE)
  554.         {
  555. /* Stop the device if still on line */
  556. if (pDrvCtrl->online)
  557.     sn83932Stop (pDrvCtrl);
  558.         /* Reset the Chip to pre-empt any further action */
  559. snChipReset (pDrvCtrl);
  560.         /* release EndData objects */
  561.         END_OBJECT_UNLOAD (&pDrvCtrl->endData);
  562.         /* Free up malloc'd memory */
  563.         cacheDmaFree (pDrvCtrl->pMem);
  564. /* Denote device as detached */
  565. pDrvCtrl->endData.attached = FALSE;
  566. }
  567.     return OK;
  568.     }
  569. /******************************************************************************
  570. *
  571. * snInitMem - establish shared memory region for sonic chip
  572. *
  573. * The driver and the device share areas of memory.  Each area has a
  574. * specific use.  The device imposes a nasty restriction, in that
  575. * an area's bounds must lie in the same 64k page.  The entire amount of
  576. * shared memory that is needed is much less than 64k.  Therefore, we
  577. * will group all the individual areas into one area, and attempt to
  578. * ensure that this total area lies in a single 64k page.
  579. *
  580. * We must also consider data cache coherency of this shared memory.
  581. * We therefore use the special system functions that allow us to
  582. * obtain cache-safe memory, or at least allow us to maintain the
  583. * coherency of this memory ourselves.
  584. *
  585. * RETURNS: OK or ERROR.
  586. */
  587. LOCAL STATUS snInitMem
  588.     (
  589.     DRV_CTRL * pDrvCtrl
  590.     )
  591.     {
  592.     int cnt;
  593.     u_long temp; /* Temporary address holder */
  594.     char *pCur; /* Block local variable */
  595.     CAM_DESC * pCam; /* CAM working descriptor */
  596.     TX_DESC * pTXD;
  597.     RX_DESC * pRXD;                              /* Rx working descriptor */
  598.     RRA_DESC * pRRAD;                            /* RRA working descriptor */
  599.     /* The first step is to calculate the size of this shared region. */ 
  600.     pDrvCtrl->shMemSize =
  601.                     CAM_SIZE +      /* the area used for Ethernet addrs   */
  602.                     RRA_SIZE +      /* the area that describes Rx buffers */
  603.                     RDA_SIZE +      /* the area that holds Rx descriptors */
  604.                     TDA_SIZE +      /* the area that holds Tx descriptors */
  605.                     RBA_SIZE;       /* the area that holds all Rx buffers */
  606.     /*
  607.      * That was easy.  Now we request some memory from the system.
  608.      * For now, we are taking a simple approach.  We simply request one
  609.      * big region, large enough to ensure that we can position our shared
  610.      * area in a single 64k page.  This approach will waste memory, but
  611.      * blame the board designers who picked the SONIC without realizing
  612.      * that the device has this weird restriction.
  613.      */
  614.     if (!CACHE_DMA_IS_WRITE_COHERENT ())
  615.         return (ERROR);
  616.     pDrvCtrl->pMem = cacheDmaMalloc (pDrvCtrl->shMemSize + 0x00010000);
  617.     if (pDrvCtrl->pMem == NULL)                 /* no memory, so abort */
  618.         return (ERROR);
  619.     /*
  620.      * Find start of 64k page in the region.  This becomes start of our
  621.      * region.
  622.      */
  623.     pDrvCtrl->pShMem = (char *)
  624.                        (((u_long)pDrvCtrl->pMem & 0xffff0000) + 0x00010000);
  625.     /***** Carve up the shared area into specific areas *****/
  626.     pCur = pDrvCtrl->pShMem;                /* start of shared area */
  627.     pDrvCtrl->CDA = (u_long) pCur;          /* CAM area */
  628.     pCur += CAM_SIZE;                       /* advance the pointer */
  629.     pDrvCtrl->RSA = (u_long) pCur;          /* receive resource table */
  630.     pCur += RRA_SIZE;                       /* advance the pointer */
  631.     pDrvCtrl->REA = (u_long) pCur;          /* save end pointer */
  632.     pDrvCtrl->RDA = (u_long) pCur;          /* receive descriptor area */
  633.     pCur += RDA_SIZE;                       /* advance the pointer */
  634.     pDrvCtrl->pTDA = (TX_DESC *)pCur;       /* transmit descriptor area */
  635.     pCur += TDA_SIZE;                       /* advance the pointer */
  636.     pDrvCtrl->RBA1 = (u_long) pCur;         /* Receive Buffer 1 */
  637.     pCur += RX_BUF_SIZE + RX_BUF_EXTRA;     /* advance the pointer */
  638.     pDrvCtrl->RBA2 = (u_long) pCur;         /* Receive Buffer 2 */
  639.     pCur += RX_BUF_SIZE + RX_BUF_EXTRA;     /* advance the pointer */
  640.     pDrvCtrl->RBA3 = (u_long) pCur;         /* Receive Buffer 3 */
  641.     pCur += RX_BUF_SIZE + RX_BUF_EXTRA;     /* advance the pointer */
  642.     pDrvCtrl->RBA4 = (u_long) pCur;         /* Receive Buffer 4 */
  643.     /* Init the CAM Descriptors to all broadcasts */
  644.     pCam = (CAM_DESC *)pDrvCtrl->CDA;
  645.     /* Program the descriptor entry for each CAM register */
  646.     for (cnt = 0; cnt < CAM_COUNT; cnt++, pCam++)
  647. {
  648.      pCam->cep  = cnt; 
  649.      pCam->cap0 = 0xffff;
  650.      pCam->cap1 = 0xffff;
  651.      pCam->cap2 = 0xffff;
  652. }
  653.     pDrvCtrl->pCamEnableMask = (u_long *)pCam;
  654.     *pDrvCtrl->pCamEnableMask = 0; /* All Addresses Disabled */
  655.     /*** init the Tx descriptors ***/
  656.     pTXD = pDrvCtrl->pTDA;                      /* get initial ptr */
  657.     bzero ((char *)pTXD, TDA_SIZE);             /* zero the whole enchilada */
  658.     for (cnt = 0; cnt < NUM_TX_DESC; cnt++)     /* loop thru each */
  659.         {
  660. pTXD->number = cnt;
  661.         pTXD->pLink = pTXD + 1;                 /* link to next */
  662.         pTXD++;                                 /* bump to next */
  663.         }
  664.     /*
  665.      * The link field of the last desc is special; it needs to point
  666.      * back to the first desc.  So, we fix it here.
  667.      */
  668.     (--pTXD)->pLink = pDrvCtrl->pTDA;
  669.     pDrvCtrl->pTXDFree = pDrvCtrl->pTDA;              /* initial value */
  670.     pDrvCtrl->pTXDReclaim = pDrvCtrl->pTDA;           /* initial value */
  671.     pDrvCtrl->pTXDLast = pDrvCtrl->pTDA;              /* initial value */
  672.     /*** init the Rx buffer descriptors ***/
  673.     /* Build the RRA */
  674.     pRRAD = (RRA_DESC *)pDrvCtrl->RSA;           /* get ptr to first entry */
  675.     /* Stuff buffer ptr; least significant 16 bits, then most significant 16 */
  676.     temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RBA1);
  677.     pRRAD->buff_ptr0 = temp & UMASK;
  678.     pRRAD->buff_ptr1 = temp >> 16;
  679.     /* Stuff word count; least significant 16 bits, then most significant 16 */
  680.     pRRAD->buff_wc0 = (RX_BUF_SIZE >> 1) & UMASK;
  681.     pRRAD->buff_wc1 = (RX_BUF_SIZE >> 1) >> 16;
  682.     pRRAD++;                                    /* bump to next entry */
  683.     /* Stuff buffer ptr; least significant 16 bits, then most significant 16 */
  684.     temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RBA2);
  685.     pRRAD->buff_ptr0 = (u_long) temp & UMASK;
  686.     pRRAD->buff_ptr1 = (u_long) temp >> 16;
  687.     /* Stuff word count; least significant 16 bits, then most significant 16 */
  688.     pRRAD->buff_wc0 = RX_BUF_SIZE >> 1 & UMASK;
  689.     pRRAD->buff_wc1 = RX_BUF_SIZE >> 1 >> 16;
  690.     pRRAD++;                                    /* bump to next entry */
  691.     /* Stuff buffer ptr; least significant 16 bits, then most significant 16 */
  692.     temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RBA3);
  693.     pRRAD->buff_ptr0 = (u_long) temp & UMASK;
  694.     pRRAD->buff_ptr1 = (u_long) temp >> 16;
  695.     /* Stuff word count; least significant 16 bits, then most significant 16 */
  696.     pRRAD->buff_wc0 = RX_BUF_SIZE >> 1 & UMASK;
  697.     pRRAD->buff_wc1 = RX_BUF_SIZE >> 1 >> 16;
  698.     pRRAD++;                                    /* bump to next entry */
  699.     /* Stuff buffer ptr; least significant 16 bits, then most significant 16 */
  700.     temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RBA4);
  701.     pRRAD->buff_ptr0 = (u_long) temp & UMASK;
  702.     pRRAD->buff_ptr1 = (u_long) temp >> 16;
  703.     /* Stuff word count; least significant 16 bits, then most significant 16 */
  704.     pRRAD->buff_wc0 = RX_BUF_SIZE >> 1 & UMASK;
  705.     pRRAD->buff_wc1 = RX_BUF_SIZE >> 1 >> 16;
  706.     /* Setup the Rx frame descriptors */
  707.     pRXD = (RX_DESC *) pDrvCtrl->RDA;           /* get initial ptr */
  708.     bzero ((char *)pRXD, RDA_SIZE);             /* zero the whole tomato */
  709.     pDrvCtrl->pRXDNext = pRXD;                  /* start from the start! */
  710.     pDrvCtrl->pRXDLast =                        /* stuff ptr to last */
  711.                     (RX_DESC *) ((u_long)pRXD + RDA_SIZE - RX_DESC_SIZ);
  712.     while (pRXD <= pDrvCtrl->pRXDLast)          /* loop thru each */
  713.         {
  714.         pRXD->in_use = IN_USE;                  /* set IN_USE by device */
  715.         pRXD->link =                            /* set link */
  716.             (RX_DESC *) CACHE_DMA_VIRT_TO_PHYS (pRXD + 1);
  717.         pRXD++;                                 /* bump to next */
  718.         }
  719.     /*
  720.      * The link field of the last desc is special; it points nowhere,
  721.      * but must mark the end-of-list.  So, we fix it here.
  722.      */
  723.     pDrvCtrl->pRXDLast->link = RX_EOL;
  724.     /* memory allocation for NetPool */
  725.     if((pDrvCtrl->endData.pNetPool = malloc (sizeof(NET_POOL))) == NULL)
  726.         return (ERROR);
  727.     /* number of clusters in each cluster pool */
  728.     SnClDescTbl[0].clNum = NUM_OPTIMAL_CLUSTER;
  729.     SnClDescTbl[1].clNum = NUM_MTU_CLUSTER;
  730.     /* number of cluster blocks */
  731.     SnMclConfig.clBlkNum = NUM_CL_BLK;
  732.     /* number of mblks */
  733.     SnMclConfig.mBlkNum = NUM_MBLK;
  734.     /* memory requirement for cluster blks and mblks */
  735.     SnMclConfig.memSize = ((SnMclConfig.mBlkNum * (MSIZE + sizeof (long)))
  736.                            + (SnMclConfig.clBlkNum * (CL_BLK_SZ  + 
  737.    sizeof (long))));
  738.     if ((SnMclConfig.memArea = (char *) memalign (sizeof(long),
  739.                                 SnMclConfig.memSize)) == NULL)
  740.         return (ERROR);
  741.     /* memory requirement for cluster pools */
  742.     SnClDescTbl[0].memSize =((SnClDescTbl[0].clNum * 
  743.                              (OPTIMAL_CLUSTER_SIZE +8))+ sizeof(int));
  744.     SnClDescTbl[1].memSize =((SnClDescTbl[1].clNum * (MTU_CLUSTER_SIZE +8))
  745.                              + sizeof(int)); 
  746.     if((SnClDescTbl[0].memArea =(char *) memalign (sizeof(long),
  747.                                  SnClDescTbl[0].memSize))==NULL) 
  748.         return(ERROR); 
  749.     if((SnClDescTbl[1].memArea = (char *) memalign (sizeof(long),
  750.                                  SnClDescTbl[1].memSize))==NULL) 
  751.         return(ERROR); 
  752.     if (netPoolInit(pDrvCtrl->endData.pNetPool, &SnMclConfig,
  753.                     &SnClDescTbl[0],SnClDescTblNumEnt, NULL) == ERROR) 
  754.         {
  755. #ifdef DEBUG
  756.     SN_LOGMSG("could not init bufferingn",0,0,0,0,0,0);
  757. #endif
  758.         return(ERROR);
  759.         }
  760.     /*
  761.      * obtain the poolId for each cluster pool, needed when obtaining *
  762.      * a cluster 
  763.      */
  764.     pDrvCtrl->pClPoolId[0] = clPoolIdGet(pDrvCtrl->endData.pNetPool,
  765.                                          OPTIMAL_CLUSTER_SIZE,FALSE);
  766.     pDrvCtrl->pClPoolId[1] = clPoolIdGet(pDrvCtrl->endData.pNetPool,
  767.                                          MTU_CLUSTER_SIZE,FALSE);
  768. #ifdef DEBUG
  769.     SN_LOGMSG("init mem okn",0,0,0,0,0,0);
  770. #endif
  771.     
  772.     return OK;
  773.     } 
  774. /*======================================================================*
  775.  * D E V I C E   C O N T R O L   R O U T I N E S
  776.  *======================================================================*/
  777. /*******************************************************************************
  778. *
  779. * snChipReset - Place chip in Reset mode
  780. */
  781. LOCAL void snChipReset
  782.     (
  783.     DRV_CTRL * pDrvCtrl
  784.     )
  785.     {
  786.     pDrvCtrl->pDev->cr = RST;
  787.     pDrvCtrl->pDev->rsc = 0;  /* set the sequence counter to zero */
  788.     }
  789. /*******************************************************************************
  790. *
  791. * snChipInit -  Initialize the device registers
  792. *
  793. * Returns: N/A
  794. *
  795. */
  796. LOCAL void snChipInit 
  797.     (
  798.     DRV_CTRL * pDrvCtrl
  799.     )
  800.     {
  801.     SONIC * pDev;                       /* ptr to the device regs */
  802.     u_long temp; /* holder of physical addresses */
  803.     pDrvCtrl->txBlocked = FALSE;
  804.     pDev = pDrvCtrl->pDev;
  805.     pDev->cr = RST;                     /* Turn ON RESET */
  806.                                         /* Data Control */
  807.     pDev->dcr = snEndDcr;
  808.     if (snEndDcr2)
  809. pDev->dcr2 = snEndDcr2;
  810.     pDev->imr = 0;                      /* All Interrupts off */
  811.     pDev->isr = 0x7fff;                 /* Clear ISR */
  812.     temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RSA);
  813.     pDev->urra = temp >> 16;            /* Upper RSA */
  814.     pDev->rsa = temp & UMASK;           /* Lower RSA */
  815.     temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->REA);
  816.     pDev->rea = temp & UMASK;           /* Lower REA */
  817.     temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RSA);
  818.     pDev->rrp = temp & UMASK;           /* point to first desc */
  819.     pDev->rwp = temp & UMASK;           /* point to first desc */
  820.     pDev->rsc = 0;
  821.     temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RDA);
  822.     pDev->urda = temp >> 16;            /* Upper RDA */
  823.     pDev->crda = temp & UMASK;          /* Lower RDA */
  824.     temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->pTDA);
  825.     pDev->utda = temp >> 16;            /* first TXD */
  826.     pDev->ctda = temp & UMASK;
  827.     pDev->cr = RST_OFF;                 /* Turn OFF RESET */
  828.     pDev->cr = RRRA;                    /* prime with RRA read */
  829.     pDev->rcr = BRD; /* Accept broadcasts */
  830. /* Multicasts (up to 15) are  *
  831.  * programmed directly into the *
  832.  * CAM registers. *
  833.  */
  834.     }
  835. /*******************************************************************************
  836. *
  837. * snChipStart - hardware startup  of chip - sets up interupt masks and turns
  838. * on the receiver. 
  839. *
  840. * RETURNS N/A
  841. *
  842. */
  843. LOCAL void snChipStart 
  844.     (
  845.     DRV_CTRL * pDrvCtrl
  846.     )
  847.     {
  848.     SONIC *pDev;                        /* ptr to the device regs */
  849.     /* Point to device registers */
  850.     pDev = pDrvCtrl->pDev;
  851.     /* Enable transmit, receive, transmit error, & receive buffer exhaustion */
  852.     /*SL* RDE cannot occur since there is space for 512 64 byte packets */
  853.     /* Enable appropriate interrupts (those configured to be enabled) */
  854.     pDev->imr = (pDrvCtrl->imr & SN_IMR_INIT);
  855.     /* Turn on receiver */
  856.     pDev->cr = RXEN; 
  857.     }
  858. /*******************************************************************************
  859. *
  860. * snCamMacLoad - put the local Ethernet address in the CAM
  861. *
  862. * First we set up a data area with the enet addr, then we tell the device
  863. * where it is and command the device to read it.  When the device is done,
  864. * it will interrupt us.  We wait for this interrupt with a semaphore that
  865. * will be given by the interrupt handler.
  866. *
  867. * We now load all 16 CAM registers.  At initialization, all CAM descriptors
  868. * were programmed to be broadcasts.  However, none were enabled.  In this
  869. * routine, we program the hardware MAC address of the device unit.  The
  870. * first CAM entry is reserved for the physical address of the unit.
  871. * The remaining 15 are allotted to multicast addresses.  Nonewithstanding,
  872. * whenever we load the CAM, all 16 descriptors are loaded.
  873. *
  874. */
  875. LOCAL void snCamMacLoad
  876.     (
  877.     DRV_CTRL * pDrvCtrl
  878.     )
  879.     {
  880.      CAM_DESC * pCam;
  881.      SONIC * pDev;
  882.     /* Initialize pointers */
  883.     pDev = pDrvCtrl->pDev;
  884.     pCam = (CAM_DESC *)pDrvCtrl->CDA;
  885.     /* Turn off load-Cam isr indication if set */
  886.     if (pDev->isr & LCD)
  887. pDev->isr = LCD;
  888.     /* Program the descriptor entry for CAM register 0 */
  889.     pCam->cep  = 0; 
  890.     pCam->cap0 = (pDrvCtrl->enetAddr[1] << 8) | pDrvCtrl->enetAddr[0];
  891.     pCam->cap1 = (pDrvCtrl->enetAddr[3] << 8) | pDrvCtrl->enetAddr[2];
  892.     pCam->cap2 = (pDrvCtrl->enetAddr[5] << 8) | pDrvCtrl->enetAddr[4];
  893.     /* Enable the filtering for this address */
  894.     *pDrvCtrl->pCamEnableMask |= 1;
  895.     /* Set up Load registers */
  896.     pDev->cdp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pCam) & UMASK;
  897.     pDev->cdc = CAM_COUNT;                         /* Number of Entries */
  898.     pDev->cr = LCAM;                               /* issue "load CAM" cmd */
  899.     /*
  900.      * Wait for operation to complete since we can't do anything until
  901.      * the MAC address is registered.  A "dead time" loop here is deemed
  902.      * OK, since we are in initialization phase, and will only do this
  903.      * once.
  904.      */
  905.     while (!(pDev->isr & LCD))
  906.         ;
  907.     pDev->isr = LCD;                        /* clear the event flag */
  908.     }
  909. /*******************************************************************************
  910. *
  911. * snCamMcastLoad - Load all configured Multicast addresses in the CAM
  912. *
  913. * This routine differs from the previous one in that only the
  914. * entries that were set aside for multicast addresses are updated.
  915. *
  916. */
  917. LOCAL void snCamMcastLoad
  918.     (
  919.     DRV_CTRL * pDrvCtrl
  920.     )
  921.     {
  922.     MULTI_TABLE tmpTable;
  923.     CAM_DESC *pCam;
  924.     SONIC *pDev;
  925.     int num;
  926.     int intLevel;
  927.     pCam = (CAM_DESC *)pDrvCtrl->CDA;
  928.     pDev = pDrvCtrl->pDev;
  929.     /* Update our Multicast table */
  930.     tmpTable.pTable = (char *)pDrvCtrl->mcastTable;
  931.     tmpTable.len = sizeof (pDrvCtrl->mcastTable);
  932.     etherMultiGet (&pDrvCtrl->endData.multiList, &tmpTable);
  933.     /* Record the first multicast descriptor before we increment the pointer*/
  934.     pCam++;
  935.     pDev->cdp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pCam) & UMASK;
  936.     for (num = 1; num <= pDrvCtrl->endData.nMulti; num++, pCam++)
  937.      /* Program each descriptor entry for the appropriate CAM entry */
  938.      pCam->cep  = num; 
  939.      pCam->cap0 = (tmpTable.pTable[1] << 8) | tmpTable.pTable[0];
  940.      pCam->cap1 = (tmpTable.pTable[3] << 8) | tmpTable.pTable[2];
  941.      pCam->cap2 = (tmpTable.pTable[5] << 8) | tmpTable.pTable[4];
  942. /* Increment to next address */
  943. tmpTable.pTable += 6;
  944.         /* Enable the filtering for this address */
  945.         *pDrvCtrl->pCamEnableMask |= (1 << num);
  946. }
  947.         
  948.     /* Set up Load registers */
  949.     pDev->cdc = CAM_COUNT - 1;                     /* 15 MCAST entries */
  950.     /* Make sure the TXP bit is not set in the CR, wait if it is, then load CAM    */
  951.     intLevel = intLock();
  952.     while (pDev->cr & TXP)
  953. continue;
  954.     /* safe to issue "load CAM" cmd */
  955.     pDev->cr = LCAM;
  956.     intUnlock(intLevel);
  957.     /* Make sure load command has finished before continuing */
  958.     while (!(pDev->isr & LCD))
  959. continue;
  960.     /* Turn off LCD indication */
  961.     pDev->isr = LCD;
  962.     }
  963. /*============================================================================*
  964.  *  D R I V E R C O N T R O L     R O U T I N E S
  965.  *============================================================================*/
  966. /*******************************************************************************
  967. *
  968. * sn83932Ioctl - the driver I/O control function
  969. *
  970. * Process an ioctl request.
  971. * This is one of the routines that can be called from "outside" via
  972. * the interface structure.
  973. * Cannot be called before the attach, since DRV_CTRL ptr would be NULL.
  974. *
  975. *  Returns:   0 - successful
  976. * EINVAL - invalid argument(s)
  977. * NOMANUAL
  978. *
  979. */
  980. LOCAL int sn83932Ioctl
  981.     (
  982.      DRV_CTRL *pDrvCtrl, /* ptr to device control info */
  983.      int cmd, /* ioctl command */
  984.      caddr_t data /* argument data */
  985.     )
  986.     {
  987.      int value; /* Value of data when *
  988.  * passed-by-value *
  989.  */
  990.     /* Sanity Check */
  991.     if (pDrvCtrl == NULL)
  992. return EINVAL;
  993.     switch (cmd)
  994.         {
  995.         case EIOCSADDR:
  996.     /* Set physical address - only valid if device is off line */
  997.     /* Copy address into the MIB table as well */
  998.     /* New address takes affect after device is started */
  999. #ifdef DEBUG
  1000.     SN_LOGMSG ("Set Address...n",0,0,0,0,0,0);
  1001. #endif
  1002.          if (data == NULL)
  1003. return EINVAL;
  1004.     if (pDrvCtrl->online)
  1005. return EINVAL;
  1006.     /* Copy the address into the device control block */
  1007.     bcopy ((char *)data,
  1008.    (char *)pDrvCtrl->enetAddr,
  1009.    sizeof(pDrvCtrl->enetAddr)); 
  1010.     /* Copy the address to the MIB table */
  1011.          bcopy ((char *)data,
  1012.    (char *)pDrvCtrl->endData.mib2Tbl.ifPhysAddress.phyAddress,
  1013.    pDrvCtrl->endData.mib2Tbl.ifPhysAddress.addrLength);
  1014.     /* Program the new ethernet address */
  1015.     snCamMacLoad (pDrvCtrl);
  1016.             break;
  1017.         case EIOCGADDR:
  1018.     /* Copy address in device control area to user space */
  1019. #ifdef DEBUG
  1020.     SN_LOGMSG ("Get Address...n",0,0,0,0,0,0);
  1021. #endif
  1022.          if (data == NULL)
  1023. return EINVAL;
  1024.     bcopy ((char *)pDrvCtrl->enetAddr,
  1025.    (char *)data,
  1026.    sizeof (pDrvCtrl->enetAddr));
  1027.     break;
  1028. case EIOCSFLAGS:
  1029.     /* Set/Clear interface flags */
  1030. #ifdef DEBUG
  1031.     SN_LOGMSG ("Set Flags - %x...n",(int)data,0,0,0,0,0);
  1032. #endif
  1033.     value = (int)data;
  1034.     if (value < 0)
  1035. {/* Clear denoted flags */
  1036. value = -value;
  1037. value--;
  1038. pDrvCtrl->endData.flags &= ~value;
  1039. }
  1040.     else
  1041. /* Set flags */
  1042. pDrvCtrl->endData.flags |= value;
  1043.     snIfConfig (pDrvCtrl, value);
  1044.     break;
  1045. case EIOCGFLAGS:
  1046.     /* Get interface flags */
  1047. #ifdef DEBUG
  1048.     SN_LOGMSG ("Get Flags...n",0,0,0,0,0,0);
  1049. #endif
  1050.          if (data == NULL)
  1051. return EINVAL;
  1052.     *(int *)data = END_FLAGS_GET (&pDrvCtrl->endData);
  1053.     break;
  1054. case EIOCPOLLSTART:
  1055.     /* Put device in poll mode */
  1056.     snPollStart (pDrvCtrl);
  1057.     break;
  1058. case EIOCPOLLSTOP:
  1059.     /* Put device into interrupt mode */
  1060.     snPollStop (pDrvCtrl);
  1061.     break;
  1062. /*SL*/ case EIOCGMIB2:
  1063.     /* Get the MIB2 table */
  1064. #ifdef DEBUG
  1065.     SN_LOGMSG ("Get MIBS...n",0,0,0,0,0,0);
  1066. #endif
  1067.          if (data == NULL)
  1068. return EINVAL;
  1069.     bcopy ((char *)&pDrvCtrl->endData.mib2Tbl, (char *)data,
  1070.    sizeof (pDrvCtrl->endData.mib2Tbl));
  1071.     break;
  1072. case EIOCGFBUF:
  1073.     /* Get some minimum buf size of first buffer in scatter xmit */
  1074.     
  1075. #ifdef DEBUG
  1076.     SN_LOGMSG ("Get MIN_BUF_SIZE...n",0,0,0,0,0,0);
  1077. #endif
  1078.     if (data == NULL)
  1079. return EINVAL;
  1080.     *(int *)data = MIN_1STXMTBUF_SIZE;
  1081.     break;
  1082. default:
  1083. #ifdef DEBUG
  1084.     SN_LOGMSG ("Undefined Command - Returnn",
  1085.                0, 0, 0, 0, 0, 0);
  1086. #endif
  1087.     return EINVAL;
  1088.         }
  1089. #ifdef DEBUG
  1090.     SN_LOGMSG ("Donen", 0, 0, 0, 0, 0, 0);
  1091. #endif 
  1092.     return 0;
  1093.     }
  1094. /*******************************************************************************
  1095. *
  1096. * sn83932MCastAddrAdd - add a multicast address for the device
  1097. *
  1098. * This routine adds a multicast address to whatever the driver
  1099. * is already listening for.  
  1100. * NOMANUAL
  1101. *
  1102. */
  1103. LOCAL STATUS sn83932MCastAddrAdd
  1104.     (
  1105.     DRV_CTRL * pDrvCtrl,
  1106.     char * pAddr
  1107.     )
  1108.     {
  1109.     int retVal;
  1110.     
  1111.     /* Sanity Check */
  1112.     if (pDrvCtrl == NULL)
  1113. return EINVAL;
  1114. #ifdef DEBUG
  1115.     SN_LOGMSG  ("sn83932McastAddrAdd - %x:%x:%x:%x:%x:%xn",
  1116.                  pAddr[0], pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5]);
  1117. #endif
  1118.     if (pDrvCtrl->endData.nMulti == MAX_MCASTS)
  1119. return ERROR;
  1120.     retVal = etherMultiAdd (&pDrvCtrl->endData.multiList, pAddr);
  1121.     if (retVal == ENETRESET)
  1122.         {
  1123.         pDrvCtrl->endData.nMulti++;
  1124.         snCamMcastLoad (pDrvCtrl);
  1125. retVal = OK;
  1126.         }
  1127. #ifdef DEBUG
  1128.     SN_LOGMSG ("Mcast Donen", 0,0,0,0,0,0);
  1129. #endif 
  1130.     return ((retVal == OK) ? OK : ERROR);
  1131.     }
  1132. /*******************************************************************************
  1133. *
  1134. * sn83932MCastAddrDel - delete a multicast address for the device
  1135. *
  1136. * This routine deletes a multicast address from the current list of
  1137. * multicast addresses.
  1138. *
  1139. * NOMANUAL
  1140. */
  1141. LOCAL STATUS sn83932MCastAddrDel
  1142.     (
  1143.     DRV_CTRL * pDrvCtrl,
  1144.     char *  pAddr
  1145.     )
  1146.     {
  1147.     int retVal;
  1148.     
  1149.     /* Sanity Check */
  1150.     if (pDrvCtrl == NULL)
  1151. return EINVAL;
  1152. #ifdef DEBUG
  1153.     SN_LOGMSG ("sn83932astAddrDel%x:%x:%x:%x:%x:%xn",pAddr[0], 
  1154.        pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5]);
  1155. #endif
  1156.                   
  1157.     retVal = etherMultiDel (&pDrvCtrl->endData.multiList, pAddr);
  1158.     if (retVal == ENETRESET)
  1159.         {
  1160.         pDrvCtrl->endData.nMulti--;
  1161.         snCamMcastLoad (pDrvCtrl);
  1162. retVal = OK;
  1163.         }
  1164.     return ((retVal == OK) ? OK : ERROR);
  1165.     }
  1166. /*******************************************************************************
  1167. *
  1168. * sn83932MCastAddrGet - get the current multicast address list
  1169. *
  1170. * This routine returns the current multicast address list in <pTable>
  1171. *
  1172. * NOMANUAL
  1173. */
  1174. LOCAL STATUS sn83932MCastAddrGet
  1175.     (
  1176.     DRV_CTRL * pDrvCtrl,
  1177.     MULTI_TABLE * pTable
  1178.     )
  1179.     {
  1180.     
  1181.     /* Sanity Check */
  1182.     if (pDrvCtrl == NULL)
  1183. return EINVAL;
  1184. #ifdef DEBUG
  1185.     SN_LOGMSG ("sn83932astAddrGetn", 0, 0, 0, 0, 0, 0);
  1186. #endif
  1187.     return (etherMultiGet (&pDrvCtrl->endData.multiList, pTable));
  1188.     }
  1189. /*******************************************************************************
  1190. *
  1191. * snPollStart - Put the device into polling mode.  We first wait until any
  1192. *         outstanding interrupt requests are processed normally.
  1193. *
  1194. * RETURNS:  N/A
  1195. *
  1196. * NOMANUAL
  1197. */
  1198. LOCAL void snPollStart
  1199.     (
  1200.      DRV_CTRL * pDrvCtrl
  1201.     )
  1202.     {
  1203.     int intLevel;
  1204.     /* if offline, then only set flag */
  1205.     if (!pDrvCtrl->online)
  1206. {
  1207. pDrvCtrl->flags |= SN_POLLING;
  1208. return;
  1209. }
  1210.     if (pDrvCtrl->flags & SN_POLLING)
  1211. return;
  1212.     intLevel = intLock();
  1213.     pDrvCtrl->pDev->imr = 0;      /*SL* &= ~SN_IMR_DATA; */
  1214.     /* Mark device as polling */
  1215.     pDrvCtrl->flags |= SN_POLLING;
  1216.     intUnlock (intLevel);
  1217.     } 
  1218. /*******************************************************************************
  1219. *
  1220. * snPollStop - Put the device into interrupt mode.  This is the default mode 
  1221. * for the device.   Nothing is done if the device is not in polling mode. 
  1222. *
  1223. * RETURNS:  N/A
  1224. *
  1225. */
  1226. LOCAL void snPollStop
  1227.     (
  1228.      DRV_CTRL *pDrvCtrl
  1229.     )
  1230.     {
  1231.     int  intLevel;
  1232.     intLevel = intLock();
  1233.     /* Mark device as polling */
  1234.     pDrvCtrl->flags &= ~SN_POLLING;
  1235.     /* Mask in data interrupts */
  1236.     pDrvCtrl->pDev->imr = pDrvCtrl->imr;
  1237. #ifdef LED_DEBUG
  1238.     PutLED ('I', 0);
  1239. #endif
  1240.     intUnlock (intLevel);
  1241.     } 
  1242. /*******************************************************************************
  1243. *
  1244. * snIfConfig - Config the device according to allowable interface flag
  1245. * revisions by the application.  This is called from within the
  1246. * Ioctl call to register IF flag changes.
  1247. *
  1248. * RETURNS:  N/A
  1249. *
  1250. */
  1251. LOCAL void snIfConfig
  1252.     (
  1253.      DRV_CTRL * pDrvCtrl,
  1254.      int flags
  1255.     )
  1256.     {
  1257.     u_char *pDrvFlags; /* ptr to the device's local flags */
  1258.     pDrvFlags = &pDrvCtrl->flags;
  1259.     if (flags & IFF_PROMISC)
  1260. {
  1261. if (!(*pDrvFlags & SN_PROMISC))
  1262.     {/* Put device into promiscuous mode */
  1263.     pDrvCtrl->pDev->rcr |= PRO;
  1264.     *pDrvFlags |= IFF_PROMISC;
  1265.     }
  1266. }
  1267.     else
  1268. {
  1269. if (flags & SN_PROMISC)
  1270.     {/* Turn off promiscuous mode */
  1271.     pDrvCtrl->pDev->rcr &= ~PRO;
  1272.     *pDrvFlags &= ~IFF_PROMISC;
  1273.     }
  1274. }
  1275.     if (flags & IFF_ALLMULTI)
  1276. {
  1277. if (!(*pDrvFlags & SN_ALLMULTI))
  1278.     {/* Accept ALL multicast packets */
  1279.     pDrvCtrl->pDev->rcr |= AMC;
  1280.     *pDrvFlags |= SN_ALLMULTI;
  1281.     }
  1282. }
  1283.     else
  1284. {
  1285.      if (flags & SN_ALLMULTI)
  1286.     {/* Filter multicasts according to multicast entries */
  1287.     pDrvCtrl->pDev->rcr &= ~AMC;
  1288.     *pDrvFlags &= ~SN_ALLMULTI;
  1289.     }
  1290. }
  1291.     }
  1292. /*============================================================================*
  1293.  *  T R A N S M I T     R O U T I N E S
  1294.  *============================================================================*/
  1295. /*******************************************************************************
  1296. *
  1297. * sn83932Send - the driver send routine
  1298. *
  1299. * This routine takes a NET_BUFFER and sends off the data within the NET_BUFFER.
  1300. * The data must already have the addressing information properly installed
  1301. * in it.  This is done by a higher layer.  The last arguments are a free
  1302. * routine to be called when the device is done with the buffer and a pointer
  1303. * to the argument to pass to the free routine.  Supports NET_BUFFER chaining. 
  1304. *
  1305. * RETURNS: OK or ERROR.
  1306. * NOMANUAL
  1307. */
  1308. LOCAL STATUS sn83932Send
  1309.     (
  1310.     DRV_CTRL * pDrvCtrl,        /* device record ptr */
  1311.     M_BLK_ID pMblk                   /* data to be sent */
  1312.     )
  1313.     {
  1314.     TX_DESC * pTXD;                            /* Tx descriptor to be used */
  1315.     u_long addr;
  1316.     int totalLength = 0;                       /* keep track of total length
  1317. * of the mblk chain 
  1318. */
  1319.     M_BLK_ID pChunk;                           /* tmp mblk to travel 
  1320. * the chain 
  1321. */
  1322.     int count =0;                     
  1323.     BOOL No_Mblk =FALSE;                       /* set in case all the data 
  1324. * is contained in the first 
  1325. * mblk of a chain 
  1326. */
  1327.     BOOL Exceed = FALSE;                       /* set if num of mblks in a 
  1328. * chain exceed max fragments 
  1329. * a tx desc can habdle 
  1330. */
  1331.     char * pBuf = NULL;
  1332.     /* Sanity Check */
  1333.     if (pDrvCtrl == NULL)
  1334.         {
  1335.         netMblkClChainFree(pMblk); /* free the given mBlk chain */
  1336.         errno = EINVAL;
  1337.         return (ERROR);
  1338.         }
  1339. #ifdef LED_DEBUG
  1340.     PutLED ('x',2)
  1341. #endif
  1342.     /*
  1343.      * Obtain exclusive access to transmitter.  This is necessary because
  1344.      * we might have more than one stack transmitting at once.
  1345.      */
  1346.     END_TX_SEM_TAKE (&pDrvCtrl->endData, WAIT_FOREVER);
  1347.     if (pDrvCtrl->flags & SN_POLLING)
  1348.         {
  1349.         netMblkClChainFree(pMblk); /* free the given mBlk chain */
  1350.         errno = EINVAL;
  1351.         END_TX_SEM_GIVE (&pDrvCtrl->endData);
  1352.         return (ERROR);
  1353.         }
  1354.     if (pDrvCtrl->txBlocked)
  1355.         {
  1356.         END_TX_SEM_GIVE (&pDrvCtrl->endData);
  1357.         return (END_ERR_BLOCK); 
  1358.         }
  1359.     /* count the number of cluster in the chain */
  1360.     pChunk=pMblk;
  1361.     while(pChunk!= NULL)
  1362.         {
  1363.         if(pChunk->mBlkHdr.mLen > 0)
  1364.             count++;
  1365.         pChunk=pChunk->mBlkHdr.mNext;
  1366.         }
  1367.     if(count >= MAX_TX_FRAGS)
  1368.         {   
  1369. /* allocate a cluster from the cluster pool of MTU size */
  1370.         pBuf = netClusterGet(pDrvCtrl->endData.pNetPool,
  1371.      pDrvCtrl->pClPoolId[1]);
  1372.         if(pBuf == NULL)
  1373.             {
  1374.             END_M2_OUTDISCARDS (&pDrvCtrl->endData);
  1375.             pDrvCtrl->txBlocked = TRUE;
  1376.             END_TX_SEM_GIVE (&pDrvCtrl->endData);
  1377.             return (END_ERR_BLOCK);
  1378.             }
  1379. #ifdef PULI_LED_DEBUG
  1380.   PutLED('E',3);
  1381. #endif
  1382.         Exceed=TRUE;
  1383.         }   /*free mblk*/
  1384.     /* See if transmit descriptor is available */
  1385.     pTXD = pDrvCtrl->pTXDFree;
  1386.     if (pTXD->flag == IN_USE)
  1387.      {  /* No room  - clean-up & return */
  1388. #ifdef DEBUG
  1389.     SN_LOGMSG("transmit descriptor in usen",0,0,0,0,0,0); 
  1390. #endif
  1391. if(Exceed)
  1392.     netClFree(pDrvCtrl->endData.pNetPool,(UINT8 *)pBuf);
  1393.         END_M2_OUTDISCARDS (&pDrvCtrl->endData);
  1394.         pDrvCtrl->txBlocked = TRUE;
  1395.         /* Release the TX semaphore */
  1396. END_TX_SEM_GIVE (&pDrvCtrl->endData);
  1397. return (END_ERR_BLOCK);
  1398. }  /* No room */
  1399.     /* Mark this descriptor as "in use" */
  1400.     pTXD->flag   = IN_USE;
  1401.     pTXD->status = 0;
  1402.     /*
  1403.      * Build a transmit descriptor.
  1404.      * Loop thru each fragment in the mbuf chain and stuff our info.
  1405.      */
  1406.     /*
  1407.      * loop through the chain until last mblk is pointing to NULL, 
  1408.      * consider clusters only if their length is positive number and if not, 
  1409.      * get the next mblk 
  1410.      */
  1411.     if(Exceed)
  1412.         {
  1413.         count=0;
  1414.         if(pMblk->mBlkHdr.mData[5] & 0x01)
  1415.             END_M2_OUTNUCAST (&pDrvCtrl->endData);
  1416.         else
  1417.             END_M2_OUTUCAST (&pDrvCtrl->endData);
  1418.        
  1419.         /*
  1420.          * copy all the data in each mblk of the chain to the newly 
  1421.  * allocate cluster
  1422.  */
  1423.         totalLength = netMblkToBufCopy(pMblk,pBuf,NULL);
  1424. /*Free mblk chain after copying */
  1425.         netMblkClChainFree(pMblk);
  1426.         CACHE_USER_FLUSH(pBuf,totalLength);
  1427.         /* set the data pointers and the correponding size of each fragment */
  1428.         addr = (u_long) CACHE_DMA_VIRT_TO_PHYS (pBuf);
  1429.         pTXD->frag [count].frag_ptr0 = (u_long) addr & UMASK;
  1430.         pTXD->frag [count].frag_ptr1 = (u_long) addr >> 16;
  1431.         pTXD->frag [count].frag_size = totalLength;
  1432.         count++;
  1433.         /* Record the buffer's free routine for later invocation */
  1434.         pDrvCtrl->freeBuf[pTXD->number].pfreeRtn  = (FUNCPTR)netClFree;
  1435.         pDrvCtrl->freeBuf[pTXD->number].pSpare1= pDrvCtrl->endData.pNetPool;
  1436.         pDrvCtrl->freeBuf[pTXD->number].pSpare2=pBuf;
  1437.         }
  1438.     else
  1439.         /* 
  1440.          * loop through the chain until last mblk is pointing to NULL,
  1441.          * consider clusters only if their length is positive number 
  1442.  * and if not,
  1443.  * get the next mblk
  1444.  */
  1445.         {
  1446.         pChunk =pMblk;
  1447.         for(count=0;pChunk != NULL;) 
  1448.             {
  1449.             /* if all the data is contained in the first mblk */
  1450.             if((pChunk->mBlkHdr.mLen == pMblk->mBlkPktHdr.len) 
  1451.        && pChunk==pMblk)
  1452.                 No_Mblk=TRUE;
  1453.             if (pChunk->mBlkHdr.mLen <= 0)
  1454.         {
  1455.                 pChunk =pChunk->mBlkHdr.mNext;
  1456.                 continue;
  1457.         }  
  1458.     /*
  1459.      * Check if frame contains a broadcast/multicast destination
  1460.              * address.  Update appropriate MIB variable accordingly.
  1461.      */
  1462.             if ((count == 0)  &&  (pChunk->mBlkHdr.mData[5] & 0x01))
  1463.         END_M2_OUTNUCAST (&pDrvCtrl->endData);
  1464.             else
  1465.                 END_M2_OUTUCAST (&pDrvCtrl->endData);
  1466.             /* ensure data is flushed */
  1467.             CACHE_USER_FLUSH (pChunk->mBlkHdr.mData,pChunk->mBlkHdr.mLen);
  1468.             /*
  1469.              * set the data pointers and the correponding size of 
  1470.      * each fragment 
  1471.      */
  1472.             addr = (u_long) CACHE_DMA_VIRT_TO_PHYS (pChunk->mBlkHdr.mData);
  1473.             pTXD->frag [count].frag_ptr0 = (u_long) addr & UMASK;
  1474.             pTXD->frag [count].frag_ptr1 = (u_long) addr >> 16;
  1475.             pTXD->frag [count].frag_size = pChunk->mBlkHdr.mLen;
  1476.             /* keep track of total packet length */
  1477.             totalLength += pChunk->mBlkHdr.mLen;
  1478.             if(No_Mblk)
  1479.                 {
  1480.                 count=1;
  1481.                 break;
  1482.                 }
  1483.              /* loop through */
  1484.              pChunk =pChunk->mBlkHdr.mNext;
  1485.              count++;
  1486.              }
  1487.         /* Record the buffer's free routine for later invocation */
  1488.         pDrvCtrl->freeBuf[pTXD->number].pfreeRtn = (FUNCPTR)netMblkClChainFree;
  1489.         pDrvCtrl->freeBuf[pTXD->number].pSpare1= pMblk;
  1490.         pDrvCtrl->freeBuf[pTXD->number].pSpare2=NULL;
  1491.         }
  1492.     /* Set total packet size & fragment count */
  1493.     pTXD->pkt_size = max (ETHERSMALL, totalLength);   /* set packet size */
  1494.     pTXD->frag_count = count;                     /* set fragment count */
  1495.     if (totalLength < ETHERSMALL)
  1496.         {
  1497.         pTXD->frag[count-1].frag_size += (ETHERSMALL - totalLength);
  1498. totalLength = ETHERSMALL;
  1499. }
  1500.     /* Update MIB variable accordingly */
  1501.     END_M2_OUTOCTETS (&pDrvCtrl->endData, totalLength);
  1502.     /* Reset the actual pLink field of the last transmitted descriptor */
  1503.     pDrvCtrl->pTXDLast->frag[pDrvCtrl->pTXDLast->frag_count].frag_ptr0
  1504. &= ~TX_EOL;
  1505.     /* copy link field to where device will expect it  & set the EOL bit */
  1506.     pTXD->frag [count].frag_ptr0 =
  1507.         (u_long) CACHE_DMA_VIRT_TO_PHYS (pTXD->pLink) | TX_EOL;
  1508.     /* Adjust pointer to next TXD. */
  1509.     pDrvCtrl->pTXDFree = (TX_DESC *)((u_long)pTXD->pLink & ~TX_EOL);
  1510.     pDrvCtrl->pTXDLast = pTXD;
  1511.     /* start the transmitter but make sure the load-cam bit is not set */
  1512.     while (pDrvCtrl->pDev->cr & LCAM)
  1513.         continue;
  1514.     pDrvCtrl->pDev->cr = TXP;
  1515.     /* Release Transmit semaphore */
  1516.     END_TX_SEM_GIVE (&pDrvCtrl->endData);
  1517.     return OK;
  1518.     }
  1519. /*******************************************************************************
  1520. *
  1521. * sn83932PollSend - the driver send routine
  1522. *
  1523. * This routine is valid only when called while the device is in Polling
  1524. * mode.  The NetBuffer passed in must not be in a chained configuration.
  1525. * If either of these rules are broken, the driver returns EINVAL.
  1526. * The transmit descriptor is filled with the relevant data and the
  1527. * transmitter started.  The transmit descriptor status is then polled for
  1528. * completion.  The transmit descriptor is cleared and the data buffer
  1529. * is freed.
  1530. * Note:  The same descriptor is used for each invocation of this function.
  1531. *
  1532. * RETURNS:  OK,
  1533. *   EINVAL - invalid usage
  1534. *   EAGAIN - error in transmission or busy
  1535. * NOMANUAL
  1536. */
  1537. LOCAL STATUS sn83932PollSend
  1538.     (
  1539.     DRV_CTRL * pDrvCtrl,
  1540.     M_BLK_ID pMblk
  1541.     )
  1542.     {
  1543.     TX_DESC *pTXD;
  1544.     u_long  addr;
  1545.     int retval;
  1546.     volatile u_short stat = 0;
  1547.     /* Sanity Check */
  1548.     if (pDrvCtrl == NULL)
  1549. return EINVAL;
  1550.     /* Buffer chaining not supported in Poll Mode */
  1551.     if (!(pDrvCtrl->flags & SN_POLLING) || (pMblk->mBlkHdr.mNext!=NULL))
  1552. return (EINVAL);
  1553.     if (pDrvCtrl->txBlocked)
  1554.         return (END_ERR_BLOCK);
  1555.     
  1556.     /* See if transmit descriptor is available  */
  1557.     pTXD = pDrvCtrl->pTXDFree;
  1558.     if (pTXD->flag == IN_USE)
  1559.      {/* No Room */
  1560. return (EAGAIN);
  1561.      }
  1562.     /* Mark the descriptor as "in use" to reserve it */
  1563.     pTXD->flag   = IN_USE;
  1564.     pTXD->status = 0;
  1565.     /* ensure data is flushed */
  1566.     CACHE_USER_FLUSH (pMblk->mBlkHdr.mData, pMblk->mBlkHdr.mLen);
  1567.     /* Set up descriptor */
  1568.     pTXD->pkt_size = max (ETHERSMALL, pMblk->mBlkHdr.mLen);
  1569.     pTXD->frag_count = 1;
  1570.     /* Assign to a fragment */
  1571.     addr = (u_long) CACHE_DMA_VIRT_TO_PHYS (pMblk->mBlkHdr.mData);
  1572.     pTXD->frag [0].frag_ptr0 = (u_long) addr & UMASK;
  1573.     pTXD->frag [0].frag_ptr1 = (u_long) addr >> 16;
  1574.     pTXD->frag [0].frag_size = pTXD->pkt_size; 
  1575.     /* copy link field to where device will expect it  & set the EOL bit */
  1576.     pTXD->frag [pTXD->frag_count].frag_ptr0 =
  1577.         (u_long) CACHE_DMA_VIRT_TO_PHYS (pTXD->pLink) | TX_EOL;
  1578.     /* Set the transmitter on */
  1579.     pDrvCtrl->pDev->cr = TXP;
  1580.     /* Poll for transmit completion */
  1581.     do  {
  1582.         CACHE_DMA_INVALIDATE (&pTXD->status, sizeof (pTXD->status));
  1583. stat = pTXD->status;
  1584.     }while (!stat); 
  1585.     /* Update MIB variables */
  1586.     END_M2_OUTOCTETS (&pDrvCtrl->endData, pTXD->pkt_size);
  1587.     /* Determine if unicast or not */
  1588.     if (pMblk->mBlkHdr.mData[5] & 0x01)
  1589. END_M2_OUTNUCAST (&pDrvCtrl->endData);
  1590.     else
  1591. END_M2_OUTUCAST (&pDrvCtrl->endData);
  1592.     /* Check for successful transmission */
  1593.     if (stat & PTX)
  1594. retval = OK; /* Successful Send */
  1595.     else
  1596. {  /* Error in Sending */
  1597. END_M2_OUTERRORS (&pDrvCtrl->endData);
  1598. retval = EAGAIN;
  1599. }
  1600.     /* Free this Descriptor  for another poll request */
  1601.     pTXD->flag = NOT_IN_USE;
  1602.     pTXD->status = 0;
  1603.     /* Adjust pointer to next TXD. */
  1604.     pDrvCtrl->pTXDFree = (TX_DESC *)((u_long)pTXD->pLink & ~TX_EOL);
  1605.     pDrvCtrl->pTXDLast = pTXD;
  1606.     pDrvCtrl->pTXDReclaim = pDrvCtrl->pTXDFree;
  1607.     return (retval);
  1608.     }
  1609. /*****************************************************************************
  1610. *
  1611. * snTxReclaim - reclaims transmit descriptors that the device has serviced
  1612. *
  1613. *  - Only valid if device is not in Polling Mode -
  1614. *
  1615. */
  1616. LOCAL void snTxReclaim 
  1617.     (
  1618.     DRV_CTRL *pDrvCtrl,
  1619.     int maxReclaims
  1620.     )
  1621.     {
  1622.     TX_DESC *pTXD;
  1623.     int  intLevel;
  1624.     int numReclaims=0;
  1625.     /* No business here if we're in Poll Mode */
  1626.     if (pDrvCtrl->flags & SN_POLLING)
  1627. return;
  1628.     /* Check if someone else is in the midst of reclaiming */
  1629.     if (pDrvCtrl->flags & SN_RECLAIMING)
  1630.         {
  1631.         SN_LOGMSG("someone else is busy reclaimingn",0,0,0,0,0,0);
  1632.         return;
  1633.         }
  1634.     /* Close reclaiming to all others */
  1635.     pDrvCtrl->flags |= SN_RECLAIMING;
  1636.     pTXD = pDrvCtrl->pTXDReclaim;                  /* get ptr to desc */
  1637.     CACHE_DMA_INVALIDATE (&pTXD->status, sizeof (u_long));
  1638.     /*
  1639.      * The device is deemed to be done with the descriptor if the
  1640.      * the descriptor had been flagged as "given" to the device,
  1641.      * and the descriptor status field is set.
  1642.      */
  1643.     /*
  1644.      * Check if descriptor was used status may return 0 if xmit error 
  1645.      * occurred 
  1646.      */
  1647.     while ((pTXD->flag == IN_USE) &&
  1648.    ((pTXD->status & PTX) || !(pDrvCtrl->pDev->cr & TXP)))
  1649.         {
  1650.         if ( pTXD->status & PTX )
  1651.             {
  1652.             /* Packet was transmitted successfully. *
  1653.     * Release the data buffer(s) */
  1654.     /* Release buffer associated with each fragment in the TXD */
  1655.     (pDrvCtrl->freeBuf[pTXD->number].pfreeRtn) 
  1656.                       (pDrvCtrl->freeBuf[pTXD->number].pSpare1,
  1657.                        pDrvCtrl->freeBuf[pTXD->number].pSpare2);
  1658.             /* done with the desc, so clean it up */
  1659.             pTXD->flag    = NOT_IN_USE;
  1660.             pTXD->status  = 0;
  1661.             }
  1662.         else 
  1663.             {     /* ERROR! */
  1664.     END_M2_OUTERRORS (&pDrvCtrl->endData);
  1665.     intLevel = intLock();
  1666.     pTXD->status = 0;
  1667.     /* Make sure LCAM bit is not set or we'll lock up */
  1668.     while (pDrvCtrl->pDev->cr & LCAM)
  1669.         continue;
  1670.             pDrvCtrl->pDev->cr = TXP;           /* restart transmitter */
  1671.     intUnlock (intLevel);
  1672.     /* Get out now! */
  1673.             break;
  1674.     }/* ERROR */
  1675.         /* Advance to the next TXD. */
  1676.         pTXD = (TX_DESC *)((u_long)pTXD->pLink & ~TX_EOL);
  1677.         /* Update the reclaim pointer for next time. */
  1678.         pDrvCtrl->pTXDReclaim = pTXD;
  1679. /* Check if we've taken too long */
  1680. if (numReclaims++ ==  maxReclaims)
  1681.     break;
  1682.         /* invalidate the cache for this TXD */
  1683.         CACHE_DMA_INVALIDATE (&pTXD->status, sizeof (pTXD->status));
  1684.         } /* while */
  1685.     pDrvCtrl->flags &= ~SN_RECLAIMING;
  1686.     }
  1687. /*============================================================================*
  1688.  * R E C E I V E   R O U T I N E S
  1689.  *============================================================================*/
  1690. /****************************************************************************
  1691. *
  1692. * sn83932PollRecv - Returns the next packet waiting to be processed.  If no
  1693. * packet exists, EAGAIN indication is returned instead.
  1694. *
  1695. * RETURNS:  OK or EAGAIN
  1696. *
  1697. */
  1698. LOCAL STATUS sn83932PollRecv
  1699.     (
  1700.     DRV_CTRL *pDrvCtrl,
  1701.     M_BLK_ID pMblk 
  1702.     )
  1703.     {
  1704.      
  1705.     /* Sanity Check */
  1706.     if (pDrvCtrl == NULL || !(pDrvCtrl->flags & SN_POLLING))
  1707. return EINVAL;
  1708.     if (pMblk == NULL || pMblk->mBlkHdr.mData == NULL)
  1709. return (EINVAL);
  1710.      
  1711.     /* Process the received packet and give it to the mux */
  1712.     if (snProcessRxPkts (pDrvCtrl, 1, pMblk) == 0)
  1713. return EAGAIN;
  1714.     else
  1715. return OK;
  1716.     }
  1717. /*******************************************************************************
  1718. *
  1719. * snProcessRxPkts - Process the received packets up to the maximum
  1720. * as indicated by the supplied argument.  For each recieved
  1721. * indication, the packet is extracted, the appropriate MIB variables
  1722. * are updated and the packet is then sent up to the Mux.  This
  1723. * device does not support buffer loaning and therefore is not
  1724. * utilized.  Once the packet is sent to the mux, the receive
  1725. * descriptor pointers are adjusted appropriately.
  1726. *
  1727. * RETURNS -  Number of packets processed exclusive of errors 
  1728. *   
  1729. */
  1730. LOCAL int snProcessRxPkts 
  1731.     (
  1732.     DRV_CTRL * pDrvCtrl,         /* ptr to device's control info */
  1733.     int maxPackets, /* Max number of packets to process */
  1734.     M_BLK_ID pMblk  /* Optional net buffer for packet */
  1735.     )
  1736.     {
  1737.     END_OBJ *pEnd; /* ptr to our End structure */
  1738.     RX_DESC *pRXD; /* ptr to current descriptor */
  1739.     SONIC *pDev;                        /* ptr to the device regs */
  1740.     char *pPktHdr; /* ptr to packet */
  1741.     int recvLen; /* size of packet received */
  1742.     int ndx;                            /* index into RRA desc array */
  1743.     int packetCount; /* num of packets processed */
  1744.     int POLL_MODE=1;                    /* if in Poll mode */
  1745.     CL_BLK_ID pClBlk;                   /* cluster block pointer */
  1746.     UCHAR *    pCluster;                 /* cluster pointer */
  1747.     BOOL error=FALSE;                   /* set in case of bad packet or out of
  1748. mblks, cluster blks or cluster */
  1749.     /* Note the devices's End address */
  1750.     pEnd = &pDrvCtrl->endData;
  1751.     /* check if NOT Poll mode */
  1752.     if(pMblk==NULL)
  1753.     POLL_MODE=0;
  1754.     /* If a buffer is provided, then only one packet may be processed  */
  1755.     if (pMblk != NULL)
  1756. maxPackets = 1; 
  1757. #ifdef LED_DEBUG
  1758.     if (!(pDrvCtrl->flags & SN_POLLING))
  1759.         PutLED ('r',1);
  1760. #endif
  1761.     /* Process all received packets up to the supplied MAX */
  1762.     for (packetCount = 0; packetCount < maxPackets; )
  1763.         {
  1764.         recvLen = 0;
  1765.         /* get the next receive descriptor */
  1766.      pRXD = pDrvCtrl->pRXDNext;
  1767.      CACHE_DMA_INVALIDATE (pRXD, RX_DESC_SIZ);
  1768.         /* Check if next slot has a packet */
  1769.         if (pRXD->in_use == IN_USE)
  1770.     {
  1771. #ifdef DEBUG
  1772.    SN_LOGMSG("descriptor in usen",0,0,0,0,0,0); 
  1773. #endif
  1774.             break; 
  1775.             }
  1776.      /* Check for any error in reception */
  1777.      if (!(pRXD->status & PRX))
  1778.          { /* BAD PACKET */
  1779.     /*SL* Update MIB error count */
  1780.     END_M2_INERRORS (pEnd);
  1781. #ifdef DEBUG
  1782.     SN_LOGMSG("bad packetn",0,0,0,0,0,0);
  1783. #endif
  1784.             }/* BAD PACKET */
  1785.         else
  1786.          {    /* GOOD PACKET */
  1787.          /* Get packet length */
  1788.         recvLen  = (pRXD->byte_count & UMASK) - 4;
  1789.      
  1790.             pPktHdr = (char *)
  1791.                    (((pRXD->pkt_ptr1 & UMASK)<<16) | (pRXD->pkt_ptr0 & UMASK));
  1792.          CACHE_DMA_INVALIDATE (pPktHdr, recvLen);
  1793.     if (!POLL_MODE)
  1794.         { /* NOT POLL MODE */
  1795.                 /* Obtain the appropriate cluster depending on size of 
  1796.  * received packet 
  1797.  */
  1798.     
  1799. if(recvLen <= OPTIMAL_CLUSTER_SIZE)
  1800.     {
  1801.                if((pCluster= (UCHAR *)netClusterGet(pEnd->pNetPool,
  1802.                              pDrvCtrl->pClPoolId[0])) == NULL)
  1803.         {
  1804. #ifdef DEBUG
  1805.     SN_LOGMSG("out of clusters in the first pooln",0,0,0,0,0,0);
  1806. #endif
  1807.                         }
  1808.                     }
  1809.                 /* if packet size greater than optimal size or out of 
  1810.          * optimal size cluster 
  1811.  */
  1812.       if(recvLen > OPTIMAL_CLUSTER_SIZE || pCluster == NULL)
  1813.     {
  1814.     pCluster= (UCHAR *) netClusterGet(pEnd->pNetPool,
  1815.     pDrvCtrl->pClPoolId[1]);
  1816.                     }
  1817.         if(pCluster==NULL)
  1818.             {
  1819. #ifdef DEBUG
  1820.     SN_LOGMSG("cannot allocate clustern",0,0,0,0,0,0);
  1821. #endif
  1822.             error=TRUE;
  1823.                     }
  1824.                 /* obtain a cluster blk */
  1825.         if((!error) && (pClBlk= netClBlkGet(pEnd->pNetPool,
  1826.                 M_DONTWAIT))==NULL)
  1827.             {
  1828.     netClFree(pEnd->pNetPool,pCluster);
  1829. #ifdef DEBUG
  1830.     SN_LOGMSG("Out of Cluster Blocksn",0,0,0,0,0,0);
  1831. #endif
  1832.                     error=TRUE;
  1833.             }
  1834.                 /* obtain a mblk */
  1835.         if((!error) && (pMblk = mBlkGet(pEnd->pNetPool,M_DONTWAIT,
  1836.                                 MT_DATA))==NULL)
  1837.             {
  1838.             netClBlkFree(pEnd->pNetPool,pClBlk);
  1839.             netClFree(pEnd->pNetPool,pCluster);
  1840. #ifdef DEBUG
  1841.     SN_LOGMSG("Out of M blocksn",0,0,0,0,0,0);
  1842. #endif
  1843.             error=TRUE;
  1844.             }
  1845.                 if(!error)
  1846.     {
  1847.                     /* Joining the cluster to the MBlock */
  1848.             netClBlkJoin(pClBlk,(char *)pCluster,recvLen,NULL,0,0,0);
  1849.             netMblkClJoin(pMblk,pClBlk);
  1850.                     pMblk->m_data=pMblk->m_data+2;
  1851. #ifdef DEBUG
  1852.     SN_LOGMSG("length of packet received =%dn",recvLen,0,0,0,0,0); 
  1853. #endif
  1854.     }
  1855.              } /* NOT POLL MODE */
  1856.  
  1857.     else
  1858.         {
  1859.                 pMblk->mBlkHdr.mData = pMblk->pClBlk->clNode.pClBuf;
  1860. pMblk->mBlkHdr.mData +=2;
  1861.         }  
  1862.     if(!error)
  1863.         {
  1864.                 pMblk->mBlkHdr.mLen= recvLen;
  1865.         pMblk->mBlkHdr.mFlags |= M_PKTHDR;
  1866.         pMblk->mBlkPktHdr.len =recvLen;
  1867.         bcopy((char *) CACHE_DMA_PHYS_TO_VIRT (pPktHdr),
  1868.       (char *) pMblk->m_data,recvLen);
  1869.                 /*SL*  Update MIB2 stats here */
  1870.                 END_M2_INOCTETS (pEnd, recvLen);
  1871.                 if (pRXD->status & (MC | BC))
  1872.                     END_M2_INNUCAST (pEnd);
  1873.                 else
  1874.                     END_M2_INUCAST (pEnd);
  1875.         } 
  1876.             } /* GOOD PACKET */
  1877.         /* Update the next receive slot */
  1878. pDrvCtrl->pRXDNext = (RX_DESC *) CACHE_DMA_PHYS_TO_VIRT (pRXD->link);
  1879.         /* Make it the last descriptor in the chain */
  1880. pDrvCtrl->pRXDLast->link = (RX_DESC *) CACHE_DMA_VIRT_TO_PHYS (pRXD);
  1881. pDrvCtrl->pRXDLast = pRXD;
  1882.         /* Check if this was the last pkt in this buffer*/
  1883.         if (pRXD->status & LPKT)
  1884.             {/* form index to RRA descriptor this packet associates with */
  1885. #ifdef DEBUG     
  1886.     SN_LOGMSG("last packet in the buffern",0,0,0,0,0,0); 
  1887. #endif
  1888.     ndx = (((pRXD->seq_no & 0x0000ff00) >> 8) + 1) % NUM_RRA_DESC;
  1889.             pDev = pDrvCtrl->pDev;
  1890.     pDev->rwp = (u_long)(&((RRA_DESC *)pDrvCtrl->RSA)[ndx]) & UMASK;
  1891.     if (pDev->isr & RBE)                /* deal with RBE condition */
  1892. {
  1893.                 pDev->isr = RBE;                /* clear the RBE condition */
  1894. #ifdef DEBUG
  1895.     SN_LOGMSG ("RBEn", 0,0,0,0,0,0);
  1896. #endif 
  1897.         }
  1898.             }
  1899.         /* Give control of this descriptor back to the device */
  1900.         pRXD->status = 0;
  1901.         pRXD->in_use = IN_USE;                   /* Set to IN_USE by device */
  1902.         pRXD->link = RX_EOL;                     /* Last one */
  1903.       
  1904.         /* in case of bad packet or out of clusters or cluster blks or mblks */
  1905.         if(recvLen==0 || error)
  1906.     break;
  1907.         /* send the packet up the stack if NOT Poll mode */
  1908.         if(!POLL_MODE)
  1909.             END_RCV_RTN_CALL (pEnd, pMblk);
  1910.         /* increment the packet count */
  1911.         packetCount++;
  1912.         }/* for */
  1913.         return (packetCount);
  1914.     }
  1915.  /*====================================================================*
  1916.   * E V E N T   R O U T I N E S
  1917.   *====================================================================*/
  1918. /*******************************************************************************
  1919. *
  1920. * sn83932Int - handle controller interrupt
  1921. *
  1922. * This routine is called at interrupt level in response to an interrupt from
  1923. * the controller.
  1924. *
  1925. * NOMANUAL
  1926. * RETURNS: N/A.
  1927. */
  1928. LOCAL void sn83932Int
  1929.     (
  1930.      DRV_CTRL  * pDrvCtrl
  1931.     )
  1932.     {
  1933.     SONIC *pDev; /* ptr to the device regs */
  1934. #ifdef LED_DEBUG
  1935.     if (pDrvCtrl->flags & SN_POLLING)
  1936. PutLED ('I', 0);
  1937. #endif
  1938.     /* Point to the SONIC device registers */
  1939.     pDev = pDrvCtrl->pDev;
  1940.     /*** Check for bus retry ***/
  1941.     if (pDev->isr & BR)
  1942.         {
  1943. pDev->isr = BR;
  1944. #ifdef DEBUG
  1945. logMsg ("Bus Retry (int)n", 0,0,0,0,0,0);
  1946. #endif
  1947. }
  1948.     /* Check for a timer interrupt */
  1949.     if ((pDev->isr & pDev->imr) & TCEN)
  1950. {/* Timer Interrupt */
  1951. #ifdef LED_DEBUG
  1952. PutLED ('T', 3);
  1953. #endif
  1954. if (pDrvCtrl->timerIntHandler)
  1955.     {/* Call handler if it exists */
  1956.     pDev->cr = STP;
  1957.     pDev->isr = TCEN;
  1958.     (*pDrvCtrl->timerIntHandler)();
  1959.     pDev->wt0 = pDrvCtrl->ticks & 0xffff;
  1960.     pDev->wt1 = pDrvCtrl->ticks >> 16;
  1961.     pDev->cr = ST;
  1962.     }
  1963. }
  1964.     /*----------------------------------------*/
  1965.     /* Check for any packet (data) interrupts */
  1966.     /*----------------------------------------*/
  1967.     if ((pDev->isr & pDev->imr) & SN_IMR_DATA)
  1968. {
  1969.         /* disable further data interrupts */
  1970. pDev->imr = (pDrvCtrl->imr & ~SN_IMR_DATA);
  1971.         /* Queue event handler for the netTask */
  1972.         (void) netJobAdd ((FUNCPTR)snEventHandler,
  1973.                           (int)pDrvCtrl, 0, 0, 0, 0);
  1974. }
  1975.     sysEnetIntAck (pDrvCtrl->unit);                /* do system int ack */
  1976.     }
  1977. /*******************************************************************************
  1978. *
  1979. * snEventHandler - device event handler, a netTask job
  1980. */
  1981. LOCAL void snEventHandler
  1982.     (
  1983.      DRV_CTRL * pDrvCtrl
  1984.     )
  1985.     {
  1986.      SONIC *pDev;                         /* ptr to the device regs */
  1987.     pDev = pDrvCtrl->pDev;
  1988. #ifdef LED_DEBUG
  1989.     PutLED ('v',3);
  1990. #endif
  1991.     /* Loop, processing events */
  1992.     while ( pDev->isr & SN_IMR_DATA )
  1993.         {
  1994.         /*** Process all received packets ***/
  1995.         if (pDev->isr & PKTRX)
  1996.             {
  1997.     /* clear this interrupt */
  1998.             pDev->isr = PKTRX;                
  1999. #ifdef LED_DEBUG
  2000.     PutLED ('r',3);
  2001. #endif
  2002.     /* Process all received packets */
  2003.             snProcessRxPkts (pDrvCtrl, RX_PROCESS_FLOW, 0);
  2004.             }
  2005.         /*** Process transmitter events ***/
  2006.         if ( pDev->isr & (TXDN | TXER) )
  2007.             {
  2008.     /* Clear transmit interrupts */
  2009.             pDev->isr = (TXDN | TXER);
  2010. #ifdef LED_DEBUG
  2011.     PutLED ('x',3);
  2012. #endif
  2013.     /* Process used transmit descriptor */
  2014.             snTxReclaim (pDrvCtrl, TX_PROCESS_FLOW);
  2015.             if (pDrvCtrl->txBlocked)
  2016.                 {
  2017.                 netJobAdd ((FUNCPTR)muxTxRestart, (int)&pDrvCtrl->endData,
  2018. 0, 0, 0, 0);
  2019.                 pDrvCtrl->txBlocked = FALSE;
  2020.                 }
  2021.             }
  2022.         }
  2023. #ifdef LED_DEBUG
  2024.     PutLED ('V',3);
  2025. #endif
  2026.     /* Enable the interrupts */
  2027.     pDev->imr = pDrvCtrl->imr;
  2028.     }
  2029. /*===========================================================================*
  2030.  * T I M E R   R O U T I N E S
  2031.  *===========================================================================*/
  2032. /*******************************************************************************
  2033. *
  2034. * snEndClkEnable - enable the SONIC timer interrupt
  2035. *
  2036. * This routine enables the SONIC timer to give a periodic interrupt.
  2037. * The <unit> parameter selects the SONIC device.  The <ticksPerSecond>
  2038. * parameter specifies the number of interrupts to generate per second.
  2039. * When an interrupt occurs, the function in <intHandler> is called.
  2040. *
  2041. * NOTE:
  2042. * The SONIC clock interrupt is dependent on the SONIC interface being
  2043. * configured and enabled.  For this reason, this interrupt is unsuitable
  2044. * for use as the main system clock.  It is suitable for use as an auxiliary
  2045. * clock source for boards that have no other source of clock.
  2046. *
  2047. * RETURNS: N/A
  2048. *
  2049. * SEE ALSO: snEndClkDisable()
  2050. *
  2051. * NOMANUAL
  2052. */
  2053. void snEndClkEnable
  2054.     (
  2055.     int unit, /* unit number */
  2056.     int ticksPerSecond, /* interrupt frequency */
  2057.     FUNCPTR intHandler /* interrupt handler */
  2058.     )
  2059.     {
  2060.     DRV_CTRL *pDrvCtrl;
  2061.     SONIC *pDev;
  2062.     int key;
  2063.     pDrvCtrl = (DRV_CTRL *)endFindByName (SN_DEV_NAME, unit);
  2064.     if (pDrvCtrl == NULL)
  2065.         {
  2066.         SN_LOGMSG ("Device entry not found for unit %d n",unit,0,0,0,0,0);
  2067.         }
  2068.     else
  2069.         {
  2070.         pDev = pDrvCtrl->pDev;
  2071.         key = intLock ();
  2072.         pDrvCtrl->timerIntHandler = intHandler;
  2073.         pDrvCtrl->ticks = 5000000 / ticksPerSecond;
  2074.         pDrvCtrl->imr |= TCEN;
  2075.         if (pDev)
  2076.     {
  2077.     pDev->cr = STP;
  2078.     pDev->wt0 = pDrvCtrl->ticks & 0xffff;
  2079.     pDev->wt1 = pDrvCtrl->ticks >> 16;
  2080.     pDev->imr |= TCEN;
  2081.     pDev->cr = ST;
  2082.     }
  2083.         intUnlock (key);
  2084.         }
  2085.     }
  2086. /*******************************************************************************
  2087. *
  2088. * snEndClkDisable - disable the SONIC timer interrupt
  2089. *
  2090. * This routine disables the SONIC timer interrupt.  The <unit> parameter
  2091. * selects the SONIC device.
  2092. *
  2093. * RETURNS: N/A
  2094. *
  2095. * SEE ALSO: snEndClkEnable()
  2096. *
  2097. * NOMANUAL
  2098. */
  2099. void snEndClkDisable
  2100.     (
  2101.     int unit /* unit number */
  2102.     )
  2103.     {
  2104.     DRV_CTRL *pDrvCtrl;
  2105.     SONIC *pDev;
  2106.     int key;
  2107.     pDrvCtrl = (DRV_CTRL *)endFindByName (SN_DEV_NAME, unit);
  2108.     if (pDrvCtrl == NULL)
  2109.         {
  2110.         SN_LOGMSG ("Device entry not found for unit %d n",unit,0,0,0,0,0);
  2111.         }
  2112.     else
  2113.         {
  2114.         pDev = pDrvCtrl->pDev;
  2115.         if (pDev)
  2116.     {
  2117.     key = intLock ();
  2118.     pDev->imr &= ~TCEN; 
  2119.     pDrvCtrl->imr &= ~TCEN;
  2120.     pDev->cr = STP;
  2121.     intUnlock (key);
  2122.     }
  2123.         }
  2124.     }
  2125. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2126.  * SECTION: NOTES
  2127.  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2128. /*
  2129. NOTES:
  2130.     There are some things unsupported in this version:
  2131.     a) buffer loaning on receive
  2132.     b) output hooks
  2133.     c) trailer protocol
  2134.     d) promiscuous mode *SL*  Supported in END Model *SL*
  2135.     Also, the receive setup needs work so that the number of RRA descriptors
  2136.     is not fixed at four.  It would be a nice addition to allow all the
  2137.     sizes of the shared memory structures to be specified by the runtime
  2138.     functions that call our init routines.
  2139. */
  2140. /* END OF FILE */