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

VxWorks

开发平台:

C/C++

  1. /* ultraEnd.c - SMC Ultra Elite END network interface driver */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01h,14jan02,dat  (more) Removing warnings from Diab compiler
  8. 01g,21sep01,dat  Removing ANSI errors for diab compiler
  9. 01f,28aug00,stv  corrected the handling of EIOCSFLAGS ioctl (SPR# 29423).
  10. 01e,02aug00,stv  removed netMblkClChainFree() in Pollsend routine (SPR# 32885).
  11. 01d,11jun00,ham  removed reference to etherLib.
  12. 01c,27jan00,dat  fixed use of NULL, removed warnings
  13. 01b,09mar99,sbs  changed SYS_INT_ENABLE and SYS_INT_DISABLE to use
  14.                  device specific BSP routines. 
  15. 01a,06jan99,dra  written.
  16. */
  17. /*
  18. DESCRIPTION
  19. This module implements the SMC Elite Ultra Ethernt network interface driver.
  20. This driver supports single transmission and multiple reception.  The
  21. Current register is a write pointer to the ring.  The Bound register
  22. is a read pointer from the ring.  This driver gets the Current
  23. register at the interrupt level and sets the Bound register at the
  24. task level.  The interrupt is only masked during configuration or in
  25. polled mode.
  26. CONFIGURATION
  27. The W1 jumper should be set in the position of "Software Configuration".
  28. The defined I/O address in config.h must match the one stored in EEROM. 
  29. The RAM address, the RAM size, and the IRQ level are defined in config.h. 
  30. IRQ levels 2,3,5,7,10,11,15 are supported.
  31. EXTERNAL SUPPORT REQUIREMENTS
  32. This driver requires several external support functions, defined as macros:
  33. .CS
  34.     SYS_INT_CONNECT(pDrvCtrl, routine, arg)
  35.     SYS_INT_DISCONNECT (pDrvCtrl, routine, arg)
  36.     SYS_INT_ENABLE(pDrvCtrl)
  37.     SYS_INT_DISABLE(pDrvCtrl)
  38.     SYS_IN_BYTE(pDrvCtrl, reg, pData)
  39.     SYS_OUT_BYTE(pDrvCtrl, reg, pData)
  40. .CE
  41. These macros allow the driver to be customized for BSPs that use
  42. special versions of these routines.
  43. The macro SYS_INT_CONNECT is used to connect the interrupt handler to
  44. the appropriate vector.  By default it is the routine intConnect().
  45. The macro SYS_INT_DISCONNECT is used to disconnect the interrupt handler prior
  46. to unloading the module.  By default this is a dummy routine that
  47. returns OK.
  48. The macro SYS_INT_ENABLE is used to enable the interrupt level for the
  49. end device.  It is called once during initialization. It calls an
  50. external board level routine sysUltraIntEnable().
  51. The macro SYS_INT_DISABLE is used to disable the interrupt level for the
  52. end device.  It is called once during shutdown. It calls an
  53. external board level routine sysUltraIntDisable().
  54. The macros SYS_IN_BYTE and SYS_OUT_BYTE are used for accessing the
  55. ultra device.  The default macros map these operations onto
  56. sysInByte() and sysOutByte().
  57. INCLUDES:
  58. end.h endLib.h etherMultiLib.h
  59. SEE ALSO: muxLib, endLib
  60. .I "Writing an Enhanced Network Driver"
  61. */
  62. /* includes */
  63. #include "vxWorks.h"
  64. #include "stdlib.h"
  65. #include "cacheLib.h"
  66. #include "intLib.h"
  67. #include "end.h" /* Common END structures. */
  68. #include "endLib.h"
  69. #include "lstLib.h" /* Needed to maintain protocol list. */
  70. #include "wdLib.h"
  71. #include "iv.h"
  72. #include "semLib.h"
  73. #include "logLib.h"
  74. #include "netLib.h"
  75. #include "stdio.h"
  76. #include "sysLib.h"
  77. #include "errno.h"
  78. #include "errnoLib.h"
  79. #include "memLib.h"
  80. #include "iosLib.h"
  81. #undef ETHER_MAP_IP_MULTICAST
  82. #include "etherMultiLib.h" /* multicast stuff. */
  83. #include "net/mbuf.h"
  84. #include "net/unixLib.h"
  85. #include "net/protosw.h"
  86. #include "net/systm.h"
  87. #include "net/if_subr.h"
  88. #include "net/route.h"
  89. #include "sys/socket.h"
  90. #include "sys/ioctl.h"
  91. #include "sys/times.h"
  92. #include "drv/end/ultraEnd.h"
  93. /* defines */
  94. /* Configuration items */
  95. #define ULTRA_SPEED_10M 10000000 /* 10Mbs */
  96. #define ULTRA_SPEED ULTRA_SPEED_10M
  97. /* Definitions for the flags field */
  98. #define ULTRA_POLLING 0x01
  99. #define ULTRA_TX_IN_PROGRESS 0x02
  100. #define ULTRA_TX_BLOCKED 0x04
  101. #define ULTRA_RCV_HANDLING_FLAG 0x08
  102. /* Debug macros */
  103. #undef DRV_DEBUG
  104. #ifdef DRV_DEBUG
  105. #define DRV_DEBUG_OFF 0x0000
  106. #define DRV_DEBUG_RX 0x0001
  107. #define DRV_DEBUG_TX 0x0002
  108. #define DRV_DEBUG_INT 0x0004
  109. #define DRV_DEBUG_POLL (DRV_DEBUG_POLL_RX | DRV_DEBUG_POLL_TX)
  110. #define DRV_DEBUG_POLL_RX 0x0008
  111. #define DRV_DEBUG_POLL_TX 0x0010
  112. #define DRV_DEBUG_LOAD 0x0020
  113. #define DRV_DEBUG_IOCTL 0x0040
  114. #define DRV_DEBUG_ERR 0x0080
  115. #define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)
  116.     do
  117.         {
  118. if (ultraDebug & (FLG))
  119.     logMsg (X0, X1, X2, X3, X4, X5, X6);
  120. }
  121.     while (0)
  122. #define DRV_PRINT(FLG, X)
  123.     do
  124.         {
  125. if (ultraDebug & (FLG))
  126.     printf X;
  127. }
  128.     while (0)
  129. #else /* DRV_DEBUG */
  130. #define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) do {} while (0)
  131. #define DRV_PRINT(FLG, X) do {} while (0)
  132. #endif /* DRV_DEBUG */
  133. /* Cache macros */
  134. #define ULTRA_CACHE_INVALIDATE(address, len) 
  135.         CACHE_DRV_INVALIDATE (&pDrvCtrl->cacheFuncs, (address), (len))
  136. /*
  137.  * Default macro definitions for BSP interface.  These macros can be
  138.  * redefined in a wrapper file, to generate a new module with an
  139.  * optimized interface.
  140.  */
  141. /* Macro to connect interrupt handler to vector */
  142. #ifndef SYS_INT_CONNECT
  143. #define SYS_INT_CONNECT(pDrvCtrl,rtn,arg,pResult) 
  144.     { 
  145.     IMPORT STATUS sysIntConnect(); 
  146.     *(pResult) = intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC ((pDrvCtrl)->ivec), 
  147.    rtn, (int)(arg)); 
  148.     }
  149. #endif
  150. /* Macro to disconnect interrupt handler from vector */
  151. LOCAL VOID dummyIsr (void) { }
  152. #ifndef SYS_INT_DISCONNECT
  153. #define SYS_INT_DISCONNECT(pDrvCtrl,rtn,arg,pResult) 
  154.     { 
  155.     IMPORT STATUS intConnect(); 
  156.     *(pResult) = intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC ((pDrvCtrl)->ivec), 
  157.      dummyIsr, (int)(arg)); 
  158.     }
  159. #endif
  160. /* Macro to enable the appropriate interrupt level */
  161. #ifndef SYS_INT_ENABLE
  162. #define SYS_INT_ENABLE(pDrvCtrl) 
  163.         IMPORT void sysUltraIntEnable(); 
  164. sysUltraIntEnable ((pDrvCtrl)->intLevel); 
  165. }
  166. #endif
  167. /* Macro to disable the appropriate interrupt level */
  168. #ifndef SYS_INT_DISABLE
  169. #define SYS_INT_DISABLE(pDrvCtrl) 
  170.         IMPORT void sysUltraIntDisable(); 
  171. sysUltraIntDisable ((pDrvCtrl)->intLevel); 
  172. }
  173. #endif
  174. /*
  175.  * Macros to do a byte access to the chip.  Default assumes an
  176.  * I/O mapped device accessed in the x86 fashion.
  177.  */
  178. #ifndef SYS_OUT_BYTE
  179. #define SYS_OUT_BYTE(pDrvCtrl, addr, value) 
  180.  (sysOutByte ((pDrvCtrl)->ioAddr+(addr), value))
  181. #endif
  182. #ifndef SYS_IN_BYTE
  183. #define SYS_IN_BYTE(pDrvCtrl, addr, pData) 
  184.  (*(pData) = sysInByte ((pDrvCtrl)->ioAddr+(addr)))
  185. #endif
  186. /* A shortcut for getting the hardware address from the MIB II stuff. */
  187. #define END_HADDR(pEnd)
  188. ((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)
  189. #define END_HADDR_LEN(pEnd) 
  190. ((pEnd)->mib2Tbl.ifPhysAddress.addrLength)
  191. /* typedefs */
  192. /* The definition of the driver control structure */
  193. typedef struct ultra_device
  194.     {
  195.     END_OBJ     endObj; /* The class we inherit from. */
  196.     END_ERR lastError; /* Last error passed to muxError */
  197.     int unit; /* unit number */
  198.     int         ivec;                   /* interrupt vector */
  199.     int         ilevel; /* interrupt level */
  200.     int ioAddr; /* address of ultra's shared memory */
  201.     int memAddr; /* address of ultra's shared memory */
  202.     int memSize; /* size of ultra's shared memory */
  203.     int config; /* device config (TP, BNC) */
  204.     int offset; /* packet data offset */
  205.     UINT transmitPage[2]; /* start of TX packets */
  206.     UINT transmitCnt; /* number of TX packets sent */
  207.     UCHAR current; /* location of current RX packet */
  208.     UCHAR nextPacket; /* location of next RX packet */
  209.     UCHAR istat; /* current interrupt status */
  210.     UCHAR tstat; /* current TX status */
  211.     UCHAR rstat; /* current RX status */
  212.     UCHAR uppByteCnt; /* last upper byte count */
  213.     UCHAR intLevel; /* interrupt level from table */
  214.     ULONG flags; /* Our local flags. */
  215.     UCHAR enetAddr[6]; /* ethernet address */
  216.     UCHAR mcastFilter[8]; /* multicast address mask */
  217.     CACHE_FUNCS cacheFuncs;             /* cache function pointers */
  218.     CL_POOL_ID clPoolId; /* cluster pool */
  219.     } ULTRA_DEVICE;
  220. /* globals */
  221. #ifdef DRV_DEBUG
  222. int ultraDebug = 0x00;
  223. #endif /* DRV_DEBUG */
  224. /* locals */
  225. LOCAL IRQ_TABLE irqTable [] = 
  226.     {
  227.     { 2, 0x15},    { 2, 0x15},    { 2, 0x15},    { 3, 0x19},
  228.     { 3, 0x19},    { 5, 0x1d},    { 5, 0x1d},    { 7, 0x51},
  229.     { 7, 0x51},    { 7, 0x51},    {10, 0x55},    {11, 0x59},
  230.     {11, 0x59},    {11, 0x59},    {11, 0x59},    {15, 0x5d}
  231.     };
  232. /* forward declarations */
  233. IMPORT int endMultiLstCnt (END_OBJ* pEnd);
  234. LOCAL void ultraInt (ULTRA_DEVICE *pDrvCtrl);
  235. LOCAL STATUS ultraRecv (ULTRA_DEVICE *pDrvCtrl);
  236. LOCAL void ultraConfig (ULTRA_DEVICE *pDrvCtrl);
  237. LOCAL int ultraPacketGet  (ULTRA_DEVICE *pDrvCtrl, char *pDst);
  238. LOCAL void ultraAddrFilterSet (ULTRA_DEVICE *pDrvCtrl);
  239. LOCAL void ultraHandleRcvInt  (ULTRA_DEVICE *pDrvCtrl);
  240. LOCAL STATUS ultraParse (ULTRA_DEVICE* pDrvCtrl, char* initString);
  241. LOCAL STATUS ultraMemInit (ULTRA_DEVICE* pDrvCtrl, int clNum);
  242. LOCAL STATUS ultraPollStart (ULTRA_DEVICE* pDrvCtrl);
  243. LOCAL STATUS ultraPollStop (ULTRA_DEVICE* pDrvCtrl);
  244. LOCAL void ultraReset (ULTRA_DEVICE* pDrvCtrl);
  245. /* Ultra Specific interfaces. */
  246. LOCAL STATUS ultraStart (void* pObj);
  247. LOCAL STATUS ultraStop (void* pObj);
  248. LOCAL STATUS ultraUnload (void* pObj);
  249. LOCAL int ultraIoctl (void* pObj, int cmd, caddr_t data);
  250. LOCAL STATUS ultraSend (void* pObj, M_BLK_ID pBuf);
  251.   
  252. LOCAL STATUS ultraMCastAdd (void* pObj, char* pAddress);
  253. LOCAL STATUS ultraMCastDel (void* pObj, char* pAddress);
  254. LOCAL STATUS ultraMCastGet (void* pObj, MULTI_TABLE* pTable);
  255. LOCAL STATUS ultraPollSend (void* pObj, M_BLK_ID pBuf);
  256. LOCAL STATUS ultraPollRcv (void* pObj, M_BLK_ID pBuf);
  257. /* This is the only externally visible interface. */
  258. END_OBJ*  ultraLoad (char* initString);
  259. /*
  260.  * Declare our function table.  This is static across all driver
  261.  * instances.
  262.  */
  263. LOCAL NET_FUNCS ultraFuncTable =
  264.     {
  265.     (FUNCPTR)ultraStart, /* Function to start the device. */
  266.     (FUNCPTR)ultraStop, /* Function to stop the device. */
  267.     (FUNCPTR)ultraUnload, /* Unloading function for the driver. */
  268.     (FUNCPTR)ultraIoctl, /* Ioctl function for the driver. */
  269.     (FUNCPTR)ultraSend, /* Send function for the driver. */
  270.     (FUNCPTR)ultraMCastAdd, /* Multicast add function for the driver */
  271.     (FUNCPTR)ultraMCastDel, /* Multicast delete function for the driver */
  272.     (FUNCPTR)ultraMCastGet, /* Multicast get function for the driver */
  273.     (FUNCPTR)ultraPollSend, /* Polling send function */
  274.     (FUNCPTR)ultraPollRcv, /* Polling receive function */
  275.     endEtherAddressForm, /* put address info into a NET_BUFFER */
  276.     endEtherPacketDataGet,  /* get pointer to data in NET_BUFFER */
  277.     endEtherPacketAddrGet  /* Get packet addresses. */
  278.     };
  279. /*******************************************************************************
  280. *
  281. * ultraLoad - initialize the driver and device
  282. *
  283. * This routine initializes the driver and the device to the operational state.
  284. * All of the device-specific parameters are passed in <initString>, which
  285. * expects a string of the following format:
  286. *
  287. * <unit>:<ioAddr>:<memAddr>:<vecNum>:<intLvl>:<config>:<offset>"
  288. *
  289. * This routine can be called in two modes. If it is called with an empty but
  290. * allocated string, it places the name of this device (that is, "ultra") into 
  291. * the <initString> and returns 0.
  292. *
  293. * If the string is allocated and not empty, the routine attempts to load
  294. * the driver using the values specified in the string.
  295. *
  296. * RETURNS: An END object pointer, or NULL on error, or 0 and the name of the
  297. * device if the <initString> was NULL.
  298. */
  299. END_OBJ* ultraLoad
  300.     (
  301.     char * initString /* String to be parsed by the driver. */
  302.     )
  303.     {
  304.     ULTRA_DEVICE * pDrvCtrl;
  305.     
  306.     if (initString == NULL)
  307.         return (NULL);
  308.     
  309.     if (initString[0] == EOS)
  310.         {
  311.         bcopy ((char *)DEV_NAME, initString, DEV_NAME_LEN);
  312.         return (NULL);
  313.         }
  314.     
  315.     DRV_LOG (DRV_DEBUG_LOAD, "ultraLoad: loadingn",
  316.      (int) DEV_NAME, 2, 3, 4, 5, 6);
  317.     /* allocate the device structure */
  318.             
  319.     pDrvCtrl = (ULTRA_DEVICE *)calloc (sizeof (ULTRA_DEVICE), 1);
  320.     if (pDrvCtrl == NULL)
  321. goto errorExit;
  322.     /* parse the init string, filling in the device structure */
  323.     if (ultraParse (pDrvCtrl, initString) == ERROR)
  324. {
  325. logMsg ("ultraLoad: bad initialization stringn",
  326. 1, 2, 3, 4, 5, 6);
  327. goto errorExit;
  328. }
  329.     DRV_LOG (DRV_DEBUG_LOAD,
  330.      "ultraLoad: unit=%d ivec=%x ilevel=%x ioAddr=%x memAddr=%x config=%xn",
  331.      pDrvCtrl->unit,
  332.      pDrvCtrl->ivec, pDrvCtrl->ilevel,
  333.      pDrvCtrl->ioAddr,  pDrvCtrl->memAddr,
  334.      pDrvCtrl->config);
  335.     /* Setup the rest of pDrvCtrl */
  336.     pDrvCtrl->intLevel = irqTable [pDrvCtrl->ilevel].irq;
  337.     pDrvCtrl->transmitPage[0] = ULTRA_TSTART0;
  338.     pDrvCtrl->transmitPage[1] = ULTRA_TSTART1;
  339.     pDrvCtrl->transmitCnt = 0;
  340.     pDrvCtrl->memSize = ULTRA_RAMSIZE;
  341.     pDrvCtrl->cacheFuncs = cacheDmaFuncs;
  342.     /* Reset the device */
  343.     ultraReset (pDrvCtrl);
  344.     /* Get ethernet address from card */
  345.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_PS0 | CMD_STP);
  346.     SYS_IN_BYTE (pDrvCtrl, CTRL_LAN0, &pDrvCtrl->enetAddr[0]);
  347.     SYS_IN_BYTE (pDrvCtrl, CTRL_LAN1, &pDrvCtrl->enetAddr[1]);
  348.     SYS_IN_BYTE (pDrvCtrl, CTRL_LAN2, &pDrvCtrl->enetAddr[2]);
  349.     SYS_IN_BYTE (pDrvCtrl, CTRL_LAN3, &pDrvCtrl->enetAddr[3]);
  350.     SYS_IN_BYTE (pDrvCtrl, CTRL_LAN4, &pDrvCtrl->enetAddr[4]);
  351.     SYS_IN_BYTE (pDrvCtrl, CTRL_LAN5, &pDrvCtrl->enetAddr[5]);
  352.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_STP);
  353.     /* initialize the END and MIB2 parts of the structure */
  354.     if (END_OBJ_INIT (&pDrvCtrl->endObj, (DEV_OBJ *)pDrvCtrl, "ultra",
  355.                       pDrvCtrl->unit, &ultraFuncTable,
  356.                       "SMC Ultra Elite Enhanced Network Driver.") == ERROR)
  357. goto errorExit;
  358.     if (END_MIB_INIT (&pDrvCtrl->endObj, M2_ifType_ethernet_csmacd,
  359.                       &pDrvCtrl->enetAddr[0], 6, ETHERMTU,
  360.       ULTRA_SPEED) == ERROR)
  361. goto errorExit;
  362.     /* Perform memory allocation */
  363.     if (ultraMemInit (pDrvCtrl, 128) == ERROR)
  364. {
  365. #if (CPU_FAMILY==I80X86)
  366. /* Probably the bootrom case, try to get by with fewer clusters. */
  367. if (ultraMemInit (pDrvCtrl, 8) == ERROR)
  368.     goto errorExit;
  369. #else /* (CPU_FAMILY==I80X86) */
  370. goto errorExit;
  371. #endif /* (CPU_FAMILY==I80X86) */
  372. }
  373.     /* Reconfigure the device */
  374.     ultraConfig (pDrvCtrl);
  375.     DRV_LOG (DRV_DEBUG_LOAD, "ultraLoad: donen",
  376.      1, 2, 3, 4, 5, 6);
  377.     /* Set the flags to indicate readiness */
  378.     END_OBJ_READY (&pDrvCtrl->endObj,
  379.     IFF_UP | IFF_RUNNING | IFF_NOTRAILERS | IFF_BROADCAST
  380.     | IFF_MULTICAST | IFF_SIMPLEX);
  381.     
  382.     return (&pDrvCtrl->endObj);
  383. errorExit:
  384.     DRV_LOG (DRV_DEBUG_LOAD, "ultraLoad: errorExitn",
  385.      1, 2, 3, 4, 5, 6);
  386.     if (pDrvCtrl != NULL)
  387. free ((char *)pDrvCtrl);
  388.     return (NULL);
  389.     }
  390.    
  391. /*******************************************************************************
  392. *
  393. * ultraParse - parse the init string
  394. *
  395. * Parse the input string.  Fill in values in the driver control structure.
  396. * The initialization string format is:
  397. * <unit>:<ioAddr>:<memAddr>:<vecNum>:<intLvl>:<config>:<offset>"
  398. *
  399. * .IP <unit>
  400. * Device unit number, a small integer.
  401. * .IP <ioAddr>
  402. * I/O address
  403. * .IP <memAddr>
  404. * Memory address, assumed to be 16k bytes in length.
  405. * .IP <vecNum>
  406. * Interrupt vector number (used with sysIntConnect()).
  407. * .IP <intLvl>
  408. * Interrupt level.
  409. * .IP <config>
  410. * Ultra config (0: RJ45 + AUI(Thick)  1: RJ45 + BNC(Thin)).
  411. * .IP <offset>
  412. * Memory offset for alignment.
  413. *
  414. * RETURNS: OK, or ERROR if any arguments are invalid.
  415. */
  416. LOCAL STATUS ultraParse
  417.     (
  418.     ULTRA_DEVICE * pDrvCtrl, /* device pointer */
  419.     char * initString /* information string */
  420.     )
  421.     {
  422.     char * tok;
  423.     char * pHolder = NULL;
  424.     
  425.     /* Parse the initString */
  426.     /* Unit number. */
  427.     tok = strtok_r (initString, ":", &pHolder);
  428.     if (tok == NULL)
  429. return (ERROR);
  430.     pDrvCtrl->unit = atoi (tok);
  431.     /* I/O address. */
  432.     
  433.     tok = strtok_r (NULL, ":", &pHolder);
  434.     if (tok == NULL)
  435. return (ERROR);
  436.     pDrvCtrl->ioAddr = strtoul (tok, NULL, 16);
  437.     /* Memory address. */
  438.     
  439.     tok = strtok_r (NULL, ":", &pHolder);
  440.     if (tok == NULL)
  441. return (ERROR);
  442.     pDrvCtrl->memAddr = strtoul (tok, NULL, 16);
  443.     /* Interrupt vector. */
  444.     tok = strtok_r (NULL, ":", &pHolder);
  445.     if (tok == NULL)
  446. return (ERROR);
  447.     pDrvCtrl->ivec = strtoul (tok, NULL, 16);
  448.     /* Interrupt level. */
  449.     tok = strtok_r (NULL, ":", &pHolder);
  450.     if (tok == NULL)
  451. return (ERROR);
  452.     pDrvCtrl->ilevel = strtoul (tok, NULL, 16);
  453.     /* config */
  454.     
  455.     tok = strtok_r (NULL, ":", &pHolder);
  456.     if (tok == NULL)
  457. return (ERROR);
  458.     pDrvCtrl->config = strtoul (tok, NULL, 16);
  459.     /* offset */
  460.     
  461.     tok = strtok_r (NULL, ":", &pHolder);
  462.     if (tok == NULL)
  463. return (ERROR);
  464.     pDrvCtrl->offset = strtoul (tok, NULL, 16);
  465.     
  466.     return (OK);
  467.     }
  468. /*******************************************************************************
  469. *
  470. * ultraMemInit - initialize memory for the chip
  471. *
  472. * Using data in the control structure, setup and initialize the memory
  473. * areas needed.  If the memory address is not already specified, then allocate
  474. * cache safe memory.
  475. *
  476. * RETURNS: OK or ERROR.
  477. */
  478. LOCAL STATUS ultraMemInit
  479.     (
  480.     ULTRA_DEVICE * pDrvCtrl, /* device to be initialized */
  481.     int clNum /* number of clusters to allocate */
  482.     )
  483.     {
  484.     CL_DESC clDesc;                      /* cluster description */
  485.     M_CL_CONFIG ultraMclBlkConfig;
  486.     bzero ((char *)&ultraMclBlkConfig, sizeof(ultraMclBlkConfig));
  487.     bzero ((char *)&clDesc, sizeof(clDesc));
  488.     
  489.     pDrvCtrl->endObj.pNetPool = (NET_POOL_ID) malloc (sizeof(NET_POOL));
  490.     if (pDrvCtrl->endObj.pNetPool == NULL)
  491.         return (ERROR);
  492.     clDesc.clNum   = clNum;
  493.     clDesc.clSize  = MEM_ROUND_UP(ULTRA_BUFSIZ + pDrvCtrl->offset);
  494.     clDesc.memSize = ((clDesc.clNum * (clDesc.clSize + 4)) + 4);
  495.     ultraMclBlkConfig.mBlkNum = clDesc.clNum * 2;
  496.     ultraMclBlkConfig.clBlkNum = clDesc.clNum;
  497.     /*
  498.      * mBlk and cluster configuration memory size initialization
  499.      * memory size adjusted to hold the netPool pointer at the head.
  500.      */
  501.     ultraMclBlkConfig.memSize =
  502.       (ultraMclBlkConfig.mBlkNum * (M_BLK_SZ + sizeof (long)))
  503.       + (ultraMclBlkConfig.clBlkNum * (CL_BLK_SZ + sizeof (long)));
  504.     ultraMclBlkConfig.memArea = (char *) memalign(sizeof (long),
  505.   ultraMclBlkConfig.memSize);
  506.     if (ultraMclBlkConfig.memArea == NULL)
  507. {
  508. free (pDrvCtrl->endObj.pNetPool);
  509. pDrvCtrl->endObj.pNetPool = NULL;
  510. return (ERROR);
  511. }
  512.     
  513.     clDesc.memArea = (char *) malloc (clDesc.memSize);
  514.     if (clDesc.memArea == NULL)
  515. {
  516. free (ultraMclBlkConfig.memArea);
  517. free (pDrvCtrl->endObj.pNetPool);
  518. pDrvCtrl->endObj.pNetPool = NULL;
  519. return (ERROR);
  520. }
  521.     /* Initialize the net buffer pool with transmit buffers */
  522.     if (netPoolInit (pDrvCtrl->endObj.pNetPool, &ultraMclBlkConfig,
  523.      &clDesc, 1, NULL) == ERROR)
  524. {
  525. free (clDesc.memArea);
  526. free (ultraMclBlkConfig.memArea);
  527. free (pDrvCtrl->endObj.pNetPool);
  528. pDrvCtrl->endObj.pNetPool = NULL;
  529. return (ERROR);
  530. }
  531.     pDrvCtrl->clPoolId = clPoolIdGet (pDrvCtrl->endObj.pNetPool,
  532.       ULTRA_BUFSIZ + pDrvCtrl->offset, FALSE);
  533.     DRV_LOG (DRV_DEBUG_LOAD, "%s%d: ultraMemInit: %d clustersn",
  534.      (int) DEV_NAME, pDrvCtrl->unit, clNum, 4, 5, 6);
  535.     return (OK);
  536.     }
  537. /******************************************************************************
  538. *
  539. * ultraReset - reset the ultra device
  540. *
  541. * Stop and reset the Ultra chip.
  542. *
  543. * RETURNS: N/A
  544. */
  545. LOCAL void ultraReset
  546.     (
  547.     ULTRA_DEVICE * pDrvCtrl
  548.     )
  549.     {     
  550.     int tmp;
  551.     DRV_LOG (DRV_DEBUG_LOAD, "%s%d: ultraResetn",
  552.      (int)DEV_NAME, pDrvCtrl->unit,
  553.      3, 4, 5, 6);
  554.     SYS_OUT_BYTE (pDrvCtrl, LAN_INTMASK, 0x00);
  555.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_STP);
  556.     do
  557. SYS_IN_BYTE (pDrvCtrl, LAN_INTSTAT, &tmp);
  558.     while ((tmp & ISTAT_RST) != ISTAT_RST);
  559.     SYS_OUT_BYTE (pDrvCtrl, CTRL_CON, CON_RESET);
  560.     SYS_OUT_BYTE (pDrvCtrl, CTRL_CON, 0x00);
  561.     SYS_OUT_BYTE (pDrvCtrl, CTRL_HARD, 0x08);
  562.     taskDelay (sysClkRateGet () >> 2);
  563.     SYS_OUT_BYTE (pDrvCtrl, CTRL_CON, CON_MENABLE);
  564.     SYS_OUT_BYTE (pDrvCtrl, LAN_INTSTAT, 0xff);
  565.     DRV_LOG (DRV_DEBUG_LOAD, "%s%d: ultraReset donen",
  566.      (int)DEV_NAME, pDrvCtrl->unit,
  567.      3, 4, 5, 6);
  568.     }
  569. /******************************************************************************
  570. *
  571. * ultraStart - start the device
  572. *
  573. * This function calls BSP functions to connect interrupts and start the
  574. * device running in interrupt mode.
  575. *
  576. * RETURNS: OK or ERROR
  577. *
  578. */
  579. LOCAL STATUS ultraStart
  580.     (
  581.     void * pObj /* device ID */
  582.     )
  583.     {
  584.     STATUS result;
  585.     ULTRA_DEVICE * pDrvCtrl = pObj;
  586.     
  587.     DRV_LOG (DRV_DEBUG_LOAD, "%s%d: ultraStartn",
  588.      (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  589.     
  590.     SYS_INT_CONNECT (pDrvCtrl, ultraInt, (int)pDrvCtrl, &result);
  591.     if (result == ERROR)
  592. {
  593. DRV_LOG (DRV_DEBUG_LOAD,
  594.  "%s%d: ultraStart: could not attach interruptn",
  595.  (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  596. return (ERROR);
  597. }
  598.     SYS_INT_ENABLE (pDrvCtrl);
  599.     /* start the device */
  600.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_STA);
  601.     /* initialize Transmit Configuration Register */
  602.     SYS_OUT_BYTE (pDrvCtrl, LAN_TCON, 0x00);
  603.     /* enable interrupts */
  604.       
  605.     SYS_OUT_BYTE (pDrvCtrl, LAN_INTMASK, 0x00);
  606.     SYS_OUT_BYTE (pDrvCtrl, CTRL_INT, INT_ENABLE);
  607.     SYS_OUT_BYTE (pDrvCtrl, LAN_INTMASK,
  608.   IM_OVWE | IM_TXEE | IM_PTXE | IM_PRXE);
  609.     return (OK);
  610.     }
  611. /******************************************************************************
  612. *
  613. * ultraStop - stop the device
  614. *
  615. * This function calls BSP functions to disconnect interrupts and stop
  616. * the device from operating in interrupt mode.
  617. *
  618. * RETURNS: OK or ERROR.
  619. */
  620. LOCAL STATUS ultraStop
  621.     (
  622.     void * pObj /* device to be stopped */
  623.     )
  624.     {     
  625.     int tmp;
  626.     int oldLevel;
  627.     STATUS result = OK;
  628.     ULTRA_DEVICE * pDrvCtrl = pObj;
  629.     DRV_LOG (DRV_DEBUG_LOAD, "%s%d: ultraStopn",
  630.      (int)DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  631.     /* Stop/disable the device. */
  632.     oldLevel = intLock ();
  633.     SYS_OUT_BYTE (pDrvCtrl, LAN_INTMASK, 0x00);
  634.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_STP);
  635.     do
  636. SYS_IN_BYTE (pDrvCtrl, LAN_INTSTAT, &tmp);
  637.     while ((tmp & ISTAT_RST) != ISTAT_RST);
  638.     SYS_OUT_BYTE (pDrvCtrl, LAN_RCON, 0x00);
  639.     SYS_OUT_BYTE (pDrvCtrl, LAN_TCON, TCON_LB1);
  640.     SYS_OUT_BYTE (pDrvCtrl, LAN_INTSTAT, 0xff);
  641.     SYS_INT_DISABLE (pDrvCtrl);
  642.     intUnlock (oldLevel);
  643.     
  644.     /* Remove the ISR */
  645.     
  646.     SYS_INT_DISCONNECT (pDrvCtrl, ultraInt, (int)pDrvCtrl, &result);
  647.     if (result == ERROR)
  648. {
  649. DRV_LOG (DRV_DEBUG_LOAD, "Could not disconnect interrupt!n",
  650. 1, 2, 3, 4, 5, 6);
  651. }
  652.     return (result);
  653.     }
  654. /******************************************************************************
  655. *
  656. * ultraConfig - reconfigure the interface under us.
  657. *
  658. * Reconfigure the interface setting promiscuous mode, and changing the
  659. * multicast interface list.
  660. *
  661. * RETURNS: N/A.
  662. */
  663. LOCAL void ultraConfig
  664.     (
  665.     ULTRA_DEVICE * pDrvCtrl /* device to be re-configured */
  666.     )
  667.     {
  668.     int i;
  669.     int tmp;
  670.     UCHAR rcon;
  671.     UCHAR memAddr;
  672.     UCHAR intLevel;
  673.     UCHAR ioAddr;
  674.     UCHAR eeromGcon;
  675.     DRV_LOG (DRV_DEBUG_LOAD, "%s%d: ultraConfig: flags=%xn",
  676.      (int) DEV_NAME, pDrvCtrl->unit, pDrvCtrl->flags, 4, 5, 6);
  677.       
  678.     /* Mask interrupts */
  679.     SYS_OUT_BYTE (pDrvCtrl, LAN_INTMASK, 0x00);
  680.     /* program Command Register for page 0, stop device */
  681.     
  682.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_STP);
  683.     do
  684. SYS_IN_BYTE (pDrvCtrl, LAN_INTSTAT, &tmp);
  685.     while ((tmp & ISTAT_RST) != ISTAT_RST);
  686.     
  687.     /* get values set by EEROM */
  688.     SYS_OUT_BYTE (pDrvCtrl, CTRL_HARD, 0x80);
  689.     SYS_IN_BYTE (pDrvCtrl, CTRL_GCON, &eeromGcon);
  690.     /* IO address, Memory address, Interrupt request */
  691.     memAddr = (((pDrvCtrl->memAddr & 0x1e000) >> 13)
  692.        | ((pDrvCtrl->memAddr & 0x20000) >> 10));
  693.     intLevel = (((pDrvCtrl->intLevel & 0x03) << 2)
  694. | ((pDrvCtrl->intLevel & 0x04) << 6));
  695.     ioAddr = (((pDrvCtrl->ioAddr & 0xe000) >> 8)
  696.       | ((pDrvCtrl->ioAddr & 0x01e0) >> 4));
  697.     SYS_OUT_BYTE (pDrvCtrl, CTRL_HARD, 0x80);
  698.     SYS_OUT_BYTE (pDrvCtrl, CTRL_IOADDR, ioAddr);
  699.     SYS_OUT_BYTE (pDrvCtrl, CTRL_MEMADDR, memAddr | 0x10);
  700.     if (pDrvCtrl->config == 1)
  701.         SYS_OUT_BYTE (pDrvCtrl, CTRL_GCON,
  702.       irqTable [pDrvCtrl->intLevel].reg | (eeromGcon & 0x20));
  703.     else if (pDrvCtrl->config == 2)
  704.         SYS_OUT_BYTE (pDrvCtrl, CTRL_GCON,
  705.       (irqTable [pDrvCtrl->intLevel].reg | 0x02
  706.        | (eeromGcon & 0x20)));
  707.     else
  708.         SYS_OUT_BYTE (pDrvCtrl, CTRL_GCON,
  709.       irqTable [pDrvCtrl->intLevel].reg | (eeromGcon & 0x22));
  710.     /* set FINE16 bit in BIO register to get finer res for M16CS decode */
  711.     SYS_IN_BYTE (pDrvCtrl, CTRL_BIO, &tmp); 
  712.     SYS_OUT_BYTE (pDrvCtrl, CTRL_BIO, tmp | BIO_FINE16);
  713.     SYS_OUT_BYTE (pDrvCtrl, CTRL_HARD, 0x00);
  714.     /* 16 bit enable */
  715.     SYS_OUT_BYTE (pDrvCtrl, CTRL_BIOS, BIOS_M16EN);
  716.     /* initialize Data Configuration Register */
  717.     SYS_OUT_BYTE (pDrvCtrl, LAN_DCON, DCON_BSIZE1 | DCON_BUS16);
  718.     /* initialize Receive Configuration Register */
  719.    
  720.     ultraAddrFilterSet (pDrvCtrl);
  721.     /* always accept broadcast packets */
  722.     rcon = RCON_BROAD;
  723.     if (END_MULTI_LST_CNT(&pDrvCtrl->endObj) > 0)
  724. rcon |= RCON_GROUP;
  725.     if (END_FLAGS_GET(&pDrvCtrl->endObj) & IFF_PROMISC)
  726. rcon |= (RCON_PROM | RCON_GROUP);
  727.     if (END_FLAGS_GET(&pDrvCtrl->endObj) & (IFF_PROMISC|IFF_ALLMULTI))
  728. {
  729. /* receive all multicast packets */
  730. rcon |= RCON_GROUP;
  731. /* Set multicast hashing array to all 1's */
  732. for (i = 0; i < 8; ++i)
  733.     pDrvCtrl->mcastFilter[i] = 0xff;
  734. }
  735.     SYS_OUT_BYTE (pDrvCtrl, LAN_RCON, rcon);
  736.     if (rcon & RCON_GROUP)
  737. DRV_LOG (DRV_DEBUG_IOCTL, "%s%d: Setting multicast mode on!n",
  738.  (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  739.     if (rcon & RCON_PROM)
  740. DRV_LOG (DRV_DEBUG_IOCTL, "%s%d: Setting promiscuous mode on!n",
  741.  (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  742.     /* place the Ultra in external LOOPBACK mode */
  743.     SYS_OUT_BYTE (pDrvCtrl, LAN_TCON, TCON_LB1);
  744.     /* initialize Receive Buffer Ring */
  745.     SYS_OUT_BYTE (pDrvCtrl, LAN_RSTART, ULTRA_PSTART);
  746.     SYS_OUT_BYTE (pDrvCtrl, LAN_RSTOP, ULTRA_PSTOP);
  747.     SYS_OUT_BYTE (pDrvCtrl, LAN_BOUND, ULTRA_PSTART);
  748.     /* clear Interrupt Status Register */
  749.  
  750.     SYS_OUT_BYTE (pDrvCtrl, LAN_INTSTAT, 0xff);
  751.     /* initialize Interrupt Mask Register */
  752.     SYS_OUT_BYTE (pDrvCtrl, LAN_INTMASK, 0x00);
  753.     /* Set command register for page 1 */
  754.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_PS0 | CMD_STP);
  755.     /* Program ethernet address (page 1) */
  756.     SYS_OUT_BYTE (pDrvCtrl, LAN_STA0, pDrvCtrl->enetAddr[0]);
  757.     SYS_OUT_BYTE (pDrvCtrl, LAN_STA1, pDrvCtrl->enetAddr[1]);
  758.     SYS_OUT_BYTE (pDrvCtrl, LAN_STA2, pDrvCtrl->enetAddr[2]);
  759.     SYS_OUT_BYTE (pDrvCtrl, LAN_STA3, pDrvCtrl->enetAddr[3]);
  760.     SYS_OUT_BYTE (pDrvCtrl, LAN_STA4, pDrvCtrl->enetAddr[4]);
  761.     SYS_OUT_BYTE (pDrvCtrl, LAN_STA5, pDrvCtrl->enetAddr[5]);
  762.     /* Program multicast mask (page 1) */
  763.     SYS_OUT_BYTE (pDrvCtrl, LAN_MAR0, pDrvCtrl->mcastFilter[0]);
  764.     SYS_OUT_BYTE (pDrvCtrl, LAN_MAR1, pDrvCtrl->mcastFilter[1]);
  765.     SYS_OUT_BYTE (pDrvCtrl, LAN_MAR2, pDrvCtrl->mcastFilter[2]);
  766.     SYS_OUT_BYTE (pDrvCtrl, LAN_MAR3, pDrvCtrl->mcastFilter[3]);
  767.     SYS_OUT_BYTE (pDrvCtrl, LAN_MAR4, pDrvCtrl->mcastFilter[4]);
  768.     SYS_OUT_BYTE (pDrvCtrl, LAN_MAR5, pDrvCtrl->mcastFilter[5]);
  769.     SYS_OUT_BYTE (pDrvCtrl, LAN_MAR6, pDrvCtrl->mcastFilter[6]);
  770.     SYS_OUT_BYTE (pDrvCtrl, LAN_MAR7, pDrvCtrl->mcastFilter[7]);
  771.     /* Initialize current page pointer (page 1) */
  772.     SYS_OUT_BYTE (pDrvCtrl, LAN_CURR, ULTRA_PSTART + 1);
  773.     pDrvCtrl->nextPacket = ULTRA_PSTART + 1;
  774.     /* Switch to page 2 registers */
  775.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_PS1 | CMD_STP);
  776.     /* Program wait states (0) */
  777.     SYS_OUT_BYTE (pDrvCtrl, LAN_ENH, 0x00);
  778.     /* put the Ultra in START mode */
  779.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_STA);
  780.     /* Take interface out of loopback */
  781.     SYS_OUT_BYTE (pDrvCtrl, LAN_TCON, 0x00);
  782.     if (!(pDrvCtrl->flags & ULTRA_POLLING))
  783. {
  784. SYS_OUT_BYTE (pDrvCtrl, CTRL_INT, INT_ENABLE);
  785. SYS_OUT_BYTE (pDrvCtrl, LAN_INTMASK,
  786.       IM_OVWE | IM_TXEE | IM_PTXE | IM_PRXE);
  787. }
  788.     }
  789. /******************************************************************************
  790. *
  791. * ultraInt - handle controller interrupt
  792. *
  793. * This routine is called at interrupt level in response to an interrupt from
  794. * the controller.
  795. *
  796. * RETURNS: N/A.
  797. */
  798. LOCAL void ultraInt
  799.     (
  800.     ULTRA_DEVICE * pDrvCtrl /* interrupting device */
  801.     )
  802.     {
  803.     UCHAR istat;
  804.     
  805.     /* Acknowledge interrupt, get Transmit/Receive status */
  806.     pDrvCtrl->istat = 0;
  807.     do
  808. {
  809. SYS_IN_BYTE (pDrvCtrl, LAN_INTSTAT, &istat);
  810. SYS_OUT_BYTE (pDrvCtrl, LAN_INTSTAT, istat);
  811. pDrvCtrl->istat |= istat;
  812. }
  813.     while (istat != 0);
  814.     SYS_IN_BYTE (pDrvCtrl, LAN_TSTAT, &pDrvCtrl->tstat);
  815.     SYS_IN_BYTE (pDrvCtrl, LAN_RSTAT, &pDrvCtrl->rstat);
  816.     DRV_LOG (DRV_DEBUG_INT,
  817.      "%s%d: istat %x tstat %x rstat %x flags %xn",
  818.      (int) DEV_NAME, pDrvCtrl->unit,
  819.      pDrvCtrl->istat, pDrvCtrl->tstat,
  820.      pDrvCtrl->rstat, pDrvCtrl->flags);
  821.     /* Receive-error */
  822.     if (pDrvCtrl->istat & ISTAT_RXE)
  823. END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  824.     /* Receive, Overwrite */
  825.     if (pDrvCtrl->istat & (ISTAT_PRX | ISTAT_OVW))
  826. {
  827. if (pDrvCtrl->istat & ISTAT_OVW)
  828.     {
  829.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  830.     DRV_LOG (DRV_DEBUG_RX | DRV_DEBUG_INT | DRV_DEBUG_ERR,
  831.      "%s%d: overwrite errorn",
  832.      (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  833.     }
  834. if (!(pDrvCtrl->flags & ULTRA_RCV_HANDLING_FLAG))
  835.     {
  836.     if (netJobAdd ((FUNCPTR) ultraHandleRcvInt,
  837.    (int) pDrvCtrl, 0, 0, 0, 0) == ERROR)
  838. {
  839. /* Error - will have to wait until next RX interrupt recv'd */
  840. logMsg ("%s%d: failed to queue ultraHandleRcvIntn",
  841. (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  842. /* failed netJobAdd causes panic, stop device */
  843. SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_STP);
  844. return;
  845. }
  846.     pDrvCtrl->flags |= ULTRA_RCV_HANDLING_FLAG;
  847.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_PS0);
  848.     SYS_IN_BYTE (pDrvCtrl, LAN_CURR, &pDrvCtrl->current);
  849.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, 0);
  850.     DRV_LOG (DRV_DEBUG_RX | DRV_DEBUG_INT,
  851.      "%s%d: queued ultraHandleRcvInt: curr=%x next=%xn",
  852.      (int) DEV_NAME, pDrvCtrl->unit,
  853.      pDrvCtrl->current, pDrvCtrl->nextPacket, 5, 6);
  854.     }
  855. }
  856.     /* Transmit-error, Transmit */
  857.     if (pDrvCtrl->istat & (ISTAT_TXE | ISTAT_PTX))
  858. {
  859. if (pDrvCtrl->istat & ISTAT_TXE)
  860.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, -1);
  861. if ((pDrvCtrl->istat & ISTAT_TXE)
  862.     || (pDrvCtrl->tstat & (TSTAT_ABORT | TSTAT_UNDER | TSTAT_CDH
  863.    | TSTAT_OWC | TSTAT_PTX)))
  864.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_ERRS, +1);
  865. pDrvCtrl->flags &= ~ULTRA_TX_IN_PROGRESS;
  866. if (pDrvCtrl->flags & ULTRA_TX_BLOCKED)
  867.     {
  868.     DRV_LOG (DRV_DEBUG_TX | DRV_DEBUG_INT,
  869.      "%s%d: queuing muxTxRestartn",
  870.      (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  871.     if (netJobAdd ((FUNCPTR)muxTxRestart,
  872.    (int) &pDrvCtrl->endObj, 0, 0, 0, 0) == ERROR)
  873. {
  874. /* Error - can't queue, transmitter is hung. */
  875. logMsg ("%s%d: failed to queue muxTxRestartn",
  876. (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  877. /* failed netJobAdd causes panic, stop device */
  878. SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_STP);
  879. return;
  880. }
  881.     pDrvCtrl->flags &= ~ULTRA_TX_BLOCKED;
  882.     }
  883. }
  884.     }
  885. /******************************************************************************
  886. *
  887. * ultraPacketGet - get next received message
  888. *
  889. * Get next received packet into the supplied buffer.
  890. *
  891. * RETURNS: length of the next packet, or a negative number if none available.
  892. */
  893. LOCAL int ultraPacketGet
  894.     (
  895.     ULTRA_DEVICE * pDrvCtrl,
  896.     char * pDst
  897.     )
  898.     {
  899.     int len;
  900.     char * pSrc;
  901.     int wrapSize = 0;
  902.     UINT packetSize;
  903.     int oldLevel;
  904.     ULTRA_HEADER * pH;
  905.     if (pDrvCtrl->nextPacket == pDrvCtrl->current)
  906. return (0);
  907.     /* Invalidate cache and get pointer to header */
  908.     ULTRA_CACHE_INVALIDATE ((UCHAR *)(pDrvCtrl->memAddr + (ULTRA_PSTART << 8)),
  909.     (pDrvCtrl->memSize - (ULTRA_PSTART << 8)));
  910.     pH = (ULTRA_HEADER *)(pDrvCtrl->memAddr + (pDrvCtrl->nextPacket << 8));
  911.     DRV_LOG (DRV_DEBUG_RX, "%s%d: ultraPacketGet: %02x/%d/%02x/%02xn",
  912.      (int) DEV_NAME, pDrvCtrl->unit,
  913.      pH->next, (((UINT)pH->uppByteCnt << 8) + pH->lowByteCnt),
  914.      pDrvCtrl->nextPacket, pDrvCtrl->uppByteCnt);
  915.     if ((pH->next < ULTRA_PSTART) || (pH->next >= ULTRA_PSTOP))
  916. {
  917. pH->next = pDrvCtrl->nextPacket + pDrvCtrl->uppByteCnt + 1;
  918. DRV_LOG (DRV_DEBUG_RX | DRV_DEBUG_ERR,
  919.  "%s%d: ultraPacketGet: fix pH->next (%x)n",
  920.  (int) DEV_NAME, pDrvCtrl->unit, pH->next, 4, 5, 6);
  921. if (pH->next >= ULTRA_PSTOP)
  922.     pH->next = ULTRA_PSTART + (pH->next - ULTRA_PSTOP);
  923. }
  924.     if (pH->rstat & RSTAT_PRX)
  925. {
  926. /* 3Com says this status marks a packet bit-shifted in memory;
  927.  * the data cannot be trusted but the NIC header is OK.
  928.  */
  929. if (pH->rstat & (RSTAT_DFR | RSTAT_DIS))
  930.     {
  931.     DRV_LOG (DRV_DEBUG_RX | DRV_DEBUG_ERR,
  932.      "%s%d: ultraPacketGet: bit-shifted packetn",
  933.      (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  934.     packetSize = -2;
  935.     goto doneGet;
  936.     }
  937. }
  938.     else
  939. {
  940. DRV_LOG (DRV_DEBUG_RX | DRV_DEBUG_ERR,
  941.  "%s%d: ultraPacketGet: corrupted packetn",
  942.  (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  943. packetSize = -2;
  944. goto doneGet;
  945. }
  946.     /* Compute packet size, excluding Ultra header */
  947.     pSrc = ((char *)pH) + sizeof(ULTRA_HEADER);
  948.     packetSize = (((UINT)pH->uppByteCnt << 8) + pH->lowByteCnt
  949.   - sizeof(ULTRA_HEADER));
  950.     if ((packetSize < ULTRA_MIN_SIZE) || (packetSize > ULTRA_MAX_SIZE))
  951. {
  952. END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  953. DRV_LOG (DRV_DEBUG_RX | DRV_DEBUG_ERR,
  954.  "%s%d: ultraPacketGet: bad size packet %dn",
  955.  (int) DEV_NAME, pDrvCtrl->unit, packetSize, 4, 5, 6);
  956. packetSize = -2;
  957. goto doneGet;
  958. }
  959.     /* copy separated frame to network buffer */
  960.     len = packetSize;
  961.     if ((pSrc+packetSize) > (char *)(pDrvCtrl->memAddr + (ULTRA_PSTOP << 8)))
  962. {
  963. wrapSize = (char *)(pDrvCtrl->memAddr + (ULTRA_PSTOP << 8)) - pSrc;
  964. bcopy (pSrc, pDst, wrapSize);
  965. len -= wrapSize;
  966. pSrc = (char *) (pDrvCtrl->memAddr + (ULTRA_PSTART << 8));
  967. pDst += wrapSize;
  968. }
  969.     bcopy (pSrc, pDst, len);
  970.     
  971.     DRV_LOG (DRV_DEBUG_RX, "%s%d: ultraPacketGet: c/n=%x/%x len/next=%d/%xn",
  972.      (int) DEV_NAME, pDrvCtrl->unit,
  973.      pDrvCtrl->current, pDrvCtrl->nextPacket,
  974.      (((UINT)pH->uppByteCnt << 8) + pH->lowByteCnt), pH->next);
  975.  
  976. doneGet:
  977.     /* Mark packet as received. */
  978.     oldLevel = intLock ();
  979.     pDrvCtrl->nextPacket = pH->next;
  980.     pDrvCtrl->uppByteCnt = pH->uppByteCnt;
  981.     if (pDrvCtrl->nextPacket != ULTRA_PSTART)
  982. SYS_OUT_BYTE (pDrvCtrl, LAN_BOUND, pDrvCtrl->nextPacket - 1);
  983.     else
  984. SYS_OUT_BYTE (pDrvCtrl, LAN_BOUND, ULTRA_PSTOP - 1);
  985.     intUnlock (oldLevel);
  986.     return (packetSize);
  987.     }
  988. /******************************************************************************
  989. *
  990. * ultraRecv - process the next incoming packet.
  991. *
  992. * Handle one incoming packet.  The packet is checked for errors.
  993. *
  994. * RETURNS: OK or ERROR.
  995. */
  996. LOCAL STATUS ultraRecv
  997.     (
  998.     ULTRA_DEVICE * pDrvCtrl /* interrupting device */
  999.     )
  1000.     {
  1001.     int len;
  1002.     char * pBuf;
  1003.     CL_BLK_ID pClBlk;
  1004.     M_BLK_ID pMblk;      /* MBLK to send upstream */
  1005.     /* Allocate an MBLK, and a replacement buffer */
  1006.     pBuf = netClusterGet (pDrvCtrl->endObj.pNetPool, pDrvCtrl->clPoolId);
  1007.     if (!pBuf)
  1008. {
  1009. DRV_LOG (DRV_DEBUG_RX, "%s%d: ultraRecv: Out of clusters!n",
  1010.  (int) DEV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  1011. pDrvCtrl->lastError.errCode = END_ERR_WARN;
  1012. pDrvCtrl->lastError.pMesg = "out of clusters";
  1013. muxError (&pDrvCtrl->endObj, &pDrvCtrl->lastError);
  1014. return (ERROR);
  1015. }
  1016.     /* Read in offset packet so IP header is long-aligned */
  1017.     len = ultraPacketGet (pDrvCtrl, pBuf + pDrvCtrl->offset);
  1018.     if (len <= 0)
  1019. {
  1020. DRV_LOG (DRV_DEBUG_RX, "%s%d: ultraRecv: bad packet (%d)n",
  1021.  (int) DEV_NAME, pDrvCtrl->unit, len, 0, 0, 0);
  1022. END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1023. netClFree (pDrvCtrl->endObj.pNetPool, (UCHAR *) pBuf);
  1024. return (OK);
  1025. }
  1026.     pMblk = mBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT, MT_DATA);
  1027.     if (!pMblk)
  1028. {
  1029. DRV_LOG (DRV_DEBUG_RX, "%s%d: ultraRecv: out of M blocksn",
  1030.  (int) DEV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  1031. pDrvCtrl->lastError.errCode = END_ERR_WARN;
  1032. pDrvCtrl->lastError.pMesg = "out of M blocks.";
  1033. muxError (&pDrvCtrl->endObj, &pDrvCtrl->lastError);
  1034. END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
  1035. netClFree (pDrvCtrl->endObj.pNetPool, (UCHAR *) pBuf);
  1036. return (OK);
  1037. }
  1038.     pClBlk = netClBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT);
  1039.     if (!pClBlk)
  1040. {
  1041. DRV_LOG (DRV_DEBUG_RX, "%s%d: ultraRecv: out of CL blocksn",
  1042.  (int) DEV_NAME, pDrvCtrl->unit, 0, 0, 0, 0);
  1043. pDrvCtrl->lastError.errCode = END_ERR_WARN;
  1044. pDrvCtrl->lastError.pMesg = "out of CL blocks.";
  1045. muxError (&pDrvCtrl->endObj, &pDrvCtrl->lastError);
  1046. netMblkFree (pDrvCtrl->endObj.pNetPool, (M_BLK_ID)pMblk);
  1047. netClFree (pDrvCtrl->endObj.pNetPool, (UCHAR *) pBuf);
  1048. return (OK);
  1049. }
  1050.     /* Associate the data pointer with the MBLK */
  1051.     netClBlkJoin (pClBlk, pBuf, ULTRA_BUFSIZ, NULL, 0, 0, 0);
  1052.     
  1053.     /* Associate the data pointer with the MBLK */
  1054.     netMblkClJoin (pMblk, pClBlk);
  1055.     pMblk->mBlkHdr.mFlags |= M_PKTHDR;
  1056.     pMblk->mBlkHdr.mLen    = len;
  1057.     pMblk->mBlkPktHdr.len  = len;
  1058.     pMblk->mBlkHdr.mData  += pDrvCtrl->offset; /* match ultraPacketGet */
  1059.     /* Call the upper layer's receive routine. */
  1060.     END_RCV_RTN_CALL (&pDrvCtrl->endObj, pMblk);
  1061.     /* Record received packet */
  1062.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
  1063.     return (OK);
  1064.     }
  1065. /******************************************************************************
  1066. *
  1067. * ultraHandleRcvInt - task level interrupt service for input packets
  1068. *
  1069. * This routine is called at task level indirectly by the interrupt
  1070. * service routine to do any message received processing.
  1071. *
  1072. * RETURNS: N/A.
  1073. */
  1074. LOCAL void ultraHandleRcvInt
  1075.     (
  1076.     ULTRA_DEVICE * pDrvCtrl /* interrupting device */
  1077.     )
  1078.     {
  1079.     DRV_LOG (DRV_DEBUG_RX,
  1080.      "%s%d: ultraHandleRcvInt: begin, flags=%x curr=%x next=%xn",
  1081.      (int) DEV_NAME, pDrvCtrl->unit,
  1082.      pDrvCtrl->flags, pDrvCtrl->current, pDrvCtrl->nextPacket, 6);
  1083.     while (TRUE)
  1084. {
  1085. int oldLevel;
  1086.     
  1087. /* Refresh the current pointer, and check if done. */
  1088. oldLevel = intLock ();
  1089. SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_PS0);
  1090. SYS_IN_BYTE (pDrvCtrl, LAN_CURR, &pDrvCtrl->current);
  1091. SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, 0);
  1092. if (pDrvCtrl->nextPacket == pDrvCtrl->current)
  1093.     {
  1094.     /* all packets consumed. */
  1095.     pDrvCtrl->flags &= ~ULTRA_RCV_HANDLING_FLAG;
  1096.     intUnlock (oldLevel);
  1097.     break;
  1098.     }
  1099. intUnlock (oldLevel);
  1100. if (ultraRecv (pDrvCtrl) == ERROR)
  1101.     {
  1102.     /*
  1103.      * ultraRecv only errors if out of clusters or the like.  We
  1104.      * need to exit this loop and let the netTask run for a bit
  1105.      * in order for it to clean up its memory.
  1106.      */
  1107.     oldLevel = intLock ();
  1108.     pDrvCtrl->flags &= ~ULTRA_RCV_HANDLING_FLAG;
  1109.     intUnlock (oldLevel);
  1110.     break;
  1111.     }
  1112. }
  1113.     DRV_LOG (DRV_DEBUG_RX,
  1114.      "%s%d: ultraHandleRcvInt: done, flags=%x curr=%x next=%xn",
  1115.      (int) DEV_NAME, pDrvCtrl->unit,
  1116.      pDrvCtrl->flags, pDrvCtrl->current, pDrvCtrl->nextPacket, 6);
  1117.     }
  1118. /******************************************************************************
  1119. *
  1120. * ultraSend - the driver send routine
  1121. *
  1122. * This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
  1123. * The buffer must already have the addressing information properly installed
  1124. * in it.  This is done by a higher layer.  The last arguments are a free
  1125. * routine to be called when the device is done with the buffer and a pointer
  1126. * to the argument to pass to the free routine.  
  1127. *
  1128. * RETURNS: OK or ERROR.
  1129. */
  1130. LOCAL STATUS ultraSend
  1131.     (
  1132.     void * pObj, /* device ptr */
  1133.     M_BLK_ID pMblk /* data to send */
  1134.     )
  1135.     {
  1136.     int oldLevel;
  1137.     int len;
  1138.     UINT transmitPage;
  1139.     char * pBuf;
  1140.     ULTRA_DEVICE * pDrvCtrl = (ULTRA_DEVICE *) pObj;
  1141.        
  1142.     /*
  1143.      * Obtain exclusive access to transmitter.  This is necessary because
  1144.      * we might have more than one stack transmitting at once.
  1145.      */
  1146.     if (!(pDrvCtrl->flags & ULTRA_POLLING))
  1147. END_TX_SEM_TAKE (&pDrvCtrl->endObj, WAIT_FOREVER);
  1148.     if (pDrvCtrl->flags & ULTRA_TX_IN_PROGRESS)
  1149. {
  1150. int cnt;
  1151. /*
  1152.  * Wait up to 1 second. Testing on a slow 486 pc platform this
  1153.  * loop never waited more than 2 ticks at 60/sec.
  1154.  */
  1155. cnt = sysClkRateGet ();
  1156. while ((pDrvCtrl->flags & ULTRA_TX_IN_PROGRESS) && (cnt-- > 0))
  1157.     taskDelay (1);
  1158. DRV_LOG (DRV_DEBUG_TX,
  1159.  "%s%d: ultraSend: TX_IN_PROGRESS: waited %d ticksn",
  1160.  (int) DEV_NAME, pDrvCtrl->unit,
  1161.  sysClkRateGet() - cnt, 0, 0, 0);
  1162. }
  1163.     /* If TX still in progress, note blocked and return ERROR */
  1164.     oldLevel = intLock ();
  1165.     if (pDrvCtrl->flags & ULTRA_TX_IN_PROGRESS)
  1166. {
  1167. DRV_LOG (DRV_DEBUG_TX, "%s%d: ultraSend: TX_IN_PROGRESS (flags=%x)n",
  1168.  (int) DEV_NAME, pDrvCtrl->unit, pDrvCtrl->flags, 4, 5, 6);
  1169. pDrvCtrl->flags |= ULTRA_TX_BLOCKED;
  1170. if (!(pDrvCtrl->flags & ULTRA_POLLING))
  1171.     END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1172. intUnlock (oldLevel);
  1173.         return (END_ERR_BLOCK);
  1174. }
  1175.     intUnlock (oldLevel);
  1176.     /* Copy and free the MBLK */
  1177.     transmitPage = pDrvCtrl->transmitPage [pDrvCtrl->transmitCnt & 1];
  1178.     pBuf = (char *)(pDrvCtrl->memAddr + (transmitPage << 8));
  1179.     len = netMblkToBufCopy (pMblk, pBuf, NULL);
  1180.     len = max (len, ETHERSMALL);
  1181.     netMblkClChainFree (pMblk);
  1182.     DRV_LOG (DRV_DEBUG_TX, "%s%d: ultraSend, packet %d, len=%dn",
  1183.      (int) DEV_NAME, pDrvCtrl->unit, pDrvCtrl->transmitCnt, len, 5, 6);
  1184.     
  1185.     /* Flush the write pipe */
  1186.     CACHE_PIPE_FLUSH ();
  1187.    
  1188.     /* Transfer to the device and mark TX in progress. */
  1189.     oldLevel = intLock ();
  1190.     SYS_OUT_BYTE (pDrvCtrl, LAN_TSTART, transmitPage);
  1191.     SYS_OUT_BYTE (pDrvCtrl, LAN_TCNTH, len >> 8);
  1192.     SYS_OUT_BYTE (pDrvCtrl, LAN_TCNTL, len & 0xff);
  1193.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_TXP);
  1194.     pDrvCtrl->transmitCnt++;
  1195.     pDrvCtrl->flags |= ULTRA_TX_IN_PROGRESS;
  1196.     intUnlock (oldLevel);
  1197.     /* update statistics */
  1198.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);
  1199.     /* Release semaphore */
  1200.     if (!(pDrvCtrl->flags & ULTRA_POLLING))
  1201. END_TX_SEM_GIVE (&pDrvCtrl->endObj);
  1202.     return (OK);
  1203.     }
  1204.   
  1205. /******************************************************************************
  1206. *
  1207. * ultraIoctl - the driver I/O control routine
  1208. *
  1209. * Process an ioctl request.
  1210. *
  1211. * RETURNS: A command specific response, usually OK or ERROR.
  1212. */
  1213. LOCAL int ultraIoctl
  1214.     (
  1215.     void * pObj, /* device receiving command */
  1216.     int cmd, /* ioctl command code */
  1217.     caddr_t data /* command argument */
  1218.     )
  1219.     {
  1220.     long value;
  1221.     int error = 0;
  1222.     ULTRA_DEVICE * pDrvCtrl = pObj; /* device receiving command */
  1223.     
  1224.     switch ((UINT)cmd)
  1225.          {
  1226.         case EIOCSADDR:
  1227.     if (data == NULL)
  1228. return (EINVAL);
  1229.             bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->endObj),
  1230.    END_HADDR_LEN(&pDrvCtrl->endObj));
  1231.             break;
  1232.         case EIOCGADDR:
  1233.     if (data == NULL)
  1234. return (EINVAL);
  1235.             bcopy ((char *)END_HADDR(&pDrvCtrl->endObj), (char *)data,
  1236.    END_HADDR_LEN(&pDrvCtrl->endObj));
  1237.             break;
  1238.         case EIOCSFLAGS:
  1239.     value = (long)data;
  1240.     if (value < 0)
  1241. {
  1242. value = -value;
  1243. value--;
  1244. END_FLAGS_CLR (&pDrvCtrl->endObj, value);
  1245. }
  1246.     else
  1247. {
  1248. END_FLAGS_SET (&pDrvCtrl->endObj, value);
  1249. }
  1250.     ultraConfig (pDrvCtrl);
  1251.             break;
  1252.         case EIOCGFLAGS:
  1253.     *(int *)data = END_FLAGS_GET(&pDrvCtrl->endObj);
  1254.             break;
  1255. case EIOCPOLLSTART: /* Begin polled operation */
  1256.     ultraPollStart (pDrvCtrl);
  1257.     break;
  1258. case EIOCPOLLSTOP: /* Ultra polled operation */
  1259.     ultraPollStop (pDrvCtrl);
  1260.     break;
  1261.         case EIOCGMIB2: /* return MIB information */
  1262.             if (data == NULL)
  1263.                 return (EINVAL);
  1264.             bcopy ((char *)&pDrvCtrl->endObj.mib2Tbl, (char *)data,
  1265.    sizeof(pDrvCtrl->endObj.mib2Tbl));
  1266.             break;
  1267.         case EIOCGFBUF: /* return minimum First Buffer for chaining */
  1268.             if (data == NULL)
  1269.                 return (EINVAL);
  1270.             *(int *)data = ULTRA_MIN_FBUF;
  1271.     break;
  1272.         case EIOCGHDRLEN:
  1273.             if (data == NULL)
  1274.                 return (EINVAL);
  1275.             *(int *)data = SIZEOF_ETHERHEADER;
  1276.             break;
  1277.         default:
  1278.             error = EINVAL;
  1279.         }
  1280.     return (error);
  1281.     }
  1282. /******************************************************************************
  1283. *
  1284. * ultraAddrFilterSet - set the address filter for multicast addresses
  1285. *
  1286. * This routine goes through all of the multicast addresses on the list
  1287. * of addresses (added with the ultraMCastAdd() routine) and sets the
  1288. * device's filter correctly.
  1289. *
  1290. * RETURNS: N/A.
  1291. */
  1292. LOCAL void ultraAddrFilterSet
  1293.     (
  1294.     ULTRA_DEVICE * pDrvCtrl /* device pointer */
  1295.     )
  1296.     {          
  1297.     int len;
  1298.     int count;
  1299.     u_char c;
  1300.     u_char * pCp;
  1301.     u_long crc;
  1302.     ETHER_MULTI * pCurr;
  1303.     pDrvCtrl->mcastFilter[0] = 0x00;
  1304.     pDrvCtrl->mcastFilter[1] = 0x00;
  1305.     pDrvCtrl->mcastFilter[2] = 0x00;
  1306.     pDrvCtrl->mcastFilter[3] = 0x00;
  1307.     pDrvCtrl->mcastFilter[4] = 0x00;
  1308.     pDrvCtrl->mcastFilter[5] = 0x00;
  1309.     pDrvCtrl->mcastFilter[6] = 0x00;
  1310.     pDrvCtrl->mcastFilter[7] = 0x00;
  1311.     for (pCurr = END_MULTI_LST_FIRST (&pDrvCtrl->endObj);
  1312.  pCurr != NULL;
  1313.  pCurr = END_MULTI_LST_NEXT(pCurr))
  1314. {
  1315. /*
  1316.  * AUTODIN-II, adapted for ethernet (bit reversed),
  1317.  * taken from the ln7990End.c driver
  1318.  */
  1319. pCp = (unsigned char *)&pCurr->addr;
  1320. crc = 0xffffffff;
  1321. for (len = 6; --len >= 0;)
  1322.     {
  1323.     c = *pCp++;
  1324.     for (count = 0; count < 8; count++)
  1325. {
  1326. if ((c & 0x01) ^ (crc & 0x01))
  1327.     {
  1328.     crc >>= 1;
  1329.     crc = crc ^ 0xedb88320;
  1330.     }
  1331. else
  1332.     {
  1333.     crc >>= 1;
  1334.     }
  1335. c >>= 1;
  1336. }
  1337.     }
  1338. /* Just want the 6 most significant bits. */
  1339. crc = crc >> 26;
  1340. /* Turn on the corresponding bit in the filter. */
  1341. pDrvCtrl->mcastFilter [crc >> 3] |= (1 << (crc & 0x07));
  1342. }
  1343.     }
  1344. /*****************************************************************************
  1345. *
  1346. * ultraMCastAdd - add a multicast address for the device
  1347. *
  1348. * This routine adds a multicast address to whatever the driver
  1349. * is already listening for.  It then resets the address filter.
  1350. *
  1351. * RETURNS: OK or ERROR.
  1352. */
  1353. LOCAL STATUS ultraMCastAdd
  1354.     (
  1355.     void * pObj, /* device pointer */
  1356.     char * pAddress /* new address to add */
  1357.     )
  1358.     {     
  1359.     ULTRA_DEVICE * pDrvCtrl = pObj; /* device pointer */
  1360.     DRV_LOG (DRV_DEBUG_LOAD, "%s%d: ultraMCastAddn",
  1361.      (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  1362.     if (etherMultiAdd (&pDrvCtrl->endObj.multiList, pAddress) == ENETRESET)
  1363. ultraConfig (pDrvCtrl);
  1364.     return (OK);
  1365.     }
  1366. /*****************************************************************************
  1367. *
  1368. * ultraMCastDel - delete a multicast address for the device
  1369. *
  1370. * This routine removes a multicast address from whatever the driver
  1371. * is listening for.  It then resets the address filter.
  1372. *
  1373. * RETURNS: OK or ERROR.
  1374. */
  1375. LOCAL STATUS ultraMCastDel
  1376.     (
  1377.     void * pObj, /* device pointer */
  1378.     char * pAddress /* address to be deleted */
  1379.     )
  1380.     {
  1381.     ULTRA_DEVICE * pDrvCtrl = pObj; /* device pointer */
  1382.     DRV_LOG (DRV_DEBUG_LOAD, "%s%d: ultraMCastDeln",
  1383.      (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  1384.     if (etherMultiDel (&pDrvCtrl->endObj.multiList, pAddress) == ENETRESET)
  1385. ultraConfig (pDrvCtrl);
  1386.     return (OK);
  1387.     }
  1388. /*****************************************************************************
  1389. *
  1390. * ultraMCastGet - get the multicast address list for the device
  1391. *
  1392. * This routine gets the multicast list of whatever the driver
  1393. * is already listening for.
  1394. *
  1395. * RETURNS: OK or ERROR.
  1396. */
  1397. LOCAL STATUS ultraMCastGet
  1398.     (
  1399.     void * pObj, /* device pointer */
  1400.     MULTI_TABLE * pTable /* address table to be filled in */
  1401.     )
  1402.     {     
  1403.     ULTRA_DEVICE * pDrvCtrl = pObj; /* device pointer */
  1404.     return (etherMultiGet (&pDrvCtrl->endObj.multiList, pTable));
  1405.     }
  1406. /******************************************************************************
  1407. *
  1408. * ultraUnload - unload a driver from the system
  1409. *
  1410. * This function first brings down the device, and then frees any
  1411. * stuff that was allocated by the driver in the load function.
  1412. *
  1413. * RETURNS: OK or ERROR.
  1414. */
  1415. LOCAL STATUS ultraUnload
  1416.     (
  1417.     void * pObj /* device to be unloaded */
  1418.     )
  1419.     {     
  1420.     ULTRA_DEVICE * pDrvCtrl = pObj; /* device to be unloaded */
  1421.     DRV_LOG (DRV_DEBUG_LOAD, "%s%d: ultraUnloadn",
  1422.      (int) DEV_NAME, pDrvCtrl->unit,
  1423.      3, 4, 5, 6);
  1424.     END_OBJECT_UNLOAD (&pDrvCtrl->endObj);
  1425.     return (OK);
  1426.     }
  1427. /******************************************************************************
  1428. *
  1429. * ultraPollStart - start polled mode operations
  1430. *
  1431. * RETURNS: OK or ERROR.
  1432. */
  1433. LOCAL STATUS ultraPollStart
  1434.     (
  1435.     ULTRA_DEVICE * pDrvCtrl
  1436.     )
  1437.     {     
  1438.     int oldLevel;
  1439.     DRV_LOG (DRV_DEBUG_POLL, "%s%d: ultraPollStartn",
  1440.      (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  1441.     oldLevel = intLock ();
  1442.     SYS_OUT_BYTE (pDrvCtrl, LAN_INTMASK, 0x00);
  1443.     pDrvCtrl->flags |= ULTRA_POLLING;
  1444.     intUnlock (oldLevel);
  1445.     return (OK);
  1446.     }
  1447. /******************************************************************************
  1448. *
  1449. * ultraPollStop - stop polled mode operations
  1450. *
  1451. * This function terminates polled mode operation.  The device returns to
  1452. * interrupt mode.
  1453. *
  1454. * The device interrupts are enabled, the current mode flag is switched
  1455. * to indicate interrupt mode and the device is then reconfigured for
  1456. * interrupt operation.
  1457. *
  1458. * RETURNS: OK or ERROR.
  1459. */
  1460. LOCAL STATUS ultraPollStop
  1461.     (
  1462.     ULTRA_DEVICE * pDrvCtrl
  1463.     )
  1464.     {     
  1465.     int oldLevel;
  1466.     DRV_LOG (DRV_DEBUG_POLL, "%s%d: ultraPollStopn",
  1467.      (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  1468.     oldLevel = intLock ();
  1469.     SYS_OUT_BYTE (pDrvCtrl, LAN_INTMASK,
  1470.   IM_OVWE | IM_TXEE | IM_PTXE | IM_PRXE);
  1471.     pDrvCtrl->flags &= ~ULTRA_POLLING;
  1472.     intUnlock (oldLevel);
  1473.     return (OK);
  1474.     }
  1475. /******************************************************************************
  1476. *
  1477. * ultraPollRcv - routine to receive a packet in polled mode.
  1478. *
  1479. * This routine is called by a user to try and get a packet from the
  1480. * device.
  1481. *
  1482. * RETURNS: OK upon success.  EAGAIN is returned when no packet is available.
  1483. */
  1484. LOCAL STATUS ultraPollRcv
  1485.     (
  1486.     void * pObj, /* device to be polled */
  1487.     M_BLK_ID pMblk /* ptr to buffer */
  1488.     )
  1489.     {
  1490.     int len;
  1491.     ULTRA_DEVICE * pDrvCtrl = pObj; /* device to be polled */
  1492.     /* Don't call DRV_LOG until past the busy-wait */
  1493.     /* If no packet is available, return immediately */
  1494.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_PS0);
  1495.     SYS_IN_BYTE (pDrvCtrl, LAN_CURR, &pDrvCtrl->current);
  1496.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, 0);
  1497.     if (pDrvCtrl->nextPacket == pDrvCtrl->current)
  1498.         return (EAGAIN);
  1499.     DRV_LOG (DRV_DEBUG_POLL_RX, "%s%d: ultraPollRcvn",
  1500.      (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  1501.     /* Upper layer must provide a valid buffer. */
  1502.     if ((pMblk->mBlkHdr.mLen < ULTRA_MAX_SIZE)
  1503. || !(pMblk->mBlkHdr.mFlags & M_EXT))
  1504. {
  1505.         DRV_LOG (DRV_DEBUG_POLL_RX,
  1506.  "%s%d: ultraPollRecv: bad mblk, mLen=%d mFlags=%xn",
  1507.  (int) DEV_NAME, pDrvCtrl->unit,
  1508.  pMblk->mBlkHdr.mLen, pMblk->mBlkHdr.mFlags, 5, 6);
  1509. return (EAGAIN);
  1510. }
  1511.     /* Process device packet into net buffer */
  1512.     pMblk->mBlkHdr.mData += pDrvCtrl->offset;
  1513.     len = ultraPacketGet (pDrvCtrl, pMblk->mBlkHdr.mData);
  1514.     pMblk->mBlkHdr.mFlags |= M_PKTHDR; /* set the packet header */
  1515.     pMblk->mBlkHdr.mLen = len; /* set the data len */
  1516.     pMblk->mBlkPktHdr.len = len; /* set the total len */
  1517.     DRV_LOG (DRV_DEBUG_POLL_RX, "%s%d: ultraPollRcv done, len=%dn",
  1518.      (int) DEV_NAME, pDrvCtrl->unit, len, 4, 5, 6);
  1519.     return (OK);
  1520.     }
  1521. /******************************************************************************
  1522. *
  1523. * ultraPollSend - routine to send a packet in polled mode.
  1524. *
  1525. * This routine is called by a user to try and send a packet on the
  1526. * device.  As this is a single-transmit device, we actually wait
  1527. * for the previous transmit to complete, otherwise parts of the
  1528. * packet may be dropped.
  1529. *
  1530. * RETURNS: OK upon success.  EAGAIN if device is busy.
  1531. */
  1532. LOCAL STATUS ultraPollSend
  1533.     (
  1534.     void * pObj, /* device to be polled */
  1535.     M_BLK_ID pMblk /* packet to send */
  1536.     )
  1537.     {
  1538.     UCHAR cmdStat;
  1539.     int len;
  1540.     UINT transmitPage;
  1541.     char * pBuf;
  1542.     ULTRA_DEVICE * pDrvCtrl = pObj;
  1543.     DRV_LOG (DRV_DEBUG_POLL_TX, "%s%d: ultraPollSendn",
  1544.      (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  1545.     /* Wait for the last transmit to complete */
  1546.     do
  1547. SYS_IN_BYTE (pDrvCtrl, LAN_CMD, &cmdStat);
  1548.     while (cmdStat & CMD_TXP);
  1549.     /* Process the net buffer into a device transmit packet */
  1550.     transmitPage = pDrvCtrl->transmitPage [pDrvCtrl->transmitCnt & 1];
  1551.     pBuf = (char *)(pDrvCtrl->memAddr + (transmitPage << 8));
  1552.     len = netMblkToBufCopy (pMblk, pBuf, NULL);
  1553.     len = max (len, ETHERSMALL);
  1554.     DRV_LOG (DRV_DEBUG_POLL_TX, "%s%d: ultraPollSend: len=%dn",
  1555.      (int) DEV_NAME, pDrvCtrl->unit, len, 4, 5, 6);
  1556.     /* Flush the write pipe */
  1557.     CACHE_PIPE_FLUSH ();
  1558.    
  1559.     /* Transfer to the device */
  1560.     SYS_OUT_BYTE (pDrvCtrl, LAN_TSTART, transmitPage);
  1561.     SYS_OUT_BYTE (pDrvCtrl, LAN_TCNTH, len >> 8);
  1562.     SYS_OUT_BYTE (pDrvCtrl, LAN_TCNTL, len & 0xff);
  1563.     SYS_OUT_BYTE (pDrvCtrl, LAN_CMD, CMD_TXP);
  1564.     pDrvCtrl->transmitCnt++;
  1565.     /* Bump the statistic counter. */
  1566.     END_ERR_ADD (&pDrvCtrl->endObj, MIB2_OUT_UCAST, +1);
  1567.     DRV_LOG (DRV_DEBUG_POLL_TX, "%s%d: ultraPollSend: donen",
  1568.      (int) DEV_NAME, pDrvCtrl->unit, 3, 4, 5, 6);
  1569.     return (OK);
  1570.     }