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

VxWorks

开发平台:

C/C++

  1. /* if_seeq.c - Seeq 8005 Ethernet network interface driver */
  2. /* Copyright 1984-1996 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01a,21apr96,mem  written, based on other drivers.
  8. */
  9. /*
  10. This module implements the Seeq 8005 Ethernet network interface
  11. driver.
  12. This driver was originally developed for the Motorola IDP ethernet
  13. card.
  14. At this time, the driver makes the following assumptions:
  15.   - A 16-bit path to the SEEQ chip is available.
  16. This driver is designed to be moderately generic, operating unmodified
  17. across the range of architectures and targets supported by VxWorks.
  18. To achieve this, the driver must be given several target-specific
  19. parameters, and some external support routines must be provided.
  20. These parameters, and the mechanisms used to communicate them to the
  21. driver, are detailed below.  If any of the assumptions stated below
  22. are not true for your particular hardware, this driver will probably
  23. not function correctly with it.
  24. BOARD LAYOUT
  25. We have yet to see documentation on the jumpers, so don't change them.
  26. EXTERNAL INTERFACE
  27. This driver provides the standard external interface with the
  28. following exceptions.  All initialization is performed within the
  29. attach routine; there is no separate initialization routine.
  30. Therefore, in the global interface structure, the function pointer to
  31. the initialization routine is NULL.
  32. The only user-callable routine is seeqattach(), which publishes the
  33. `seeq' interface and initializes the driver and device.
  34. TARGET-SPECIFIC PARAMETERS
  35. .iP "base address of device registers"
  36. This parameter is passed to the driver by seeqattach().  It indicates
  37. to the driver where to find the device registers.
  38. .iP "interrupt vector"
  39. This parameter is passed to the driver by seeqattach().
  40. .iP "interrupt level"
  41. This parameter is passed to the driver by seeqattach().
  42. .iP "Ethernet address"
  43. This parameter is obtained directly from a global memory location.
  44. During initialization, the driver needs to know the Ethernet address for
  45. the SEEQ device.  The driver assumes that this address is available in
  46. a global, six-byte character array, seeqEnetAddr[].  This array is
  47. typically created and stuffed by the BSP code.
  48. .LP
  49. SYSTEM RESOURCE USAGE
  50. When implemented, this driver requires the following system resources:
  51.     - one interrupt vector
  52.     - one watchdog timer
  53.     - 12 bytes in the initialized data section (data)
  54.     - 4264 bytes in the uninitialized data section (BSS)
  55.     - 4096 bytes of allocated buffer space.
  56. The above data and BSS requirements are for the MCF5200 architecture
  57. and may vary for other architectures.  Code size (text) varies greatly
  58. between architectures and is therefore not quoted here.
  59. SEE ALSO: ifLib, 
  60. .I "SEEQ 8005 Advanced Ethernet Data Link Controller"
  61. */
  62. /* includes */
  63. #include "vxWorks.h"
  64. #include "stdlib.h"
  65. #include "taskLib.h"
  66. #include "logLib.h"
  67. #include "intLib.h"
  68. #include "netLib.h"
  69. #include "stdio.h"
  70. #include "stdlib.h"
  71. #include "sysLib.h"
  72. #include "wdLib.h"
  73. #include "iv.h"
  74. #include "memLib.h"
  75. #include "sys/ioctl.h"
  76. #include "etherLib.h"
  77. #ifndef DOC             /* don't include when building documentation */
  78. #include "net/mbuf.h"
  79. #endif  /* DOC */
  80. #include "net/protosw.h"
  81. #include "sys/socket.h"
  82. #include "errno.h"
  83. #include "net/if.h"
  84. #include "net/route.h"
  85. #include "netinet/in.h"
  86. #include "netinet/in_systm.h"
  87. #include "netinet/in_var.h"
  88. #include "netinet/ip.h"
  89. #include "netinet/if_ether.h"
  90. #include "net/if_subr.h"
  91. #include "semLib.h"
  92. /*HELP#include "drv/netif/if_seeq.h"            /* device description header */
  93. #include "if_seeq.h"            /* device description header */
  94. /* defines */
  95. #define DEBUG
  96. #define MAX_UNITS 1 /* maximum units supported */
  97. #define SEEQ_TX_OUTSTANDING 1 /* seeqTransmit outstanding */
  98. #define SEEQ_RX_OUTSTANDING 2 /* seeqReceive outstanding */
  99. /* Offset to LSB */
  100. #if _BYTE_ORDER == _BIG_ENDIAN
  101. #define SEEQ_LSB_OFFSET 1 /* offset to LSB */
  102. #define SEEQ_MSB_SHIFT 8 /* shift to MSB */
  103. #define SEEQ_CFG2_BSWAP  SEEQ_CONF2_BYTE_SWAP /* config2 bswap bit */
  104. #else /* _BYTE_ORDER == _BIG_ENDIAN */
  105. #define SEEQ_LSB_OFFSET 0 /* offset to LSB */
  106. #define SEEQ_MSB_SHIFT 0 /* shift to MSB */
  107. #define SEEQ_CFG2_BSWAP  0 /* config2 bswap bit */
  108. #endif /* _BYTE_ORDER == _BIG_ENDIAN */
  109. /* How much free space is in the TX buffer */
  110. #define TX_SPACE(pDrv) 
  111. (((pDrv)->txNext < (pDrv)->txCurr) 
  112.  ? ((pDrv)->txCurr - (pDrv)->txNext) 
  113.  : ((((pDrv)->tea + 1) << 8) - ((pDrv)->txNext - (pDrv)->txCurr)))
  114. /* typedefs */
  115. typedef struct mbuf MBUF;
  116. typedef struct arpcom IDR;                  /* Interface Data Record wrapper */
  117. typedef struct ifnet IFNET;                 /* real Interface Data Record */
  118. typedef struct sockaddr SOCK;
  119. typedef struct ex_msg EX_MSG;               /* an EXOS message */
  120. /* The definition of the driver control structure */
  121. typedef struct drv_ctrl /* DRV_CTRL */
  122.     {
  123.     IDR idr; /* Interface Data Record */
  124.     int unit; /* unit # */
  125.     BOOL attached; /* indicates unit is attached */
  126.     int flags; /* misc flags */
  127.     int inum; /* interrupt number */
  128.     int ilevel; /* interrupt level */
  129.     SEEQ_DEVICE *devAdrs; /* device structure address */
  130.     WDOG_ID watchDog; /* watchDog for waiting for chip */
  131.     BOOL expired; /* flag watchDog has expired */
  132.     USHORT rea; /* receive end area */
  133.     UINT rxNext; /* local buffer pointer for next packet */
  134.     UCHAR *rxBuf; /* receive buffer */
  135.     int txCount; /* # packets waiting to transmit */
  136.     USHORT tea; /* transmit end area */
  137.     UINT txEnd; /* end of tx area */
  138.     UINT txCurr; /* end of current xmit packet */
  139.     UINT txNext; /* local buffer pointer for next packet */
  140.     UCHAR *txBuf; /* transmit buffer */
  141.     int txLow; /* count of TX low reports */
  142.     } DRV_CTRL;
  143. #define DRV_CTRL_SIZ    sizeof(DRV_CTRL)
  144. /* globals */
  145. IMPORT UCHAR seeqEnetAddr []; /* Ethernet address to load */
  146. #ifdef DEBUG
  147. BOOL seeqDebug = 0;
  148. #endif
  149. int seeqIntCnt = 0;
  150. int seeqTimeoutCnt = 0;
  151. /* locals */
  152. LOCAL DRV_CTRL  drvCtrl [MAX_UNITS];
  153. /* forward declarations */
  154. IMPORT void ether_attach ();
  155. void seeqChipReset (int unit);
  156. void seeqRxReset (int unit);
  157. void seeqTxReset (int unit);
  158. void seeqInt (int unit);
  159. LOCAL void seeqReset (int unit);
  160. LOCAL void seeqReceive (int unit);
  161. LOCAL void seeqTransmit (int unit);
  162. LOCAL void seeqStart (int unit);
  163. LOCAL int seeqOutput (IDR *ifp, MBUF *m0, SOCK *dst);
  164. LOCAL int seeqIoctl (IDR *ifp, int cmd, caddr_t data);
  165. LOCAL void seeqTimeout (DRV_CTRL *pDrvCtrl);
  166. LOCAL STATUS seeqFlushFIFO (DRV_CTRL *pDrvCtrl);
  167. LOCAL STATUS seeqSetDMARead (DRV_CTRL *pDrvCtrl, USHORT addr);
  168. LOCAL STATUS seeqSetDMAWrite (DRV_CTRL *pDrvCtrl, USHORT addr);
  169. #ifndef SEEQ_READ
  170. #define SEEQ_READ(reg) 
  171. *(USHORT *)(reg)
  172. #endif
  173. #ifndef SEEQ_READ_BYTE
  174. #define SEEQ_READ_BYTE(reg) 
  175. *((volatile UCHAR *)(reg))
  176. #endif
  177. #ifndef SEEQ_WRITE
  178. #define SEEQ_WRITE(reg,data) 
  179. *(USHORT *)(reg) = (USHORT)data
  180. #endif
  181. #ifndef SEEQ_WRITE_BYTE
  182. #define SEEQ_WRITE_BYTE(reg,data) 
  183. *(volatile UCHAR *)(reg) = (UCHAR)data
  184. #endif
  185. /******************************************************************************
  186. *
  187. * seeqattach - publish the `seeq' network interface and initialize
  188. * the driver and device
  189. *
  190. * This routine publishes the `seeq' interface by filling in a network
  191. * interface record and adding this record to the system list.  This
  192. * routine also initializes the driver and the device to the operational
  193. * state.
  194. *
  195. * RETURNS: OK or ERROR.
  196. */
  197. STATUS seeqattach
  198.     (
  199.     int       unit, /* unit number */
  200.     char     *devAdrs, /* SEEQ I/O address */
  201.     int       inum, /* interrupt number */
  202.     int       ilevel /* interrupt level */
  203.     )
  204.     {
  205.     DRV_CTRL *pDrvCtrl;
  206.     /* Sanity check the unit number */
  207.     if (unit < 0 || unit >= MAX_UNITS)
  208. return (ERROR);
  209.     /* Ensure single invocation per system life */
  210.     pDrvCtrl = & drvCtrl [unit];
  211.     if (pDrvCtrl->attached)
  212. return (OK);
  213.     if ((pDrvCtrl->watchDog = wdCreate()) == NULL)
  214. return (ERROR);
  215.     if (!(pDrvCtrl->txBuf = (UCHAR *) malloc (2048)))
  216. {
  217. wdDelete (pDrvCtrl->watchDog);
  218. return (ERROR);
  219. }
  220.     if (!(pDrvCtrl->rxBuf = (UCHAR *) malloc (2048)))
  221. {
  222. wdDelete (pDrvCtrl->watchDog);
  223. free (pDrvCtrl->rxBuf);
  224. return (ERROR);
  225. }
  226.     /* Publish the interface data record */
  227.     ether_attach (&pDrvCtrl->idr.ac_if, unit, "seeq",
  228.   (FUNCPTR) NULL, (FUNCPTR) seeqIoctl,
  229.   (FUNCPTR) seeqOutput, (FUNCPTR) seeqReset);
  230.     /* Save some values */
  231.     pDrvCtrl->inum  = inum;  /* interrupt vector */
  232.     pDrvCtrl->ilevel  = ilevel;  /* interrupt level */
  233.     pDrvCtrl->devAdrs  = (SEEQ_DEVICE *)devAdrs; /* SEEQ I/O address */
  234.     /* Obtain our Ethernet address and save it */
  235.     bcopy ((char *) seeqEnetAddr, (char *) pDrvCtrl->idr.ac_enaddr, 6);
  236.     if (intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC(inum), seeqInt, unit) == ERROR)
  237. return (ERROR);
  238.     /* Reset the device */
  239.     seeqChipReset (pDrvCtrl->unit);
  240.     /* The interface is now up. */
  241.     pDrvCtrl->idr.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_NOTRAILERS);
  242.     /* Set our flag */
  243.     pDrvCtrl->attached = TRUE;
  244.     /*
  245.      * Enable the receiver, enable TX & RX interrupts,
  246.      * ack any pending interrupts.
  247.      */
  248.     SEEQ_WRITE (pDrvCtrl->devAdrs->pCmd,
  249. SEEQ_CMD_RX_ON  | SEEQ_CMD_RX_EN
  250. | SEEQ_CMD_TX_OFF | SEEQ_CMD_TX_EN
  251. | SEEQ_CMD_ALL_ACK);
  252.     return (OK);
  253.     }
  254. /******************************************************************************
  255. *
  256. * seeqTimeout - note that the watchdog timer has expired.
  257. *
  258. * NOMANUAL
  259. */
  260. LOCAL void seeqTimeout
  261.     (
  262.     DRV_CTRL  *pDrvCtrl
  263.     )
  264.     {
  265. #ifdef DEBUG
  266.     if (seeqDebug)
  267. logMsg ("seeqTimeout(%x)n", (int) pDrvCtrl, 0, 0, 0, 0, 0);
  268. #endif
  269.     ++seeqTimeoutCnt;
  270.     pDrvCtrl->expired = TRUE;
  271.     }
  272. /******************************************************************************
  273. *
  274. * seeqFlushFIFO - Wait for the seeq DMA FIFO to flush
  275. *
  276. * NOMANUAL
  277. */
  278. LOCAL STATUS seeqFlushFIFO
  279.     (
  280.     DRV_CTRL  *pDrvCtrl
  281.     )
  282.     {
  283.     SEEQ_DEVICE *pDev = pDrvCtrl->devAdrs;
  284.     pDrvCtrl->expired = FALSE;
  285.     wdStart (pDrvCtrl->watchDog, 2 * sysClkRateGet(),
  286.      (FUNCPTR) seeqTimeout, (int) pDrvCtrl);
  287.     /* flush the FIFO */
  288.     while (!(SEEQ_READ(pDev->pStat) & SEEQ_STAT_FIFO_EMPTY)
  289.        && !pDrvCtrl->expired)
  290. taskDelay(1);
  291.     wdCancel (pDrvCtrl->watchDog);
  292.     if (pDrvCtrl->expired)
  293. return (ERROR);
  294.     return (OK);
  295.     }
  296. /******************************************************************************
  297. *
  298. * seeqSetDMARead - Setup the FIFO for reading
  299. *
  300. * NOMANUAL
  301. */
  302. LOCAL STATUS seeqSetDMARead
  303.     (
  304.     DRV_CTRL  *pDrvCtrl,
  305.     USHORT    addr
  306.     )
  307.     {
  308.     SEEQ_DEVICE *pDev = pDrvCtrl->devAdrs;
  309.     /* Point into local buffer memory */
  310.     SEEQ_WRITE (pDev->pCfg1, ((SEEQ_READ(pDev->pCfg1) & 0xfff0)
  311. | SEEQ_CONF1_LBUFFER));
  312.     
  313.     /* Wait for FIFO ready if in write direction */
  314.     if (!(SEEQ_READ(pDev->pCmd) & SEEQ_STAT_FIFO_DIR))
  315. if (seeqFlushFIFO (pDrvCtrl) != OK)
  316.     return (ERROR);
  317.     /* Set DMA address */
  318.     SEEQ_WRITE (pDev->pDma, addr);
  319.     /* Set direction to read */
  320.     SEEQ_WRITE (pDev->pCmd, ((SEEQ_READ(pDev->pStat) & SEEQ_STAT_CMD_MASK)
  321. | SEEQ_CMD_FIFO_READ) );
  322.     pDrvCtrl->expired = FALSE;
  323.     wdStart (pDrvCtrl->watchDog, 2 * sysClkRateGet(),
  324.      (FUNCPTR) seeqTimeout, (int) pDrvCtrl);
  325.     /* Wait for ready */
  326.     while (!(SEEQ_READ(pDev->pStat) & SEEQ_STAT_BUF_INT) && !pDrvCtrl->expired)
  327. taskDelay(1);
  328.     wdCancel (pDrvCtrl->watchDog);
  329.     /* ack buffer window interrupt */
  330.     SEEQ_WRITE (pDev->pCmd, ((SEEQ_READ(pDev->pStat) & SEEQ_STAT_CMD_MASK)
  331.     | SEEQ_CMD_BUF_ACK));
  332.     if (pDrvCtrl->expired)
  333. return (ERROR);
  334.     return (OK);
  335.     }
  336. /******************************************************************************
  337. *
  338. * seeqSetDMAWrite - Setup the FIFO for writing.
  339. *
  340. * NOMANUAL
  341. */
  342. LOCAL STATUS seeqSetDMAWrite
  343.     (
  344.     DRV_CTRL  *pDrvCtrl,
  345.     USHORT    addr
  346.     )
  347.     {
  348.     SEEQ_DEVICE *pDev = pDrvCtrl->devAdrs;
  349.     /* Point into local buffer memory */
  350.     SEEQ_WRITE (pDev->pCfg1,  ((SEEQ_READ(pDev->pCfg1) & 0xfff0)
  351. | SEEQ_CONF1_LBUFFER));
  352.     
  353.     
  354.     /* If already in write mode, wait until buffer writing is complete. */
  355.     if (SEEQ_READ(pDev->pCmd) & SEEQ_STAT_FIFO_DIR)
  356. {
  357. /* read direction */
  358. SEEQ_WRITE (pDev->pCmd, ((SEEQ_READ(pDev->pStat) & SEEQ_STAT_CMD_MASK)
  359.     | SEEQ_CMD_FIFO_WRITE) );
  360. }
  361.     else
  362. {
  363. /* write direction: wait until buffer writing is complete. */
  364. if (seeqFlushFIFO (pDrvCtrl) != OK)
  365.     return (ERROR);
  366. }
  367.     /* Set DMA address */
  368.     SEEQ_WRITE (pDev->pDma, addr);
  369.     return (OK);
  370.     }
  371. /******************************************************************************
  372. *
  373. * seeqChipReset - hardware reset of chip (stop it)
  374. *
  375. * NOMANUAL
  376. */
  377. void seeqChipReset
  378.     (
  379.     int unit
  380.     )
  381.     {
  382.     int i;
  383.     int oldLevel;
  384.     DRV_CTRL *pDrvCtrl = &drvCtrl[unit];
  385.     SEEQ_DEVICE *pDev;
  386.     volatile UCHAR *bwind;
  387.     /* Sanity check the unit number */
  388.     if (unit < 0 || unit >= MAX_UNITS)
  389. return;
  390. #ifdef DEBUG
  391.     if (seeqDebug)
  392. logMsg ("seeqChipReset(%d)n", unit, 0, 0, 0, 0, 0);
  393. #endif
  394.     pDrvCtrl->flags = 0;
  395.     pDrvCtrl->txCount = 0;
  396.     /* Reset the chip */
  397.     pDev = pDrvCtrl->devAdrs;
  398.     SEEQ_WRITE (pDev->pCfg1, 0);
  399.     SEEQ_WRITE (pDev->pCfg2, SEEQ_CONF2_RESET);
  400.     /* Delay at least 4us */
  401.     taskDelay (1);
  402.     /* Check status register for 0x5800 */
  403.     if (SEEQ_READ(pDev->pStat) != 0x5800)
  404. {
  405. logMsg ("seeq: probe at 0x%x failed, got 0x%04xn",
  406. (int) pDrvCtrl->devAdrs->pCmd, SEEQ_READ(pDev->pStat),
  407. 0, 0, 0, 0);
  408. }
  409.     /* lock interrupts */
  410.     oldLevel = intLock ();
  411.     /* Program the interrupt vector */
  412.     SEEQ_WRITE (pDev->pCfg1, ((SEEQ_READ(pDev->pCfg1) & 0xfff0)
  413. | SEEQ_CONF1_IVEC));
  414.     SEEQ_WRITE (pDev->pBwind, pDrvCtrl->inum);
  415.     /* Program station addr 0 w/ our e-net addr */
  416.     /* Turn Tx, Rx and DMA off, then ack any interrupts */
  417.     SEEQ_WRITE (pDev->pCmd, (SEEQ_CMD_FIFO_WRITE | SEEQ_CMD_ALL_OFF));
  418.     SEEQ_WRITE (pDev->pCmd, (SEEQ_CMD_FIFO_WRITE | SEEQ_CMD_ALL_OFF
  419.     | SEEQ_CMD_ALL_ACK));
  420.     /* Select address 0 */
  421.     SEEQ_WRITE (pDev->pCfg1, ((SEEQ_READ(pDev->pCfg1) & 0xfff0) | 0));
  422.     /* Get byte pointer to buffer window */
  423.     bwind = ((volatile UCHAR *) pDev->pBwind) + SEEQ_LSB_OFFSET;
  424.     /* Program the ethernet address */
  425.     for (i = 0; i < 6; ++i)
  426. SEEQ_WRITE_BYTE (bwind, ((UCHAR *)pDrvCtrl->idr.ac_enaddr)[i]);
  427.     /*
  428.      * Configure the local memory buffer to allow half of the
  429.      * space for transmit and half for receive.
  430.      */
  431.     pDrvCtrl->tea = 0x7f;
  432.     pDrvCtrl->rea = 0xffff;
  433.     pDrvCtrl->rxNext = (pDrvCtrl->tea + 1) << 8;
  434.     pDrvCtrl->txEnd = ((pDrvCtrl->tea + 1) << 8) - 1;
  435.     pDrvCtrl->txNext = 0;
  436.     pDrvCtrl->txCurr = 0;
  437.     pDrvCtrl->txLow = 0;
  438.     SEEQ_WRITE(pDev->pCfg1, (*pDev->pCfg1 & 0xfff0) | SEEQ_CONF1_TXEND);
  439.     SEEQ_WRITE(pDev->pBwind, pDrvCtrl->tea);
  440.     SEEQ_WRITE(pDev->pTxptr, pDrvCtrl->txNext);
  441.     SEEQ_WRITE(pDev->pRxptr, pDrvCtrl->rxNext);
  442.     SEEQ_WRITE(pDev->pRxend, pDrvCtrl->rea);
  443.     /*
  444.      * Config1 register setup:
  445.      *
  446.      * Specific Addr 0: Enabled
  447.      * Specific Addr 1: Disabled
  448.      * Specific Addr 2: Disabled
  449.      * Specific Addr 3: Disabled
  450.      * Specific Addr 4: Disabled
  451.      * Specific Addr 5: Disabled
  452.      * DMA Burst Length: 1 byte
  453.      * DMA Burst Interval: continuous
  454.      * MatchMode: Specific Addresses + Broadcast Addr
  455.      */
  456.     *pDev->pCfg1 = SEEQ_CONF1_ADDR0_EN
  457. | SEEQ_CONF1_RX_SPEC_BROAD
  458. | SEEQ_CONF1_DMA_BURST_INTERVAL_0;
  459.     /*
  460.      * Config2 register setup:
  461.      *
  462.      * select byte swapping, or not. Yes for BIG_ENDIAN
  463.      * AutoUpdate REA:  Disabled.
  464.      * Receive While Transmitting: Enabled.
  465.      * CRC ErrorEnable: CRC Error packets not accepted.
  466.      * Dribble Error Enable: Dribble packets not accepted.
  467.      * Pass Long/Short Enable: Neither long or short packets accepted.
  468.      * Preamble Select:  Std 802.3 64 bit preamble selected.
  469.      * RecCRC: CRC is stripped from incoming packets.
  470.      * XmitNoCRC: Outgoing packets have CRC appended.
  471.      * Loopback:  Loopback disabled.
  472.      * CTRLO: CTRL0 pin is low.
  473.      * RESET: Not asserted.
  474.      */
  475.     SEEQ_WRITE (pDev->pCfg2, SEEQ_CFG2_BSWAP);
  476.     /*
  477.      * Configure for RX and TX off and interrupts disabled.
  478.      * Ack any pending interrupts.
  479.      */
  480.     SEEQ_WRITE (pDev->pCmd, (SEEQ_CMD_RX_OFF | SEEQ_CMD_TX_OFF
  481.     | SEEQ_CMD_ALL_ACK));
  482.     intUnlock (oldLevel);
  483.     }
  484. /******************************************************************************
  485. *
  486. * seeqTxReset - Reset the TX
  487. *
  488. * NOMANUAL
  489. */
  490. void seeqTxReset
  491.     (
  492.     int unit
  493.     )
  494.     {
  495.     int oldLevel;
  496.     DRV_CTRL *pDrvCtrl = &drvCtrl[unit];
  497.     SEEQ_DEVICE *pDev;
  498.     /* Sanity check the unit number */
  499.     if (unit < 0 || unit >= MAX_UNITS)
  500. return;
  501. #ifdef DEBUG
  502.     if (seeqDebug)
  503. logMsg ("seeqTxReset(%d)n", unit, 0, 0, 0, 0, 0);
  504. #endif
  505.     pDev = pDrvCtrl->devAdrs;
  506.     oldLevel = intLock ();
  507.     /* Report an error */
  508.     ++pDrvCtrl->idr.ac_if.if_oerrors;
  509.     /* Recover - disable the TX */
  510.     SEEQ_WRITE (pDev->pCmd, ((SEEQ_READ(pDev->pStat) & SEEQ_STAT_CMD_MASK)
  511.     | SEEQ_CMD_TX_OFF));
  512.     pDrvCtrl->txNext = 0;
  513.     pDrvCtrl->txCurr = 0;
  514.     pDrvCtrl->txCount = 0;
  515.     SEEQ_WRITE (pDev->pTxptr, 0);
  516.     /* Ack the buffer and TX interrupts */
  517.     SEEQ_WRITE (pDev->pCmd, ((SEEQ_READ(pDev->pStat) & SEEQ_STAT_CMD_MASK)
  518.     | SEEQ_CMD_TX_ACK | SEEQ_CMD_BUF_ACK));
  519.     intUnlock (oldLevel);
  520.     }
  521. /******************************************************************************
  522. *
  523. * seeqRxReset - Reset the RX
  524. *
  525. * NOMANUAL
  526. */
  527. void seeqRxReset
  528.     (
  529.     int unit
  530.     )
  531.     {
  532.     int oldLevel;
  533.     DRV_CTRL *pDrvCtrl = &drvCtrl[unit];
  534.     SEEQ_DEVICE *pDev;
  535.     /* Sanity check the unit number */
  536.     if (unit < 0 || unit >= MAX_UNITS)
  537. return;
  538. #ifdef DEBUG
  539.     if (seeqDebug)
  540. logMsg ("seeqRxReset(%d)n", unit, 0, 0, 0, 0, 0);
  541. #endif
  542.     pDev = pDrvCtrl->devAdrs;
  543.     oldLevel = intLock ();
  544.     /* Report an error */
  545.     ++pDrvCtrl->idr.ac_if.if_ierrors;
  546.     /* Recover - disable the RX */
  547.     SEEQ_WRITE (pDev->pCmd, ((SEEQ_READ(pDev->pStat) & SEEQ_STAT_CMD_MASK)
  548.     | SEEQ_CMD_RX_OFF));
  549.     pDrvCtrl->rxNext = (pDrvCtrl->tea + 1) << 8;
  550.     SEEQ_WRITE (pDev->pRxptr, pDrvCtrl->rxNext);
  551.     /* Ack the buffer and RX interrupts */
  552.     SEEQ_WRITE (pDev->pCmd, ((SEEQ_READ(pDev->pStat) & SEEQ_STAT_CMD_MASK)
  553.     | SEEQ_CMD_RX_ACK | SEEQ_CMD_BUF_ACK
  554.     | SEEQ_CMD_RX_ON ));
  555.     intUnlock (oldLevel);
  556.     }
  557. /******************************************************************************
  558. *
  559. * seeqReset - reset the interface
  560. *
  561. * Mark interface as inactive & reset the chip
  562. *
  563. * NOMANUAL
  564. */
  565. LOCAL void seeqReset
  566.     (
  567.     int unit
  568.     )
  569.     {
  570.     int oldLevel;
  571.     DRV_CTRL *pDrvCtrl = &drvCtrl[unit];
  572.     /* Sanity check the unit number */
  573.     if (unit < 0 || unit >= MAX_UNITS)
  574. return;
  575.     oldLevel = intLock ();
  576.     /* Reset the chip */
  577.     SEEQ_WRITE (pDrvCtrl->devAdrs->pCfg1, 0);
  578.     SEEQ_WRITE (pDrvCtrl->devAdrs->pCfg2, SEEQ_CONF2_RESET);
  579.     /* Mark the interface as down */
  580.     pDrvCtrl->idr.ac_if.if_flags = 0;
  581.     intUnlock (oldLevel);
  582.     }
  583. /******************************************************************************
  584. *
  585. * seeqReceive - handle receiving packets.
  586. *
  587. * NOMANUAL
  588. */
  589. LOCAL void seeqReceive
  590.     (
  591.     int unit
  592.     )
  593.     {
  594.     USHORT nextFrame;
  595.     USHORT headerStatus;
  596.     int pktByteCnt = 0;
  597.     DRV_CTRL *pDrvCtrl = &drvCtrl[unit];
  598.     SEEQ_DEVICE *pDev = pDrvCtrl->devAdrs;
  599.     /* If interface was shutdown, abort service request */
  600.     if (!(pDrvCtrl->idr.ac_if.if_flags & IFF_UP))
  601. {
  602. pDrvCtrl->flags &= ~SEEQ_RX_OUTSTANDING;
  603. return;
  604. }
  605.     if (!(pDrvCtrl->flags & SEEQ_RX_OUTSTANDING))
  606. {
  607. #ifdef DEBUG
  608. if (seeqDebug)
  609.     logMsg ("seeq: no RX request outstandingn",
  610.     0, 0, 0, 0, 0, 0);
  611. #endif
  612. return;
  613. }
  614.     pDrvCtrl->flags &= ~SEEQ_RX_OUTSTANDING;
  615.     do
  616. {
  617. int i;
  618. USHORT frameStatus;
  619. USHORT frameLength;
  620. USHORT tmp;
  621. if (seeqSetDMARead(pDrvCtrl, pDrvCtrl->rxNext) != OK)
  622.     {
  623.     /* re-queue for later processing. */
  624. #ifdef DEBUG
  625.     if (seeqDebug)
  626. logMsg ("RX: Set DMA failedn", 0, 0, 0, 0, 0, 0);
  627. #endif
  628.     seeqRxReset (pDrvCtrl->unit);
  629.     pDrvCtrl->flags |= SEEQ_RX_OUTSTANDING;
  630.     netJobAdd ((FUNCPTR) seeqReceive, unit, 0, 0, 0, 0);
  631.     break;
  632.     }
  633. nextFrame = SEEQ_READ (pDev->pBwind);
  634. /* Get the header and frame status */
  635. tmp = SEEQ_READ (pDev->pBwind);
  636. headerStatus = tmp >> 8;
  637. frameStatus = tmp & 0x00ff;
  638. /*
  639.  * Stop under any of the following conditions:
  640.  *   The packet isn't done
  641.  *   The next packet is this packet (looped back).
  642.  */
  643. if (!(frameStatus & SEEQ_RX_PSTAT_DONE)
  644.     || (nextFrame == pDrvCtrl->rxNext))
  645.     break;
  646. if (nextFrame < pDrvCtrl->rxNext)
  647.     {
  648.     /* The receiver wrapped around */
  649.     frameLength = (pDrvCtrl->rea+1) - pDrvCtrl->rxNext - 4
  650. + (nextFrame - (int)((pDrvCtrl->tea + 1)<<8));
  651.     }
  652. else
  653.     {
  654.     /* The frame is sequential, not wrapped */
  655.     frameLength = nextFrame - pDrvCtrl->rxNext - 4;
  656.     }
  657. /* account for space consumed in the buffer. */
  658. pktByteCnt += frameLength + 4;
  659. if (pktByteCnt > 0x8000)
  660.     {
  661. #ifdef DEBUG
  662.     if (seeqDebug)
  663. logMsg ("RX packet overflowsn", 0, 0, 0, 0, 0, 0);
  664. #endif
  665.     seeqRxReset (pDrvCtrl->unit);
  666.     break;
  667.     }
  668. #ifdef DEBUG
  669. if (seeqDebug)
  670.     logMsg ("RX pkt: @ 0x%04x Frame 0x%02x Header 0x%02x len %4d nxt 0x%04xn",
  671.     pDrvCtrl->rxNext, frameStatus, headerStatus,
  672.     frameLength, nextFrame, 0);
  673. #endif
  674. if (frameStatus != SEEQ_RX_PSTAT_DONE)
  675.     {
  676.     /* one of the errors */
  677.     if (frameStatus & SEEQ_RX_PSTAT_OVERSIZE)
  678. ++pDrvCtrl->idr.ac_if.if_ierrors;
  679.     if (frameStatus & SEEQ_RX_PSTAT_CRC)
  680. ++pDrvCtrl->idr.ac_if.if_ierrors;
  681.     if (frameStatus & SEEQ_RX_PSTAT_DRIBBLE)
  682. ++pDrvCtrl->idr.ac_if.if_ierrors;
  683.     if (frameStatus & SEEQ_RX_PSTAT_SHORT)
  684. ++pDrvCtrl->idr.ac_if.if_ierrors;
  685.     }
  686. else
  687.     {
  688.     ETH_HDR *pHdr = (ETH_HDR *) pDrvCtrl->rxBuf;
  689.     char *bufp = (char *) pDrvCtrl->rxBuf;
  690.     /* Read in the entire packet */
  691.     for (i = 0; i < frameLength/2; ++i)
  692. {
  693. ((USHORT *) bufp)[i] = SEEQ_READ (pDev->pBwind);
  694. }
  695.     /* Get the last odd byte */
  696.     if (frameLength & 1)
  697. {
  698. bufp[frameLength-1] = SEEQ_READ_BYTE (pDev->pBwind);
  699. }
  700.     /* call input hook if any */
  701.     if ((etherInputHookRtn == NULL)
  702. || !(*etherInputHookRtn) (&pDrvCtrl->idr.ac_if,
  703.   bufp, frameLength))
  704. {
  705. MBUF *pMbuf;
  706. bufp += SIZEOF_ETHERHEADER;
  707. frameLength -= SIZEOF_ETHERHEADER;
  708. pMbuf = copy_to_mbufs (bufp, frameLength, 0,
  709.        (IFNET *) &pDrvCtrl->idr.ac_if);
  710. if (pMbuf != NULL)
  711.     {
  712.     do_protocol_with_type (ntohs (pHdr->ether_type), pMbuf,
  713.    &pDrvCtrl->idr, frameLength);
  714.     pDrvCtrl->idr.ac_if.if_ipackets++;
  715.     }
  716. }
  717.     }
  718. /* adjust circular buffer */
  719. pDrvCtrl->rxNext = nextFrame;
  720. SEEQ_WRITE (pDev->pRxend, (nextFrame >> 8));
  721. } while (headerStatus & SEEQ_RX_HSTAT_CHAIN);
  722.     }
  723. /******************************************************************************
  724. *
  725. * seeqTransmit - handle transmitted packets.
  726. *
  727. * NOMANUAL
  728. */
  729. LOCAL void seeqTransmit
  730.     (
  731.     int unit
  732.     )
  733.     {
  734.     int pktCount;
  735.     DRV_CTRL *pDrvCtrl = &drvCtrl[unit];
  736.     SEEQ_DEVICE *pDev = pDrvCtrl->devAdrs;
  737.     BOOL resetTx = FALSE;
  738. #ifdef DEBUG
  739.     if (seeqDebug)
  740. logMsg ("TX Cnt %d Curr 0x%04x Next 0x%04x Space 0x%04xn",
  741. pDrvCtrl->txCount, pDrvCtrl->txCurr,
  742. pDrvCtrl->txNext, TX_SPACE(pDrvCtrl),
  743. 0, 0);
  744. #endif
  745.     /* If interface was shutdown, abort service request */
  746.     if (!(pDrvCtrl->idr.ac_if.if_flags & IFF_UP))
  747. {
  748. pDrvCtrl->flags &= ~SEEQ_TX_OUTSTANDING;
  749. return;
  750. }
  751.     if (!(pDrvCtrl->flags & SEEQ_TX_OUTSTANDING))
  752. {
  753. #ifdef DEBUG
  754. if (seeqDebug)
  755.     logMsg ("seeq: no TX request outstandingn",
  756.     0, 0, 0, 0, 0, 0);
  757. #endif
  758. return;
  759. }
  760.     pDrvCtrl->flags &= ~SEEQ_TX_OUTSTANDING;
  761.     pktCount = pDrvCtrl->txCount;
  762.     if (!pDrvCtrl->txCount)
  763. {
  764. #ifdef DEBUG
  765. if (seeqDebug)
  766.     logMsg ("seeq: no xmit curr 0x%04x next 0x%04x space 0x%04xn",
  767.     pDrvCtrl->txCurr, pDrvCtrl->txNext, TX_SPACE(pDrvCtrl),
  768.     0, 0, 0);
  769. #endif
  770. return;
  771. }
  772.     /* Now process the packets */
  773.     while (1)
  774. {
  775. USHORT tmp;
  776. USHORT nextFrame;
  777. USHORT frameCommand;
  778. USHORT frameStatus;
  779. if (seeqSetDMARead(pDrvCtrl, pDrvCtrl->txCurr) != OK)
  780.     {
  781.     /* re-queue for later processing. */
  782. #ifdef DEBUG
  783.     if (seeqDebug)
  784. logMsg ("TX: Set DMA failedn", 0, 0, 0, 0, 0, 0);
  785. #endif
  786.     seeqTxReset (pDrvCtrl->unit);
  787.     pDrvCtrl->flags |= SEEQ_TX_OUTSTANDING;
  788.     netJobAdd ((FUNCPTR) seeqTransmit, unit, 0, 0, 0, 0);
  789.     break;
  790.     }
  791. /* Move curr to the end of the last transmitted packet */
  792. nextFrame = SEEQ_READ (pDev->pBwind);
  793. /* get the frame status and command */
  794. tmp = SEEQ_READ (pDev->pBwind);
  795. frameCommand = tmp >> 8;
  796. frameStatus = tmp & 0x00ff;
  797. #ifdef DEBUG
  798. if (seeqDebug)
  799.     logMsg ("TX @ 0x%04x command %02x status 0x%02x next 0x%04xn",
  800.     pDrvCtrl->txCurr, frameCommand, frameStatus, nextFrame,
  801.     0, 0);
  802. #endif
  803. /*
  804.  * At this point, we should be at a valid TX header since
  805.  * txCount > 0.
  806.  */
  807. if (nextFrame > pDrvCtrl->txEnd)
  808.     {
  809. #ifdef DEBUG
  810.     if (seeqDebug)
  811. logMsg ("TX: bad next pointern", 0, 0, 0, 0, 0, 0);
  812. #endif
  813.     resetTx = TRUE;
  814.     }
  815. if (!(frameCommand & SEEQ_TX_CMD_XMIT))
  816.     {
  817. #ifdef DEBUG
  818.     if (seeqDebug)
  819. logMsg ("TX: not an xmit headern", 0, 0, 0, 0, 0, 0);
  820. #endif
  821.     resetTx = TRUE;
  822.     }
  823. if (!(frameCommand & SEEQ_TX_CMD_CHAIN))
  824.     {
  825. #ifdef DEBUG
  826.     if (seeqDebug)
  827. logMsg ("TX: ran off endn", 0, 0, 0, 0, 0, 0);
  828. #endif
  829.     resetTx = TRUE;
  830.     }
  831. if (!(frameCommand & SEEQ_TX_CMD_DATA))
  832.     {
  833. #ifdef DEBUG
  834.     if (seeqDebug)
  835. logMsg ("TX: no data in packetn", 0, 0, 0, 0, 0, 0);
  836. #endif
  837.     resetTx = TRUE;
  838.     }
  839. if (resetTx)
  840.     {
  841. #ifdef DEBUG
  842.     if (seeqDebug)
  843. logMsg ("TX: reset cnt %d curr 0x%04x cmd %02x stat 0x%02x next 0x%04xn",
  844. pDrvCtrl->txCount, pDrvCtrl->txCurr, frameCommand,
  845. frameStatus, nextFrame, 0);
  846. #endif
  847.     seeqTxReset (pDrvCtrl->unit);
  848.     break;
  849.     }
  850. /* If not done, stop processing. */
  851. if (!(frameStatus & SEEQ_TX_PSTAT_DONE))
  852.     break;
  853. /* Check for error status. */
  854. if (frameStatus & SEEQ_TX_PSTAT_BABBLE)
  855.     ++pDrvCtrl->idr.ac_if.if_oerrors;
  856. if (frameStatus & SEEQ_TX_PSTAT_COLL16)
  857.     pDrvCtrl->idr.ac_if.if_collisions += 16;
  858. else if (frameStatus & SEEQ_TX_PSTAT_COLL)
  859.     ++pDrvCtrl->idr.ac_if.if_collisions;
  860. /* Move past this packet. */
  861. pDrvCtrl->txCurr = nextFrame;
  862. /* Exit if all packets accounted for. */
  863. if (!--pDrvCtrl->txCount)
  864.     break;
  865. }
  866.     /* If packets where waiting on the queue for free space, re-start */
  867.     if (((pktCount != pDrvCtrl->txCount) || resetTx)
  868. && (pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL))
  869. (void)netJobAdd ((FUNCPTR) seeqStart, unit, 0, 0, 0, 0);
  870.     }
  871. /******************************************************************************
  872. *
  873. * seeqInt - handle controller interrupt
  874. *
  875. * This routine is called at interrupt level in response to an interrupt from
  876. * the controller.  All of the real work is handled at task level through
  877. * netJobAdd.
  878. *
  879. * NOMANUAL
  880. */
  881. void seeqInt
  882.     (
  883.     int unit
  884.     )
  885.     {
  886.     USHORT status;
  887.     DRV_CTRL *pDrvCtrl = &drvCtrl[unit];
  888.     SEEQ_DEVICE *pDev = pDrvCtrl->devAdrs;
  889.     ++seeqIntCnt;
  890.     status = SEEQ_READ (pDev->pStat);
  891.     SEEQ_WRITE (pDev->pCmd, ((SEEQ_READ(pDev->pStat) & SEEQ_STAT_CMD_MASK) | SEEQ_CMD_ALL_ACK));
  892.     if (pDrvCtrl->idr.ac_if.if_flags & IFF_UP)
  893. {
  894. /* Make sure only one TX and RX request is outstanding at a time. */
  895. if ((status & SEEQ_STAT_RX_INT)
  896.     && !(pDrvCtrl->flags & SEEQ_RX_OUTSTANDING))
  897.     {
  898.     pDrvCtrl->flags |= SEEQ_RX_OUTSTANDING;
  899.     netJobAdd ((FUNCPTR) seeqReceive, unit, 0, 0, 0, 0);
  900.     }
  901. if ((status & SEEQ_STAT_TX_INT)
  902.     && !(pDrvCtrl->flags & SEEQ_TX_OUTSTANDING))
  903.     {
  904.     pDrvCtrl->flags |= SEEQ_TX_OUTSTANDING;
  905.     netJobAdd ((FUNCPTR) seeqTransmit, unit, 0, 0, 0, 0);
  906.     }
  907. }
  908.     }
  909. /******************************************************************************
  910. *
  911. * seeqOutput - the driver output routine
  912. *
  913. * NOMANUAL
  914. */
  915. LOCAL int seeqOutput
  916.     (
  917.     IDR  *pIDR,
  918.     MBUF *pMbuf,
  919.     SOCK *pDest
  920.     )
  921.     {
  922.     return ether_output ((IFNET*)pIDR, pMbuf, pDest,
  923.  (FUNCPTR) seeqStart, pIDR);
  924.     }
  925. /******************************************************************************
  926. *
  927. * seeqStart - start outputing a packet.
  928. *
  929. * Get another datagram to send off of the interface queue,
  930. * and map it to the interface before starting the output.
  931. * This routine is called by seeqOutput().
  932. *
  933. * NOMANUAL
  934. */
  935. LOCAL void seeqStart
  936.     (
  937.     int unit
  938.     )
  939.     {
  940.     DRV_CTRL *pDrvCtrl = &drvCtrl[unit];
  941.     SEEQ_DEVICE *pDev = pDrvCtrl->devAdrs;
  942.     int space;
  943.     int s;
  944.     s = splnet ();
  945.     space = TX_SPACE(pDrvCtrl);
  946.     if (space < (ETHERMTU + 8))
  947. {
  948. #ifdef DEBUG
  949. if (seeqDebug)
  950.     logMsg ("TX: low space %4d: flags %d curr 0x%04x next 0x%04xn",
  951.     space, pDrvCtrl->flags, pDrvCtrl->txCurr, pDrvCtrl->txNext,
  952.     0, 0);
  953. #endif
  954. /* May have dropped a TX interrupt */
  955. if (pDrvCtrl->txLow++ > 2)
  956.     {
  957.     pDrvCtrl->txLow = 0;
  958.     seeqTxReset (pDrvCtrl->unit);
  959.     }
  960. else if (!(pDrvCtrl->flags & SEEQ_TX_OUTSTANDING))
  961.     {
  962.     pDrvCtrl->flags |= SEEQ_TX_OUTSTANDING;
  963.     netJobAdd ((FUNCPTR) seeqTransmit, unit, 0, 0, 0, 0);
  964.     }
  965. }
  966.     /* Only start if we have at least enough room */
  967.     if ((space >= ETHERMTU + 8)
  968. && pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL)
  969. {
  970. MBUF *pMbuf;
  971. int len;
  972. UCHAR *buf;
  973. USHORT txNext;
  974. BOOL error = FALSE;
  975. pDrvCtrl->txLow = 0;
  976. IF_DEQUEUE(&pDrvCtrl->idr.ac_if.if_snd, pMbuf);
  977. /* copy packet to write buffer */
  978. copy_from_mbufs (pDrvCtrl->txBuf, pMbuf, len);
  979. buf = (UCHAR *) pDrvCtrl->txBuf;
  980. /* After this point, if there's a problem with the chip, the
  981.    packet is lost. */
  982. /* Adjust length to ensure minimum packet size */
  983. len = max (ETHERSMALL, len);
  984. ++pDrvCtrl->txCount;
  985. #ifdef DEBUG
  986. if (seeqDebug > 1)
  987.     {
  988.     int i;
  989.     char *ptr;
  990.     static char lbuf[4096];
  991.     sprintf(lbuf, "TX %4d:", len);
  992.     ptr = lbuf + strlen(lbuf);
  993.     for (i = 0; i < len; ++i, ptr += 3)
  994. sprintf(ptr , " %02x", buf[i]);
  995.     logMsg ("%sn", (int) lbuf, 0, 0, 0, 0, 0);
  996.     }
  997. #endif
  998. /* Compute where the next packet will go */
  999. txNext = pDrvCtrl->txNext + len + 4;
  1000. if (txNext > pDrvCtrl->txEnd)
  1001.     txNext -= (pDrvCtrl->txEnd + 1);
  1002. #ifdef DEBUG
  1003. if (seeqDebug)
  1004.     logMsg ("TX pkt: @ %04x len %4d space %5d next %04xn",
  1005.     pDrvCtrl->txNext, len, TX_SPACE(pDrvCtrl), txNext,
  1006.     0, 0);
  1007. #endif
  1008. /* place a transmit request (while TX possibly running) */
  1009. /* Setup for writing */
  1010. if (seeqSetDMAWrite(pDrvCtrl, pDrvCtrl->txNext) != OK)
  1011.     error = TRUE;
  1012. if (error == FALSE)
  1013.     {
  1014.     /* Write a dummy header, so TX will stop if it catches up. */
  1015.     SEEQ_WRITE (pDev->pBwind, 0);
  1016.     SEEQ_WRITE (pDev->pBwind, 0);
  1017.     /* Write out the packet, two bytes at a time */
  1018.     for ( ; len >= 2; len -= 2, buf += 2)
  1019. {
  1020. SEEQ_WRITE (pDev->pBwind, *(USHORT *)buf);
  1021. }
  1022.     if (len)
  1023. {
  1024. SEEQ_WRITE_BYTE (pDev->pBwind, *buf);
  1025. }
  1026.     /* Write dummy end header to stop chain */
  1027.     SEEQ_WRITE (pDev->pBwind, 0);
  1028.     SEEQ_WRITE (pDev->pBwind, 0);
  1029.     /* Flush FIFO and move back and write the real header */
  1030.     if (seeqSetDMAWrite (pDrvCtrl, pDrvCtrl->txNext) != OK)
  1031. error = TRUE;
  1032.     }
  1033. if (error == FALSE)
  1034.     {
  1035.     /* TX packet header: next pointer (2 bytes) */
  1036.     SEEQ_WRITE (pDev->pBwind, txNext);
  1037.     /* TX packet header: cmd and status bytes */
  1038.     SEEQ_WRITE (pDev->pBwind,
  1039. ((SEEQ_TX_CMD_SUCC_EN
  1040.  | SEEQ_TX_CMD_DATA
  1041.  | SEEQ_TX_CMD_CHAIN
  1042.  | SEEQ_TX_CMD_XMIT) << SEEQ_MSB_SHIFT));
  1043.     /* Flush FIFO */
  1044.     if (seeqFlushFIFO (pDrvCtrl) != OK)
  1045. error = TRUE;
  1046.     }
  1047. if (error == FALSE)
  1048.     {
  1049.     /* If TX has stopped, reload xmit pointer. */
  1050.     if (!(SEEQ_READ(pDev->pStat) & SEEQ_STAT_TX_ON))
  1051. {
  1052. SEEQ_WRITE (pDev->pTxptr, pDrvCtrl->txNext);
  1053. }
  1054.     /* Adjust pointer to next buffer */
  1055.     pDrvCtrl->txNext = txNext;
  1056.     /* Turn on Tx and ack the buffer interrupt */
  1057.     SEEQ_WRITE (pDev->pCmd,  
  1058. ((SEEQ_READ(pDev->pStat) & SEEQ_STAT_CMD_MASK)
  1059.  | SEEQ_CMD_TX_ON | SEEQ_CMD_BUF_ACK));
  1060.     }
  1061. if (error == TRUE)
  1062.     seeqTxReset (pDrvCtrl->unit);
  1063. }
  1064.     splx (s);
  1065.     }
  1066. /******************************************************************************
  1067. *
  1068. * seeqIoctl - the driver I/O control routine
  1069. *
  1070. * Process an ioctl request.
  1071. *
  1072. * NOMANUAL
  1073. */
  1074. LOCAL int seeqIoctl
  1075.     (
  1076.     IDR  *ifp,
  1077.     int            cmd,
  1078.     caddr_t        data
  1079.     )
  1080.     {
  1081.     int error = OK;
  1082.     switch (cmd)
  1083.         {
  1084.       case (int)SIOCSIFADDR:
  1085. ifp->ac_ipaddr = IA_SIN (data)->sin_addr;
  1086. break;
  1087.       case (int)SIOCSIFFLAGS:
  1088. /* No further work to be done */
  1089. break;
  1090.       default:
  1091. error = EINVAL;
  1092.         }
  1093.     return (error);
  1094.     }