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