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

VxWorks

开发平台:

C/C++

  1. /* if_fn.c - Fujitsu MB86960 NICE Ethernet network interface driver */
  2. /* Copyright 1992-1997 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01v,15jul97,spm  added ARP request to SIOCSIFADDR ioctl handler
  8. 01u,07apr97,spm  code cleanup, corrected statistics, and upgraded to BSD 4.4
  9. 01t,02mar95,jdi  fixed line break in fnattach() title.
  10. 01s,05jul94,vin  removed spl calls, fixed collision control
  11. 01r,10may94,vin  fixed input parameter passed to etherInputHook
  12. 01q,04mar94,vin  added input & output hooks, removed explicit copying from
  13.  mbufs in the fnOutput(). Alternate scheme to detect 
  14.  transmit done implemented which negates the requirement for
  15.  processing the transmit done interrupt. 
  16. 01p,07jul93,rfs  Fixed SPR #2374.
  17. 01o,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  18. 01n,19feb93,jdi  documentation cleanup.
  19. 01m,22oct92,rfs  Fixed SPR #1710.
  20. 01l,13oct92,rfs  Added documentation.
  21. 01k,02oct92,rfs  Made multiple attach calls return OK, not ERROR.
  22. 01j,09sep92,gae  documentation tweaks.
  23. 01i,31aug92,rfs  Free MBUFs on output if flags down.
  24. 01h,16jul92,rfs  Consolidated attach() and init().
  25. 01g,11jul92,jwt  incorporated JDI documentation cleanup; SPARC #ifdefs.
  26. 01f,16jun92,jwt  passed through the ansification filter
  27.                  -changed includes to have absolute path from h/
  28.                  -fixed #else and #endif
  29.                  -changed copyright notice
  30.                  -fixed path names for #include files.
  31. 01e,14may92,rfs  Added semaphore for transmitter access. Added one-time-only
  32.                  calling of the attach() and init() routines.  Reduced size
  33.                  of SRAM buffer.
  34. 01d,14apr92,rfs  Changed Rx to only look at "good packet" status bit.
  35.                  Changed all splnet() to splimp().
  36. 01c,25mar92,jwt  enhanced interrupt and cache support; cleanup.
  37. 01b,24mar92,rfs  Moved sysEnet* () support routines to the sysLib.
  38.                  Changed the attach and init routines to support new
  39.                  method of obtaining board specific parameters.
  40.                  Changed name of the NICE device header file.
  41.                  Changed the name of the support routines called to access
  42.                  ASI space.
  43. 01a,10mar92,rfs  Created from mule driver source.
  44. */
  45. /*
  46. This module implements the Fujitsu MB86960 NICE Ethernet network interface
  47. driver.
  48. This driver is non-generic and has only been run on the Fujitsu SPARClite
  49. Evaluation Board.  It currently supports only unit number zero.
  50. The driver must be given several target-specific parameters, and some external
  51. support routines must be provided.  These parameters, and the mechanisms used
  52. to communicate them to the driver, are detailed below.
  53. BOARD LAYOUT
  54. This device is on-board.  No jumpering diagram is necessary.
  55. EXTERNAL INTERFACE
  56. This driver provides the standard external interface with the following
  57. exceptions.  All initialization is performed within the attach routine;
  58. there is no separate initialization routine.  Therefore, in the global interface
  59. structure, the function pointer to the initialization routine is NULL.
  60. The only user-callable routine is fnattach(), which publishes the `fn'
  61. interface and initializes the driver and device.
  62. TARGET-SPECIFIC PARAMETERS
  63. External support routines provide all parameters:
  64. .iP "device I/O address"
  65. This parameter specifies the base address of the device's I/O register
  66. set.  This address is assumed to live in SPARClite alternate address
  67. space.
  68. .iP "interrupt vector"
  69. This parameter specifies the interrupt vector to be used by the driver
  70. to service an interrupt from the NICE device.  The driver will connect
  71. the interrupt handler to this vector by calling intConnect().
  72. .iP "Ethernet address"
  73. This parameter specifies the unique, six-byte address assigned to the
  74. VxWorks target on the Ethernet.
  75. .LP
  76. EXTERNAL SUPPORT REQUIREMENTS
  77. This driver requires five external support functions:
  78. .iP "char *sysEnetIOAddrGet (int unit)" "" 9 -1
  79. This routine returns the base address of the NICE
  80. control registers.  The driver calls this routine 
  81. once, using fnattach().
  82. .iP "int sysEnetVectGet (int unit)"
  83. This routine returns the interrupt vector number
  84. to be used to connect the driver's interrupt handler.
  85. The driver calls this routine once, using fnattach().
  86. .iP "STATUS sysEnetAddrGet (int unit, char *pCopy)"
  87. This routine provides the six-byte Ethernet address
  88. used by <unit>.  It must copy the six-byte
  89. address to the space provided by <pCopy>.  It 
  90. returns OK, or ERROR if it fails.
  91. The driver calls this routine once, using fnattach().
  92. .iP "void sysEnetIntEnable (int unit), void sysEnetIntDisable (int unit)"
  93. These routines enable or disable the interrupt from the NICE for the
  94. specified <unit>.  Typically, this involves interrupt controller hardware,
  95. either internal or external to the CPU.  The driver calls these 
  96. routines only during initialization, using fnattach().
  97. .LP
  98. SYSTEM RESOURCE USAGE
  99. When implemented, this driver requires the following system resources:
  100.     - one mutual exclusion semaphore
  101.     - one interrupt vector
  102.     - 3944 bytes in text section (text)
  103.     - 0 bytes in the initialized data section (data)
  104.     - 3152 bytes in the uninitialized data section (BSS)
  105. The above data and BSS requirements are for the SPARClite architecture and may
  106. vary for other architectures.  Code size (text) varies greatly between
  107. architectures and is therefore not quoted here.
  108. The NICE device maintains a private buffer for all packets transmitted and
  109. received.  Therefore, the driver does not require any system memory to share
  110. with the device.  This also eliminates all data cache coherency issues.
  111. SEE ALSO: ifLib
  112. */
  113. /* includes */
  114. #include "vxWorks.h"            /* direct references */
  115. #include "sys/types.h"          /* direct references */
  116. #include "sys/ioctl.h"          /* direct references */
  117. #include "sys/socket.h" /* direct references */
  118. #include "net/mbuf.h"           /* direct references */
  119. #include "net/if.h"             /* direct and indirect references */
  120. #include "net/if_subr.h"
  121. #include "netinet/in.h"         /* indirect references only */
  122. #include "netinet/in_systm.h"   /* indirect references only */
  123. #include "netinet/in_var.h"     /* direct references */
  124. #include "netinet/if_ether.h"   /* direct references */
  125. #include "iv.h"                 /* direct references */
  126. #include "errno.h"              /* direct references */
  127. #include "semLib.h"             /* direct references */
  128. #include "intLib.h"
  129. #include "logLib.h"
  130. #include "netLib.h"
  131. #include "etherLib.h"
  132. #include "stdio.h"
  133. #include "drv/netif/if_fn.h"    /* device description */
  134. /***** COMPILATION SWITCHES *****/
  135. #undef FN_DEBUG
  136. /* defines */
  137. #define MAX_UNITS 1 /* maximum units supported */ 
  138. #define DRV_CTRL_SIZ sizeof (DRV_CTRL)
  139. #define ENET_HDR_REAL_SIZ 14
  140. /* Pre-defined interrupt masks */
  141. #define NORM_INTRMASK    (DLCR3_RX_PKT | DLCR3_OVR_FLO) 
  142. #define NO_RX_INTRMASK   (DLCR3_OVR_FLO)
  143. /* Start transmission */
  144. #define KICK_TRANSMIT (BMR10_TMST | BMR11_MASK16 | BMR11_RST_TX16 
  145.  | BMR11_OPT_16_COLL | 0x0100) 
  146. /* typedefs */
  147. typedef struct arpcom IDR;
  148. typedef struct nice_ctrl /* Driver control structure */
  149.     {
  150.     IDR idr;  /* interface data record */
  151.     BOOL attached; /* indicates unit is attached */
  152.     char *pDev; /* ptr to the device registers */
  153.     int vector; /* vector number to use */
  154. #ifdef BSD43_DRIVER
  155.     SEM_ID TxSem; /* transmitter semaphore */
  156. #endif
  157.     } DRV_CTRL;
  158. /* shorthand for struct members */
  159. #define fn_if  idr.ac_if
  160. #define fn_enaddr  idr.ac_enaddr
  161. /* Debug support */
  162. #ifdef FN_DEBUG
  163. #define DEBUG_SPEC  (fnDebug & 0x01)        /* debug special routines */
  164. #define DEBUG_TX    (fnDebug & 0x02)        /* debug transmit routines */
  165. #define DEBUG_RX    (fnDebug & 0x04)        /* debug receive routines */
  166. #define DEBUG_INTR  (fnDebug & 0x08)        /* debug interrupt routines */
  167. #endif /* FN_DEBUG */
  168. /* globals */
  169. #ifdef FN_DEBUG
  170. int fnDebug;                    /* set this from shell to select debugging */
  171. #endif /* FN_DEBUG */
  172. /* External functions not defined in any header files.
  173.  * Some of these are the functions required of the BSP modules.
  174.  */
  175. extern char *   sysEnetIOAddrGet ();
  176. extern int      sysEnetVectGet ();
  177. extern STATUS   sysEnetAddrGet ();
  178. extern STATUS   sysEnetIntEnable ();
  179. extern STATUS   sysEnetIntDisable ();
  180. extern STATUS   sysEnetIntAck ();
  181. extern BOOL arpresolve ();
  182. /* External functions that access the alternate address space that the
  183.  * device lives in.
  184.  */
  185. #if (CPU_FAMILY == SPARC)
  186. extern u_short      sysAsiGeth();
  187. extern void         sysAsiSeth();
  188. #endif
  189. /* locals */
  190. /* driver control structures, one per unit */ 
  191. LOCAL DRV_CTRL drvCtrl [MAX_UNITS];  
  192. LOCAL int overFlowCnt; /* overFlow Count */
  193. LOCAL int rcvPktError; /* receive packet error */
  194. /* forward declarations */
  195. LOCAL int fnIoctl (struct ifnet * pIfnet, int cmd, char * pArgs);
  196. LOCAL int fnReset (int unit);
  197. #ifdef BSD43_DRIVER
  198. LOCAL int fnOutput (struct arpcom * pIDR, struct mbuf * pMbuf,
  199.   struct sockaddr * pDest);
  200. #else
  201. LOCAL int       fnTxStartup (DRV_CTRL *pDrvCtrl);
  202. #endif
  203. LOCAL void fnRxEvent (DRV_CTRL *pDrvCtrl);
  204. LOCAL BOOL fnRxMore (DRV_CTRL *pDrvCtrl);
  205. LOCAL STATUS fnRxProcessPkt (DRV_CTRL *pDrvCtrl);
  206. LOCAL void fnIntr (int unit);
  207. #ifdef BSD43_DRIVER
  208. LOCAL BOOL convertDestAddr (IDR *pIdr, struct sockaddr * pDestSktAddr, 
  209.  char * pDestEnetAddr, u_short * pPacketType,
  210.  struct mbuf * pMbuf);
  211. #endif
  212. /*******************************************************************************
  213. *
  214. * fnattach - publish the `fn' network interface and initialize the driver and device
  215. *
  216. * The routine publishes the `fn' interface by filling in a network interface
  217. * record and adding this record to the system list.  This routine also
  218. * initializes the driver and the device to the operational state.
  219. *
  220. * RETURNS: OK or ERROR.
  221. */
  222. STATUS fnattach
  223.     (
  224.     int unit /* unit number */
  225.     )
  226.     {
  227.     char * pDev; /* ptr to the device */
  228.     DRV_CTRL *  pDrvCtrl;
  229.     /* Sanity check the unit number */
  230.     if (unit < 0 || unit >= MAX_UNITS)
  231.         return (ERROR);
  232.     /* Ensure single invocation per system life */
  233.     pDrvCtrl = & drvCtrl [unit];
  234.     if (pDrvCtrl->attached)
  235.         return (OK);
  236.     /* Publish our existence as an available interface */
  237. #ifdef BSD43_DRIVER
  238.     ether_attach (&pDrvCtrl->fn_if, unit, "fn", NULL, fnIoctl, 
  239.                   fnOutput, fnReset);
  240. #else
  241.     ether_attach (
  242.                  &pDrvCtrl->fn_if, 
  243.                  unit,
  244.                  "fn",
  245.                  (FUNCPTR) NULL,
  246.                  (FUNCPTR) fnIoctl,
  247.                  (FUNCPTR) ether_output,
  248.                  (FUNCPTR) fnReset
  249.                  );
  250.     pDrvCtrl->fn_if.if_start = (FUNCPTR)fnTxStartup;
  251. #endif
  252. { /*   Driver initialization    */
  253. /* First obtain the board and unit specific info from the BSP. */
  254. pDev = sysEnetIOAddrGet (unit);
  255. if (pDev == NULL)
  256.     {
  257.     printf ("fn: error obtaining IO addrn");
  258.     return (ERROR);
  259.     }
  260. pDrvCtrl->pDev = pDev;                  /* save ptr in ctrl struct */
  261. pDrvCtrl->vector = sysEnetVectGet (unit);
  262. if (pDrvCtrl->vector == NULL)
  263.     {
  264.     printf ("fn: error obtaining interrupt vectorn");
  265.     return (ERROR);
  266.     }
  267. if (sysEnetAddrGet (unit, pDrvCtrl->fn_enaddr) == ERROR)
  268.     {
  269.     printf ("fn: error obtaining Ethernet addressn");
  270.     return (ERROR);
  271.     }
  272. #ifdef BSD43_DRIVER
  273. pDrvCtrl->TxSem = semMCreate    (
  274.  SEM_Q_PRIORITY |
  275.  SEM_DELETE_SAFE |
  276.  SEM_INVERSION_SAFE
  277. );
  278. if (pDrvCtrl->TxSem == NULL)
  279.     {
  280.     printf ("fn: error creating transmitter semaphoren");
  281.     return (ERROR);
  282.     }
  283. #endif
  284. /* Connect the interrupt routine. */
  285. intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (pDrvCtrl->vector), fnIntr, 
  286.     unit);
  287. } /* End block */
  288. { /*    device initialization    */
  289. /* Block local variables */
  290. u_short temp;                               /* scratch pad */
  291. /* initial setup of config register 1 */
  292. #if (CPU_FAMILY == SPARC)
  293. sysAsiSeth  (pDev + NICE_CONFIG,
  294.      DLCR6_DISABLE_DLC   |           /* resets things */
  295.      DLCR6_BIT_6         |           /* just do it */
  296.      DLCR6_SYS_BUS_16    |           /* use 16 bits */
  297.      DLCR6_BUF_BUS_16    |           /* use 16 bits */
  298.      DLCR6_TBS_4KB       |           /* Tx buf is 4kb */
  299.      DLCR6_BS_16KB       |           /* total buf is 16k */
  300.      DLCR7_CNF_NICE      |           /* normal NICE mode */
  301.      DLCR7_PWRDN_OFF     |           /* normal power mode */
  302.      DLCR7_BIT_4         |           /* just do it */
  303.      DLCR7_REG_BNK_DLC   |           /* map node ID regs */
  304.      DLCR7_ENDIAN_LITTLE             /* device is little */
  305.      );
  306. #endif
  307. /* Mask off all interrupts and clear all event flags. */
  308. #if (CPU_FAMILY == SPARC)
  309. sysAsiSeth (pDev + NICE_INTRMASK, 0);
  310. sysAsiSeth (pDev + NICE_STATUS, 0xffff);
  311. #endif
  312. /* Disable device interrupt at system level and clear any pended. */
  313. sysEnetIntDisable (unit);
  314. /* The secondary DLC register group is mapped in.  Set the node ID. */
  315. #if (CPU_FAMILY == SPARC)
  316. sysAsiSeth (pDev + NICE_ADDR1, ((u_short *) pDrvCtrl->fn_enaddr) [0]);
  317. sysAsiSeth (pDev + NICE_ADDR2, ((u_short *) pDrvCtrl->fn_enaddr) [1]);
  318. sysAsiSeth (pDev + NICE_ADDR3, ((u_short *) pDrvCtrl->fn_enaddr) [2]);
  319. #endif
  320. /* Change register map. Select buffer memory register group. */
  321. #if (CPU_FAMILY == SPARC)
  322. temp = sysAsiGeth (pDev + NICE_CONFIG);
  323. #endif
  324. temp &= ~DLCR7_REG_BNK; /* clear bank select bits */
  325. temp |= DLCR7_REG_BNK_BMR; /* add desired bits */
  326. #if (CPU_FAMILY == SPARC)
  327. sysAsiSeth (pDev + NICE_CONFIG, temp);
  328. #endif
  329. /* Setup the receiver and transmitter modes. */
  330. #if (CPU_FAMILY == SPARC)
  331. sysAsiSeth (pDev + NICE_MODE, DLCR4_LBC | DLCR5_BIT_2 | DLCR5_AF0);
  332. #endif
  333. /* Do the board specific interrupt enable for the device. */
  334. sysEnetIntEnable (unit);
  335. /* Enable specific interrupts. */
  336. #if (CPU_FAMILY == SPARC)
  337. sysAsiSeth (pDev + NICE_INTRMASK, NORM_INTRMASK);
  338. #endif
  339. /* Enable the DLC. */
  340. #if (CPU_FAMILY == SPARC)
  341. temp = sysAsiGeth (pDev + NICE_CONFIG);     /* get config reg */
  342. #endif
  343. temp &= ~DLCR6_DISABLE_DLC;                 /* clear the disable bit */
  344. #if (CPU_FAMILY == SPARC)
  345. sysAsiSeth (pDev + NICE_CONFIG, temp);      /* update config reg */
  346. /* set collision control drop packet after 16 collisions */
  347. sysAsiSeth (pDev + NICE_TRANSMIT, (BMR11_MASK16 | BMR11_RST_TX16
  348.    | BMR11_OPT_16_COLL));
  349. #endif
  350. } /* End block */
  351.     /* Set our interface flags. */
  352.     pDrvCtrl->idr.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_NOTRAILERS);
  353.     /* That's all */
  354.     pDrvCtrl->attached = TRUE;
  355.     return (OK);
  356.     } /* End of fnattach() */
  357. /*******************************************************************************
  358. *
  359. * fnIoctl - the driver I/O control routine
  360. *
  361. * This routine will process an ioctl request 
  362. *
  363. * RETURNS: 0 or errno
  364. */
  365. LOCAL int fnIoctl 
  366.     (
  367.     struct ifnet * pIfnet, /* ptr to our interface struct */
  368.     int cmd, /* the command code */
  369.     char * pArgs /* ptr to the command arguments */
  370.     )
  371.     {
  372.     int errno; /* hold error value or zero */
  373.     int   unit = pIfnet->if_unit;
  374.     DRV_CTRL *  pDrvCtrl = &drvCtrl[unit];
  375. #ifdef FN_DEBUG
  376.     if (DEBUG_SPEC)
  377.         printf  (
  378.                 "fn: ioctl: pIfnet=%x  cmd=%x  pArgs=%xn",
  379.                 pIfnet, cmd, pArgs
  380.                 );
  381. #endif /* FN_DEBUG */
  382.     errno = 0;                              /* assume no error */
  383.     switch (cmd)
  384.         {
  385.         case SIOCSIFADDR:                   /* set i/f address */
  386. #ifdef FN_DEBUG
  387.             if (DEBUG_SPEC)
  388.                 printf ("fn: ioctl: set addrn");
  389. #endif /* FN_DEBUG */
  390.             /* copy the INET address into our arpcom structure */
  391.             pDrvCtrl->idr.ac_ipaddr = IA_SIN (pArgs)->sin_addr;
  392.             arpwhohas (pIfnet, &IA_SIN (pArgs)->sin_addr);
  393.             break;
  394.         case SIOCGIFADDR:                   /* get i/f address */
  395. #ifdef FN_DEBUG
  396.             if (DEBUG_SPEC)
  397.                 printf ("fn: ioctl: get addrn");
  398. #endif /* FN_DEBUG */
  399.             bcopy   (
  400.                     (caddr_t) pDrvCtrl->fn_enaddr,
  401.                     (caddr_t) ((struct ifreq *)pArgs)->ifr_addr.sa_data,
  402.                     6
  403.                     );
  404.             break;
  405.         case SIOCSIFFLAGS:                  /* set i/f flags */
  406. #ifdef FN_DEBUG
  407.             if (DEBUG_SPEC)
  408.                 printf ("fn: ioctl: set flagsn");
  409. #endif /* FN_DEBUG */
  410.             break;
  411.         case SIOCGIFFLAGS:                  /* get i/f flags */
  412. #ifdef FN_DEBUG
  413.             if (DEBUG_SPEC)
  414.                 printf ("fn: ioctl: get flagsn");
  415. #endif /* FN_DEBUG */
  416.             *(short *)pArgs = pIfnet->if_flags;
  417.             break;
  418.         default :
  419.             errno = EINVAL;
  420.         }
  421.     return (errno);
  422.     } /* End of fnIoctl() */
  423. /*******************************************************************************
  424. *
  425. * fnReset - the driver reset routine
  426. *
  427. * This routine resets the device
  428. *
  429. * RETURNS: OK.
  430. */
  431. LOCAL int fnReset 
  432.     (
  433.     int unit
  434.     )
  435.     {
  436. #ifdef FN_DEBUG
  437.     if (DEBUG_SPEC)
  438.         printf ("fnResetn");
  439. #endif /* FN_DEBUG */
  440.     return (OK);
  441.     } /* End of fnReset() */
  442. #ifdef BSD43_DRIVER
  443. /*******************************************************************************
  444. *
  445. * fnOutput - The driver's output routine
  446. *
  447. * This routine is responsible for tranmitting packets over physical media.
  448. * The destination address is passed to this function as a pointer to a
  449. * generic socket address structure.  This address information is first
  450. * converted to the six byte destination address and type field that we
  451. * need to build a proper Ethernet frame.
  452. *
  453. * The data to be sent out is held in a chain of mbufs.  This function is
  454. * passed a pointer to the head mbuf.  The data in each mbuf fragment must
  455. * be copied to the device's packet buffer.
  456. *
  457. * RETURNS: OK, or ERROR
  458. */
  459. LOCAL int fnOutput 
  460.     (
  461.     struct arpcom * pIDR, /* ptr to our interface struct */
  462.     struct mbuf * pMbuf, /* ptr to the mbufs to send */
  463.     struct sockaddr * pDest /* ptr to dest socket addr */
  464.     )
  465.     {
  466.     char  destEnetAddr [6]; /* space for enet addr */
  467.     u_short packetType; /* type field for the packet */
  468.     int pktLen; /* total length of packet */
  469.     int dataLen; /* real length of data portion */
  470.     int loopy; /* loop counter */
  471.     char *nicePort; /* ptr to the nice buffer port */
  472.     u_short *pSource; /* ptr to source of data byte */
  473.     DRV_CTRL *  pDrvCtrl;  /* ptr to driver control structure */
  474.     static char privateBuf [ETHERMTU + ENET_HDR_REAL_SIZ];
  475. #ifdef FN_DEBUG
  476.     if (DEBUG_TX)
  477.         printf  (
  478.                 "fn: Tx: pIfnet=%x  pMbuf=%x  pDest=%xn",
  479.                 pIfnet, pMbuf, pDest
  480.                 );
  481. #endif /* FN_DEBUG */
  482.     /* Check ifnet flags. Return error if incorrect. */
  483.     if  (
  484.         (pIfnet->if_flags & (IFF_UP | IFF_RUNNING)) !=
  485.         (IFF_UP | IFF_RUNNING)
  486.         )
  487.         {
  488.         m_freem (pMbuf);
  489.         return (ENETDOWN);
  490.         }
  491.     /* Attempt to convert socket addr into enet addr and packet type.
  492.      * Note that if ARP resolution of the address is required, the ARP
  493.      * module will call our routine again to transmit the ARP request
  494.      * packet.  This means we may actually call ourselves recursively!
  495.      */
  496.     if (convertDestAddr (pIDR, pDest, destEnetAddr, &packetType, pMbuf) 
  497.            == FALSE)
  498.         return (OK);    /* I KNOW returning OK is stupid, but it is correct */
  499.     /* Get driver control pointer */
  500.     pDrvCtrl = &drvCtrl [pIDR->ac_if.if_unit];
  501.     /* get ptr to the buffer port */
  502.     nicePort = pDrvCtrl->pDev + NICE_PORT;
  503.     semTake (pDrvCtrl->TxSem, WAIT_FOREVER); /* take the xmit semaphore */
  504.     bcopy (destEnetAddr, privateBuf, 6);
  505.     bcopy ( (char *) pDrvCtrl->fn_enaddr, (privateBuf + 6), 6);
  506.     ((struct ether_header *)privateBuf)->ether_type = packetType;
  507.     dataLen = 0;
  508.     copy_from_mbufs ((privateBuf + ENET_HDR_REAL_SIZ),
  509.   pMbuf, 
  510.   dataLen);  /* stuffed by macro */
  511. #ifdef FN_DEBUG
  512.     if (DEBUG_TX)
  513.         printf ("fn: Tx: dataLen=%dn", dataLen);
  514. #endif /* FN_DEBUG */
  515.     
  516.     /* Ensure we send a legal size frame. */
  517.     dataLen += ENET_HDR_REAL_SIZ;
  518.     pktLen = max (ETHERSMALL, dataLen);
  519.     /* taking care of short packets, pad with 0s */
  520.     if (dataLen < ETHERSMALL)
  521. for (loopy = dataLen; loopy < pktLen; loopy++)
  522.             privateBuf [loopy] = 0;
  523.     /*
  524.      * Support for network interface hooks. Call output hook
  525.      * if any specified. If the routine returns non-zero, 
  526.      * assume the hook has taken care of the frame (don't send
  527.      * on interface). See etherLib for more information
  528.      */
  529.     if ((etherOutputHookRtn != NULL) && 
  530. (* etherOutputHookRtn) (&pDrvCtrl->fn_if, privateBuf, pktLen))
  531. goto outputDone; /* goto the end */
  532.     /* Tell the device the length; in little endian order */
  533. #if (CPU_FAMILY == SPARC)
  534.     sysAsiSeth  (nicePort,
  535.                 ((pktLen & 0xff00) >> 8) |
  536.                 ((pktLen & 0x00ff) << 8)
  537.                 );
  538. #endif
  539.     pSource = (u_short *) privateBuf;
  540.     for (loopy = pktLen; loopy > 0 ; loopy -= sizeof (u_short))
  541. {
  542. #if (CPU_FAMILY == SPARC)
  543.      sysAsiSeth (nicePort, *pSource);
  544. #endif
  545. pSource++;
  546. }
  547.     if (pktLen % sizeof (u_short)) /* packet size is odd */
  548. {
  549. unsigned short lastByte;
  550. lastByte = 0;
  551. ((char *) (&lastByte)) [0] = ((char *) (pSource)) [0];
  552. #if (CPU_FAMILY == SPARC)
  553.  sysAsiSeth (nicePort, lastByte);
  554. #endif
  555. }
  556.     /* See if transmitter is free and start it orelse  wait.  */
  557. #if (CPU_FAMILY == SPARC)
  558.     while ((sysAsiGeth (pDrvCtrl->pDev + NICE_TRANSMIT)) & (0x7f << 8))
  559.      ; /* loop until transmit count is 0 */
  560.     sysAsiSeth (pDrvCtrl->pDev + NICE_TRANSMIT, KICK_TRANSMIT);
  561. #endif
  562.     /* Bump the statistic counter. */
  563.     pDrvCtrl->fn_if.if_opackets++;
  564.     /* That's all. */
  565.     outputDone:
  566.     semGive (pDrvCtrl->TxSem);
  567.     return (0);
  568.     } /* End of fnOutput() */
  569. #else
  570. /*******************************************************************************
  571. *
  572. * fnTxStartup - kick start the transmitter after generic ether_output
  573. *
  574. * This routine is responsible for tranmitting packets over physical media.
  575. * The data to be sent out is held in a chain of mbufs. The data in each mbuf 
  576. * fragment must be copied to the device's packet buffer.
  577. *
  578. * RETURNS: OK, or ERROR
  579. */
  580. LOCAL int fnTxStartup
  581.     (
  582.     DRV_CTRL *  pDrvCtrl  /* pointer to driver control structure */
  583.     )
  584.     {
  585.     struct mbuf * pMbuf; /* ptr to the mbufs to send */
  586.     int pktLen; /* total length of packet */
  587.     int dataLen; /* real length of data portion */
  588.     int loopy; /* loop counter */
  589.     char *nicePort; /* ptr to the nice buffer port */
  590.     u_short *pSource; /* ptr to source of data byte */
  591.     static char privateBuf [ETHERMTU];
  592.     /* get ptr to the buffer port */
  593.     nicePort = pDrvCtrl->pDev + NICE_PORT;
  594.     while (pDrvCtrl->idr.ac_if.if_snd.ifq_head)
  595.         {
  596.         /* Dequeue a packet from the send queue. */
  597.         IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf);
  598.         /*
  599.          * This driver maintains transmit resources internally. The 
  600.          * CPU cannot retrieve or examine them.
  601.          */
  602.         copy_from_mbufs (privateBuf, pMbuf, dataLen);
  603. #ifdef FN_DEBUG
  604.         if (DEBUG_TX)
  605.             printf ("fn: Tx: dataLen=%dn", dataLen);
  606. #endif /* FN_DEBUG */
  607.     
  608.         /* Ensure we send a legal size frame. */
  609.         pktLen = max (ETHERSMALL, dataLen);
  610.         /* taking care of short packets, pad with 0s */
  611.         if (dataLen < ETHERSMALL)
  612.     for (loopy = dataLen; loopy < pktLen; loopy++)
  613.                privateBuf [loopy] = 0;
  614.         /*
  615.          * Support for network interface hooks. Call output hook
  616.          * if any specified. If the routine returns non-zero, 
  617.          * assume the hook has taken care of the frame (don't send
  618.          * on interface). See etherLib for more information
  619.          */
  620.         if ( (etherOutputHookRtn != NULL) && 
  621.      (* etherOutputHookRtn) (&pDrvCtrl->fn_if, privateBuf, pktLen))
  622.             continue;
  623.          /* Tell the device the length; in little endian order */
  624. #if (CPU_FAMILY == SPARC)
  625.         sysAsiSeth  (nicePort,
  626.                      ( (pktLen & 0xff00) >> 8) | ( (pktLen & 0x00ff) << 8));
  627. #endif
  628.         pSource = (u_short *)privateBuf;
  629.         for (loopy = pktLen; loopy > 0 ; loopy -= sizeof (u_short))
  630.     {
  631. #if (CPU_FAMILY == SPARC)
  632.          sysAsiSeth (nicePort, *pSource);
  633. #endif
  634.     pSource++;
  635.     }
  636.         if (pktLen % sizeof (u_short)) /* packet size is odd */
  637.     {
  638.     unsigned short lastByte;
  639.     lastByte = 0;
  640.     ( (char *) (&lastByte))[0] = ((char *) (pSource))[0];
  641. #if (CPU_FAMILY == SPARC)
  642.     sysAsiSeth (nicePort, lastByte);
  643. #endif
  644.     }
  645.         /* See if transmitter is free and start it orelse  wait.  */
  646. #if (CPU_FAMILY == SPARC)
  647.         while ( (sysAsiGeth (pDrvCtrl->pDev + NICE_TRANSMIT)) & (0x7f << 8))
  648.          ;  /* loop until transmit count is 0 */
  649.         sysAsiSeth (pDrvCtrl->pDev + NICE_TRANSMIT, KICK_TRANSMIT);
  650. #endif
  651.         /* Bump the statistic counter. */
  652.         pDrvCtrl->fn_if.if_opackets++;
  653.         }
  654.     return (0);
  655.     }
  656. #endif
  657. /*******************************************************************************
  658. *
  659. * fnRxEvent - process the receiver event from the device
  660. *
  661. * This routine is the top level receiver handler.  Runs as long as packets 
  662. * left in the buffer.
  663. *
  664. * RETURNS: N/A
  665. */
  666. LOCAL void fnRxEvent 
  667.     (
  668.     DRV_CTRL *  pDrvCtrl  /* pointer to driver control structure */
  669.     )
  670.     {
  671.     char * pDev; /* ptr to the device regs */
  672.     /* Check ifnet flags. Return if we're down, leaving interrupt disabled. */
  673.     if  (
  674.         (pDrvCtrl->fn_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
  675.         (IFF_UP | IFF_RUNNING)
  676.         )
  677.         return;
  678.     pDev = pDrvCtrl->pDev;                      /* get ptr to device */
  679.     /* While more packets, process the packet. */
  680.     while ( fnRxMore (pDrvCtrl) )
  681. {
  682.         if (fnRxProcessPkt (pDrvCtrl) == ERROR)
  683.     {
  684.     rcvPktError++;  /* bump the recieve packet error counter */
  685.             break;
  686.     }
  687. }
  688.     /* Turn the receive interrupts on again. */
  689. #if (CPU_FAMILY == SPARC)
  690.     sysAsiSeth (pDev + NICE_INTRMASK, NORM_INTRMASK);
  691. #endif
  692.     } /* End of fnRxEvent() */
  693. /*******************************************************************************
  694. *
  695. * fnRxMore - indicates more packets in the buffer
  696. *
  697. * This routine indicates that there are more packets left in the buffer
  698. *
  699. * RETURNS: TRUE or FALSE
  700. */
  701. LOCAL BOOL fnRxMore 
  702.     (
  703.     DRV_CTRL *  pDrvCtrl  /* pointer to driver control structure */ 
  704.     )
  705.     {
  706.     u_short  mode;
  707.     char * pDev; /* ptr to the device regs */
  708.     pDev = pDrvCtrl->pDev; /* get ptr to device */
  709. #if (CPU_FAMILY == SPARC)
  710.     mode = sysAsiGeth (pDev + NICE_MODE);
  711. #endif
  712.     if (mode & DLCR5_BUF_EMPTY)
  713.         return (FALSE);
  714.     else
  715.         return (TRUE);
  716.     } /* End of fnRxMore() */
  717. /*******************************************************************************
  718. *
  719. * fnRxProcessPkt - process the next available packet
  720. *
  721. * RETURNS: OK, or ERROR.
  722. */
  723. LOCAL STATUS fnRxProcessPkt 
  724.     (
  725.     DRV_CTRL *  pDrvCtrl  /* pointer to driver control structure */
  726.     )
  727.     {
  728.     int loopy; /* loop counter */
  729.     int  dataLen; /* length of packet data */
  730.     char * pDev; /* ptr to the device regs */
  731.     u_short * pDest; /* ptr to destination */
  732.     struct mbuf * pMbuf; /* ptr to mbufs */
  733.     RX_HDR  rxHdr; /* an Rx pkt header */
  734.     /* allocate space for one received frame */
  735.     static struct rx_frame
  736.         {
  737.         struct ether_header enetHdr;            /* the Ethernet header */
  738.         char data [1500];                       /* the data field */
  739.         } rxFrame;
  740.     pDev = pDrvCtrl->pDev;                      /* get ptr to device */
  741.     /* Fill our local copy of the Rx header from the device's buffer. */
  742. #if (CPU_FAMILY == SPARC)
  743.     rxHdr.status = sysAsiGeth (pDev + NICE_PORT);
  744.     rxHdr.len    = sysAsiGeth (pDev + NICE_PORT);
  745. #endif
  746.     rxHdr.len    = ((rxHdr.len & 0xff00) >> 8) |            /* swap bytes */
  747.                     ((rxHdr.len & 0x00ff) << 8);
  748.     /* Clear the status bit for packet ready. */
  749. #if (CPU_FAMILY == SPARC)
  750.     sysAsiSeth (pDev + NICE_STATUS, DLCR1_RX_PKT);
  751. #endif
  752. #ifdef FN_DEBUG
  753.     if (DEBUG_RX)
  754.         printf  (
  755.                 "fn: Rx: status=%04x  len=%dn",
  756.                 rxHdr.status & 0xff00,  rxHdr.len
  757.                 );
  758. #endif /* FN_DEBUG */
  759.     /* Sanity check the packet info. */
  760.     if  (
  761.         (!(rxHdr.status & RX_HDR_STAT_GOOD))        ||
  762.         (rxHdr.len < 60)                            ||
  763.         (rxHdr.len > 1514)
  764.         )
  765.         {
  766.         printf  ("fn: Fatal error, invalid receiver header %04x %04xn",
  767.                 rxHdr.status, rxHdr.len);
  768.         pDrvCtrl->fn_if.if_ierrors++;                       /* bump errors */
  769.         pDrvCtrl->fn_if.if_flags &= ~(IFF_UP | IFF_RUNNING);   /* flags down */
  770.         return (ERROR);
  771.         }
  772.     /* Bump the statistic counter */
  773.     pDrvCtrl->fn_if.if_ipackets++;
  774.     /* Fill our frame buffer from the device's buffer. */
  775.     pDest = (u_short *) &rxFrame;                   /* stuff ptr */
  776.     for (loopy = rxHdr.len; loopy > 0; loopy -= sizeof (u_short))
  777. #if (CPU_FAMILY == SPARC)
  778.         *pDest++ = sysAsiGeth (pDev + NICE_PORT);
  779. #else
  780.         ;
  781. #endif
  782.     /*
  783.      * Support for network interface hooks. Call input hook if any
  784.      * specified. If the routine returns non-zero, assume the 
  785.      * hook has taken care of the frame. See etherLib in the Vxworks
  786.      * Reference Manual for more information.
  787.      */
  788.     if ((etherInputHookRtn != NULL) &&
  789. ((*etherInputHookRtn) (&pDrvCtrl->fn_if, (char *) &rxFrame , rxHdr.len) 
  790.  != 0))
  791.      return (OK);
  792.     /* Copy our frame buffer into mbufs. */
  793.     dataLen = rxHdr.len - ENET_HDR_REAL_SIZ;        /* obtain data length */
  794.     pMbuf = copy_to_mbufs (rxFrame.data, dataLen, 0, &pDrvCtrl->fn_if);
  795.     /* Give the mbufs to the upper layers */
  796.     if (pMbuf != NULL)
  797. #ifdef BSD43_DRIVER
  798.         do_protocol_with_type   (
  799.                                 rxFrame.enetHdr.type,   /* packet type */
  800.                                 pMbuf,                  /* the mbufs */
  801.                                 &pDrvCtrl->idr,  /* interface data record */
  802.                                 dataLen                 /* length of data */
  803.                                 );
  804. #else
  805.         do_protocol (&rxFrame.enetHdr, pMbuf, &pDrvCtrl->idr, dataLen);
  806. #endif
  807.     else
  808.         pDrvCtrl->idr.ac_if.if_ierrors++;
  809. #ifdef FN_DEBUG
  810.     logMsg ("fn: Sent packet up.n", 0, 0,  0, 0, 0, 0);
  811. #endif
  812.     return (OK);
  813.     } /* End of fnRxProcessPkt() */
  814. /*******************************************************************************
  815. *
  816. * fnIntr - the driver interrupt handler routine
  817. *
  818. * This routine is called at interrupt level in response to an interrupt from
  819. * the controller.
  820. *
  821. * RETURNS: N/A
  822. */
  823. LOCAL void fnIntr 
  824.     (
  825.     int unit /* unit number to service */
  826.     )
  827.     {
  828.     char *pDev; /* ptr to the device regs */
  829.     u_short event;
  830.     u_short reg;
  831.     DRV_CTRL *  pDrvCtrl;  /* ptr to driver control structure */
  832.     pDrvCtrl = &drvCtrl [unit]; 
  833.     pDev    = pDrvCtrl->pDev;
  834. #if (CPU_FAMILY == SPARC)
  835.     event   = sysAsiGeth (pDev + NICE_STATUS);      /* get intr status */
  836.     reg     = sysAsiGeth (pDev + NICE_INTRMASK);    /* get current mask */
  837. #endif
  838. #ifdef FN_DEBUG
  839.     if (DEBUG_INTR)
  840.         logMsg ("fn: Intr: event=%04xn", event, 0, 0, 0, 0, 0);
  841. #endif /* FN_DEBUG */
  842.     /* Handle receiver overflow event. */
  843.     if (event & DLCR1_OVR_FLO)
  844. {
  845. overFlowCnt++;  /* bump the counter */
  846. #if (CPU_FAMILY == SPARC)
  847.   sysAsiSeth (pDev + NICE_STATUS, DLCR1_OVR_FLO); 
  848. #endif
  849.   return; 
  850.     /* Handle the receiver event, only if it was enabled. */
  851.     if ((reg & DLCR3_RX_PKT) && (event & DLCR1_RX_PKT))
  852.         {
  853. #if (CPU_FAMILY == SPARC)
  854.         sysAsiSeth (pDev + NICE_INTRMASK, NO_RX_INTRMASK);  /* disable */
  855. #endif
  856.         netJobAdd ((FUNCPTR)fnRxEvent, (int)pDrvCtrl, 0,0,0,0);
  857.         }
  858.     /* ACK the interrupts */
  859. #if (CPU_FAMILY == SPARC)
  860.     sysAsiSeth (pDev + NICE_STATUS, event);
  861. #endif
  862.     } /* End of fnIntr() */
  863. #ifdef BSD43_DRIVER
  864. /*******************************************************************************
  865. *
  866. * convertDestAddr - converts socket addr into enet addr and packet type
  867. *
  868. * RETURNS: TRUE or FALSE
  869. */
  870. LOCAL BOOL convertDestAddr 
  871.     (
  872.     IDR *  pIDR,  /* ptr to interface data record */
  873.     struct sockaddr * pDestSktAddr, /* ptr to a generic sock addr */
  874.     char * pDestEnetAddr, /* where to write enet addr */
  875.     u_short * pPacketType, /* where to write packet type */
  876.     struct mbuf * pMbuf /* ptr to mbuf data */
  877.     )
  878.     {
  879.     /***** Internet family *****/
  880.     {
  881.     struct in_addr destIPAddr; /* not used */
  882.     int trailers; /* not supported */
  883.     if (pDestSktAddr->sa_family == AF_INET)
  884.         {
  885.         *pPacketType = ETHERTYPE_IP;            /* stuff packet type */
  886.         destIPAddr = ((struct sockaddr_in *) pDestSktAddr)->sin_addr;
  887.  
  888.         if (!arpresolve (pIDR, pMbuf, &destIPAddr, pDestEnetAddr, &trailers))
  889.             return (FALSE);     /* if not yet resolved */
  890.         return (TRUE);
  891.         }
  892.     }
  893.     /***** Generic family *****/
  894.     {
  895.     struct ether_header * pEnetHdr;
  896.     if (pDestSktAddr->sa_family == AF_UNSPEC)
  897.         {
  898.         pEnetHdr = (struct ether_header *) pDestSktAddr->sa_data;
  899.         bcopy ( (char *)pEnetHdr->ether_dhost, pDestEnetAddr, 6);
  900.         *pPacketType = pEnetHdr->ether_type;
  901.         return (TRUE);
  902.         }
  903.     }
  904.     /* Unsupported family */
  905.     
  906.     return (FALSE);
  907.     }
  908. #endif    /* BSD43_DRIVER */
  909. /* END OF FILE */