rp.c revision 153084
1/*-
2 * Copyright (c) Comtrol Corporation <support@comtrol.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted prodived that the follwoing conditions
7 * are met.
8 * 1. Redistributions of source code must retain the above copyright
9 *    notive, this list of conditions and the following disclainer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials prodided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *       This product includes software developed by Comtrol Corporation.
16 * 4. The name of Comtrol Corporation may not be used to endorse or
17 *    promote products derived from this software without specific
18 *    prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/dev/rp/rp.c 153084 2005-12-04 10:06:06Z ru $");
36
37/*
38 * rp.c - for RocketPort FreeBSD
39 */
40
41#include "opt_compat.h"
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/fcntl.h>
46#include <sys/malloc.h>
47#include <sys/serial.h>
48#include <sys/tty.h>
49#include <sys/conf.h>
50#include <sys/kernel.h>
51#include <machine/resource.h>
52#include <machine/bus.h>
53#include <sys/bus.h>
54#include <sys/rman.h>
55
56#define ROCKET_C
57#include <dev/rp/rpreg.h>
58#include <dev/rp/rpvar.h>
59
60static const char RocketPortVersion[] = "3.02";
61
62static Byte_t RData[RDATASIZE] =
63{
64   0x00, 0x09, 0xf6, 0x82,
65   0x02, 0x09, 0x86, 0xfb,
66   0x04, 0x09, 0x00, 0x0a,
67   0x06, 0x09, 0x01, 0x0a,
68   0x08, 0x09, 0x8a, 0x13,
69   0x0a, 0x09, 0xc5, 0x11,
70   0x0c, 0x09, 0x86, 0x85,
71   0x0e, 0x09, 0x20, 0x0a,
72   0x10, 0x09, 0x21, 0x0a,
73   0x12, 0x09, 0x41, 0xff,
74   0x14, 0x09, 0x82, 0x00,
75   0x16, 0x09, 0x82, 0x7b,
76   0x18, 0x09, 0x8a, 0x7d,
77   0x1a, 0x09, 0x88, 0x81,
78   0x1c, 0x09, 0x86, 0x7a,
79   0x1e, 0x09, 0x84, 0x81,
80   0x20, 0x09, 0x82, 0x7c,
81   0x22, 0x09, 0x0a, 0x0a
82};
83
84static Byte_t RRegData[RREGDATASIZE]=
85{
86   0x00, 0x09, 0xf6, 0x82,	       /* 00: Stop Rx processor */
87   0x08, 0x09, 0x8a, 0x13,	       /* 04: Tx software flow control */
88   0x0a, 0x09, 0xc5, 0x11,	       /* 08: XON char */
89   0x0c, 0x09, 0x86, 0x85,	       /* 0c: XANY */
90   0x12, 0x09, 0x41, 0xff,	       /* 10: Rx mask char */
91   0x14, 0x09, 0x82, 0x00,	       /* 14: Compare/Ignore #0 */
92   0x16, 0x09, 0x82, 0x7b,	       /* 18: Compare #1 */
93   0x18, 0x09, 0x8a, 0x7d,	       /* 1c: Compare #2 */
94   0x1a, 0x09, 0x88, 0x81,	       /* 20: Interrupt #1 */
95   0x1c, 0x09, 0x86, 0x7a,	       /* 24: Ignore/Replace #1 */
96   0x1e, 0x09, 0x84, 0x81,	       /* 28: Interrupt #2 */
97   0x20, 0x09, 0x82, 0x7c,	       /* 2c: Ignore/Replace #2 */
98   0x22, 0x09, 0x0a, 0x0a	       /* 30: Rx FIFO Enable */
99};
100
101#if 0
102/* IRQ number to MUDBAC register 2 mapping */
103Byte_t sIRQMap[16] =
104{
105   0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
106};
107#endif
108
109Byte_t rp_sBitMapClrTbl[8] =
110{
111   0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
112};
113
114Byte_t rp_sBitMapSetTbl[8] =
115{
116   0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
117};
118
119/***************************************************************************
120Function: sReadAiopID
121Purpose:  Read the AIOP idenfication number directly from an AIOP.
122Call:	  sReadAiopID(CtlP, aiop)
123	  CONTROLLER_T *CtlP; Ptr to controller structure
124	  int aiop: AIOP index
125Return:   int: Flag AIOPID_XXXX if a valid AIOP is found, where X
126		 is replace by an identifying number.
127	  Flag AIOPID_NULL if no valid AIOP is found
128Warnings: No context switches are allowed while executing this function.
129
130*/
131int sReadAiopID(CONTROLLER_T *CtlP, int aiop)
132{
133   Byte_t AiopID;		/* ID byte from AIOP */
134
135   rp_writeaiop1(CtlP, aiop, _CMD_REG, RESET_ALL);     /* reset AIOP */
136   rp_writeaiop1(CtlP, aiop, _CMD_REG, 0x0);
137   AiopID = rp_readaiop1(CtlP, aiop, _CHN_STAT0) & 0x07;
138   if(AiopID == 0x06)
139      return(1);
140   else 			       /* AIOP does not exist */
141      return(-1);
142}
143
144/***************************************************************************
145Function: sReadAiopNumChan
146Purpose:  Read the number of channels available in an AIOP directly from
147	  an AIOP.
148Call:	  sReadAiopNumChan(CtlP, aiop)
149	  CONTROLLER_T *CtlP; Ptr to controller structure
150	  int aiop: AIOP index
151Return:   int: The number of channels available
152Comments: The number of channels is determined by write/reads from identical
153	  offsets within the SRAM address spaces for channels 0 and 4.
154	  If the channel 4 space is mirrored to channel 0 it is a 4 channel
155	  AIOP, otherwise it is an 8 channel.
156Warnings: No context switches are allowed while executing this function.
157*/
158int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop)
159{
160   Word_t x, y;
161
162   rp_writeaiop4(CtlP, aiop, _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
163   rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0);	   /* read from SRAM, chan 0 */
164   x = rp_readaiop2(CtlP, aiop, _INDX_DATA);
165   rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0x4000);  /* read from SRAM, chan 4 */
166   y = rp_readaiop2(CtlP, aiop, _INDX_DATA);
167   if(x != y)  /* if different must be 8 chan */
168      return(8);
169   else
170      return(4);
171}
172
173/***************************************************************************
174Function: sInitChan
175Purpose:  Initialization of a channel and channel structure
176Call:	  sInitChan(CtlP,ChP,AiopNum,ChanNum)
177	  CONTROLLER_T *CtlP; Ptr to controller structure
178	  CHANNEL_T *ChP; Ptr to channel structure
179	  int AiopNum; AIOP number within controller
180	  int ChanNum; Channel number within AIOP
181Return:   int: TRUE if initialization succeeded, FALSE if it fails because channel
182	       number exceeds number of channels available in AIOP.
183Comments: This function must be called before a channel can be used.
184Warnings: No range checking on any of the parameters is done.
185
186	  No context switches are allowed while executing this function.
187*/
188int sInitChan(	CONTROLLER_T *CtlP,
189		CHANNEL_T *ChP,
190		int AiopNum,
191		int ChanNum)
192{
193   int i, ChOff;
194   Byte_t *ChR;
195   static Byte_t R[4];
196
197   if(ChanNum >= CtlP->AiopNumChan[AiopNum])
198      return(FALSE);		       /* exceeds num chans in AIOP */
199
200   /* Channel, AIOP, and controller identifiers */
201   ChP->CtlP = CtlP;
202   ChP->ChanID = CtlP->AiopID[AiopNum];
203   ChP->AiopNum = AiopNum;
204   ChP->ChanNum = ChanNum;
205
206   /* Initialize the channel from the RData array */
207   for(i=0; i < RDATASIZE; i+=4)
208   {
209      R[0] = RData[i];
210      R[1] = RData[i+1] + 0x10 * ChanNum;
211      R[2] = RData[i+2];
212      R[3] = RData[i+3];
213      rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)&R[0]));
214   }
215
216   ChR = ChP->R;
217   for(i=0; i < RREGDATASIZE; i+=4)
218   {
219      ChR[i] = RRegData[i];
220      ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
221      ChR[i+2] = RRegData[i+2];
222      ChR[i+3] = RRegData[i+3];
223   }
224
225   /* Indexed registers */
226   ChOff = (Word_t)ChanNum * 0x1000;
227
228   ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
229   ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
230   ChP->BaudDiv[2] = (Byte_t)BRD9600;
231   ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8);
232   rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->BaudDiv[0]);
233
234   ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
235   ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
236   ChP->TxControl[2] = 0;
237   ChP->TxControl[3] = 0;
238   rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
239
240   ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
241   ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
242   ChP->RxControl[2] = 0;
243   ChP->RxControl[3] = 0;
244   rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
245
246   ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
247   ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
248   ChP->TxEnables[2] = 0;
249   ChP->TxEnables[3] = 0;
250   rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxEnables[0]);
251
252   ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
253   ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
254   ChP->TxCompare[2] = 0;
255   ChP->TxCompare[3] = 0;
256   rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxCompare[0]);
257
258   ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
259   ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
260   ChP->TxReplace1[2] = 0;
261   ChP->TxReplace1[3] = 0;
262   rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxReplace1[0]);
263
264   ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
265   ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
266   ChP->TxReplace2[2] = 0;
267   ChP->TxReplace2[3] = 0;
268   rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxReplace2[0]);
269
270   ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
271   ChP->TxFIFO = ChOff + _TX_FIFO;
272
273   rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
274   rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum);  /* remove reset Tx FIFO count */
275   rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
276   rp_writech2(ChP,_INDX_DATA,0);
277   ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
278   ChP->RxFIFO = ChOff + _RX_FIFO;
279
280   rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
281   rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum);  /* remove reset Rx FIFO count */
282   rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
283   rp_writech2(ChP,_INDX_DATA,0);
284   rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
285   rp_writech2(ChP,_INDX_DATA,0);
286   ChP->TxPrioCnt = ChOff + _TXP_CNT;
287   rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt);
288   rp_writech1(ChP,_INDX_DATA,0);
289   ChP->TxPrioPtr = ChOff + _TXP_PNTR;
290   rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioPtr);
291   rp_writech1(ChP,_INDX_DATA,0);
292   ChP->TxPrioBuf = ChOff + _TXP_BUF;
293   sEnRxProcessor(ChP); 	       /* start the Rx processor */
294
295   return(TRUE);
296}
297
298/***************************************************************************
299Function: sStopRxProcessor
300Purpose:  Stop the receive processor from processing a channel.
301Call:	  sStopRxProcessor(ChP)
302	  CHANNEL_T *ChP; Ptr to channel structure
303
304Comments: The receive processor can be started again with sStartRxProcessor().
305	  This function causes the receive processor to skip over the
306	  stopped channel.  It does not stop it from processing other channels.
307
308Warnings: No context switches are allowed while executing this function.
309
310	  Do not leave the receive processor stopped for more than one
311	  character time.
312
313	  After calling this function a delay of 4 uS is required to ensure
314	  that the receive processor is no longer processing this channel.
315*/
316void sStopRxProcessor(CHANNEL_T *ChP)
317{
318   Byte_t R[4];
319
320   R[0] = ChP->R[0];
321   R[1] = ChP->R[1];
322   R[2] = 0x0a;
323   R[3] = ChP->R[3];
324   rp_writech4(ChP, _INDX_ADDR,*(DWord_t *)&R[0]);
325}
326
327/***************************************************************************
328Function: sFlushRxFIFO
329Purpose:  Flush the Rx FIFO
330Call:	  sFlushRxFIFO(ChP)
331	  CHANNEL_T *ChP; Ptr to channel structure
332Return:   void
333Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
334	  while it is being flushed the receive processor is stopped
335	  and the transmitter is disabled.  After these operations a
336	  4 uS delay is done before clearing the pointers to allow
337	  the receive processor to stop.  These items are handled inside
338	  this function.
339Warnings: No context switches are allowed while executing this function.
340*/
341void sFlushRxFIFO(CHANNEL_T *ChP)
342{
343   int i;
344   Byte_t Ch;			/* channel number within AIOP */
345   int RxFIFOEnabled;		       /* TRUE if Rx FIFO enabled */
346
347   if(sGetRxCnt(ChP) == 0)	       /* Rx FIFO empty */
348      return;			       /* don't need to flush */
349
350   RxFIFOEnabled = FALSE;
351   if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
352   {
353      RxFIFOEnabled = TRUE;
354      sDisRxFIFO(ChP);		       /* disable it */
355      for(i=0; i < 2000/200; i++)	/* delay 2 uS to allow proc to disable FIFO*/
356	 rp_readch1(ChP,_INT_CHAN);		/* depends on bus i/o timing */
357   }
358   sGetChanStatus(ChP); 	 /* clear any pending Rx errors in chan stat */
359   Ch = (Byte_t)sGetChanNum(ChP);
360   rp_writech1(ChP,_CMD_REG,Ch | RESRXFCNT);     /* apply reset Rx FIFO count */
361   rp_writech1(ChP,_CMD_REG,Ch);		       /* remove reset Rx FIFO count */
362   rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
363   rp_writech2(ChP,_INDX_DATA,0);
364   rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
365   rp_writech2(ChP,_INDX_DATA,0);
366   if(RxFIFOEnabled)
367      sEnRxFIFO(ChP);		       /* enable Rx FIFO */
368}
369
370/***************************************************************************
371Function: sFlushTxFIFO
372Purpose:  Flush the Tx FIFO
373Call:	  sFlushTxFIFO(ChP)
374	  CHANNEL_T *ChP; Ptr to channel structure
375Return:   void
376Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
377	  while it is being flushed the receive processor is stopped
378	  and the transmitter is disabled.  After these operations a
379	  4 uS delay is done before clearing the pointers to allow
380	  the receive processor to stop.  These items are handled inside
381	  this function.
382Warnings: No context switches are allowed while executing this function.
383*/
384void sFlushTxFIFO(CHANNEL_T *ChP)
385{
386   int i;
387   Byte_t Ch;			/* channel number within AIOP */
388   int TxEnabled;		       /* TRUE if transmitter enabled */
389
390   if(sGetTxCnt(ChP) == 0)	       /* Tx FIFO empty */
391      return;			       /* don't need to flush */
392
393   TxEnabled = FALSE;
394   if(ChP->TxControl[3] & TX_ENABLE)
395   {
396      TxEnabled = TRUE;
397      sDisTransmit(ChP);	       /* disable transmitter */
398   }
399   sStopRxProcessor(ChP);	       /* stop Rx processor */
400   for(i = 0; i < 4000/200; i++)	 /* delay 4 uS to allow proc to stop */
401      rp_readch1(ChP,_INT_CHAN);	/* depends on bus i/o timing */
402   Ch = (Byte_t)sGetChanNum(ChP);
403   rp_writech1(ChP,_CMD_REG,Ch | RESTXFCNT);     /* apply reset Tx FIFO count */
404   rp_writech1(ChP,_CMD_REG,Ch);		       /* remove reset Tx FIFO count */
405   rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
406   rp_writech2(ChP,_INDX_DATA,0);
407   if(TxEnabled)
408      sEnTransmit(ChP); 	       /* enable transmitter */
409   sStartRxProcessor(ChP);	       /* restart Rx processor */
410}
411
412/***************************************************************************
413Function: sWriteTxPrioByte
414Purpose:  Write a byte of priority transmit data to a channel
415Call:	  sWriteTxPrioByte(ChP,Data)
416	  CHANNEL_T *ChP; Ptr to channel structure
417	  Byte_t Data; The transmit data byte
418
419Return:   int: 1 if the bytes is successfully written, otherwise 0.
420
421Comments: The priority byte is transmitted before any data in the Tx FIFO.
422
423Warnings: No context switches are allowed while executing this function.
424*/
425int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
426{
427   Byte_t DWBuf[4];		/* buffer for double word writes */
428   Word_t *WordPtr;	     /* must be far because Win SS != DS */
429
430   if(sGetTxCnt(ChP) > 1)	       /* write it to Tx priority buffer */
431   {
432      rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); /* get priority buffer status */
433      if(rp_readch1(ChP,_INDX_DATA) & PRI_PEND) /* priority buffer busy */
434	 return(0);		       /* nothing sent */
435
436      WordPtr = (Word_t *)(&DWBuf[0]);
437      *WordPtr = ChP->TxPrioBuf;       /* data byte address */
438
439      DWBuf[2] = Data;		       /* data byte value */
440      rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)(&DWBuf[0]))); /* write it out */
441
442      *WordPtr = ChP->TxPrioCnt;       /* Tx priority count address */
443
444      DWBuf[2] = PRI_PEND + 1;	       /* indicate 1 byte pending */
445      DWBuf[3] = 0;		       /* priority buffer pointer */
446      rp_writech4(ChP,_INDX_ADDR,*((DWord_t *)(&DWBuf[0]))); /* write it out */
447   }
448   else 			       /* write it to Tx FIFO */
449   {
450      sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data);
451   }
452   return(1);			       /* 1 byte sent */
453}
454
455/***************************************************************************
456Function: sEnInterrupts
457Purpose:  Enable one or more interrupts for a channel
458Call:	  sEnInterrupts(ChP,Flags)
459	  CHANNEL_T *ChP; Ptr to channel structure
460	  Word_t Flags: Interrupt enable flags, can be any combination
461	     of the following flags:
462		TXINT_EN:   Interrupt on Tx FIFO empty
463		RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
464			    sSetRxTrigger())
465		SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
466		MCINT_EN:   Interrupt on modem input change
467		CHANINT_EN: Allow channel interrupt signal to the AIOP's
468			    Interrupt Channel Register.
469Return:   void
470Comments: If an interrupt enable flag is set in Flags, that interrupt will be
471	  enabled.  If an interrupt enable flag is not set in Flags, that
472	  interrupt will not be changed.  Interrupts can be disabled with
473	  function sDisInterrupts().
474
475	  This function sets the appropriate bit for the channel in the AIOP's
476	  Interrupt Mask Register if the CHANINT_EN flag is set.  This allows
477	  this channel's bit to be set in the AIOP's Interrupt Channel Register.
478
479	  Interrupts must also be globally enabled before channel interrupts
480	  will be passed on to the host.  This is done with function
481	  sEnGlobalInt().
482
483	  In some cases it may be desirable to disable interrupts globally but
484	  enable channel interrupts.  This would allow the global interrupt
485	  status register to be used to determine which AIOPs need service.
486*/
487void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
488{
489   Byte_t Mask; 		/* Interrupt Mask Register */
490
491   ChP->RxControl[2] |=
492      ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
493
494   rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
495
496   ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
497
498   rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
499
500   if(Flags & CHANINT_EN)
501   {
502      Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum];
503      rp_writech1(ChP,_INT_MASK,Mask);
504   }
505}
506
507/***************************************************************************
508Function: sDisInterrupts
509Purpose:  Disable one or more interrupts for a channel
510Call:	  sDisInterrupts(ChP,Flags)
511	  CHANNEL_T *ChP; Ptr to channel structure
512	  Word_t Flags: Interrupt flags, can be any combination
513	     of the following flags:
514		TXINT_EN:   Interrupt on Tx FIFO empty
515		RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
516			    sSetRxTrigger())
517		SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
518		MCINT_EN:   Interrupt on modem input change
519		CHANINT_EN: Disable channel interrupt signal to the
520			    AIOP's Interrupt Channel Register.
521Return:   void
522Comments: If an interrupt flag is set in Flags, that interrupt will be
523	  disabled.  If an interrupt flag is not set in Flags, that
524	  interrupt will not be changed.  Interrupts can be enabled with
525	  function sEnInterrupts().
526
527	  This function clears the appropriate bit for the channel in the AIOP's
528	  Interrupt Mask Register if the CHANINT_EN flag is set.  This blocks
529	  this channel's bit from being set in the AIOP's Interrupt Channel
530	  Register.
531*/
532void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
533{
534   Byte_t Mask; 		/* Interrupt Mask Register */
535
536   ChP->RxControl[2] &=
537	 ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
538   rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->RxControl[0]);
539   ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
540   rp_writech4(ChP,_INDX_ADDR,*(DWord_t *)&ChP->TxControl[0]);
541
542   if(Flags & CHANINT_EN)
543   {
544      Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum];
545      rp_writech1(ChP,_INT_MASK,Mask);
546   }
547}
548
549/*********************************************************************
550  Begin FreeBsd-specific driver code
551**********************************************************************/
552
553struct callout_handle rp_callout_handle;
554
555static int	rp_num_ports_open = 0;
556static int	rp_ndevs = 0;
557
558static int rp_num_ports[4];	/* Number of ports on each controller */
559
560#define POLL_INTERVAL 1
561
562#define RP_ISMULTIPORT(dev)	((dev)->id_flags & 0x1)
563#define RP_MPMASTER(dev)	(((dev)->id_flags >> 8) & 0xff)
564#define RP_NOTAST4(dev) 	((dev)->id_flags & 0x04)
565
566static	struct	rp_port *p_rp_addr[4];
567static	struct	rp_port *p_rp_table[MAX_RP_PORTS];
568#define rp_addr(unit)	(p_rp_addr[unit])
569#define rp_table(port)	(p_rp_table[port])
570
571/*
572 * The top-level routines begin here
573 */
574
575static	void	rpbreak(struct tty *, int);
576static	void	rpclose(struct tty *tp);
577static	int	rpmodem(struct tty *, int, int);
578static	int	rpparam(struct tty *, struct termios *);
579static	void	rpstart(struct tty *);
580static	void	rpstop(struct tty *, int);
581static	t_open_t	rpopen;
582
583static void rp_do_receive(struct rp_port *rp, struct tty *tp,
584			CHANNEL_t *cp, unsigned int ChanStatus)
585{
586	int	spl;
587	unsigned	int	CharNStat;
588	int	ToRecv, wRecv, ch, ttynocopy;
589
590	ToRecv = sGetRxCnt(cp);
591	if(ToRecv == 0)
592		return;
593
594/*	If status indicates there are errored characters in the
595	FIFO, then enter status mode (a word in FIFO holds
596	characters and status)
597*/
598
599	if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
600		if(!(ChanStatus & STATMODE)) {
601			ChanStatus |= STATMODE;
602			sEnRxStatusMode(cp);
603		}
604	}
605/*
606	if we previously entered status mode then read down the
607	FIFO one word at a time, pulling apart the character and
608	the status. Update error counters depending on status.
609*/
610	if(ChanStatus & STATMODE) {
611		while(ToRecv) {
612			if(tp->t_state & TS_TBLOCK) {
613				break;
614			}
615			CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
616			ch = CharNStat & 0xff;
617
618			if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
619				ch |= TTY_FE;
620			else if (CharNStat & STMPARITYH)
621				ch |= TTY_PE;
622			else if (CharNStat & STMRCVROVRH)
623				rp->rp_overflows++;
624
625			ttyld_rint(tp, ch);
626			ToRecv--;
627		}
628/*
629	After emtying FIFO in status mode, turn off status mode
630*/
631
632		if(sGetRxCnt(cp) == 0) {
633			sDisRxStatusMode(cp);
634		}
635	} else {
636		/*
637		 * Avoid the grotesquely inefficient lineswitch routine
638		 * (ttyinput) in "raw" mode.  It usually takes about 450
639		 * instructions (that's without canonical processing or echo!).
640		 * slinput is reasonably fast (usually 40 instructions plus
641		 * call overhead).
642		 */
643		ToRecv = sGetRxCnt(cp);
644		if ( tp->t_state & TS_CAN_BYPASS_L_RINT ) {
645			if ( ToRecv > RXFIFO_SIZE ) {
646				ToRecv = RXFIFO_SIZE;
647			}
648			wRecv = ToRecv >> 1;
649			if ( wRecv ) {
650				rp_readmultich2(cp,sGetTxRxDataIO(cp),(u_int16_t *)rp->RxBuf,wRecv);
651			}
652			if ( ToRecv & 1 ) {
653				((unsigned char *)rp->RxBuf)[(ToRecv-1)] = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
654			}
655			tk_nin += ToRecv;
656			tk_rawcc += ToRecv;
657			tp->t_rawcc += ToRecv;
658			ttynocopy = b_to_q((char *)rp->RxBuf, ToRecv, &tp->t_rawq);
659			ttwakeup(tp);
660		} else {
661			while (ToRecv) {
662				if(tp->t_state & TS_TBLOCK) {
663					break;
664				}
665				ch = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp));
666				spl = spltty();
667				ttyld_rint(tp, ch);
668				splx(spl);
669				ToRecv--;
670			}
671		}
672	}
673}
674
675static void rp_handle_port(struct rp_port *rp)
676{
677	CHANNEL_t	*cp;
678	struct	tty	*tp;
679	unsigned	int	IntMask, ChanStatus;
680
681	if(!rp)
682		return;
683
684	cp = &rp->rp_channel;
685	tp = rp->rp_tty;
686	IntMask = sGetChanIntID(cp);
687	IntMask = IntMask & rp->rp_intmask;
688	ChanStatus = sGetChanStatus(cp);
689	if(IntMask & RXF_TRIG)
690		if(!(tp->t_state & TS_TBLOCK) && (tp->t_state & TS_CARR_ON) && (tp->t_state & TS_ISOPEN)) {
691			rp_do_receive(rp, tp, cp, ChanStatus);
692		}
693	if(IntMask & DELTA_CD) {
694		if(ChanStatus & CD_ACT) {
695			if(!(tp->t_state & TS_CARR_ON) ) {
696				(void)ttyld_modem(tp, 1);
697			}
698		} else {
699			if((tp->t_state & TS_CARR_ON)) {
700				(void)ttyld_modem(tp, 0);
701				if(ttyld_modem(tp, 0) == 0) {
702					rpclose(tp);
703				}
704			}
705		}
706	}
707/*	oldcts = rp->rp_cts;
708	rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
709	if(oldcts != rp->rp_cts) {
710		printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
711	}
712*/
713}
714
715static void rp_do_poll(void *not_used)
716{
717	CONTROLLER_t	*ctl;
718	struct rp_port	*rp;
719	struct tty	*tp;
720	int	unit, aiop, ch, line, count;
721	unsigned char	CtlMask, AiopMask;
722
723	for(unit = 0; unit < rp_ndevs; unit++) {
724	rp = rp_addr(unit);
725	ctl = rp->rp_ctlp;
726	CtlMask = ctl->ctlmask(ctl);
727	for(aiop=0; CtlMask; CtlMask >>=1, aiop++) {
728		if(CtlMask & 1) {
729			AiopMask = sGetAiopIntStatus(ctl, aiop);
730			for(ch = 0; AiopMask; AiopMask >>=1, ch++) {
731				if(AiopMask & 1) {
732					line = (unit << 5) | (aiop << 3) | ch;
733					rp = rp_table(line);
734					rp_handle_port(rp);
735				}
736			}
737		}
738	}
739
740	for(line = 0, rp = rp_addr(unit); line < rp_num_ports[unit];
741			line++, rp++) {
742		tp = rp->rp_tty;
743		if((tp->t_state & TS_BUSY) && (tp->t_state & TS_ISOPEN)) {
744			count = sGetTxCnt(&rp->rp_channel);
745			if(count == 0)
746				tp->t_state &= ~(TS_BUSY);
747			if(!(tp->t_state & TS_TTSTOP) &&
748				(count <= rp->rp_restart)) {
749				ttyld_start(tp);
750			}
751		}
752	}
753	}
754	if(rp_num_ports_open)
755		rp_callout_handle = timeout(rp_do_poll,
756					    (void *)NULL, POLL_INTERVAL);
757}
758
759int
760rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
761{
762	int	oldspl, unit;
763	int	num_chan;
764	int	aiop, chan, port;
765	int	ChanStatus, line, count;
766	int	retval;
767	struct	rp_port *rp;
768	struct tty *tp;
769
770	unit = device_get_unit(ctlp->dev);
771
772	printf("RocketPort%d (Version %s) %d ports.\n", unit,
773		RocketPortVersion, num_ports);
774	rp_num_ports[unit] = num_ports;
775	callout_handle_init(&rp_callout_handle);
776
777	ctlp->rp = rp = (struct rp_port *)
778		malloc(sizeof(struct rp_port) * num_ports, M_TTYS, M_NOWAIT | M_ZERO);
779	if (rp == NULL) {
780		device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n");
781		retval = ENOMEM;
782		goto nogo;
783	}
784
785	count = unit * 32;      /* board times max ports per card SG */
786
787	bzero(rp, sizeof(struct rp_port) * num_ports);
788	oldspl = spltty();
789	rp_addr(unit) = rp;
790	splx(oldspl);
791
792	port = 0;
793	for(aiop=0; aiop < num_aiops; aiop++) {
794		num_chan = sGetAiopNumChan(ctlp, aiop);
795		for(chan=0; chan < num_chan; chan++, port++, rp++) {
796			tp = rp->rp_tty = ttyalloc();
797			tp->t_sc = rp;
798			tp->t_param = rpparam;
799			tp->t_oproc = rpstart;
800			tp->t_stop = rpstop;
801			tp->t_break = rpbreak;
802			tp->t_modem = rpmodem;
803			tp->t_close = rpclose;
804			tp->t_open = rpopen;
805			tp->t_ififosize = 512;
806			tp->t_ispeedwat = (speed_t)-1;
807			tp->t_ospeedwat = (speed_t)-1;
808			rp->rp_port = port;
809			rp->rp_ctlp = ctlp;
810			rp->rp_unit = unit;
811			rp->rp_chan = chan;
812			rp->rp_aiop = aiop;
813
814			rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
815				DELTA_CD | DELTA_CTS | DELTA_DSR;
816#ifdef notdef
817			ChanStatus = sGetChanStatus(&rp->rp_channel);
818#endif /* notdef */
819			if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
820				device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
821					      unit, aiop, chan);
822				retval = ENXIO;
823				goto nogo;
824			}
825			ChanStatus = sGetChanStatus(&rp->rp_channel);
826			rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
827			line = (unit << 5) | (aiop << 3) | chan;
828			rp_table(line) = rp;
829			ttycreate(tp, TS_CALLOUT, "R%r%r", unit, port);
830		}
831	}
832
833	rp_ndevs++;
834	return (0);
835
836nogo:
837	rp_releaseresource(ctlp);
838
839	return (retval);
840}
841
842void
843rp_releaseresource(CONTROLLER_t *ctlp)
844{
845	int i, s, unit;
846	struct	rp_port *rp;
847
848
849	unit = device_get_unit(ctlp->dev);
850	if (rp_addr(unit) != NULL) {
851		for (i = 0; i < rp_num_ports[unit]; i++) {
852			rp = rp_addr(unit) + i;
853			ttyfree(rp->rp_tty);
854		}
855	}
856
857	if (ctlp->rp != NULL) {
858		s = spltty();
859		for (i = 0 ; i < sizeof(p_rp_addr) / sizeof(*p_rp_addr) ; i++)
860			if (p_rp_addr[i] == ctlp->rp)
861				p_rp_addr[i] = NULL;
862		for (i = 0 ; i < sizeof(p_rp_table) / sizeof(*p_rp_table) ; i++)
863			if (p_rp_table[i] == ctlp->rp)
864				p_rp_table[i] = NULL;
865		splx(s);
866		free(ctlp->rp, M_DEVBUF);
867		ctlp->rp = NULL;
868	}
869}
870
871void
872rp_untimeout(void)
873{
874	untimeout(rp_do_poll, (void *)NULL, rp_callout_handle);
875}
876
877static int
878rpopen(struct tty *tp, struct cdev *dev)
879{
880	struct	rp_port *rp;
881	int	oldspl, flags;
882	unsigned int	IntMask, ChanStatus;
883
884	rp = dev->si_drv1;
885
886	oldspl = spltty();
887
888	flags = 0;
889	flags |= SET_RTS;
890	flags |= SET_DTR;
891	rp->rp_channel.TxControl[3] =
892		((rp->rp_channel.TxControl[3]
893		& ~(SET_RTS | SET_DTR)) | flags);
894	rp_writech4(&rp->rp_channel,_INDX_ADDR,
895		*(DWord_t *) &(rp->rp_channel.TxControl[0]));
896	sSetRxTrigger(&rp->rp_channel, TRIG_1);
897	sDisRxStatusMode(&rp->rp_channel);
898	sFlushRxFIFO(&rp->rp_channel);
899	sFlushTxFIFO(&rp->rp_channel);
900
901	sEnInterrupts(&rp->rp_channel,
902		(TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
903	sSetRxTrigger(&rp->rp_channel, TRIG_1);
904
905	sDisRxStatusMode(&rp->rp_channel);
906	sClrTxXOFF(&rp->rp_channel);
907
908/*	sDisRTSFlowCtl(&rp->rp_channel);
909	sDisCTSFlowCtl(&rp->rp_channel);
910*/
911	sDisTxSoftFlowCtl(&rp->rp_channel);
912
913	sStartRxProcessor(&rp->rp_channel);
914
915	sEnRxFIFO(&rp->rp_channel);
916	sEnTransmit(&rp->rp_channel);
917
918/*	sSetDTR(&rp->rp_channel);
919	sSetRTS(&rp->rp_channel);
920*/
921
922	rp_num_ports_open++;
923
924	IntMask = sGetChanIntID(&rp->rp_channel);
925	IntMask = IntMask & rp->rp_intmask;
926	ChanStatus = sGetChanStatus(&rp->rp_channel);
927
928	if(rp_num_ports_open == 1)
929		rp_callout_handle = timeout(rp_do_poll,
930					    (void *)NULL, POLL_INTERVAL);
931
932	device_busy(rp->rp_ctlp->dev);
933	return(0);
934}
935
936static void
937rpclose(struct tty *tp)
938{
939	struct	rp_port	*rp;
940	CHANNEL_t	*cp;
941
942	rp = tp->t_sc;
943	cp = &rp->rp_channel;
944
945	sFlushRxFIFO(cp);
946	sFlushTxFIFO(cp);
947	sDisTransmit(cp);
948	sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
949	sDisRTSFlowCtl(cp);
950	sDisCTSFlowCtl(cp);
951	sDisTxSoftFlowCtl(cp);
952	sClrTxXOFF(cp);
953
954	if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) {
955		sClrDTR(cp);
956	}
957	if(ISCALLOUT(tp->t_dev)) {
958		sClrDTR(cp);
959	}
960	tp->t_actout = FALSE;
961	wakeup(&tp->t_actout);
962	wakeup(TSA_CARR_ON(tp));
963	device_unbusy(rp->rp_ctlp->dev);
964}
965
966static void
967rpbreak(struct tty *tp, int sig)
968{
969	struct rp_port	*rp;
970
971	rp = tp->t_sc;
972	if (sig) {
973		sSendBreak(&rp->rp_channel);
974	} else {
975		sClrBreak(&rp->rp_channel);
976	}
977}
978
979static int
980rpmodem(struct tty *tp, int sigon, int sigoff)
981{
982	struct rp_port	*rp;
983	int i, j, k;
984
985	rp = tp->t_sc;
986	if (sigon != 0 || sigoff != 0) {
987		i = j = 0;
988		if (sigon & SER_DTR)
989			i = SET_DTR;
990		if (sigoff & SER_DTR)
991			j = SET_DTR;
992		if (sigon & SER_RTS)
993			i = SET_RTS;
994		if (sigoff & SER_RTS)
995			j = SET_RTS;
996		rp->rp_channel.TxControl[3] &= ~i;
997		rp->rp_channel.TxControl[3] |= j;
998		rp_writech4(&rp->rp_channel,_INDX_ADDR,
999			*(DWord_t *) &(rp->rp_channel.TxControl[0]));
1000	} else {
1001		i = sGetChanStatusLo(&rp->rp_channel);
1002		j = rp->rp_channel.TxControl[3];
1003		k = 0;
1004		if (j & SET_DTR)
1005			k |= SER_DTR;
1006		if (j & SET_RTS)
1007			k |= SER_RTS;
1008		if (i & CD_ACT)
1009			k |= SER_DCD;
1010		if (i & DSR_ACT)
1011			k |= SER_DSR;
1012		if (i & CTS_ACT)
1013			k |= SER_CTS;
1014		return(k);
1015	}
1016	return (0);
1017}
1018
1019static struct speedtab baud_table[] = {
1020	{B0,	0},		{B50,	BRD50},		{B75,	BRD75},
1021	{B110,	BRD110}, 	{B134,	BRD134}, 	{B150,	BRD150},
1022	{B200,	BRD200}, 	{B300,	BRD300}, 	{B600,	BRD600},
1023	{B1200,	BRD1200},	{B1800,	BRD1800},	{B2400,	BRD2400},
1024	{B4800,	BRD4800},	{B9600,	BRD9600},	{B19200, BRD19200},
1025	{B38400, BRD38400},	{B7200,	BRD7200},	{B14400, BRD14400},
1026				{B57600, BRD57600},	{B76800, BRD76800},
1027	{B115200, BRD115200},	{B230400, BRD230400},
1028	{-1,	-1}
1029};
1030
1031static int
1032rpparam(tp, t)
1033	struct tty *tp;
1034	struct termios *t;
1035{
1036	struct rp_port	*rp;
1037	CHANNEL_t	*cp;
1038	int	oldspl, cflag, iflag, oflag, lflag;
1039	int	ospeed;
1040#ifdef RPCLOCAL
1041	int	devshift;
1042#endif
1043
1044
1045	rp = tp->t_sc;
1046	cp = &rp->rp_channel;
1047	oldspl = spltty();
1048
1049	cflag = t->c_cflag;
1050#ifdef RPCLOCAL
1051	devshift = umynor / 32;
1052	devshift = 1 << devshift;
1053	if ( devshift & RPCLOCAL ) {
1054		cflag |= CLOCAL;
1055	}
1056#endif
1057	iflag = t->c_iflag;
1058	oflag = t->c_oflag;
1059	lflag = t->c_lflag;
1060
1061	ospeed = ttspeedtab(t->c_ispeed, baud_table);
1062	if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1063		return(EINVAL);
1064
1065	tp->t_ispeed = t->c_ispeed;
1066	tp->t_ospeed = t->c_ospeed;
1067	tp->t_cflag = cflag;
1068	tp->t_iflag = iflag;
1069	tp->t_oflag = oflag;
1070	tp->t_lflag = lflag;
1071
1072	if(t->c_ospeed == 0) {
1073		sClrDTR(cp);
1074		return(0);
1075	}
1076	rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1077
1078	/* Set baud rate ----- we only pay attention to ispeed */
1079	sSetDTR(cp);
1080	sSetRTS(cp);
1081	sSetBaud(cp, ospeed);
1082
1083	if(cflag & CSTOPB) {
1084		sSetStop2(cp);
1085	} else {
1086		sSetStop1(cp);
1087	}
1088
1089	if(cflag & PARENB) {
1090		sEnParity(cp);
1091		if(cflag & PARODD) {
1092			sSetOddParity(cp);
1093		} else {
1094			sSetEvenParity(cp);
1095		}
1096	}
1097	else {
1098		sDisParity(cp);
1099	}
1100	if((cflag & CSIZE) == CS8) {
1101		sSetData8(cp);
1102		rp->rp_imask = 0xFF;
1103	} else {
1104		sSetData7(cp);
1105		rp->rp_imask = 0x7F;
1106	}
1107
1108	if(iflag & ISTRIP) {
1109		rp->rp_imask &= 0x7F;
1110	}
1111
1112	if(cflag & CLOCAL) {
1113		rp->rp_intmask &= ~DELTA_CD;
1114	} else {
1115		rp->rp_intmask |= DELTA_CD;
1116	}
1117
1118	/* Put flow control stuff here */
1119
1120	if(cflag & CCTS_OFLOW) {
1121		sEnCTSFlowCtl(cp);
1122	} else {
1123		sDisCTSFlowCtl(cp);
1124	}
1125
1126	if(cflag & CRTS_IFLOW) {
1127		rp->rp_rts_iflow = 1;
1128	} else {
1129		rp->rp_rts_iflow = 0;
1130	}
1131
1132	if(cflag & CRTS_IFLOW) {
1133		sEnRTSFlowCtl(cp);
1134	} else {
1135		sDisRTSFlowCtl(cp);
1136	}
1137	ttyldoptim(tp);
1138
1139	if((cflag & CLOCAL) || (sGetChanStatusLo(cp) & CD_ACT)) {
1140		tp->t_state |= TS_CARR_ON;
1141		wakeup(TSA_CARR_ON(tp));
1142	}
1143
1144/*	tp->t_state |= TS_CAN_BYPASS_L_RINT;
1145	flags = rp->rp_channel.TxControl[3];
1146	if(flags & SET_DTR)
1147	else
1148	if(flags & SET_RTS)
1149	else
1150*/
1151	splx(oldspl);
1152
1153	return(0);
1154}
1155
1156static void
1157rpstart(tp)
1158	struct tty *tp;
1159{
1160	struct rp_port	*rp;
1161	CHANNEL_t	*cp;
1162	struct	clist	*qp;
1163	char	flags;
1164	int	spl, xmit_fifo_room;
1165	int	count, wcount;
1166
1167
1168	rp = tp->t_sc;
1169	cp = &rp->rp_channel;
1170	flags = rp->rp_channel.TxControl[3];
1171	spl = spltty();
1172
1173	if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
1174		ttwwakeup(tp);
1175		splx(spl);
1176		return;
1177	}
1178	if(rp->rp_xmit_stopped) {
1179		sEnTransmit(cp);
1180		rp->rp_xmit_stopped = 0;
1181	}
1182	count = sGetTxCnt(cp);
1183
1184	if(tp->t_outq.c_cc == 0) {
1185		if((tp->t_state & TS_BUSY) && (count == 0)) {
1186			tp->t_state &= ~TS_BUSY;
1187		}
1188		ttwwakeup(tp);
1189		splx(spl);
1190		return;
1191	}
1192	xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1193	qp = &tp->t_outq;
1194	if(xmit_fifo_room > 0 && qp->c_cc > 0) {
1195		tp->t_state |= TS_BUSY;
1196		count = q_to_b( qp, (char *)rp->TxBuf, xmit_fifo_room );
1197		wcount = count >> 1;
1198		if ( wcount ) {
1199			rp_writemultich2(cp, sGetTxRxDataIO(cp), (u_int16_t *)rp->TxBuf, wcount);
1200		}
1201		if ( count & 1 ) {
1202			rp_writech1(cp, sGetTxRxDataIO(cp),
1203				    ((unsigned char *)(rp->TxBuf))[(count-1)]);
1204		}
1205	}
1206	rp->rp_restart = (qp->c_cc > 0) ? rp->rp_fifo_lw : 0;
1207
1208	ttwwakeup(tp);
1209	splx(spl);
1210}
1211
1212static
1213void
1214rpstop(tp, flag)
1215	register struct tty *tp;
1216	int	flag;
1217{
1218	struct rp_port	*rp;
1219	CHANNEL_t	*cp;
1220	int	spl;
1221
1222	rp = tp->t_sc;
1223	cp = &rp->rp_channel;
1224
1225	spl = spltty();
1226
1227	if(tp->t_state & TS_BUSY) {
1228		if((tp->t_state&TS_TTSTOP) == 0) {
1229			sFlushTxFIFO(cp);
1230		} else {
1231			if(rp->rp_xmit_stopped == 0) {
1232				sDisTransmit(cp);
1233				rp->rp_xmit_stopped = 1;
1234			}
1235		}
1236	}
1237	splx(spl);
1238	rpstart(tp);
1239}
1240