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

VxWorks

开发平台:

C/C++

  1. /* tempNetif.c - template ethernet network interface driver */
  2. /* Copyright 1989-1997 Wind River Systems, Inc. */
  3. /*
  4. TODO - Remove the template modification history and begin a new history
  5. starting with version 01a and growing the history upward with
  6. each revision.
  7. modification history
  8. --------------------
  9. 01d,24sep97,dat  documentation cleanup, added TEMPLATE_NETIF_{READ | WRITE}
  10. 01c,25aug97,dat  removed IFNET references
  11. 01b,08aug97,dat  fixed compilation bugs
  12. 01a,30jul97,dat  written (from if_ei.c, ver 03h)
  13. */
  14. /*
  15. .SH TODO
  16. Replace the documentation for this template driver with documentation
  17. for the driver being written.  
  18. Begin with an overview of the complete device.  Indicate if the new driver
  19. only implements a sub-section of the whole device or not.
  20. Describe all of the operating modes of the device, and indicate which
  21. ones this driver implements.
  22. Document the device initialization steps to be used in the BSP to create
  23. and initialize the device.  Document all the macros that
  24. can be used to customize the driver to a particular hardware environment.
  25. Document anything that will help the user to understand how this device
  26. works and interacts with this driver.
  27. This template assumes the device uses some type of transmit frame descriptor
  28. (tfd) and a similar receive frame descriptor (rfd).  There is an array or
  29. list for each.  There are dummy declarations for a TFD and an RFD structure.
  30. INTERRUPTS
  31. This driver requires the BSP to perform the intConnect function.  The BSP
  32. should connect the templateInt() function using a single argument 'unit'
  33. to the appropriate vector.  This driver will use the TEMPLATE_INT_ENABLE()
  34. and TEMPLATE_INT_DISABLE() macros to enable and disable interrupts. The
  35. macro TEMPLATE_INT_INIT() is used to initialize the interrupt system during
  36. driver initialization time.  The macro TEMPLATE_INT_ACK() is used to
  37. perform interrupt acknowledge functions external to the driver.
  38. HARDWARE 
  39. The macros TEMPLATE_NETIF_READ() and TEMPLATE_NETIF_WRITE() are used for
  40. all accesses to actual chip.  These macros can be redefined to create
  41. custom modules for special situations.
  42. NOTES:
  43. This template driver was abstracted from the Intel 82596 driver, if_ei.c.
  44. It is a fairly common device that has its own DMA controller built in.
  45. Transmit data is assigned to a TFD (transmit frame descriptor) and the TFD
  46. is linked to a command list that the device monitors.  Similar incoming
  47. packets are in RFDs (receive frame descriptors).  An interrupt occurs when
  48. there are RFDs ready with incoming data.  The RFD is then unlinked from the
  49. receive queue and processed.  When the incoming data is no longer needed the
  50. buffer and RFD and returned to the free pool of RFDs, for reuse.
  51. WARNINGS:
  52. Do not use printf statements within code executed by netTask. A deadlock
  53. is possible when the shell is redirected to the network.  Use logMsg()
  54. instead. (SPR 8954)
  55. SEE ALSO: ifLib
  56. */
  57. #include "vxWorks.h"
  58. #include "wdLib.h"
  59. #include "iv.h"
  60. #include "vme.h"
  61. #include "net/mbuf.h"
  62. #include "net/unixLib.h"
  63. #include "net/protosw.h"
  64. #include "sys/socket.h"
  65. #include "sys/ioctl.h"
  66. #include "errno.h"
  67. #include "memLib.h"
  68. #include "intLib.h"
  69. #include "net/if.h"
  70. #include "net/route.h"
  71. #include "iosLib.h"
  72. #include "errnoLib.h"
  73. #include "cacheLib.h"
  74. #include "logLib.h"
  75. #include "netLib.h"
  76. #include "stdio.h"
  77. #include "stdlib.h"
  78. #include "sysLib.h"
  79. #include "netinet/in.h"
  80. #include "netinet/in_systm.h"
  81. #include "netinet/in_var.h"
  82. #include "netinet/ip.h"
  83. #include "netinet/if_ether.h"
  84. #include "etherLib.h"
  85. #include "net/systm.h"
  86. #include "sys/times.h"
  87. #include "net/if_subr.h"
  88. /* local definitions */
  89. #define EH_SIZE 14
  90. #define MAX_UNITS       4                   /* maximum units to support */
  91. #define MAX_RFDS_LOANED 8                   /* max RFDs that can be loaned */
  92. /* Typedefs for external structures that are not typedef'd in their .h files */
  93. typedef struct mbuf MBUF;
  94. typedef struct arpcom IDR;                  /* Interface Data Record wrapper */
  95. typedef struct ifnet IFNET;                 /* real Interface Data Record */
  96. typedef struct sockaddr SOCK;
  97. typedef struct rfd { /* TODO - This is a dummy RFD structure */
  98.     ETH_HDR* pEnetHdr;
  99.     int status;
  100.     int count;
  101.     int reserved;
  102.     int actualCnt;
  103.     int refCnt;
  104.     char * enetData;
  105.     int bufSize;
  106.     } RFD;
  107. typedef RFD TFD; /* TODO - This is a dummy TFD structure */
  108. /* The definition of the driver control structure */
  109. typedef struct drv_ctrl /* TODO - This is a dummy driver control structure */
  110.     {
  111.     IDR idr; /* interface data record */
  112.     BOOL attached; /* indicates attach() called */
  113.     volatile UCHAR * pCsr; /* Control status register */
  114.     char * memBase; /* memory pool base */
  115.     volatile BOOL rcvHandling; /* flag, indicates netTask active */
  116.     volatile BOOL txCleaning; /* flag, indicates netTask active */
  117.     volatile BOOL txIdle; /* flag, indicates idle transmitter */
  118.     volatile int nLoanRfds; /* number of loanable RFDs left */
  119.     CACHE_FUNCS cacheFuncs; /* cache descriptor */
  120.     int intLevel; /* interrupt level # */
  121.     } DRV_CTRL;
  122. #define DRV_CTRL_SIZ  sizeof(DRV_CTRL)
  123. /* hardware abstraction macros */
  124. #ifndef TEMPLATE_NETIF_READ
  125. #define TEMPLATE_NETIF_READ(pDrvCtrl, reg, result) 
  126. ((result) = (*(pDrvCtrl->reg)))
  127. #endif /* TEMPLATE_NETIF_READ */
  128. #ifndef TEMPLATE_NETIF_WRITE
  129. #define TEMPLATE_NETIF_WRITE(pDrvCtrl, reg, data) 
  130. ((*(pDrvCtrl->reg)) = (data))
  131. #endif /* TEMPLATE_NETIF_WRITE */
  132. /* Dummy declarations of bits in the CSR register */
  133. #define TEMPLATE_CSR_RX_PEND 0x1
  134. #define TEMPLATE_CSR_TX_PEND 0x2
  135. #define TEMPLATE_CSR_RFD_READY 0x4
  136. /* Dummy declarations of CSR commands */
  137. #define TEMPLATE_CMD_RESET 0x1
  138. #define TEMPLATE_CMD_TX_START 0x2
  139. #define TEMPLATE_CMD_RX_START 0x4
  140. /* declarations for default macro definitions */
  141. IMPORT STATUS sysIntEnable (int);
  142. IMPORT STATUS sysIntDisable (int);
  143. IMPORT STATUS sysIntAck (int);
  144. IMPORT STATUS sysTemplateAddrGet (int, void *);
  145. #ifndef TEMPLATE_INT_ENABLE /* enable this interrupt */
  146. #define TEMPLATE_INT_ENABLE(pDrv) 
  147. sysIntEnable (pDrv->intLevel);
  148. #endif TEMPLATE_INT_ENABLE
  149. #ifndef TEMPLATE_INT_DISABLE /* disable this interrupt */
  150. #define TEMPLATE_INT_DISABLE(pDrv) 
  151. sysIntEnable (pDrv->intLevel);
  152. #endif TEMPLATE_INT_DISABLE
  153. #ifndef TEMPLATE_INT_INIT /* initialize interrupts */
  154. #define TEMPLATE_INT_INIT(pDrv) 
  155. /* do nothing */
  156. #endif TEMPLATE_INT_INIT
  157. #ifndef TEMPLATE_INT_ACK /* acknowledge interrupt */
  158. #define TEMPLATE_INT_ACK(pDrv) 
  159. sysIntAck (pDrv->intLevel);
  160. #endif TEMPLATE_INT_ACK
  161. #ifndef TEMPLATE_ENET_GET /* get ethernet MAC address */
  162. #define TEMPLATE_ENET_GET(pDrvCtrl, pResult) 
  163. *pResult = sysTemplateAddrGet (pDrvCtrl->idr.ac_if.if_unit, 
  164. (char *)pDrvCtrl->idr.ac_enaddr);
  165. #endif TEMPLATE_ENET_GET
  166. /* local data */
  167. LOCAL DRV_CTRL drvCtrl [MAX_UNITS];  /* array of driver control structs */
  168. /* forward function declarations */
  169. IMPORT STATUS templateAttach (int unit, UCHAR* pCsr, int iLevel,
  170. char* memBase, int nTfds, int nRfds);
  171. IMPORT void templateInt (int unit);
  172. LOCAL STATUS templateInit (int unit);
  173. LOCAL void templateReset (int unit);
  174. LOCAL int templateIoctl (IDR *pIDR, int cmd, caddr_t data);
  175. LOCAL int templateOutput (IDR *pIDR, MBUF *pMbuf, SOCK *pDestAddr);
  176. LOCAL void templateTxStart (int unit);
  177. LOCAL void templateHandleRecv (DRV_CTRL *pDrvCtrl);
  178. LOCAL STATUS templateReceive (DRV_CTRL *pDrvCtrl, RFD *pRfd);
  179. LOCAL void templateLoanFree (DRV_CTRL *pDrvCtrl, RFD *pRfd);
  180. LOCAL void templateRxStart (DRV_CTRL *pDrvCtrl);
  181. LOCAL void templateTfdSend (DRV_CTRL *pDrvCtrl, TFD *pTfd);
  182. LOCAL void templateTfdStart (DRV_CTRL *pDrvCtrl);
  183. LOCAL void templateRfdReturn (DRV_CTRL *pDrvCtrl, RFD *pRfd);
  184. LOCAL RFD *templateRfdGet (DRV_CTRL *pDrvCtrl);
  185. LOCAL BOOL templateRfdReady (DRV_CTRL *pDrvCtrl);
  186. LOCAL STATUS templateDeviceStart (int unit);
  187. /*******************************************************************************
  188. *
  189. * templateAttach - publish the network interface and initialize the device
  190. *
  191. * This routine publishes the `template' interface by filling in a network
  192. * interface record and adding this record to the system list.  This routine
  193. * also initializes the driver and the device to the operational state.
  194. *
  195. * The <memBase> parameter is used to inform the driver about the shared
  196. * memory region.  If this parameter is set to the constant "NONE," then this
  197. * routine will attempt to allocate the shared memory from the system.  Any
  198. * other value for this parameter is interpreted by this routine as the address
  199. * of the shared memory region to be used.
  200. *
  201. * If the caller provides the shared memory region, then the driver assumes
  202. * that this region does not require cache coherency operations, nor does it
  203. * require conversions between virtual and physical addresses.
  204. *
  205. * If the caller indicates that this routine must allocate the shared memory
  206. * region, then this routine will use cacheDmaMalloc() to obtain
  207. * some  non-cacheable memory.  The attributes of this memory will be checked,
  208. * and if the memory is not both read and write coherent, this routine will
  209. * abort and return ERROR.
  210. *
  211. * RETURNS: OK or ERROR if arguments are invalid or a hardware fault is detected.
  212. *
  213. * SEE ALSO: ifLib
  214. */
  215. STATUS templateAttach
  216.     (
  217.     int         unit,       /* unit number */
  218.     UCHAR * pCsr,     /* ptr to CSR */
  219.     int         iLevel,     /* interrupt level */
  220.     char *      memBase,    /* address of memory pool or NONE */
  221.     int         nTfds,      /* no. of transmit frames (0 = default) */
  222.     int         nRfds       /* no. of receive frames (0 = default) */
  223.     )
  224.     {
  225.     DRV_CTRL    *pDrvCtrl;
  226.     UINT        size; /* temporary size holder */
  227.     int temp;
  228.     static char *errMsg1 = "nattach: could not obtain memoryn";
  229.     /* Sanity checks */
  230.     if (unit < 0|| unit >= MAX_UNITS
  231.      || pCsr == NULL)
  232.         return (ERROR);
  233.     /* Ensure single invocation per system life */
  234.     pDrvCtrl = & drvCtrl [unit];
  235.     if (pDrvCtrl->attached)
  236.         return (OK);
  237.     /* Publish the interface record */
  238.     ether_attach    (
  239.                     &pDrvCtrl->idr.ac_if,
  240.                     unit,
  241.                     "template",
  242.                     (FUNCPTR) NULL,
  243.                     (FUNCPTR) templateIoctl,
  244.                     (FUNCPTR) templateOutput,
  245.                     (FUNCPTR) templateReset
  246.                     );
  247.     size = 1024 * 16; /* TODO - calculate the total size of memory pool */
  248.     /*
  249.      * Establish the memory area that we will share with the device.  If
  250.      * the caller has provided an area, then we assume it is non-cacheable
  251.      * and will not require the use of the special cache routines.
  252.      * If the caller did not provide an area, then we must obtain it from
  253.      * the system, using the cache savvy allocation routine.
  254.      */
  255.     switch ((int) memBase)
  256.         {
  257.         case NONE :                            /* we must obtain it */
  258.     /*
  259.      * TODO - if driver needs coherent memory, test for it and
  260.      * report error if not coherent.
  261.      */
  262.     /* allocate memory */
  263.             pDrvCtrl->memBase = cacheDmaMalloc (size);
  264.             if (pDrvCtrl->memBase == NULL)    /* no memory available */
  265.                 {
  266.                 printf (errMsg1);
  267.                 goto error;
  268.                 }
  269.             pDrvCtrl->cacheFuncs = cacheDmaFuncs;
  270.             break;
  271.         default :                               /* the user provided an area */
  272.             pDrvCtrl->memBase = memBase;        /* use the provided address */
  273.             pDrvCtrl->cacheFuncs = cacheNullFuncs;
  274.             break;
  275.         }
  276.     /* TODO - Save device specific parameters */
  277.     pDrvCtrl->intLevel = iLevel;
  278.     pDrvCtrl->pCsr = pCsr;
  279.     /*
  280.      * TODO - If needed, carve up the shared memory region into
  281.      * specific sections.
  282.      */
  283.     /* get our enet (MAC) addr */
  284.     TEMPLATE_ENET_GET (pDrvCtrl, &temp);
  285.     if (temp == ERROR)
  286. {
  287. errnoSet (S_iosLib_INVALID_ETHERNET_ADDRESS);
  288.         goto error;
  289. }
  290.     /* NOTE: The BSP will connect the ISR to the interrupt vector */
  291.     /* reset chip, set flags to indicate device is active */
  292.     if (templateInit (unit) == ERROR)
  293.         goto error;
  294.     pDrvCtrl->attached = TRUE;
  295.     pDrvCtrl->idr.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_NOTRAILERS);
  296.     return (OK);
  297. error:
  298.     /* TODO - Release allocated objects/memory */
  299.     return (ERROR);
  300.     }
  301. /*******************************************************************************
  302. *
  303. * templateInit - Initialize the interface.
  304. *
  305. * Initialization of interface; clear recorded pending operations.
  306. * Called by templateAttach().
  307. *
  308. * RETURNS: OK or ERROR if a hardware failure is detected.
  309. */
  310. LOCAL STATUS templateInit 
  311.     (
  312.     int unit /* unit number */
  313.     )
  314.     {
  315.     DRV_CTRL    *pDrvCtrl = & drvCtrl [unit];
  316.     pDrvCtrl->rcvHandling   = FALSE;  /* netTask not running our receive job */
  317.     pDrvCtrl->txCleaning    = FALSE;  /* netTask not running our clean job */
  318.     pDrvCtrl->txIdle        = TRUE;         /* transmitter idle */
  319.     /* Perform device initialization */
  320.     TEMPLATE_INT_DISABLE (pDrvCtrl);
  321.     TEMPLATE_INT_INIT (pDrvCtrl); /* board specific initialization */
  322.     /* TODO - configure chip, set up MAC address, etc */
  323.     /* TODO - setup TX and RX buffer lists/queues */
  324.     /* TODO - Setup free RFD list, and loan count */
  325.     pDrvCtrl->nLoanRfds = MAX_RFDS_LOANED;
  326.     /* Clear and enable interrupts */
  327.     TEMPLATE_INT_ACK (pDrvCtrl); /* to clear any pending interrupts */
  328.     TEMPLATE_INT_ENABLE (pDrvCtrl);
  329.     /* Start the device */
  330.     if (templateDeviceStart (unit) == ERROR)
  331.         return (ERROR);
  332.     return (OK);
  333.     }
  334. /*******************************************************************************
  335. *
  336. * templateReset - reset the ei interface
  337. *
  338. * Mark interface as inactive and reset the chip.  Called from the interface
  339. * layer as needed to shut down the device.
  340. *
  341. * RETURNS: N/A.
  342. */
  343. LOCAL void templateReset
  344.     (
  345.     int unit
  346.     )
  347.     {
  348.     DRV_CTRL *pDrvCtrl;
  349.     pDrvCtrl = & drvCtrl [unit];
  350.     pDrvCtrl->idr.ac_if.if_flags = 0;
  351.     TEMPLATE_INT_DISABLE (pDrvCtrl);
  352.     /* TODO - reset the device */
  353.     TEMPLATE_NETIF_WRITE(pDrvCtrl, pCsr, TEMPLATE_CMD_RESET);
  354.     }
  355. /*******************************************************************************
  356. *
  357. * templateIoctl - interface ioctl procedure
  358. *
  359. * Process an interface ioctl request.
  360. *
  361. * RETURNS: 0 (OK) always.
  362. */
  363. LOCAL int templateIoctl
  364.     (
  365.     IDR     *pIDR,
  366.     int     cmd,
  367.     caddr_t data
  368.     )
  369.     {
  370.     DRV_CTRL * pDrvCtrl = & drvCtrl [pIDR->ac_if.if_unit];
  371.     int retVal = OK;
  372.     int s;
  373.     s = splimp ();
  374.     switch (cmd)
  375.         {
  376.         case SIOCSIFADDR:
  377.             retVal = set_if_addr (&pIDR->ac_if, data, pDrvCtrl->idr.ac_enaddr);
  378.             break;
  379.         case SIOCSIFFLAGS:
  380.             /* Flags are set outside this module. No additional work to do. */
  381.             break;
  382.         default:
  383.             retVal = EINVAL;
  384.         }
  385.     splx (s);
  386.     return (retVal);
  387.     }
  388. /*******************************************************************************
  389. *
  390. * templateOutput - interface output routine.
  391. *
  392. * This is the entry point for packets arriving from protocols above.  This
  393. * routine merely calls our specific output routines that eventually lead
  394. * to a transmit to the network.
  395. *
  396. * RETURNS: 0 or appropriate errno (see ether_output)
  397. *
  398. * SEE ALSO:
  399. * ether_output
  400. */
  401. LOCAL int templateOutput
  402.     (
  403.     IDR *    pIDR,
  404.     MBUF *     pMbuf,
  405.     SOCK * pDestAddr
  406.     )
  407.     {
  408.     return (ether_output (&pIDR->ac_if, pMbuf, pDestAddr,
  409.             (FUNCPTR) templateTxStart, pIDR));
  410.     }
  411. /*******************************************************************************
  412. *
  413. * templateTxStart - start output on the chip
  414. *
  415. * Looks for any action on the queue, and begins output if there is anything
  416. * there.  This routine is called from several possible threads.  Each will be
  417. * described below.
  418. *
  419. * The first, and most common thread, is when a user task requests the
  420. * transmission of data.  This will cause templateOutput() to be called,
  421. * which will cause ether_output() to be called, which will cause this routine
  422. * to be called (usually).  This routine will not be called if ether_output()
  423. * finds that our interface output queue is full.  In this case, the outgoing
  424. * data will be thrown out.
  425. *
  426. * The second, and most obscure thread, is when the reception of certain
  427. * packets causes an immediate (attempted) response.  For example, ICMP echo
  428. * packets (ping), and ICMP "no listener on that port" notifications.  All
  429. * functions in this driver that handle the reception side are executed in the
  430. * context of netTask().  Always.  So, in the case being discussed, netTask() 
  431. * will receive these certain packets, cause IP to be stimulated, and cause the
  432. * generation of a response to be sent.  We then find ourselves following the
  433. * thread explained in the second example, with the important distinction that
  434. * the context is that of netTask().
  435. *
  436. * The third thread occurs when this routine runs out of TFDs and returns.  If
  437. * this occurs when our output queue is not empty, this routine would typically
  438. * not get called again until new output was requested.  Even worse, if the
  439. * output queue was also full, this routine would never get called again and
  440. * we would have a lock state.  It DOES happen.  To guard against this, the
  441. * transmit clean-up handler detects the out-of-TFDs state and calls this
  442. * function.  The clean-up handler also runs from netTask.
  443. *
  444. * Note that this function is ALWAYS called between an splnet() and an splx().
  445. * This is true because netTask(), and ether_output() take care of
  446. * this when calling this function.  Therefore, no calls to these spl functions
  447. * are needed anywhere in this output thread.
  448. *
  449. * RETURNS: N/A.
  450. */
  451. LOCAL void templateTxStart
  452.     (
  453.     int unit
  454.     )
  455.     {
  456.     MBUF * pMbuf;
  457.     int length;
  458.     TFD * pTfd = NULL;
  459.     DRV_CTRL * pDrvCtrl;
  460.     pDrvCtrl = & drvCtrl [unit];
  461.     /*
  462.      * Loop until there are no more packets ready to send or we
  463.      * have insufficient resources left to send another one.
  464.      */
  465.     while (pDrvCtrl->idr.ac_if.if_snd.ifq_head)
  466.         {
  467. /* TODO - get a free Tx packet buffer */
  468.         if (pTfd == NULL)
  469.             break;                              /* out of TFD's */
  470.         IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf);  /* dequeue a packet */
  471.         copy_from_mbufs (pTfd->pEnetHdr, pMbuf, length);
  472.         length = max (ETHERSMALL, length);
  473.         length = min (0x3fff, length);
  474.         if ((etherOutputHookRtn != NULL) &&
  475.             (* etherOutputHookRtn)
  476.             (&pDrvCtrl->idr, pTfd->pEnetHdr, length))
  477.     {
  478.     /* TODO - release the TFD */
  479.             continue;
  480.     }
  481. /* TODO - update TFD data fields: length, etc */
  482.         pTfd->count = length;
  483. templateTfdSend (pDrvCtrl, pTfd); /* txmit the TFD */
  484.         }
  485.     }
  486. /*******************************************************************************
  487. *
  488. * templateInt - entry point for handling interrupts
  489. *
  490. * The interrupting events are acknowledged to the device, so that the device
  491. * will deassert its interrupt signal.  The amount of work done here is kept
  492. * to a minimum; the bulk of the work is defered to the netTask.  Several flags
  493. * are used here to synchronize with task level code and eliminate races.
  494. *
  495. * RETURNS: N/A.
  496. */
  497. void templateInt
  498.     (
  499.     int unit
  500.     )
  501.     {
  502.     UINT16  devStatus;
  503.     DRV_CTRL *pDrvCtrl;
  504.     pDrvCtrl = & drvCtrl [unit];
  505.     /* TODO - read device status */
  506.     TEMPLATE_NETIF_READ (pDrvCtrl, pCsr, devStatus);
  507.     /* Quick exit if device did not generate interrupt */
  508.     if (devStatus == 0)
  509. return;
  510.     /* Acknowledge interrupt to reset it, either here or at end of routine. */
  511.     TEMPLATE_INT_ACK (pDrvCtrl);
  512.     /* Handle transmitter interrupt */
  513.     if (devStatus & TEMPLATE_CSR_TX_PEND)
  514.         {
  515. /* TODO - reclaim tx buffers */
  516.         if (1) /* TODO - if tx queue is not empty */
  517.             templateTfdStart (pDrvCtrl); 
  518.         else
  519.             pDrvCtrl->txIdle = TRUE;                    /* transmitter idle */
  520.         }
  521.     /* Handle receiver interrupt */
  522.     if (devStatus & TEMPLATE_CSR_RX_PEND)
  523. {
  524. if (!(pDrvCtrl->rcvHandling))
  525.             {
  526.             pDrvCtrl->rcvHandling = TRUE;
  527.             netJobAdd ((FUNCPTR) templateHandleRecv, (int) pDrvCtrl,0, 0, 0, 0);
  528.     }
  529.         }
  530.     }
  531. /*******************************************************************************
  532. *
  533. * templateHandleRecv - task level interrupt service for input packets
  534. *
  535. * This routine is called at task level indirectly by the interrupt
  536. * service routine to do any message received processing.
  537. *
  538. * RETURNS: N/A.
  539. */
  540. LOCAL void templateHandleRecv
  541.     (
  542.     DRV_CTRL *pDrvCtrl
  543.     )
  544.     {
  545.     RFD *pRfd;
  546.     do
  547.         {
  548.         pDrvCtrl->rcvHandling = TRUE; /* interlock with templateInt() */
  549.         while ((pRfd = templateRfdGet (pDrvCtrl)) != NULL)
  550.     {
  551.             if (templateReceive (pDrvCtrl, pRfd) == OK)
  552.                 templateRfdReturn (pDrvCtrl, pRfd);
  553.     }
  554.         pDrvCtrl->rcvHandling = FALSE; /* interlock with templateInt() */
  555. templateRxStart (pDrvCtrl); /* restart Rcvr */
  556.         }
  557.     while (templateRfdReady (pDrvCtrl)); /* make sure rx q still empty */
  558.     }
  559. /*******************************************************************************
  560. *
  561. * templateReceive - pass a received frame to the next layer up
  562. *
  563. * Strips the Ethernet header and passes the packet to the appropriate
  564. * protocol.  The return value indicates if buffer loaning was used to hold
  565. * the data.  A return value of OK means that loaning was not done, and it
  566. * is therefore 'ok' to return the RFD to the Rx queue.  A return value of ERROR
  567. * means that buffer loaning was employed, and so the RFD is still in use and
  568. * should not be returned to the Rx queue.  In this latter case, the RFD will
  569. * eventually be returned by the protocol, via a call to our templateLoanFree().
  570. *
  571. * RETURNS: OK if RFD was not loaned, ERROR if it was loaned.
  572. */
  573. LOCAL STATUS templateReceive
  574.     (
  575.     DRV_CTRL *pDrvCtrl,
  576.     RFD *pRfd
  577.     )
  578.     {
  579.     ETH_HDR     *pEh;
  580.     u_char      *pData;
  581.     int         len;
  582.     UINT16      etherType;
  583.     MBUF        *m = NULL;
  584.     BOOL        rfdLoaned = FALSE;
  585.     if  (0) /* TODO - check RFD for errors */
  586.         {
  587.         ++pDrvCtrl->idr.ac_if.if_ierrors; /* bump error counter */
  588.         templateRfdReturn (pDrvCtrl, pRfd); /* free the RFD */
  589.         return (ERROR);
  590.         }
  591.     /* Bump input packet counter. */
  592.     ++pDrvCtrl->idr.ac_if.if_ipackets;
  593.     len = pRfd->actualCnt; /* get frame length */
  594.     pEh = pRfd->pEnetHdr; /* get ptr to ethernet header */
  595.     /* Service input hook */
  596.     if (etherInputHookRtn != NULL)
  597.         {
  598.         if ((* etherInputHookRtn) (&pDrvCtrl->idr, (char *)pEh, len))
  599.             {
  600.             templateRfdReturn (pDrvCtrl, pRfd); /* free the RFD */
  601.             return (OK);
  602.             }
  603.         }
  604.     len -= EH_SIZE;
  605.     pData = (u_char *) pRfd->enetData;
  606.     etherType = ntohs (pEh->ether_type);
  607.     /*
  608.      * we can loan out receive frames from receive queue if:
  609.      *
  610.      * 1) the threshold of loanable frames has not been exceeded
  611.      * 2) size of the input ethernet frame is large enough to be used with
  612.      *    clustering.
  613.      */
  614.     if ((pDrvCtrl->nLoanRfds > 0) && (USE_CLUSTER (len)) &&
  615.         ((m = build_cluster (pData, len, &pDrvCtrl->idr, MC_EI, &pRfd->refCnt,
  616.                  templateLoanFree, (int) pDrvCtrl, (int) pRfd, NULL)) != NULL))
  617.         {
  618.         pDrvCtrl->nLoanRfds--; /* one less to loan */
  619.         rfdLoaned = TRUE;               /* we loaned a frame */
  620.         }
  621.     else
  622. {
  623.         m = copy_to_mbufs (pData, len, 0, &pDrvCtrl->idr);
  624. }
  625.     if (m != NULL)
  626.         do_protocol_with_type (etherType, m, &pDrvCtrl->idr, len);
  627.     return ((rfdLoaned) ? ERROR : OK);
  628.     }
  629. /*******************************************************************************
  630. *
  631. * templateLoanFree - return a loaned receive frame descriptor
  632. *
  633. * This routine is called by the protocol code when it has completed use of
  634. * an RFD that we loaned to it.
  635. *
  636. * RETURNS: N/A.
  637. */
  638. LOCAL void templateLoanFree
  639.     (
  640.     DRV_CTRL *pDrvCtrl,
  641.     RFD *pRfd
  642.     )
  643.     {
  644.     templateRfdReturn (pDrvCtrl, pRfd);
  645.     pDrvCtrl->nLoanRfds ++;
  646.     }
  647. /*******************************************************************************
  648. *
  649. * templateDeviceStart - reset and start the device
  650. *
  651. * This routine assumes interrupts from the device have been disabled, and
  652. * that the driver control structure has been initialized.
  653. *
  654. * RETURNS: OK upon success, or ERROR for a hardware failure.
  655. */
  656. LOCAL STATUS templateDeviceStart
  657.     (
  658.     int unit                              /* physical unit number */
  659.     )
  660.     {
  661.     DRV_CTRL *pDrvCtrl;
  662.     /* Get pointers */
  663.     pDrvCtrl = & drvCtrl [unit];
  664.     /* Issue the reset operation to the device */
  665.     TEMPLATE_NETIF_WRITE(pDrvCtrl, pCsr, TEMPLATE_CMD_RESET);
  666.     /* TODO - initialize the device */
  667.     /* TODO - generate error message if needed */
  668.     templateRxStart (pDrvCtrl);
  669.     return (OK);
  670.     }
  671. /*******************************************************************************
  672. *
  673. * templateTfdSend - place a transmit frame on the transmit queue
  674. *
  675. * The TFD has been filled in with the network pertinent data.  This
  676. * routine will enqueue the TFD for transmission.
  677. *
  678. * RETURNS: N/A.
  679. */
  680. LOCAL void templateTfdSend
  681.     (
  682.     DRV_CTRL *pDrvCtrl,
  683.     TFD *pTfd
  684.     )
  685.     {
  686.     int unit;
  687.     unit = pDrvCtrl->idr.ac_if.if_unit;
  688.     /* TODO - setup the TFD data fields */
  689.     pTfd->status    = 0;                    /* fill in TFD fields */
  690.     pTfd->reserved  = 0;                    /* must be zero */
  691.     TEMPLATE_INT_DISABLE (pDrvCtrl);
  692.     /* TODO - queue the TFD */
  693.     if (pDrvCtrl->txIdle)               /* transmitter idle */
  694.         templateTfdStart (pDrvCtrl); /* flush txQueue */
  695.     TEMPLATE_INT_ENABLE (pDrvCtrl);
  696.     }
  697. /*******************************************************************************
  698. *
  699. * templateTfdStart - start/restart the xmit list
  700. *
  701. * This routine is the device level xmit routine.  The packet is given to the
  702. * device for transmission.
  703. *
  704. * RETURNS: N/A.
  705. */
  706. LOCAL void templateTfdStart
  707.     (
  708.     DRV_CTRL *pDrvCtrl /* device pointer */
  709.     )
  710.     {
  711.     /* TODO - setup tx queues */
  712.     pDrvCtrl->txIdle = FALSE;                   /* transmitter busy */
  713.     /* TODO - send start command */
  714.     TEMPLATE_NETIF_WRITE (pDrvCtrl, pCsr, TEMPLATE_CMD_TX_START);
  715.     }
  716. /*******************************************************************************
  717. *
  718. * templateRxStart - start up the Receive Unit
  719. *
  720. * Starts up the Receive Unit.  Assumes that the receive structures are set up.
  721. *
  722. * RETURNS: N/A.
  723. */
  724. LOCAL void templateRxStart
  725.     (
  726.     DRV_CTRL *pDrvCtrl
  727.     )
  728.     {
  729.     /* TODO - send start command */
  730.     TEMPLATE_NETIF_WRITE(pDrvCtrl, pCsr, TEMPLATE_CMD_RX_START);
  731.     }
  732. /*******************************************************************************
  733. *
  734. * templateRfdReturn - return a RFD to the receive queue for use by the device
  735. *
  736. * This routine is used by the protocol layer to return a loaned receive buffer
  737. * back to the driver.
  738. *
  739. * RETURNS: N/A.
  740. */
  741. LOCAL void templateRfdReturn
  742.     (
  743.     DRV_CTRL* pDrvCtrl, /* device pointer */
  744.     RFD* pRfd /* buffer being returned */
  745.     )
  746.     {
  747.     int unit;
  748.     unit = pDrvCtrl->idr.ac_if.if_unit;
  749.     /* TODO - update RFD data */
  750.     pRfd->status    = 0;                    /* clear status */
  751.     pRfd->actualCnt  = 0;                   /* clear actual count */
  752.     pRfd->bufSize   = ETHERMTU + EH_SIZE;   /* fill in size */
  753.     pRfd->refCnt    = 0;                    /* initialize ref cnt */
  754.     /* TODO - link RFD back into queue */
  755.     }
  756. /*******************************************************************************
  757. *
  758. * templateRfdGet - get a received frame from the receive queue
  759. *
  760. * This routine returns a received frame descriptor (incoming packet) to
  761. * the caller.  If no RFD is available, the NULL pointer is returned.
  762. *
  763. * RETURNS:
  764. * A pointer to a valid RFD, or NULL if none available
  765. */
  766. LOCAL RFD *templateRfdGet
  767.     (
  768.     DRV_CTRL *pDrvCtrl /* device pointer */
  769.     )
  770.     {
  771.     RFD *pRfd = NULL;
  772.     if (templateRfdReady (pDrvCtrl))
  773. {
  774.         /* TODO - get RFD from device queue */
  775. }
  776.     return (pRfd);
  777.     }
  778. /*******************************************************************************
  779. *
  780. * templateRfdReady - determine if a RFD is ready for processing
  781. *
  782. * This routine is used to determine if a received frame descriptor (incoming
  783. * packet) is ready for processing.
  784. *
  785. * RETURNS:
  786. * TRUE if complete received frame is available, FALSE otherwise.
  787. */
  788. LOCAL BOOL templateRfdReady
  789.     (
  790.     DRV_CTRL *pDrvCtrl
  791.     )
  792.     {
  793.     UCHAR devStatus;
  794.     TEMPLATE_NETIF_READ(pDrvCtrl, pCsr, devStatus);
  795.     if (devStatus & TEMPLATE_CSR_RFD_READY)
  796. return TRUE;
  797.     return FALSE;
  798.     }